【问题标题】:ThreeJS rotate around axisThreeJS绕轴旋转
【发布时间】:2019-04-14 18:52:20
【问题描述】:

我想围绕浅蓝色轴旋转这个立方体。如果我改变 THREE.Vector3(0,0,0) 而不是 THREE.Vector3(0.4,0,0.9) 的旋转,我会工作

我不知道为什么立方体形状会发生变化以及为什么随着迭代次数的增加它会变小

An fiddle showing this problem(请忽略糟糕的实现。我只是换了一个旧的)

这就是我进行轮换的方式:

function rotate(deg) {
  _initTranslation = new THREE.Vector3();
  _initRotation = new THREE.Quaternion();
  _initScale = new THREE.Vector3();
  rotateMatrix = new THREE.Matrix4();

  cube.matrix.decompose(_initTranslation, _initRotation, _initScale);

  cube.matrix = rotateMatrix.compose(_initTranslation, new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0.4,1,0.9), THREE.Math.degToRad(deg)), _initScale);

  cube.matrixAutoUpdate = false;
  cube.matrixWorldNeedsUpdate = true;

}

也许有人知道我做错了什么。

var renderer, scene, camera, controls;
var geometry, material, line, vertices, last, _initTranslation, _initRotation, initScale, rotateMatrix;

var deg = 0;

init();
animate();

function init() {

  document.body.style.cssText = 'margin: 0; overflow: hidden;' ;

  renderer = new THREE.WebGLRenderer( { alpha: 1, antialias: true, clearColor: 0xffffff }  );
  renderer.setSize( window.innerWidth, window.innerHeight );
  document.body.appendChild( renderer.domElement );
  scene = new THREE.Scene();

  camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
  camera.position.set( 5, 5, 5 );
  controls = new THREE.OrbitControls( camera, renderer.domElement );
  
  geometry2 = new THREE.BoxGeometry( .5, .5, .5 );
  material2 = new THREE.MeshNormalMaterial();
  cube = new THREE.Mesh( geometry2, material2 );
  scene.add( cube );       
  

  material = new THREE.LineBasicMaterial({ color: 0x0077ff }); 
  geometry = new THREE.Geometry();
  geometry.vertices.push( new THREE.Vector3( 0, 0, 0) );
  line = new THREE.Line( geometry, material ) 
  scene.add( line );
  
  var sphereAxis = new THREE.AxesHelper(20);
  scene.add(sphereAxis);

  addStep();
  
  cube.lookAt(new THREE.Vector3(0.4,0,0.9));

}

function addStep() {

  vertices = geometry.vertices;
  last = vertices[ vertices.length - 1 ];
  vertices.push( 

    new THREE.Vector3(0.4,0,0.9) 

  );

  geometry = new THREE.Geometry();
  geometry.vertices = vertices;

  scene.remove( line );
  line = new THREE.Line( geometry, material )
  scene.add( line );

}

function animate() {
    
  rotate(deg)
  
  deg += 5
  
  requestAnimationFrame( animate ); 
  renderer.render(scene, camera);
  controls.update();

}

function rotate(deg) {
  _initTranslation = new THREE.Vector3();
  _initRotation = new THREE.Quaternion();
  _initScale = new THREE.Vector3();
  rotateMatrix = new THREE.Matrix4();
    
  cube.matrix.decompose(_initTranslation, _initRotation, _initScale);
  
  cube.matrix = rotateMatrix.compose(_initTranslation, new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0.4,0,0.9), THREE.Math.degToRad(deg)), _initScale);

    
    cube.matrixAutoUpdate = false;
    cube.matrixWorldNeedsUpdate = true;
  
  
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

【问题讨论】:

标签: javascript three.js


【解决方案1】:

Quaternion 的向量分量必须是 (normalize.)。归一化向量 (Unit vector) 的长度为 1.0。

在您的情况下,矢量分量 (THREE.Vector3(0.4, 0, 0.9)) 的长度小于 1.0:

sqrt(0.9*0.9 + 0.0*0.0 + 0.4*0.4) = sqrt(0.81 + 0.16) = sqrt(0.97) = 0.9409

