Reputation: 8350
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>
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>
Upvotes: 1
Views: 67
Reputation: 747
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 );
Upvotes: 3