四川网站建设案例单招网,wordpress 导入json,1g做网站空间,新东方在线网上课程之前文章其实也有涉及到这方面的内容#xff0c;比如在ThreeJS-3D教学三#xff1a;平移缩放物体沿轨迹运动这篇中#xff0c;通过获取轨迹点物体动起来#xff0c;其它几篇文章也有旋转的效果#xff0c;本篇我们来详细看下#xff0c;另外加了tween.js知识点#xff0…之前文章其实也有涉及到这方面的内容比如在ThreeJS-3D教学三平移缩放物体沿轨迹运动这篇中通过获取轨迹点物体动起来其它几篇文章也有旋转的效果本篇我们来详细看下另外加了tween.js知识点tween可以很好的协助 three 做动画与之相似的还有 gsap.js方法类似。
1、物体位移两种方式
mesh.position.set(x, y, z);
mesh.position.x 10;
mesh.position.y 10;
mesh.position.z 10;2、物体旋转两种方式
// 绕局部空间的轴旋转这个物体
mesh.rotateX 0.1; // 以弧度为单位旋转的角度
mesh.rotateY 0.1;
mesh.rotateZ 0.1;
// 物体的局部旋转以弧度来表示
mesh.rotation.x MathUtils.degToRad(90)
// 在局部空间中绕着该物体的轴来旋转一个物体
mesh.rotateOnAxis(new Vector3(1,0,0), 3.14); 注意这里设置的数值是弧度需要和角度区分开 角度 转 弧度 THREE.MathUtils.degToRad(deg) 弧度 转 角度 THREE.MathUtils.radToDeg (rad) 弧度 角度 / 180 * Math.PI 角度 弧度 * 180 / Math.PI π弧度 180°角度 3、tween.js Tween.js 是一个 过渡计算工具包 理论上来说只是一个工具包可以用到各种需要有过渡效果的场景一般情况下需要通过环境里面提供的辅助时间工具来实现。比如在网页上就是使用 window 下的 requestAnimationFrame 方法低端浏览器只能使用 setInterval 方法来配合了。 1简单使用 例如把一个元素的 x 坐标在 1秒内由100 增加到 200 通过以下代码可以实现
// 1. 定义元素
const position { x: 100, y: 0 };
// 2. new 一个 Tween对象构造参数传入需要变化的元素
const tween new TWEEN.Tween(position);
// 3. 设置目标
tween.to({ x: 200 }, 1000);
// 4. 启动通常情况下234步一般习惯性写在一起定义命名也省了
// 例如 new TWEEN.Tween(position).to({ x: 200 }, 1000).start();
tween.start();
// 5. 可选如果在变化过程中想自定义事件则可以通过以下事件按需使用
tween1.onStart(() {console.log(onStart);
});
tween1.onStop(() {console.log(onStop);
});
tween1.onComplete(() {console.log(onComplete);
});
tween.onUpdate(function(pos) {console.log(pos.x);
});
// 6. 设置 requestAnimationFrame在方法里面调用全局的 TWEEN.update()
// 在这个方法里面也可以加入其它的代码d3, threejs 里面经常会用到。
// 比如THREEJS里面用到的变化如 renderer.render(scene, camera); 等
function animate() {requestAnimationFrame(animate);TWEEN.update();
}
// 6. 启动全局的 animate
animate();2、连续型变化 一般情况下设置起点和终点时两个数时认为是连续型的里面有无数的可能变化到的值算上小数。 连续型变化使用 easing 做为时间变化函数默认使用的是 Liner 纯性过渡函数easing过渡 的种类很多每种还区分 IN, OUT, INOUT 算法。引用时 使用 TWEEN.Easing前缀例如
tween.easing(TWEEN.Easing.Quadratic.Out)目前内置的过渡函数下图 3、主动控制
start([time]) stop() 开始结束start 方法还接受一个时间参数如果传了的话就直接从传入的时间开始
update([time]) 更新会触发更新事件如果有监听则可以执行监听相关代码。 更新方法接受一个时间参数如果传了的话就更新到指定的时间
chain(tweenObject,[tweenObject]) 如果是多个 Tween 对像 如果 tweenA 需要等到 tweenB 结束后才能 start, 那么可以使用
tweenA.chain(tweenB);
//另外chain方法也可以接收多个参数如果 A对象 需要等待多个对像时依次传入
tweenA.chain(tweenB, tweenC, tweenD);repeat(number) 循环的次数默认是 1 所以不定义的话只过渡一次就没了可以使用上面刚说的无限循环的方法便只是一个对象无限循环时就使用
tween.repeat(Infinity); //无限循环
tween.repeat(5); //循环5次delay(time) delay 是指延时多久才开始。比如以下代码
tween.delay(1000);
tween.start();虽然已经调用 start 了但过渡动作要等 1秒 后才开始执行
大致讲这些算是给大家一个初步的认知感兴趣的可以自行查询文档下面回到咱们本次的案例中先看效果图 代码如下
!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/titlestylebody {width: 100%;height: 100%;}* {margin: 0;padding: 0;}.label {font-size: 20px;color: #000;font-weight: 700;}/stylescript src../tween.js/dist/tween.umd.js/script
/head
body
div idcontainer/div
script typeimportmap{imports: {three: ../three-155/build/three.module.js,three/addons/: ../three-155/examples/jsm/}}
/script
script typemodule
import * as THREE from three;
import Stats from three/addons/libs/stats.module.js;
import { OrbitControls } from three/addons/controls/OrbitControls.js;
import { GPUStatsPanel } from three/addons/utils/GPUStatsPanel.js;
import { CSS2DRenderer, CSS2DObject } from three/addons/renderers/CSS2DRenderer.js;
let stats, labelRenderer, gpuPanel, colors [], indices [];
let camera, scene, renderer, controls, group1, mesh2, mesh3, mesh4;
const group new THREE.Group();
let widthImg 200;
let heightImg 200;
let time 0;
init();
initHelp();
initLight();
axesHelperWord();
animate();
// 添加平面
addPlane();addBox1();
addBox2();
addBox3();
addBox4();function addBox1() {// BoxGeometry(width : Float, height : Float, depth : Float)let geo1 new THREE.BoxGeometry(6, 12, 8);let material1 new THREE.MeshLambertMaterial({color: 0x2194ce * Math.random(),side: THREE.DoubleSide,vertexColors: false});// 以图形一边为中心旋转let mesh1 new THREE.Mesh(geo1, material1);mesh1.position.x -3;mesh1.position.z 4;// 改变物体旋转的中心点 将物体放入new THREE.Group 组中通过位移实现// Group 的中心点在原点group1 new THREE.Group();group1.position.x 3;group1.position.z -4;group1.add(mesh1);scene.add(group1);// 一个包围盒子的线框scene.add(new THREE.BoxHelper(mesh1, 0xff0000));
}function addBox2() {let geo2 new THREE.BoxGeometry(6, 12, 8);let material2 new THREE.MeshLambertMaterial({color: 0x2194ce * Math.random(),side: THREE.DoubleSide,vertexColors: false});mesh2 new THREE.Mesh(geo2, material2);mesh2.position.z 30;scene.add(mesh2);// 获取 物体的最大最小 区间let box4 new THREE.Box3().setFromObject(mesh2);console.log(box4);// 将物体的中心点 给到 mesh的位置// box4.getCenter(mesh.position);
}function addBox3() {let geo3 new THREE.BoxGeometry(10, 10, 5);// geo.faces 废除const colorsAttr geo3.attributes.position.clone();// 面将由顶点颜色着色const color new THREE.Color();const n 800, n2 n / 2;for (let i 0; i colorsAttr.count; i) {const x Math.random() * n - n2;const y Math.random() * n - n2;const z Math.random() * n - n2;const vx ( x / n ) 1.5;const vy ( y / n ) 0.5;const vz ( z / n ) 0.5;color.setRGB( vx, vy, vz );colors.push( color.r, color.g, color.b );}geo3.setAttribute(color, new THREE.Float32BufferAttribute( colors, 3 ));let material new THREE.MeshLambertMaterial({// color: 0x2194ce * Math.random(),side: THREE.DoubleSide,vertexColors: true});mesh3 new THREE.Mesh(geo3, material);mesh3.position.y 10;mesh3.position.x 40;// 将盒子的 坐标点变为反向// mesh3.position.multiplyScalar(-1);scene.add(mesh3);
}function addBox4() {let geo4 new THREE.BoxGeometry(6, 12, 8);let material4 new THREE.MeshLambertMaterial({color: 0x2194ce * Math.random(),side: THREE.DoubleSide,vertexColors: false});mesh4 new THREE.Mesh(geo4, material4);mesh4.position.z -80;scene.add(mesh4);const tween1 new TWEEN.Tween(mesh4.position).to({x: 100,y: 20,z: -100},5000);tween1.start();// 无限循环 Infinity// tween1.repeat(4);// 这个方法只在使用了repeat方法后才能起作用可以从移动的终点返回到起点就像悠悠球一样// .yoyo方法在一些旧的版本中会报错 新的版本已经修复// tween1.yoyo(true);tween1.onStart(() {console.log(111);});tween1.onComplete(() {console.log(222);});// 添加第二个动画// 这个通过chain()方法可以将这两个补间衔接起来// 这样当动画启动之后程序就会在这两个补间循环。// 例如一个动画在另一个动画结束后开始。可以通过chain方法来使实现。const tween2 new TWEEN.Tween(mesh4.position).to({x: 100,y: 20,z: 100},5000);tween2.chain(tween1);tween1.chain(tween2);
}function addPlane() {// 创建一个平面 PlaneGeometry(width, height, widthSegments, heightSegments)const planeGeometry new THREE.PlaneGeometry(widthImg, heightImg, 1, 1);// 创建 Lambert 材质会对场景中的光源作出反应但表现为暗淡而不光亮。const planeMaterial new THREE.MeshPhongMaterial({color: 0xb2d3e6,side: THREE.DoubleSide});const plane new THREE.Mesh(planeGeometry, planeMaterial);// 以自身中心为旋转轴绕 x 轴顺时针旋转 45 度plane.rotation.x -0.5 * Math.PI;plane.position.set(0, -4, 0);scene.add(plane);
}function init() {camera new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 10, 2000 );camera.up.set(0, 1, 0);camera.position.set(60, 40, 60);camera.lookAt(0, 0, 0);scene new THREE.Scene();scene.background new THREE.Color( #ccc );renderer new THREE.WebGLRenderer( { antialias: true } );renderer.setPixelRatio( window.devicePixelRatio );renderer.setSize( window.innerWidth, window.innerHeight );document.body.appendChild( renderer.domElement );labelRenderer new CSS2DRenderer();labelRenderer.setSize( window.innerWidth, window.innerHeight );labelRenderer.domElement.style.position absolute;labelRenderer.domElement.style.top 0px;labelRenderer.domElement.style.pointerEvents none;document.getElementById( container ).appendChild( labelRenderer.domElement );controls new OrbitControls( camera, renderer.domElement );controls.mouseButtons {LEFT: THREE.MOUSE.PAN,MIDDLE: THREE.MOUSE.DOLLY,RIGHT: THREE.MOUSE.ROTATE};controls.enablePan true;// 设置最大最小视距controls.minDistance 20;controls.maxDistance 1000;window.addEventListener( resize, onWindowResize );stats new Stats();stats.setMode(1); // 0: fps, 1: msdocument.body.appendChild( stats.dom );gpuPanel new GPUStatsPanel( renderer.getContext() );stats.addPanel( gpuPanel );stats.showPanel( 0 );scene.add( group );
}function initLight() {const AmbientLight new THREE.AmbientLight(new THREE.Color(rgb(255, 255, 255)));scene.add( AmbientLight );
}function initHelp() {// const size 100;// const divisions 5;// const gridHelper new THREE.GridHelper( size, divisions );// scene.add( gridHelper );// The X axis is red. The Y axis is green. The Z axis is blue.const axesHelper new THREE.AxesHelper( 100 );scene.add( axesHelper );
}function axesHelperWord() {let xP addWord(X轴);let yP addWord(Y轴);let zP addWord(Z轴);xP.position.set(50, 0, 0);yP.position.set(0, 50, 0);zP.position.set(0, 0, 50);
}function addWord(word) {let name span${word}/span;let moonDiv document.createElement( div );moonDiv.className label;// moonDiv.textContent Moon;// moonDiv.style.marginTop -1em;moonDiv.innerHTML name;const label new CSS2DObject( moonDiv );group.add( label );return label;
}function onWindowResize() {camera.aspect window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize( window.innerWidth, window.innerHeight );
}function animate() {requestAnimationFrame( animate );if (mesh2) {// 围绕 x y z轴旋转 中心点是自身中心mesh2.rotateX(0.01);mesh2.rotateY(0.01);mesh2.rotateZ(0.01);}if (group1) {group1.rotateY(0.01);}if (mesh3) {let v3 new THREE.Vector3(1, 1, 0);mesh3.rotateOnAxis(v3, 0.01);}if (TWEEN) {TWEEN.update();}stats.update();controls.update();labelRenderer.render( scene, camera );renderer.render( scene, camera );
}
/script
/body
/html
这里有几个小知识点 1、改变物体旋转的中心点我们通过将物体放入new THREE.Group 组中通过位移实现 2、我们通过new THREE.Box3().setFromObject(mesh2)可以获取物体的最大最小 区间 3、tween.yoyo(true) 方法在一些旧的版本中会报错新的版本已经修复请大家使用最新版本 4、最重要的一点 不要忘记加 TWEEN.update()