0


Three.js学习五——让模型沿着轨迹移动

目录

流程

基本流程

1、添加模型
2、增加运动轨迹
3、让模型沿轨迹运动

工程文件结构如下图:
static:存放静态资源文件
three.js-master:为官网下载的代码包,包含所有需要用到的资源包,链接:https://github.com/mrdoob/three.js/archive/master.zip
index.html:页面代码
在这里插入图片描述
模型使用的是官方示例中的Soldier模型,文件位置:three.js-master\examples\models\gltf\Soldier.glb
为了方便操作我们将文件拷出来放在上图static\3dmod\gltf文件夹下,static与three.js-master同级

index.html单页代码组成

<!DOCTYPE html><html><head><meta charset="utf-8"><title>My first three.js app</title><style>
        body {margin:0;}</style></head><body><script type="importmap">{"imports":{"three":"./three.js-master/build/three.module.js"}}</script><script type="module">// 下文JS代码位置// ...</script></body></html>

参照官网例子:https://threejs.org/examples/#webgl_animation_skinning_blending中的场景和模型

搭建场景环境

import*asTHREEfrom"three";import{ OrbitControls }from"./three.js-master/examples/jsm/controls/OrbitControls.js";let scene, camera, renderer;// 渲染器开启阴影渲染:renderer.shadowMapEnabled = true;// 灯光需要开启“引起阴影”:light.castShadow = true;// 物体需要开启“引起阴影”和“接收阴影”:mesh.castShadow = mesh.receiveShadow = true;functioninit(){
    scene =newTHREE.Scene();
    camera =newTHREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight,0.1,1000);
    renderer =newTHREE.WebGLRenderer();// position and point the camera to the center of the scene
    camera.position.set(5,5,5);
    camera.lookAt(scene.position);// 增加坐标系红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.// 添加坐标系到场景中const axes =newTHREE.AxesHelper(20);
    scene.add(axes);// 调整背景颜色,边界雾化
    scene.background =newTHREE.Color(0xa0a0a0);
    scene.fog =newTHREE.Fog(0xa0a0a0,10,30);// 半球形光源const hemiLight =newTHREE.HemisphereLight(0xffffff,0x444444);
    hemiLight.position.set(0,10,0);
    scene.add(hemiLight);// 创建一个虚拟的球形网格 Mesh 的辅助对象来模拟 半球形光源 HemisphereLight.const hemiLighthelper =newTHREE.HemisphereLightHelper(hemiLight,5);
    scene.add(hemiLighthelper);// 地面const mesh =newTHREE.Mesh(newTHREE.PlaneGeometry(100,100),newTHREE.MeshPhongMaterial({color:0x999999,depthWrite:false}));
    mesh.rotation.x =- Math.PI/2;
    mesh.receiveShadow =true;
    scene.add(mesh);// 平行光const directionalLight =newTHREE.DirectionalLight(0xFFFFFF);
    directionalLight.castShadow =true;
    directionalLight.shadow.camera.near =0.5;
    directionalLight.shadow.camera.far =50;
    directionalLight.shadow.camera.left =-10;
    directionalLight.shadow.camera.right =10;
    directionalLight.shadow.camera.top =10;
    directionalLight.shadow.camera.bottom =-10;
    directionalLight.position.set(0,5,5);
    scene.add(directionalLight);// 用于模拟场景中平行光 DirectionalLight 的辅助对象. 其中包含了表示光位置的平面和表示光方向的线段.const directionalLightHelper =newTHREE.DirectionalLightHelper(directionalLight,5);
    scene.add(directionalLightHelper);
    
    renderer.shadowMap.enabled =true;
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);// 控制器const controls =newOrbitControls(camera, renderer.domElement);}// 渲染functionanimate(){requestAnimationFrame(animate);
    renderer.render(scene, camera);};

这里是添加了几个辅助对象,方便找到光照和场景坐标位置
在这里插入图片描述

添加模型

这里我们直接导入模型,在《Three.js学习四——模型导入》中有相对详细的介绍

