tween.js 和 three.js 未对齐的平滑旋转
Misalligned smooth rotation with tween.js and three.js
使用 three.js 和 tween.js 我正在尝试创建魔方。它由 27 个小立方体组成,这些立方体组合在一起按 +Math.PI/2
或 -Math.PI/2
旋转。补间库用于平滑旋转。
我的问题是,如果一张脸被旋转多次(超过 10 次),它会明显错位,我无法理解如何修复它(link 问题的视觉图像)。
这是下例中旋转对象的函数:
function rotate( ii ) {
// Creates a dummy object to group multiple objects together and
// rotate (only one object in this example).
var rotationGroup = new THREE.Object3D();
scene.add(rotationGroup);
THREE.SceneUtils.attach( box[ ii ], scene, rotationGroup );
rotationGroup.updateMatrixWorld();
// Checks that no other animations are active. If so stops the
// function (this is rude, but it's not the focus of the example).
if( TWEEN.getAll().length>0 )
return;
// Creates the tween object for animation.
var tween;
var duration = 300;
var radiants = Math.PI/2;
tween = new TWEEN.Tween( rotationGroup.rotation ).to( { z: radiants }, duration );
tween.easing( TWEEN.Easing.Quadratic.InOut );
tween.onComplete(
function() {
THREE.SceneUtils.detach( box[ ii ], rotationGroup, scene );
box[ii].updateMatrixWorld();
scene.remove(rotationGroup);
}
);
// Starts the animation.
tween.start();
}
我不知道如何在 Whosebug 上创建 运行 代码片段,所以现在我将粘贴一些代码来复制问题(不是 rubick 的代码,它更长更混乱)。
var camera, scene, renderer;
var canvas;
var cameraControls;
var clock = new THREE.Clock();
var box = [];
function main() {
init();
fillScene();
addToDOM();
animate();
function init() {
var canvasWidth = window.innerWidth;
var canvasHeight = window.innerHeight;
var canvasRatio = canvasWidth / canvasHeight;
// RENDERER
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.setSize(canvasWidth, canvasHeight);
renderer.setClearColor( 0xAAAAAA );
// CAMERA
camera = new THREE.PerspectiveCamera( 45, canvasRatio, 1, 1000 );
camera.position.set(20,15,10);
camera.lookAt( new THREE.Vector3(0,0,0) );
// CONTROLS
cameraControls = new THREE.OrbitControls(camera, renderer.domElement);
document.onkeydown = function(ev) {onKeyDown(ev);};
}
function addToDOM() {
var container = document.getElementById('WebGL-output');
var canvas = container.getElementsByTagName('canvas');
if (canvas.length>0) {
container.removeChild(canvas[0]);
}
container.appendChild( renderer.domElement );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
var delta = clock.getDelta();
cameraControls.update(delta);
TWEEN.update();
renderer.render(scene, camera);
}
function onKeyDown(ev) {
switch( ev.keyCode) {
case 65: // a
rotate(0);
break;
case 83: // s
rotate(1);
break;
case 68: // d
rotate(2);
break;
default: break;
}
}
}
function rotate( ii ) {
var rotationGroup = new THREE.Object3D();
scene.add(rotationGroup);
THREE.SceneUtils.attach( box[ ii ], scene, rotationGroup );
rotationGroup.updateMatrixWorld();
if( TWEEN.getAll().length>0 )
return;
var tween;
var duration = 300;
var radiants = Math.PI/2;
tween = new TWEEN.Tween( rotationGroup.rotation ).to( { z: radiants }, duration );
tween.easing( TWEEN.Easing.Quadratic.InOut );
tween.onComplete(
function() {
THREE.SceneUtils.detach( box[ ii ], rotationGroup, scene );
box[ii].updateMatrixWorld();
scene.remove(rotationGroup);
}
);
tween.start();
}
function fillScene() {
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0xAAAAAA, 2000, 4000 );
var axisHelper = new THREE.AxisHelper( 20 );
scene.add( axisHelper );
// LIGHTS
scene.add( new THREE.AmbientLight(0x333333) );
var light = new THREE.PointLight( 0x333333, 2 );
light.position.set(15,15,15);
scene.add(light);
light = new THREE.PointLight( 0x333333, 2 );
light.position.set(-15,-15,-15);
scene.add(light);
var boxGeometry = new THREE.BoxGeometry( 10, 3, 10);
var red = new THREE.MeshPhongMaterial({ color: 0xff0000 });
var blue = new THREE.MeshPhongMaterial({ color: 0x00ff00 });
var green = new THREE.MeshPhongMaterial({ color: 0x0000ff });
var black = new THREE.MeshPhongMaterial({ color: 0x000000 });
var materials = [
[ red, red, red, red, black, black ],
[ green, green, green, green, black, black ],
[ blue, blue, blue, blue, black, black ]
];
for( var ii=0; ii<3; ii++ ) {
box[ii] = new THREE.Mesh( boxGeometry, new THREE.MeshFaceMaterial(materials[ii]) );
box[ii].rotation.x = Math.PI/2;
box[ii].position.set(0,0,3-(ii*3));
scene.add( box[ii] );
}
}
在 js 控制台上打印 rotationGroup
和 box[ii]
的旋转似乎它们不匹配:Object3D
的旋转在第四个十进制数字上引入了一点错误.
我修改了补间完成后执行的匿名函数,添加了一些检查旋转并设置正确旋转值的代码(感谢@WestLangley 发现了解决方案)。
function() {
THREE.SceneUtils.detach( box[ ii ], rotationGroup, scene );
box[ii].updateMatrixWorld();
scene.remove(rotationGroup);
// Checks the rotation value and sets the correct one accordingly
var check = Math.floor( box[ii].rotation.z );
if( check==1 )
box[ii].rotation.z = Math.PI/2;
else if( check==3 )
box[ii].rotation.z = Math.PI;
else if( check==-2 )
box[ii].rotation.z = -Math.PI/2;
else
box[ii].rotation.z = 0;
}
使用 three.js 和 tween.js 我正在尝试创建魔方。它由 27 个小立方体组成,这些立方体组合在一起按 +Math.PI/2
或 -Math.PI/2
旋转。补间库用于平滑旋转。
我的问题是,如果一张脸被旋转多次(超过 10 次),它会明显错位,我无法理解如何修复它(link 问题的视觉图像)。
这是下例中旋转对象的函数:
function rotate( ii ) {
// Creates a dummy object to group multiple objects together and
// rotate (only one object in this example).
var rotationGroup = new THREE.Object3D();
scene.add(rotationGroup);
THREE.SceneUtils.attach( box[ ii ], scene, rotationGroup );
rotationGroup.updateMatrixWorld();
// Checks that no other animations are active. If so stops the
// function (this is rude, but it's not the focus of the example).
if( TWEEN.getAll().length>0 )
return;
// Creates the tween object for animation.
var tween;
var duration = 300;
var radiants = Math.PI/2;
tween = new TWEEN.Tween( rotationGroup.rotation ).to( { z: radiants }, duration );
tween.easing( TWEEN.Easing.Quadratic.InOut );
tween.onComplete(
function() {
THREE.SceneUtils.detach( box[ ii ], rotationGroup, scene );
box[ii].updateMatrixWorld();
scene.remove(rotationGroup);
}
);
// Starts the animation.
tween.start();
}
我不知道如何在 Whosebug 上创建 运行 代码片段,所以现在我将粘贴一些代码来复制问题(不是 rubick 的代码,它更长更混乱)。
var camera, scene, renderer;
var canvas;
var cameraControls;
var clock = new THREE.Clock();
var box = [];
function main() {
init();
fillScene();
addToDOM();
animate();
function init() {
var canvasWidth = window.innerWidth;
var canvasHeight = window.innerHeight;
var canvasRatio = canvasWidth / canvasHeight;
// RENDERER
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.setSize(canvasWidth, canvasHeight);
renderer.setClearColor( 0xAAAAAA );
// CAMERA
camera = new THREE.PerspectiveCamera( 45, canvasRatio, 1, 1000 );
camera.position.set(20,15,10);
camera.lookAt( new THREE.Vector3(0,0,0) );
// CONTROLS
cameraControls = new THREE.OrbitControls(camera, renderer.domElement);
document.onkeydown = function(ev) {onKeyDown(ev);};
}
function addToDOM() {
var container = document.getElementById('WebGL-output');
var canvas = container.getElementsByTagName('canvas');
if (canvas.length>0) {
container.removeChild(canvas[0]);
}
container.appendChild( renderer.domElement );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
var delta = clock.getDelta();
cameraControls.update(delta);
TWEEN.update();
renderer.render(scene, camera);
}
function onKeyDown(ev) {
switch( ev.keyCode) {
case 65: // a
rotate(0);
break;
case 83: // s
rotate(1);
break;
case 68: // d
rotate(2);
break;
default: break;
}
}
}
function rotate( ii ) {
var rotationGroup = new THREE.Object3D();
scene.add(rotationGroup);
THREE.SceneUtils.attach( box[ ii ], scene, rotationGroup );
rotationGroup.updateMatrixWorld();
if( TWEEN.getAll().length>0 )
return;
var tween;
var duration = 300;
var radiants = Math.PI/2;
tween = new TWEEN.Tween( rotationGroup.rotation ).to( { z: radiants }, duration );
tween.easing( TWEEN.Easing.Quadratic.InOut );
tween.onComplete(
function() {
THREE.SceneUtils.detach( box[ ii ], rotationGroup, scene );
box[ii].updateMatrixWorld();
scene.remove(rotationGroup);
}
);
tween.start();
}
function fillScene() {
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0xAAAAAA, 2000, 4000 );
var axisHelper = new THREE.AxisHelper( 20 );
scene.add( axisHelper );
// LIGHTS
scene.add( new THREE.AmbientLight(0x333333) );
var light = new THREE.PointLight( 0x333333, 2 );
light.position.set(15,15,15);
scene.add(light);
light = new THREE.PointLight( 0x333333, 2 );
light.position.set(-15,-15,-15);
scene.add(light);
var boxGeometry = new THREE.BoxGeometry( 10, 3, 10);
var red = new THREE.MeshPhongMaterial({ color: 0xff0000 });
var blue = new THREE.MeshPhongMaterial({ color: 0x00ff00 });
var green = new THREE.MeshPhongMaterial({ color: 0x0000ff });
var black = new THREE.MeshPhongMaterial({ color: 0x000000 });
var materials = [
[ red, red, red, red, black, black ],
[ green, green, green, green, black, black ],
[ blue, blue, blue, blue, black, black ]
];
for( var ii=0; ii<3; ii++ ) {
box[ii] = new THREE.Mesh( boxGeometry, new THREE.MeshFaceMaterial(materials[ii]) );
box[ii].rotation.x = Math.PI/2;
box[ii].position.set(0,0,3-(ii*3));
scene.add( box[ii] );
}
}
在 js 控制台上打印 rotationGroup
和 box[ii]
的旋转似乎它们不匹配:Object3D
的旋转在第四个十进制数字上引入了一点错误.
我修改了补间完成后执行的匿名函数,添加了一些检查旋转并设置正确旋转值的代码(感谢@WestLangley 发现了解决方案)。
function() {
THREE.SceneUtils.detach( box[ ii ], rotationGroup, scene );
box[ii].updateMatrixWorld();
scene.remove(rotationGroup);
// Checks the rotation value and sets the correct one accordingly
var check = Math.floor( box[ii].rotation.z );
if( check==1 )
box[ii].rotation.z = Math.PI/2;
else if( check==3 )
box[ii].rotation.z = Math.PI;
else if( check==-2 )
box[ii].rotation.z = -Math.PI/2;
else
box[ii].rotation.z = 0;
}