Vue3 は ThreeJS を統合して 3D 効果を実現、threejs+Vite+Vue3+TypeScript 実践講座【一記事で極めるシリーズ】

1. プロジェクトの初期化

npm install -g vite


npm init vite@latest threejs-vite-vue -- --template vue


cd threejs-vite-vue

npm install

npm run dev

プロジェクトは正常に作成されました。threejs
ここに画像の説明を挿入しますのバージョンに注目してください。

ここに画像の説明を挿入します "@types/three": "^0.155.1",

プロジェクトが正常に作成され、プロジェクトが IDE にインポートされます。

1. いくつかの依存関係を追加します

npm install vue-router

npm install three

npm install @types/three -D

npm install ant-design-vue

ここに画像の説明を挿入しますここに画像の説明を挿入しますルーティング関連の作成
ここに画像の説明を挿入しますここに画像の説明を挿入しますここに画像の説明を挿入します

import {
    
    createRouter,createWebHistory,RouteRecordRaw} from "vue-router";
const routes: RouteRecordRaw[] = [
]
const router = createRouter({
    
    
    history:createWebHistory(),
    routes
})
router.beforeEach((to)=>{
    
    
    document.title = 'three+vite+vue3'+to.meta.title as string
})

export default router

ここに画像の説明を挿入します

import {
    
     createApp } from 'vue'
import './style.css';
import Antd from 'ant-design-vue';
import App from './App.vue';
import router from './router/index';
import 'ant-design-vue/dist/reset.css';

let app = createApp(App)
app.use(router)
app.use(Antd)
app.mount('#app')

ここに画像の説明を挿入しますここに画像の説明を挿入します

import {
    
    RouteRecordRaw} from "vue-router";
const chapter1 : RouteRecordRaw[] = [
]

export default chapter1;

ここに画像の説明を挿入します

import {
    
    createRouter,createWebHistory,RouteRecordRaw} from "vue-router";
import chapter1 from "./chapter1";
const routes: RouteRecordRaw[] = [
    ...chapter1
]
const router = createRouter({
    
    
    history:createWebHistory(),
    routes
})
export default router

ここに画像の説明を挿入します

<template>
  <router-view></router-view>
</template>
<script setup>
</script>
<style scoped>
</style>

ここに画像の説明を挿入します

<template>
  <div>
    第一个场景
  </div>
</template>
<script>
export default {
    
    
  name: "index"
}
</script>
<style scoped>
</style>

2. 3Dの作成

ここに画像の説明を挿入します

.container{
    
    
    width: 100vw;
    height: 100vh;
}

1. ボード、立方体、球を描く

ここに画像の説明を挿入します

<template>
  <div ref="containerRef" class="container">
  </div>
</template>
<script lang="ts" setup>
import {
    
    onMounted, ref} from "vue";
import {
    
    
  AxesHelper, BoxGeometry,
  Color,
  Mesh,
  MeshBasicMaterial,
  PerspectiveCamera,
  PlaneGeometry,
  Scene, SphereGeometry,
  WebGLRenderer
} from "three";

const containerRef = ref<HTMLDivElement>()
//创建场景
const scene = new Scene();
//创建摄像机
const camera = new PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000)
//设置摄像机位置
camera.position.set(-30,40,30)
//设置摄像机朝向
camera.lookAt(scene.position)

//重置webGL的颜色
const renderer =  new WebGLRenderer();
renderer.setClearColor(new Color(0xeeeeee))
renderer.setSize(window.innerWidth,window.innerHeight)

//添加坐标系
const ases = new AxesHelper(20)
scene.add(ases)

//绘制板子,设置板子的宽度为60,设置板子的高度为20
const planeGeometry = new PlaneGeometry(60,20);
const meshBasicMaterial = new MeshBasicMaterial({
    
    color:0xcccccc});//设置材质颜色
const plane = new Mesh(planeGeometry,meshBasicMaterial)

plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 15
plane.position.y = 0
plane.position.z = 0
scene.add(plane)

//绘制立方体,设置板子的长宽高分别是4,4,4
const cubeGeometry = new BoxGeometry(4,4,4)
const cubeMaterial = new MeshBasicMaterial({
    
    color:0xff0000,wireframe:true})