let model =null;functionloadModel(){// 加载模型并开启阴影和接受阴影const gltfLoader =newGLTFLoader();
    gltfLoader.setPath('./static/3dmod/gltf/').load('Soldier.glb',function(gltf){// gltf.scene.rotation.y = Math.PI;// console.log("gltf", gltf)
            gltf.scene.scale.set(1,1,1)
            gltf.scene.traverse(function(object){if(object.isMesh){
                    object.castShadow =true;//阴影
                    object.receiveShadow =true;//接受别人投的阴影}});
            scene.add(gltf.scene);
            model = gltf.scene;},function(res){// console.log(res.total, res.loaded)});}

增加运动轨迹

用到了Three.js提供的CatmullRomCurve3:使用Catmull-Rom算法, 从一系列的点创建一条平滑的三维样条曲线。

let curve =null;functionmakeCurve(){//Create a closed wavey loop
    curve =newTHREE.CatmullRomCurve3([newTHREE.Vector3(0,0,0),newTHREE.Vector3(5,0,0),newTHREE.Vector3(0,0,5)]);
    curve.curveType ="catmullrom";
    curve.closed =true;//设置是否闭环
    curve.tension =0.5![请添加图片描述](https://img-blog.csdnimg.cn/12a2fa45062d44a58bb7cbf719e4b20f.gif);//设置线的张力,0为无弧度折线// 为曲线添加材质在场景中显示出来,不显示也不会影响运动轨迹,相当于一个Helperconst points = curve.getPoints(50);const geometry =newTHREE.BufferGeometry().setFromPoints(points);const material =newTHREE.LineBasicMaterial({color:0x000000});// Create the final object to add to the sceneconst curveObject =newTHREE.Line(geometry, material);
    scene.add(curveObject)}

让模型沿轨迹运动

let progress =0;// 物体运动时在运动路径的初始位置,范围0~1const velocity =0.001;// 影响运动速率的一个值,范围0~1,需要和渲染频率结合计算才能得到真正的速率// 物体沿线移动方法functionmoveOnCurve(){if(curve ==null|| model ==null){
        console.log("Loading")}else{if(progress <=1- velocity){const point = curve.getPointAt(progress);//获取样条曲线指定点坐标const pointBox = curve.getPointAt(progress + velocity);//获取样条曲线指定点坐标if(point && pointBox){
                model.position.set(point.x, point.y, point.z);// model.lookAt(pointBox.x, pointBox.y, pointBox.z); //因为这个模型加载进来默认面部是正对Z轴负方向的,所以直接lookAt会导致出现倒着跑的现象,这里用重新设置朝向的方法来解决。var targetPos = pointBox   //目标位置点var offsetAngle =0//目标移动时的朝向偏移// //以下代码在多段路径时可重复执行var mtx =newTHREE.Matrix4()//创建一个4维矩阵// .lookAt ( eye : Vector3, target : Vector3, up : Vector3 ) : this,构造一个旋转矩阵,从eye 指向 target,由向量 up 定向。
                mtx.lookAt(model.position, targetPos, model.up)//设置朝向
                mtx.multiply(newTHREE.Matrix4().makeRotationFromEuler(newTHREE.Euler(0, offsetAngle,0)))var toRot =newTHREE.Quaternion().setFromRotationMatrix(mtx)//计算出需要进行旋转的四元数值
                model.quaternion.slerp(toRot,0.2)}

            progress += velocity;}else{
            progress =0;}}};// moveOnCurve()需要在渲染中一直调用更新,以达到物体移动效果functionanimate(){requestAnimationFrame(animate);moveOnCurve();
    renderer.render(scene, camera);};

完整代码和效果

完整代码

<!DOCTYPE html><html><head><meta charset="utf-8"><title>My first three.js app</title><style>
        body {margin:0;}</style></head><body><script type="importmap">{"imports":{"three":"./three.js-master/build/three.module.js"}}</script><script type="module">import*asTHREEfrom"three";import{ OrbitControls }from"./three.js-master/examples/jsm/controls/OrbitControls.js";import{ GLTFLoader }from"./three.js-master/examples/jsm/loaders/GLTFLoader.js";let scene, camera, renderer;let curve =null, model =null;let progress =0;// 物体运动时在运动路径的初始位置,范围0~1const velocity =0.001;// 影响运动速率的一个值,范围0~1,需要和渲染频率结合计算才能得到真正的速率// 渲染器开启阴影渲染:renderer.shadowMapEnabled = true;// 灯光需要开启“引起阴影”:light.castShadow = true;// 物体需要开启“引起阴影”和“接收阴影”:mesh.castShadow = mesh.receiveShadow = true;functioninit(){
            scene =newTHREE.Scene();
            camera =newTHREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight,0.1,1000);
            renderer =newTHREE.WebGLRenderer();// position and point the camera to the center of the scene
            camera.position.set(5,5,5);
            camera.lookAt(scene.position);// 增加坐标系红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.// 添加坐标系到场景中const axes =newTHREE.AxesHelper(20);
            scene.add(axes);// 调整背景颜色,边界雾化
            scene.background =newTHREE.Color(0xa0a0a0);
            scene.fog =newTHREE.Fog(0xa0a0a0,10,30);// 半球形光源const hemiLight =newTHREE.HemisphereLight(0xffffff,0x444444);
            hemiLight.position.set(0,10,0);
            scene.add(hemiLight);// 创建一个虚拟的球形网格 Mesh 的辅助对象来模拟 半球形光源 HemisphereLight.const hemiLighthelper =newTHREE.HemisphereLightHelper(hemiLight,5);
            scene.add(hemiLighthelper);// 地面const mesh =newTHREE.Mesh(newTHREE.PlaneGeometry(100,100),newTHREE.MeshPhongMaterial({color:0x999999,depthWrite:false}));
            mesh.rotation.x =- Math.PI/2;
            mesh.receiveShadow =true;
            scene.add(mesh);// 平行光const directionalLight =newTHREE.DirectionalLight(0xFFFFFF);
            directionalLight.castShadow =true;
            directionalLight.shadow.camera.near =0.5;
            directionalLight.shadow.camera.far =50;
            directionalLight.shadow.camera.left =-10;
            directionalLight.shadow.camera.right =10;
            directionalLight.shadow.camera.top =10;
            directionalLight.shadow.camera.bottom =-10;
            directionalLight.position.set(0,5,5);
            scene.add(directionalLight);// 用于模拟场景中平行光 DirectionalLight 的辅助对象. 其中包含了表示光位置的平面和表示光方向的线段.const directionalLightHelper =newTHREE.DirectionalLightHelper(directionalLight,5);
            scene.add(directionalLightHelper);

            renderer.shadowMap.enabled =true;
            renderer.setSize(window.innerWidth, window.innerHeight);
            document.body.appendChild(renderer.domElement);// 控制器const controls =newOrbitControls(camera, renderer.domElement);}functionloadModel(){// 加载模型并开启阴影和接受阴影const gltfLoader =newGLTFLoader();
            gltfLoader.setPath('./static/3dmod/gltf/').load('Soldier.glb',function(gltf){// gltf.scene.rotation.y = Math.PI;// console.log("gltf", gltf)
                    gltf.scene.scale.set(1,1,1)
                    gltf.scene.traverse(function(object){if(object.isMesh){
                            object.castShadow =true;//阴影
                            object.receiveShadow =true;//接受别人投的阴影}});
                    scene.add(gltf.scene);
                    model = gltf.scene;},function(res){// console.log(res.total, res.loaded)});}functionmakeCurve(){//Create a closed wavey loop
            curve =newTHREE.CatmullRomCurve3([newTHREE.Vector3(0,0,0),newTHREE.Vector3(5,0,0),newTHREE.Vector3(0,0,5)]);
            curve.curveType ="catmullrom";
            curve.closed =true;//设置是否闭环
            curve.tension =0.5;//设置线的张力,0为无弧度折线// 为曲线添加材质在场景中显示出来,不显示也不会影响运动轨迹,相当于一个Helperconst points = curve.getPoints(50);const geometry =newTHREE.BufferGeometry().setFromPoints(points);const material =newTHREE.LineBasicMaterial({color:0x000000});// Create the final object to add to the sceneconst curveObject =newTHREE.Line(geometry, material);
            scene.add(curveObject)}// 物体沿线移动方法functionmoveOnCurve(){if(curve ==null|| model ==null){
                console.log("Loading")}else{if(progress <=1- velocity){const point = curve.getPointAt(progress);//获取样条曲线指定点坐标const pointBox = curve.getPointAt(progress + velocity);//获取样条曲线指定点坐标if(point && pointBox){
                        model.position.set(point.x, point.y, point.z);// model.lookAt(pointBox.x, pointBox.y, pointBox.z);//因为这个模型加载进来默认面部是正对Z轴负方向的,所以直接lookAt会导致出现倒着跑的现象,这里用重新设置朝向的方法来解决。var targetPos = pointBox   //目标位置点var offsetAngle =0//目标移动时的朝向偏移// //以下代码在多段路径时可重复执行var mtx =newTHREE.Matrix4()//创建一个4维矩阵// .lookAt ( eye : Vector3, target : Vector3, up : Vector3 ) : this,构造一个旋转矩阵,从eye 指向 target,由向量 up 定向。
                        mtx.lookAt(model.position, targetPos, model.up)//设置朝向
                        mtx.multiply(newTHREE.Matrix4().makeRotationFromEuler(newTHREE.Euler(0, offsetAngle,0)))var toRot =newTHREE.Quaternion().setFromRotationMatrix(mtx)//计算出需要进行旋转的四元数值
                        model.quaternion.slerp(toRot,0.2)}

                    progress += velocity;}else{
                    progress =0;}}};functionanimate(){requestAnimationFrame(animate);moveOnCurve();
            renderer.render(scene, camera);};init();loadModel();makeCurve();animate();</script></body></html>

效果:

请添加图片描述

标签: javascript 学习 3d

本文转载自: https://blog.csdn.net/Mr_Bobcp/article/details/125189000
版权归原作者 Mr_Bobcp 所有, 如有侵权,请联系我们删除。

“Three.js学习五——让模型沿着轨迹移动”的评论:

还没有评论