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?
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].
Apply transforms, that you would like to make relative to pivot point.
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/
// 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, 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.com/ajax/libs/three.js/91/three.js"></script>
<script src="https://threejs.org/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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With