为什么立方体并不总是用three.js制作动画 [英] Why cubes do not always animate with three.js
问题描述
在下面的代码中,立方体有时随着动画移动,有时没有.我该如何解决?
另外,我应该如何设置旋转速度?
new Vue({el: '#app',数据 () {返回 {相机:空,场景:空,渲染器:空,立方体:空,角度:空}},方法: {初始化:函数(){this.camera = new THREE.PerspectiveCamera(1, 1);this.camera.position.z = 200;//有意义this.scene = new THREE.Scene();this.clock = new THREE.Clock();//this.renderer = new THREE.WebGLRenderer({抗锯齿:真实,阿尔法:真实});let container = document.getElementById('container')this.renderer.setSize(container.offsetWidth, container.offsetHeight);container.appendChild(this.renderer.domElement);让cube2 = this.createCube()cube2.name = "cube2"//cube2.position = new THREE.Vector3(1, 0)this.scene.add(cube2);},createCube: 函数 () {//几何学//1. 从空几何开始让几何 = new THREE.Geometry();//2. 给几何体添加顶点geometry.vertices.push(//顶点 [0-3] 在 +z 中新三.Vector3(-1, 1, 1),新三.Vector3(-1, -1, 1),新三.Vector3(1, -1, 1),新三.Vector3(1, 1, 1),//在 -z 中翻转 [4-7]新三.Vector3(-1, 1, -1),new THREE.Vector3(-1, -1, -1),new THREE.Vector3(1, -1, -1),新三.Vector3(1, 1, -1),);//3. 按所需顺序连接顶点以制作面让 b = 0x1db0ec让 y = 0xffef3a让 r = 0xea353d让 w = 0xffffff//设置半面geometry.faces.push(new THREE.Face3(0, 1, 2));//蓝色geometry.faces.push(new THREE.Face3(0, 2, 3));//黄色geometry.faces.push(new THREE.Face3(5, 4, 6));//白色的geometry.faces.push(new THREE.Face3(6, 4, 7));//红色的//设置全脸geometry.faces.push(new THREE.Face3(1, 0, 5));//蓝色geometry.faces.push(new THREE.Face3(5, 0, 4));geometry.faces.push(new THREE.Face3(1, 5, 2));//白色的geometry.faces.push(new THREE.Face3(5, 6, 2));geometry.faces.push(new THREE.Face3(2, 6, 3));//红色的geometry.faces.push(new THREE.Face3(3, 6, 7));geometry.faces.push(new THREE.Face3(0, 3, 4));//黄色geometry.faces.push(new THREE.Face3(3, 7, 4));//设置人脸颜色geometry.faces[0].color.setHex(b);//半脸geometry.faces[1].color.setHex(y);geometry.faces[2].color.setHex(w);geometry.faces[3].color.setHex(r);geometry.faces[4].color.setHex(b);//整张脸geometry.faces[5].color.setHex(b);geometry.faces[6].color.setHex(w);geometry.faces[7].color.setHex(w);geometry.faces[8].color.setHex(r);geometry.faces[9].color.setHex(r);geometry.faces[10].color.setHex(y);geometry.faces[11].color.setHex(y);//材料//制作材质让材料 = 新的 THREE.MeshBasicMaterial({//颜色:0x00FF00,顶点颜色:THREE.FaceColors,线框:假,});//网let cube = new THREE.Mesh(geometry, material);返回立方体},旋转到:功能(面){如果(脸=='黄色')this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI/2, Math.PI/2));否则如果(脸=='红色')this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI/2, 0, Math.PI/2));否则如果(脸=='蓝色')this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI/2, 0, - Math.PI/2));否则如果(脸=='白')this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(- Math.PI/2, Math.PI/2, 0));否则如果(脸=='yb')this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0));否则如果(脸=='rw')this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI, 0, 0));this.animate()},动画:函数(){让 id = requestAnimationFrame(this.animate);让 delta = this.clock.getDelta();this.scene.children[0].quaternion.rotateTowards(this.angle, Math.PI * delta);this.renderer.render(this.scene, this.camera);如果 (this.scene.children[0].quaternion.equals(this.angle)) {取消动画帧(id)}}},挂载(){this.init();this.renderer.render(this.scene, this.camera);}})
#container {背景色:#aaa;宽度:20em;高度:20em;}
<script src="https://unpkg.com/vue"></script><script src="https://threejs.org/build/three.min.js"></script><div id="应用程序"><div><button v-on:click="rotateTo('yellow')">黄色</button><button v-on:click="rotateTo('red')">red</button><button v-on:click="rotateTo('blue')">blue</button><button v-on:click="rotateTo('white')">white</button><button v-on:click="rotateTo('yb')">黄色/蓝色</button><button v-on:click="rotateTo('rw')">红/白</button>
<div id="容器"></div>
更新
代码仅隔离到 Threejs 部分.
var camera = null;var 场景 = null;var 渲染器 = null;var 立方体 = 空;var 角度 = 空;在里面();renderer.render(场景,相机);函数初始化(){相机=新三.透视相机(1,1);相机.位置.z = 200;//有意义场景 = 新的 THREE.Scene();时钟 = 新的 THREE.Clock();//渲染器 = 新的 THREE.WebGLRenderer({抗锯齿:真实,阿尔法:真实});let container = document.getElementById('container');renderer.setSize(container.offsetWidth, container.offsetHeight);container.appendChild(renderer.domElement);让cube2 = createCube();cube2.name = "cube2";//cube2.position = new THREE.Vector3(1, 0)场景.添加(立方体2);}函数 createCube() {//几何学//1. 从空几何开始让几何 = new THREE.Geometry();//2. 给几何体添加顶点geometry.vertices.push(//顶点 [0-3] 在 +z 中新三.Vector3(-1, 1, 1),新三.Vector3(-1, -1, 1),新三.Vector3(1, -1, 1),新三.Vector3(1, 1, 1),//在 -z 中翻转 [4-7]新三.Vector3(-1, 1, -1),new THREE.Vector3(-1, -1, -1),new THREE.Vector3(1, -1, -1),新三.Vector3(1, 1, -1),);//3. 按所需顺序连接顶点以制作面让 b = 0x1db0ec;让 y = 0xffef3a;让 r = 0xea353d;让 w = 0xffffff;//设置半面geometry.faces.push(new THREE.Face3(0, 1, 2));//蓝色geometry.faces.push(new THREE.Face3(0, 2, 3));//黄色geometry.faces.push(new THREE.Face3(5, 4, 6));//白色的geometry.faces.push(new THREE.Face3(6, 4, 7));//红色的//设置全脸geometry.faces.push(new THREE.Face3(1, 0, 5));//蓝色geometry.faces.push(new THREE.Face3(5, 0, 4));geometry.faces.push(new THREE.Face3(1, 5, 2));//白色的geometry.faces.push(new THREE.Face3(5, 6, 2));geometry.faces.push(new THREE.Face3(2, 6, 3));//红色的geometry.faces.push(new THREE.Face3(3, 6, 7));geometry.faces.push(new THREE.Face3(0, 3, 4));//黄色geometry.faces.push(new THREE.Face3(3, 7, 4));//设置人脸颜色geometry.faces[0].color.setHex(b);//半脸geometry.faces[1].color.setHex(y);geometry.faces[2].color.setHex(w);geometry.faces[3].color.setHex(r);geometry.faces[4].color.setHex(b);//整张脸geometry.faces[5].color.setHex(b);geometry.faces[6].color.setHex(w);geometry.faces[7].color.setHex(w);geometry.faces[8].color.setHex(r);geometry.faces[9].color.setHex(r);geometry.faces[10].color.setHex(y);geometry.faces[11].color.setHex(y);//材料//制作材质让材料 = 新的 THREE.MeshBasicMaterial({//颜色:0x00FF00,顶点颜色:THREE.FaceColors,线框:假,});//网let cube = new THREE.Mesh(geometry, material);返回立方体;}函数旋转到(脸){如果(脸=='黄色')角度 = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI/2, Math.PI/2));否则如果(脸=='红色')角度 = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI/2, 0, Math.PI/2));否则如果(脸=='蓝色')角度 = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI/2, 0, -Math.PI/2));否则如果(脸=='白')角度 = new THREE.Quaternion().setFromEuler(new THREE.Euler(-Math.PI/2, Math.PI/2, 0));否则如果(脸=='yb')角度 = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0));否则如果(脸=='rw')角度 = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI, 0, 0));动画();}函数动画(){让 id = requestAnimationFrame(animate);让 delta = clock.getDelta();scene.children[0].quaternion.rotateTowards(angle, Math.PI * delta);renderer.render(场景,相机);如果 (scene.children[0].quaternion.equals(angle)) {取消动画帧(id);}}
#container {背景色:#aaa;宽度:20em;高度:20em;}
<script src="https://threejs.org/build/three.min.js"></script><div><button onclick="rotateTo('yellow')">黄色</button><button onclick="rotateTo('red')">red</button><button onclick="rotateTo('blue')">blue</button><button onclick="rotateTo('white')">white</button><button onclick="rotateTo('yb')">黄色/蓝色</button><button onclick="rotateTo('rw')">红/白</button>
<div id="container"></div>
动画不播放的原因是因为当你cancelAnimationFrame
时时钟还在运行,所以下次你调用rotateTo
delta 太高以至于动画立即结束.
您可以通过使用 cancelAnimationFrame
停止时钟来避免这种情况,并在调用 rotateTo
时重新启动它,如下所示:
function rotateTo(face) {时钟.开始()...}
function animate() {...如果 (scene.children[0].quaternion.equals(angle)) {取消动画帧(id);时钟停止()}}
至于旋转速度,rotateTowards
的第二个参数是 step,它决定了它到达那里的速度.所以如果你给它添加一个修饰符var,你就可以控制速度.
let rotSpeedMotifier = 0.2//越高越快scene.children[0].quaternion.rotateTowards(angle, Math.PI * delta * rotSpeedMotifier);
In the code below, cubes sometimes move with animation and sometimes without. How can I fix it ?
Also, how should I set rotation speed ?
new Vue({
el: '#app',
data () {
return {
camera: null,
scene: null,
renderer: null,
cube: null,
angle: null
}
},
methods: {
init: function () {
this.camera = new THREE.PerspectiveCamera(1, 1);
this.camera.position.z = 200;
// Make a scene
this.scene = new THREE.Scene();
this.clock = new THREE.Clock();
//
this.renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
let container = document.getElementById('container')
this.renderer.setSize(container.offsetWidth, container.offsetHeight);
container.appendChild(this.renderer.domElement);
let cube2 = this.createCube()
cube2.name = "cube2"
// cube2.position = new THREE.Vector3(1, 0)
this.scene.add(cube2);
},
createCube: function () {
// GEOMETRY
// 1. Start with empty geometry
let geometry = new THREE.Geometry();
// 2. Add vertices to geometry
geometry.vertices.push(
// verts [0-3] are in in +z
new THREE.Vector3(-1, 1, 1),
new THREE.Vector3(-1, -1, 1),
new THREE.Vector3(1, -1, 1),
new THREE.Vector3(1, 1, 1),
// verts [4-7] in -z
new THREE.Vector3(-1, 1, -1),
new THREE.Vector3(-1, -1, -1),
new THREE.Vector3(1, -1, -1),
new THREE.Vector3(1, 1, -1),
);
// 3. Connect vertices in desired order to make faces
let b = 0x1db0ec
let y = 0xffef3a
let r = 0xea353d
let w = 0xffffff
// Set half faces
geometry.faces.push(new THREE.Face3(0, 1, 2)); // blue
geometry.faces.push(new THREE.Face3(0, 2, 3)); // yellow
geometry.faces.push(new THREE.Face3(5, 4, 6)); // white
geometry.faces.push(new THREE.Face3(6, 4, 7)); // red
// Set whole faces
geometry.faces.push(new THREE.Face3(1, 0, 5)); // blue
geometry.faces.push(new THREE.Face3(5, 0, 4));
geometry.faces.push(new THREE.Face3(1, 5, 2)); // white
geometry.faces.push(new THREE.Face3(5, 6, 2));
geometry.faces.push(new THREE.Face3(2, 6, 3)); // red
geometry.faces.push(new THREE.Face3(3, 6, 7));
geometry.faces.push(new THREE.Face3(0, 3, 4)); // yellow
geometry.faces.push(new THREE.Face3(3, 7, 4));
// Set faces colors
geometry.faces[0].color.setHex(b); // Half face
geometry.faces[1].color.setHex(y);
geometry.faces[2].color.setHex(w);
geometry.faces[3].color.setHex(r);
geometry.faces[4].color.setHex(b); // Whole face
geometry.faces[5].color.setHex(b);
geometry.faces[6].color.setHex(w);
geometry.faces[7].color.setHex(w);
geometry.faces[8].color.setHex(r);
geometry.faces[9].color.setHex(r);
geometry.faces[10].color.setHex(y);
geometry.faces[11].color.setHex(y);
// MATERIAL
// Make a material
let material = new THREE.MeshBasicMaterial({
// color: 0x00FF00,
vertexColors: THREE.FaceColors,
wireframe: false,
});
// MESH
let cube = new THREE.Mesh(geometry, material);
return cube
},
rotateTo: function (face) {
if (face == 'yellow')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI / 2, Math.PI / 2));
else if (face == 'red')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, Math.PI / 2));
else if (face == 'blue')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, - Math.PI / 2));
else if (face == 'white')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(- Math.PI / 2, Math.PI / 2, 0));
else if (face == 'yb')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0));
else if (face == 'rw')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI, 0, 0));
this.animate()
},
animate: function () {
let id = requestAnimationFrame(this.animate);
let delta = this.clock.getDelta();
this.scene.children[0].quaternion.rotateTowards(this.angle, Math.PI * delta);
this.renderer.render(this.scene, this.camera);
if (this.scene.children[0].quaternion.equals(this.angle)) {
cancelAnimationFrame(id)
}
}
},
mounted () {
this.init();
this.renderer.render(this.scene, this.camera);
}
})
#container {
background-color: #aaa;
width: 20em;
height: 20em;
}
<script src="https://unpkg.com/vue"></script>
<script src="https://threejs.org/build/three.min.js"></script>
<div id="app">
<div>
<button v-on:click="rotateTo('yellow')">yellow</button>
<button v-on:click="rotateTo('red')">red</button>
<button v-on:click="rotateTo('blue')">blue</button>
<button v-on:click="rotateTo('white')">white</button>
<button v-on:click="rotateTo('yb')">yellow/blue</button>
<button v-on:click="rotateTo('rw')">red/white</button>
</div>
<div id="container"></div>
</div>
UPDATE
Code isolated to only the threejs portion.
var camera = null;
var scene = null;
var renderer = null;
var cube = null;
var angle = null;
init();
renderer.render(scene, camera);
function init() {
camera = new THREE.PerspectiveCamera(1, 1);
camera.position.z = 200;
// Make a scene
scene = new THREE.Scene();
clock = new THREE.Clock();
//
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
let container = document.getElementById('container');
renderer.setSize(container.offsetWidth, container.offsetHeight);
container.appendChild(renderer.domElement);
let cube2 = createCube();
cube2.name = "cube2";
// cube2.position = new THREE.Vector3(1, 0)
scene.add(cube2);
}
function createCube() {
// GEOMETRY
// 1. Start with empty geometry
let geometry = new THREE.Geometry();
// 2. Add vertices to geometry
geometry.vertices.push(
// verts [0-3] are in in +z
new THREE.Vector3(-1, 1, 1),
new THREE.Vector3(-1, -1, 1),
new THREE.Vector3(1, -1, 1),
new THREE.Vector3(1, 1, 1),
// verts [4-7] in -z
new THREE.Vector3(-1, 1, -1),
new THREE.Vector3(-1, -1, -1),
new THREE.Vector3(1, -1, -1),
new THREE.Vector3(1, 1, -1),
);
// 3. Connect vertices in desired order to make faces
let b = 0x1db0ec;
let y = 0xffef3a;
let r = 0xea353d;
let w = 0xffffff;
// Set half faces
geometry.faces.push(new THREE.Face3(0, 1, 2)); // blue
geometry.faces.push(new THREE.Face3(0, 2, 3)); // yellow
geometry.faces.push(new THREE.Face3(5, 4, 6)); // white
geometry.faces.push(new THREE.Face3(6, 4, 7)); // red
// Set whole faces
geometry.faces.push(new THREE.Face3(1, 0, 5)); // blue
geometry.faces.push(new THREE.Face3(5, 0, 4));
geometry.faces.push(new THREE.Face3(1, 5, 2)); // white
geometry.faces.push(new THREE.Face3(5, 6, 2));
geometry.faces.push(new THREE.Face3(2, 6, 3)); // red
geometry.faces.push(new THREE.Face3(3, 6, 7));
geometry.faces.push(new THREE.Face3(0, 3, 4)); // yellow
geometry.faces.push(new THREE.Face3(3, 7, 4));
// Set faces colors
geometry.faces[0].color.setHex(b); // Half face
geometry.faces[1].color.setHex(y);
geometry.faces[2].color.setHex(w);
geometry.faces[3].color.setHex(r);
geometry.faces[4].color.setHex(b); // Whole face
geometry.faces[5].color.setHex(b);
geometry.faces[6].color.setHex(w);
geometry.faces[7].color.setHex(w);
geometry.faces[8].color.setHex(r);
geometry.faces[9].color.setHex(r);
geometry.faces[10].color.setHex(y);
geometry.faces[11].color.setHex(y);
// MATERIAL
// Make a material
let material = new THREE.MeshBasicMaterial({
// color: 0x00FF00,
vertexColors: THREE.FaceColors,
wireframe: false,
});
// MESH
let cube = new THREE.Mesh(geometry, material);
return cube;
}
function rotateTo(face) {
if (face == 'yellow')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI / 2, Math.PI / 2));
else if (face == 'red')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, Math.PI / 2));
else if (face == 'blue')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, -Math.PI / 2));
else if (face == 'white')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(-Math.PI / 2, Math.PI / 2, 0));
else if (face == 'yb')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0));
else if (face == 'rw')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI, 0, 0));
animate();
}
function animate() {
let id = requestAnimationFrame(animate);
let delta = clock.getDelta();
scene.children[0].quaternion.rotateTowards(angle, Math.PI * delta);
renderer.render(scene, camera);
if (scene.children[0].quaternion.equals(angle)) {
cancelAnimationFrame(id);
}
}
#container {
background-color: #aaa;
width: 20em;
height: 20em;
}
<script src="https://threejs.org/build/three.min.js"></script>
<div>
<button onclick="rotateTo('yellow')">yellow</button>
<button onclick="rotateTo('red')">red</button>
<button onclick="rotateTo('blue')">blue</button>
<button onclick="rotateTo('white')">white</button>
<button onclick="rotateTo('yb')">yellow/blue</button>
<button onclick="rotateTo('rw')">red/white</button>
</div>
<div id="container"></div>
The reason for the animation not playing is because when you cancelAnimationFrame
the clock is still running, so the next time you call rotateTo
the delta is so high that the animation ends immediately.
you can avoid this by stopping the clock with cancelAnimationFrame
, and start it again when calling rotateTo
as follows:
function rotateTo(face) {
clock.start()
...
}
function animate() {
...
if (scene.children[0].quaternion.equals(angle)) {
cancelAnimationFrame(id);
clock.stop()
}
}
as for rotation speed, the 2nd arg of rotateTowards
is step, which determines how fast will it get there. So if you add a modifier var to it, you can control the speed.
let rotSpeedMotifier = 0.2 // the higher the faster
scene.children[0].quaternion.rotateTowards(angle, Math.PI * delta * rotSpeedMotifier );
这篇关于为什么立方体并不总是用three.js制作动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!