简体   繁体   English

如何在不修改场景树结构或几何图形的情况下更改Three.js对象的旋转原点(轴点)?

[英]How can we change the rotation origin (pivot point) of a Three.js object without modifying scene tree structure or geometry?

I know we can make the object have a new parent to act as the pivot, or we could adjust the geometry position within the mesh. 我知道我们可以让对象有一个新的父对象作为枢轴,或者我们可以调整网格中的几何位置。

But how can we achieve this mathematically without reparenting the object or modifying the object's parent, and without modifying the object's geometry (if it is a mesh)? 但是,如果不重新定义对象或修改对象的父级,并且不修改对象的几何(如果它是网格),我们如何才能以数学方式实现这一目标?

In other words, what would we have to do to its transform matrix (or the parts, rotation, position, quaternion, etc) to achieve the same, with the above requirement of not touching parents or geometry? 换句话说,我们必须对其变换矩阵(或零件,旋转,位置,四元数等)做什么才能实现相同的目标,上述要求不接触父母或几何?

  1. Take pivot matrix and inverse it. 采用枢轴矩阵并反转它。 Inversed matrix, when applied, will place pivot to world origin and your object to somewhere else. 反转矩阵在应用时会将枢轴放置到世界原点,将对象放置到其他位置。 Now your object is relative to pivot point [0,0,0]. 现在您的对象相对于轴点[0,0,0]。

  2. Apply transforms, that you would like to make relative to pivot point. 应用您想要相对于轴点的变换。

  3. Reapply initial pivot matrix (hey, not inversed!) to place object where it was before. 重新应用初始枢轴矩阵(嘿,不反转!)将对象放在之前的位置。

My example does all steps separate, mainly to explain the logic. 我的例子将所有步骤分开,主要是为了解释逻辑。 Of course, you should not transform pivot object (maybe you don't even have one). 当然,你不应该转换枢轴对象(也许你甚至没有)。 And all steps can be compressed in one line formula: 所有步骤都可以用一行公式压缩:

object.matrix = inverse(pivot.matrix)*someTranformationMatrix*pivot.matrix

Working demo you find here: https://jsfiddle.net/mmalex/hd8ex0ok/ 您可以在此处找到工作演示: https//jsfiddle.net/mmalex/hd8ex0ok/

 // example for https://stackoverflow.com/questions/55116131/how-can-we-change-the-rotation-origin-pivot-point-of-a-three-js-object-without let renderer; let camera; let controls; let scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(54, window.innerWidth / window.innerHeight, 0.1, 1000); renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setClearColor(new THREE.Color(0xfefefe)); document.body.appendChild(renderer.domElement); camera.position.x = 4; camera.position.y = 10; camera.position.z = 4; camera.lookAt(0, 0, 0); controls = new THREE.OrbitControls(camera); // white spotlight shining from the side, casting a shadow let spotLight = new THREE.SpotLight(0xffffff, 2.5, 25, Math.PI / 6); spotLight.position.set(9, 10, 1); scene.add(spotLight); var light = new THREE.AmbientLight(0x202020); // soft white light scene.add(light); // example starts here let gridHelper = new THREE.GridHelper(4, 4); scene.add(gridHelper); var axesHelper = new THREE.AxesHelper(1); axesHelper.applyMatrix(new THREE.Matrix4().makeTranslation(1.5, 0, -1.5)); axesHelper.updateMatrixWorld(true); scene.add(axesHelper); document.changePivot = function() { axesHelper.position.set(-2 + 4*Math.random(), -2 + 4*Math.random(), -2 + 4*Math.random()); axesHelper.updateMatrixWorld(true); } const geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5); const material = new THREE.MeshStandardMaterial({ color: 0xff0000 }); const topBox = new THREE.Mesh(geometry, material); topBox.applyMatrix(new THREE.Matrix4().makeRotationX(Math.PI / 8)); topBox.applyMatrix(new THREE.Matrix4().makeTranslation(0.5, 1, -0.5)); scene.add(topBox); let animate = function() { requestAnimationFrame(animate); // get world transforms from desired pivot var pivot_matrix = axesHelper.matrixWorld.clone(); // inverse it to know how to move pivot to [0,0,0] let pivot_inv = new THREE.Matrix4().getInverse(pivot_matrix, false); // place pivot to [0,0,0] // apply same transforms to object axesHelper.applyMatrix(pivot_inv); topBox.applyMatrix(pivot_inv); // say, we want to rotate 0.1deg around Y axis of pivot var desiredTransform = new THREE.Matrix4().makeRotationY(Math.PI / 180); axesHelper.applyMatrix(desiredTransform); topBox.applyMatrix(desiredTransform); // and put things back, ie apply pivot initial transformation axesHelper.applyMatrix(pivot_matrix); topBox.applyMatrix(pivot_matrix); controls.update(); renderer.render(scene, camera); }; animate(); 
 body { margin: 0; } 
 <button onclick="changePivot()">set random pivot</button> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/91/three.js"></script> <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script> 

围绕枢轴点旋转three.js对象

let renderer;
let camera;
let controls;

let scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(54, window.innerWidth / window.innerHeight, 0.1, 1000);

renderer = new THREE.WebGLRenderer({
    antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(new THREE.Color(0xfefefe));
document.body.appendChild(renderer.domElement);

camera.position.x = 5;
camera.position.y = 15.5;
camera.position.z = 5.5;
camera.lookAt(0, 0, 0);

controls = new THREE.OrbitControls(camera);

// white spotlight shining from the side, casting a shadow
let spotLight = new THREE.SpotLight(0xffffff, 2.5, 25, Math.PI / 6);
spotLight.position.set(9, 10, 1);
scene.add(spotLight);
var light = new THREE.AmbientLight(0x202020); // soft white light
scene.add(light);

// example starts here
let gridHelper = new THREE.GridHelper(4, 4);
scene.add(gridHelper);
var axesHelper = new THREE.AxesHelper(1);
axesHelper.applyMatrix(new THREE.Matrix4().makeTranslation(1.5, 0, -1.5));
scene.add(axesHelper);

const geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);
const material = new THREE.MeshStandardMaterial({
    color: 0xff0000
});
const topBox = new THREE.Mesh(geometry, material);
topBox.applyMatrix(new THREE.Matrix4().makeRotationX(Math.PI / 8));
topBox.applyMatrix(new THREE.Matrix4().makeTranslation(0.5, 1, -0.5));
scene.add(topBox);

let animate = function() {
    requestAnimationFrame(animate);

    // get world transforms from desired pivot
    axesHelper.updateMatrixWorld(true);
    var pivot_matrix = axesHelper.matrixWorld.clone();
    // inverse it to know how to move pivot to [0,0,0]
    let pivot_inv = new THREE.Matrix4().getInverse(pivot_matrix, false);

    // place pivot to [0,0,0]
    // apply same transforms to object
    axesHelper.applyMatrix(pivot_inv);
    topBox.applyMatrix(pivot_inv);

    // say, we want to rotate 0.1deg around Y axis of pivot
    var desiredTransform = new THREE.Matrix4().makeRotationY(Math.PI / 180);
    axesHelper.applyMatrix(desiredTransform);
    topBox.applyMatrix(desiredTransform);

    // and put things back, i.e. apply pivot initial transformation
    axesHelper.applyMatrix(pivot_matrix);
    topBox.applyMatrix(pivot_matrix);

    controls.update();
    renderer.render(scene, camera);
};

animate();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM