VUE uses Three.js to realize the car model driving along a fixed route (including model import formats such as glb, gltf and obj, including source code)

Table of contents

1. Templates and styles

2. Introduce three.js library and components

3. Define a single file name and define global variables

4. Create scenes, light sources, cameras, cameras and adapt to the browser window

5. Create a model

6. Rendering effect (configuration)

Seven, mounted rendering page

8. Effect display

9. Source code address (many parts of the code are ugly, you can change and package it yourself, please be merciful and thank you)


1. Templates and styles

<template>
  <div class="container">
    <div id="model"></div>
  </div>
</template>

<style scoped>
.container {
  width: 1920px;
  height: 1080px;
  position: relative;
  background-color: rgb(83, 83, 83);
}
</style>

2. Introduce three.js library and components

import * as THREE from "three";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";

3. Define a single file name and define global variables

The publicPath here is used when loading the model

name: "ThreeModel",
  data() {
    return {
      publicPath: process.env.BASE_URL,
      mesh: null,
      camera: null,
      scene: null,
      renderer: null,
      carMovePath: null,
      shperePathIndex: [1001, 666, 333],
      meshArr: [],
    };
  },

4. Create scenes, light sources, cameras, cameras and adapt to the browser window

Whether it needs to adapt to the browser window depends on the individual

// 创建场景
createScene() {
    this.scene = new THREE.Scene();
},

// 创建光源
createLight() {
    // 环境光
    const ambientLight = new THREE.AmbientLight(0x111111); // 创建环境光
    this.scene.add(ambientLight); // 将环境光添加到场景
    const directionLight = new THREE.DirectionalLight(0xffffff);
    directionLight.position.set(-20, 30, 40);
    directionLight.intensity = 1.5;
    this.scene.add(directionLight);
},

// 创建相机
createCamera() {
    this.camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        0.1,
        50000
    );
    this.camera.position.set(0, 700, 1000); // 设置相机位置
    this.camera.lookAt(new THREE.Vector3(0, 0, 0)); // 设置相机方向
    this.scene.add(this.camera);
},

//根据浏览器窗口自适应
onWindowResize() {
    this.cssRender.setSize(window.innerWidth, window.innerHeight);
    this.renderer.setSize(window.innerWidth, window.innerHeight);
    this.camera.aspect = window.innerWidth / window.innerHeight;
    this.camera.updateProjectionMatrix();
},

// 创建渲染器
createRender() {
    this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    this.renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染区域尺寸
    this.renderer.setClearColor(0x000000, 0); // 设置背景颜色
    document.getElementById("model").appendChild(this.renderer.domElement);
}

5. Create a model

First generate a circular smooth curve (according to personal modification), because I have three cars, so I intercept 1000 points of the curve, and evenly distribute the cars (i*333) .

It should be noted here that our model must be placed in the public folder, and I created a model under the public here.

Then there is the way to load the model. Compared with gltf and obj, glb is smaller and faster to render, and the loder components used by the two are also different. gltf and glb use GLTFLoader , while obj uses OBJLoader , and there are also configurations Please refer to the code for details.

// 创建模型
createModels() {
    //   let axes = new THREE.AxesHelper(6000);
    //   this.scene.add(axes);
    //使用指定的点创建一条平滑的三维样条曲线当做小车运动路径
    this.carMovePath = new THREE.CatmullRomCurve3(
        [
            new THREE.Vector3(-300, 40, 200),
            new THREE.Vector3(300, 40, 200),
            new THREE.Vector3(300, 40, -200),
        ],
        true
    );
    //参考路径上取1000个点,可以将模型安置在某个点位上
    const pathPoints = this.carMovePath.getPoints(1000);
    const THIS = this;

    // 引入三维模型(glb或者gltf格式)
    const loader = new GLTFLoader();
    for (let i = 0; i < 3; i++) {
        loader.load(`${THIS.publicPath}models/car.glb`, (glb) => {
            this.meshArr[i] = glb.scene.children[0].children[0];
            //这里就是将模型安置在i*333这个点位上
            this.meshArr[i].position.set(
                pathPoints[i * 333].x,
                pathPoints[i * 333].y,
                pathPoints[i * 333].z
            );
            //设置模型大小
            this.meshArr[i].scale.set(0.06, 0.06, 0.06);
            this.scene.add(this.meshArr[i]);
            this.renderer.render(this.scene, this.camera);
        });
    }
    // //引入三维模型(obj格式)
    // const loader = new OBJLoader();
    // for (let i = 0; i < 3; i++) {
    //   loader.load(`${THIS.publicPath}models/robot.obj`, (loadedMesh) => {
    //     // 创建材质
    //     const material = new THREE.MeshLambertMaterial({
    //       color: 0x6699ff,
    //     });
    //     // 给几何体成员赋该材质
    //     loadedMesh.children.forEach((child) => {
    //       child.material = material;
    //       child.geometry.computeVertexNormals();
    //     });
    //     //设置模型大小    
    //     loadedMesh.scale.set(35, 35, 35);
    //     this.meshArr[i] = loadedMesh;
    //     //这里就是将模型安置在i*333这个点位上
    //     this.meshArr[i].position.set(
    //         pathPoints[i * 140].x,
    //         pathPoints[i * 140].y,
    //         pathPoints[i * 140].z
    //      );
    //      this.scene.add(this.meshArr[i]);
    //   });
    // }

    //绘制一条路径参考线(根据个人需求,可以注释或删除不显示)
    const geometry = new THREE.BufferGeometry().setFromPoints(pathPoints);
    const material = new THREE.LineBasicMaterial({
        color: 0xf00,
        linewidth: 1,
    });
    const curveObject = new THREE.Line(geometry, material);
    this.scene.add(curveObject);
}

