最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How can we change the rotation origin (pivot point) of a Three.js object without modifying scene tree structure or

programmeradmin1浏览0评论

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?

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?

Share Improve this question edited Mar 12, 2019 at 14:48 trusktr asked Mar 12, 2019 at 7:27 trusktrtrusktr 45.5k58 gold badges210 silver badges287 bronze badges 8
  • You could use quaternion – soju Commented Mar 12, 2019 at 8:06
  • @soju got an example? – trusktr Commented Mar 12, 2019 at 14:48
  • I don't get what you're asking. If you want to move with the pivot somewhere else consider temporarily reparenting it and using SceneUtils attach and detach. You can put a temp object where you want the pivot to be, detach the object you want to rotate, attach to the pivot object, rotate the pivot, now detach the object from the pivot and put it back where it was in the scene with attach. In fact I think I wrote an example here stackoverflow./questions/53503767/… – user128511 Commented Mar 12, 2019 at 15:41
  • Possible duplicate: stackoverflow./questions/31953608/… – WestLangley Commented Mar 12, 2019 at 16:29
  • 1 @gman Maybe possibly useful would have been better. :-) – WestLangley Commented Mar 13, 2019 at 15:45
 |  Show 3 more ments

1 Answer 1

Reset to default 5
  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].

  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 pressed in one line formula:

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

Working demo you find here: https://jsfiddle/mmalex/hd8ex0ok/

// example for https://stackoverflow./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, i.e. 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./ajax/libs/three.js/91/three.js"></script>
<script src="https://threejs/examples/js/controls/OrbitControls.js"></script>

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();

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论