const cube = new Mesh(cubeGeometry,cubeMaterial)
cube.position.set(2,2,2)
scene.add(cube)

//绘制球体,设置球体的半径为4
const sphereGeometry = new SphereGeometry(4)
const sphereMaterial = new MeshBasicMaterial({
    
    
  color: 0x7777ff,
  wireframe:true
})
const sphere = new Mesh(sphereGeometry,sphereMaterial)
sphere.position.x = 15
sphere.position.y = 4
sphere.position.z = 2
scene.add(sphere)

onMounted(()=>{
    
    
  //设置摄像头朝向
  containerRef.value?.appendChild(renderer.domElement)
  renderer.render(scene,camera)
})

</script>
<style scoped>

</style>

ここに画像の説明を挿入します

2. 素材と照明

ナビゲーション メニュー コンポーネントを設定する
ここに画像の説明を挿入します

<template>
  <a-menu mode="horizontal" style="position: fixed">
    <a-sub-menu key="demo">
      <template #title>
        第一章
      </template>
      <a-menu-item key="1">
        <router-link to="/"> 第一个场景 </router-link>
      </a-menu-item>
      <a-menu-item key="2">
        <router-link to="/chapter1/2"> 第一个场景 </router-link>
      </a-menu-item>
    </a-sub-menu>
  </a-menu>
  <router-view></router-view>
</template>
<script setup>
</script>
<style scoped>
</style>

インデックスをコピーしてインデックス2を生成する
ここに画像の説明を挿入します

<template>
  <div ref="containerRef" class="container">
  </div>
</template>
<script lang="ts" setup>
import {
      
      onMounted, ref} from "vue";
import {
      
      
  AxesHelper, BoxGeometry,
  Color,
  Mesh,
  MeshBasicMaterial,
  PerspectiveCamera,
  PlaneGeometry,
  Scene, SphereGeometry,
  WebGLRenderer
} from "three";

const containerRef = ref<HTMLDivElement>()
//创建场景
const scene = new Scene();
//创建摄像机
const camera = new PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000)
//设置摄像机位置
camera.position.set(-30,40,30)
//设置摄像机朝向
camera.lookAt(scene.position)

//重置webGL的颜色
const renderer =  new WebGLRenderer();
renderer.setClearColor(new Color(0xeeeeee))
renderer.setSize(window.innerWidth,window.innerHeight)

//添加坐标系
const ases = new AxesHelper(20)
scene.add(ases)

//绘制板子,设置板子的宽度为60,设置板子的高度为20
const planeGeometry = new PlaneGeometry(60,20);
const meshBasicMaterial = new MeshBasicMaterial({
      
      color:0xcccccc});//设置材质颜色
const plane = new Mesh(planeGeometry,meshBasicMaterial)

plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 15
plane.position.y = 0
plane.position.z = 0
scene.add(plane)

//绘制立方体,设置板子的长宽高分别是4,4,4
const cubeGeometry = new BoxGeometry(4,4,4)
const cubeMaterial = new MeshBasicMaterial({
      
      color:0xff0000,wireframe:true})
const cube = new Mesh(cubeGeometry,cubeMaterial)
cube.position.set(2,2,2)
scene.add(cube)

//绘制球体,设置球体的半径为4
const sphereGeometry = new SphereGeometry(4)
const sphereMaterial = new MeshBasicMaterial({
      
      
  color: 0x7777ff,
  wireframe:true
})
const sphere = new Mesh(sphereGeometry,sphereMaterial)
sphere.position.x = 15
sphere.position.y = 4
sphere.position.z = 2
scene.add(sphere)

onMounted(()=>{
      
      
  //设置摄像头朝向
  containerRef.value?.appendChild(renderer.domElement)
  renderer.render(scene,camera)
})






</script>
<style scoped>

</style>

ここに画像の説明を挿入します

import {
    
    RouteRecordRaw} from "vue-router";
import Index from '../lesson/chapter1/index.vue'
import Index2 from '../lesson/chapter1/index2.vue'