6. Rendering effect (configuration)

The rendering effect is mainly to solve the problem that when the model moves in a curve, the direction of the model is tangent to the arc, so that it seems that the model is moving around the curve

//渲染效果(配置)
render() {
    //参考路径的索引由每个汽车的位置逐渐向0减少,然后又设为1001使其做往复运动
    if (this.shperePathIndex[0] === 0) {
        this.shperePathIndex[0] = 1001;
    }
    if (this.shperePathIndex[1] === 0) {
        this.shperePathIndex[1] = 1001;
    }
    if (this.shperePathIndex[2] === 0) {
        this.shperePathIndex[2] = 1001;
    }
    this.shperePathIndex[1] -= 1;
    this.shperePathIndex[0] -= 1;
    this.shperePathIndex[2] -= 1;
    // 设置小车的位置为参考路径上当前点的位置
    if (this.meshArr[0]) {
        //取相参考径上当前点的坐标
        const sphereCurveIndex = this.shperePathIndex[0] / 1000; //取值0~1
        const tmpSpherePosition = this.carMovePath.getPointAt(sphereCurveIndex);
        this.meshArr[0].position.set(
            tmpSpherePosition.x,
            tmpSpherePosition.y,
            tmpSpherePosition.z
        );
        //这个部分是处理小车的模型始终与切线相切,这样就能让小车始终围绕曲线中心运动
        // 当前点在线条上的位置
        this.meshArr[0].position.copy(tmpSpherePosition);
        // 返回一个点t在曲线上位置向量的法线向量
        const tangent = this.carMovePath.getTangentAt(sphereCurveIndex);
        // 位置向量和切线向量相加即为所需朝向的点向量
        const lookAtVec = tangent.add(tmpSpherePosition);
        this.meshArr[0].lookAt(lookAtVec);
    }
    if (this.meshArr[1]) {
        //取相参考径上当前点的坐标
        const sphereCurveIndex = this.shperePathIndex[1] / 1000; //取值0~1
        const tmpSpherePosition = this.carMovePath.getPointAt(sphereCurveIndex);
        this.meshArr[1].position.set(
            tmpSpherePosition.x,
            tmpSpherePosition.y,
            tmpSpherePosition.z
        );
        //这个部分是处理小车的模型始终与切线相切,这样就能让小车始终围绕曲线中心运动
        // 当前点在线条上的位置
        this.meshArr[1].position.copy(tmpSpherePosition);
        // 返回一个点t在曲线上位置向量的法线向量
        const tangent = this.carMovePath.getTangentAt(sphereCurveIndex);
        // 位置向量和切线向量相加即为所需朝向的点向量
        const lookAtVec = tangent.add(tmpSpherePosition);
        this.meshArr[1].lookAt(lookAtVec);
    }
    if (this.meshArr[2]) {
        //取相参考径上当前点的坐标
        const sphereCurveIndex = this.shperePathIndex[2] / 1000; //取值0~1
        const tmpSpherePosition = this.carMovePath.getPointAt(sphereCurveIndex);
        this.meshArr[2].position.set(
            tmpSpherePosition.x,
            tmpSpherePosition.y,
            tmpSpherePosition.z
        );
        //这个部分是处理小车的模型始终与切线相切,这样就能让小车始终围绕曲线中心运动
        // 当前点在线条上的位置
        this.meshArr[2].position.copy(tmpSpherePosition);
        // 返回一个点t在曲线上位置向量的法线向量
        const tangent = this.carMovePath.getTangentAt(sphereCurveIndex);
        // 位置向量和切线向量相加即为所需朝向的点向量
        const lookAtVec = tangent.add(tmpSpherePosition);
        this.meshArr[2].lookAt(lookAtVec);
    }
    //统一改变模型车头车尾的方向,使车头朝前(可以注释掉看一下)
    this.meshArr.forEach((item) => {
        item.rotateY(Math.PI);
    });
    this.renderer.render(this.scene, this.camera);
    requestAnimationFrame(this.render);
}

Seven, mounted rendering page

init() {
      this.createScene(); // 创建场景
      this.createModels(); // 创建模型
      this.createLight(); // 创建光源
      this.createCamera(); // 创建相机
      this.createRender(); // 创建渲染器
      this.render(); // 渲染
      window.onresize = this.onWindowResize;
    },

8. Effect display

9. Source code address (many parts of the code are ugly, you can change and package it yourself, please be merciful and thank you)

3D model car movement: Use Three.js to realize the car model driving along a fixed route (including model import formats such as glb, gltf and obj) https://gitee.com/halsixsixsix/car-move.git

Guess you like

Origin blog.csdn.net/weixin_43721856/article/details/128313461