这会导致立方体按时间播种。这可以通过记录缩放组件 (console.log(_initScale)) 来验证。
如果您要使用长度大于 1.0 的矢量组件(例如 THREE.Vector3(0.5, 0, 0.9),那么立方体将按比例放大。

标准化四元数的轴,解决问题:

let axis = new THREE.Vector3(0.4, 0, 0.9);
let q = new THREE.Quaternion().setFromAxisAngle(axis.normalize(), THREE.Math.degToRad(deg)); 
cube.matrix = rotateMatrix.compose(_initTranslation, q, _initScale);

如果您希望立方体的一侧与轴对齐,以这种方式,轴垂直于一侧,那么这是完全不同的。
您必须进行 2 次旋转。首先围绕 x 轴连续旋转立方体(例如),然后将 x 轴转到目标轴(0.4、0、0.9)。使用.setFromAxisAngle` 初始化一个将x轴旋转到目标轴的四元数:

let x_axis = new THREE.Vector3(1, 0, 0);
let axis = new THREE.Vector3(0.4, 0, 0.9);
let q_align = new THREE.Quaternion().setFromUnitVectors(x_axis, axis.normalize());
let q_rotate = new THREE.Quaternion().setFromAxisAngle(x_axis, THREE.Math.degToRad(deg));
let q_final = q_align.clone().multiply(q_rotate);
cube.matrix = rotateMatrix.compose(_initTranslation, q, _initScale);

查看示例,它比较了两种不同的行为:

var renderer, scene, camera, controls;
var geometry, material, line, vertices, last, _initTranslation, _initRotation, initScale, rotateMatrix;

var deg = 0;

init();
animate();

function init() {

    document.body.style.cssText = 'margin: 0; overflow: hidden;' ;

    renderer = new THREE.WebGLRenderer( { alpha: 1, antialias: true, clearColor: 0xffffff }  );
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );
    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
    camera.position.set( 1, 3, 3 );
    controls = new THREE.OrbitControls( camera, renderer.domElement );
    
    geometry2 = new THREE.BoxGeometry( .5, .5, .5 );
    material2 = new THREE.MeshNormalMaterial();
    
    let shift = 0.5
    cube = new THREE.Mesh( geometry2, material2 );
    cube.matrix.makeTranslation(shift, 0, 0);
    scene.add( cube );
    cube2 = new THREE.Mesh( geometry2, material2 );
    cube2.matrix.makeTranslation(-shift, 0, 0);
    scene.add( cube2 );       
    
    material = new THREE.LineBasicMaterial({ color: 0x0077ff }); 
    geometry = new THREE.Geometry();
    geometry.vertices.push( new THREE.Vector3(-0.4, 0, -0.9), new THREE.Vector3(0.4, 0, 0.9) );
    line = new THREE.Line( geometry, material ) 
    line.position.set(shift, 0, 0);
    scene.add( line );
    line2 = new THREE.Line( geometry, material ) 
    line2.position.set(-shift, 0, 0);
    scene.add( line2 );

    var sphereAxis = new THREE.AxesHelper(20);
    scene.add(sphereAxis);
    
    window.onresize = function() {
        renderer.setSize(window.innerWidth, window.innerHeight);
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
    }
}

function animate() {  
    rotate(deg)
    deg += 5
    
    requestAnimationFrame( animate ); 
    renderer.render(scene, camera);
    controls.update();
}

function rotate(deg) {
    _initTranslation = new THREE.Vector3();
    _initRotation = new THREE.Quaternion();
    _initScale = new THREE.Vector3();
    
    let x_axis = new THREE.Vector3(1, 0, 0);
    let axis = new THREE.Vector3(0.4, 0, 0.9);

    // cube

    cube.matrix.decompose(_initTranslation, _initRotation, _initScale);
    
    let q_align = new THREE.Quaternion().setFromUnitVectors(x_axis, axis.normalize());
    let q_rotate = new THREE.Quaternion().setFromAxisAngle(x_axis, THREE.Math.degToRad(deg));
    let q_final = q_align.clone().multiply(q_rotate);
    
    cube.matrix.compose(_initTranslation, q_final, _initScale);
    cube.matrixAutoUpdate = false;
    cube.matrixWorldNeedsUpdate = true;

    // cube2

    cube2.matrix.decompose(_initTranslation, _initRotation, _initScale);
    
    q = new THREE.Quaternion().setFromAxisAngle(axis.normalize(), THREE.Math.degToRad(deg));
    
    cube2.matrix.compose(_initTranslation, q, _initScale);
    cube2.matrixAutoUpdate = false;
    cube2.matrixWorldNeedsUpdate = true;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

【讨论】:

  • 谢谢。现在我知道为什么它缩小了。但它仍然不绕轴旋转。
  • @breezertwo “但它仍然不绕轴旋转” - 不!立方体完美地围绕轴旋转!可能你不知道绕轴旋转是什么意思。可能你想要实现完全不同的东西。我只能猜测。如果您想将立方体的任意一侧与轴“对齐”,以使轴垂直于该侧,请参阅答案中的新建议。您的问题不完整且不清楚。
  • 谢谢@Rabbid76。是的,很抱歉不清楚......但无论如何这是一个很好的解决方案。非常感谢。
猜你喜欢
  • 2017-10-13
  • 1970-01-01
  • 1970-01-01
  • 2021-07-12
  • 2016-09-10
  • 1970-01-01
  • 2016-12-11
  • 2013-09-15
  • 2016-10-06
相关资源
最近更新 更多