const chapter1 : RouteRecordRaw[] = [
    {
    
    
        path:'/',
        component: Index,
        meta:{
    
    
            title:"第一个场景"
        }
    },
    {
    
    
        path:'/chapter1/2',
        component: Index2,
        meta:{
    
    
            title:"第二个场景"
        }
    }
]
export default chapter1;

2 番目のシナリオを実装する

<template>
  <div ref="containerRef" class="container">
  </div>
</template>
<script lang="ts" setup>
import {
      
      onMounted, ref} from "vue";
import {
      
      
  AxesHelper, BoxGeometry,
  Color,
  Mesh,
  MeshBasicMaterial, MeshLambertMaterial,
  PerspectiveCamera,
  PlaneGeometry,
  Scene, SphereGeometry, SpotLight,
  WebGLRenderer
} from "three";

const containerRef = ref<HTMLDivElement>()
//创建场景
const scene = new Scene();
//创建摄像机
const camera = new PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000)
//设置摄像机位置
camera.position.set(-30,40,30)
//设置摄像机朝向
camera.lookAt(scene.position)

//重置webGL的颜色
const renderer =  new WebGLRenderer();
renderer.setClearColor(new Color(0xeeeeee))
renderer.setSize(window.innerWidth,window.innerHeight)
renderer.shadowMap.enabled = true

const spotLight = new SpotLight(0xffffff)
spotLight.castShadow = true
spotLight.position.set(-40,60,-10)
scene.add(spotLight)

//添加坐标系
const axes = new AxesHelper(20)
scene.add(axes)

//绘制板子,设置板子的宽度为60,设置板子的高度为20
const planeGeometry = new PlaneGeometry(60,20);
const meshBasicMaterial = new MeshLambertMaterial({
      
      color:0xcccccc});//设置材质颜色
const plane = new Mesh(planeGeometry,meshBasicMaterial)
plane.receiveShadow = true //设置可以接收阴影
plane.rotation.x = -0.5 * Math.PI;
//plane.position.x = 15
//plane.position.y = 0
//plane.position.z = 0

scene.add(plane)


//绘制立方体,设置板子的长宽高分别是4,4,4
const cubeGeometry = new BoxGeometry(4,4,4)
const cubeMaterial = new MeshLambertMaterial({
      
      color:0xff0000,wireframe:false})
const cube = new Mesh(cubeGeometry,cubeMaterial)
cube.castShadow = true
cube.position.set(2,2,2)
scene.add(cube)

//绘制球体,设置球体的半径为4
const sphereGeometry = new SphereGeometry(4)
const sphereMaterial = new MeshLambertMaterial({
      
      
  color: 0x7777ff,
  wireframe:false
})

const sphere = new Mesh(sphereGeometry,sphereMaterial)
sphere.castShadow = true
sphere.position.x = 15
sphere.position.y = 4
sphere.position.z = 2
scene.add(sphere)

onMounted(()=>{
      
      
  //设置摄像头朝向
  containerRef.value?.appendChild(renderer.domElement)
  renderer.render(scene,camera)
})

</script>
<style scoped>

</style>

ここに画像の説明を挿入します

3. 素材、照明、アニメーション

インデックス 2 をコピーしてインデックス 3 を作成する
ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します

<template>
  <div ref="containerRef" class="container">
  </div>
</template>
<script lang="ts" setup>
import {
      
      onMounted, ref} from "vue";
import {
      
      
  AxesHelper, BoxGeometry,
  Color,
  Mesh,
  MeshBasicMaterial, MeshLambertMaterial,
  PerspectiveCamera,
  PlaneGeometry,
  Scene, SphereGeometry, SpotLight,
  WebGLRenderer
} from "three";

const containerRef = ref<HTMLDivElement>()
//创建场景
const scene = new Scene();
//创建摄像机
const camera = new PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000)
//设置摄像机位置
camera.position.set(-30,40,30)
//设置摄像机朝向
camera.lookAt(scene.position)

//重置webGL的颜色
const renderer =  new WebGLRenderer();
renderer.setClearColor(new Color(0xeeeeee))
renderer.setSize(window.innerWidth,window.innerHeight)
renderer.shadowMap.enabled = true

