Как мы можем изменить начало вращения (точку вращения) объекта Three.js без изменения древовидной структуры или геометрии сцены? - PullRequest
1 голос
/ 12 марта 2019

Я знаю, что мы можем сделать так, чтобы у объекта появился новый родительский элемент, который мог бы выступать в качестве стержня, или мы могли бы отрегулировать положение геометрии в сетке.

Но как мы можем достичь этого математически без переопределения объекта или измененияродительский объект, и без изменения геометрии объекта (если это сетка)?

Другими словами, что мы должны сделать с его матрицей преобразования (или деталями, вращением, положением, кватернионом и т. д.)) чтобы достичь того же, с вышеуказанным требованием не трогать родителей или геометрию?

1 Ответ

2 голосов
/ 13 марта 2019
  1. Возьмите поворотную матрицу и переверните ее. Инвертированная матрица, когда она применяется, установит поворот к источнику мира, а ваш объект куда-нибудь еще. Теперь ваш объект относительно точки разворота [0,0,0].

  2. Применить преобразования, которые вы хотели бы сделать относительно точки разворота.

  3. Повторно применить начальную сводную матрицу (эй, не перевернутую!), Чтобы разместить объект там, где он был раньше.

В моем примере все шаги разделены, главным образом, для объяснения логики. Конечно, вы не должны преобразовывать объект поворота (возможно, у вас его даже нет). И все шаги могут быть сжаты в одной строке формулы:

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

Рабочая демоверсия вы найдете здесь: https://jsfiddle.net/mmalex/hd8ex0ok/

// example for /9233941/mozhem-izmenit-nachalo-vrascheniya-tochku-vrascheniya-obekta-three-izmeneniya-drevovidnoi-struktury-geometrii-stseny

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>

rotate three.js object around pivot point

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