const spotLight = new SpotLight(0xffffff)
spotLight.castShadow = true
spotLight.position.set(-40,60,-10)
scene.add(spotLight)

//添加坐标系
const axes = new AxesHelper(20)
scene.add(axes)

//绘制板子,设置板子的宽度为60,设置板子的高度为20
const planeGeometry = new PlaneGeometry(100,50);
const meshBasicMaterial = new MeshLambertMaterial({
      
      color:0xcccccc});//设置材质颜色
const plane = new Mesh(planeGeometry,meshBasicMaterial)
plane.receiveShadow = true //设置可以接收阴影
plane.rotation.x = -0.5 * Math.PI;
//plane.position.x = 15
//plane.position.y = 0
//plane.position.z = 0

scene.add(plane)


//绘制立方体,设置板子的长宽高分别是4,4,4
const cubeGeometry = new BoxGeometry(4,4,4)
const cubeMaterial = new MeshLambertMaterial({
      
      color:0xff0000,wireframe:false})
const cube = new Mesh(cubeGeometry,cubeMaterial)
cube.castShadow = true
cube.position.set(2,2,2)
scene.add(cube)


//绘制立方体,设置板子的长宽高分别是4,4,4
const cubeGeometry1 = new BoxGeometry(4,4,4)
const cubeMaterial1 = new MeshLambertMaterial({
      
      color:0xff0000,wireframe:false})
const cube1 = new Mesh(cubeGeometry1,cubeMaterial1)
cube1.castShadow = true
cube1.position.set(-10,2,2)
scene.add(cube1)



//绘制球体,设置球体的半径为4
const sphereGeometry = new SphereGeometry(4)
const sphereMaterial = new MeshLambertMaterial({
      
      
  color: 0x7777ff,
  wireframe:false
})

const sphere = new Mesh(sphereGeometry,sphereMaterial)
sphere.castShadow = true
sphere.position.x = 15
sphere.position.y = 4
sphere.position.z = 2
scene.add(sphere)


//控制物体运动
let step = 0;

function renderScene() {
      
      
  step += 0.04;

  cube.rotation.x += 0.02;
  cube.rotation.y += 0.02;
  cube.rotation.z += 0.02;

  cube1.rotation.x += -0.02;
  cube1.rotation.y += -0.02;
  cube1.rotation.z += -0.02;
  cube1.scale.set((2 + 1 * Math.cos(step)), (2 + 1 * Math.cos(step)), (2 + 1 * Math.cos(step)));

  //控制物体
  sphere.position.x = 20 + 10 * Math.cos(step); //cos为数据当中的函数 余弦函数
  sphere.position.y = 2 + 10 * Math.abs(Math.sin(step));  //abs为绝对值  sin为正弦函数

  requestAnimationFrame(renderScene)
  renderer.render(scene,camera)
}
renderScene()

onMounted(()=>{
      
      
  //设置摄像头朝向
  containerRef.value?.appendChild(renderer.domElement)
  renderer.render(scene,camera)
})

</script>
<style scoped>

</style>

ここに画像の説明を挿入します

4. パフォーマンスの監視

プラグインをインストールする

npm install stats.js

index3.vueをコピーしてindex4.vueを作成します
ここに画像の説明を挿入します

    import index4 from '../lesson/chapter1/index4.vue'

    ,
    {
    
    
        path:'/chapter1/4',
        component: index4,
        meta:{
    
    
            title:"性能监控"
        }
    }

ここに画像の説明を挿入します
ここに画像の説明を挿入します

 <div ref="statsRef"></div>

const statsRef = ref<HTMLDivElement>()

const stats = new Stats()
stats.showPanel(0)

ここに画像の説明を挿入します

  stats.update()

  //创建场景
  const scene = new Scene();
  stats.dom.style.top = "50px"
  statsRef.value?.append(stats.dom)

4 番目のシーン
http://127.0.0.1:5173/chapter1/4にアクセスしてください。

ここに画像の説明を挿入します

5.対話型制御

index4.vueをindex5.vueにコピーします

おすすめ

転載: blog.csdn.net/qq_44757034/article/details/132637592