没有几何平移和枢轴的局部网格旋转(THREEJS)

local mesh rotation without geometry translate and pivot (THREEJS)

我尝试将 "local rotation" 应用于 THREEJS 中的网格。

我想围绕几何中心应用旋转,但它是围绕几何 "origin" (0, 0, 0) 应用的。

假设:

  1. 我无法修改几何。

我现在在做什么:

mesh3D.position.copy(worldPosition);
mesh3D.rotation.setFromRotationMatrix(localRotation);
mesh3D.updateMatrixWorld(true);

以某种方式使用枢轴是唯一的解决方案吗?我还想避免这种情况,因为它会更改对象子级层次结构...

谢谢

要围绕不是对象原点的点旋转,适用以下一般操作顺序:

  1. 从对象位置减去点。
  2. 旋转。
  3. 将原点添加到对象位置。

在你的例子中,原点就是几何中心。

下面的例子是一个三角形,其中对象原点和一个角在场景原点,但三角形围绕其几何中心旋转。将 matRot = new THREE.Matrix4().makeRotationX(0.01); 更改为使用 makeRotationY/makeRotationZ 以查看它在其他方向上的工作情况。

请注意,这些变换应用于对象的局部矩阵,因此所有子对象也将跟随其父对象进行变换。

var renderer, scene, camera, controls, stats, tri;

var WIDTH = window.innerWidth,
 HEIGHT = window.innerHeight,
 FOV = 35,
 NEAR = 1,
 FAR = 1000;

function createTri(){
  var geo = new THREE.BufferGeometry();
  geo.addAttribute("position", new THREE.BufferAttribute(new Float32Array([
    -10, 20, 0,
    -20, 0, 0,
    0, 0, 0
  ]), 3));
  geo.addAttribute("normal", new THREE.BufferAttribute(new Float32Array([
    0, 0, 1,
    0, 0, 1,
    0, 0, 1
  ]), 3));
  geo.setIndex(new THREE.BufferAttribute(new Uint32Array([
    0, 1, 2
  ]), 1));
  geo.computeBoundingBox();
  
  tri = new THREE.Mesh(geo, new THREE.MeshPhongMaterial({side: THREE.DoubleSide}));
  scene.add(tri);
}

var matAdd = null, matSub = null, matRot = null;
function rotateTri(){
  var geoCenter = tri.geometry.boundingBox.getCenter();
  matAdd.makeTranslation(geoCenter.x, geoCenter.y, geoCenter.z);
  matSub.getInverse(matAdd);
  tri.applyMatrix(matSub);
  tri.applyMatrix(matRot);
  tri.applyMatrix(matAdd);  
}

function init() {
  matAdd = new THREE.Matrix4();
  matSub = new THREE.Matrix4();
  matRot = new THREE.Matrix4().makeRotationX(0.01);
  
 document.body.style.backgroundColor = "slateGray";

 renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });

 document.body.appendChild(renderer.domElement);
 document.body.style.overflow = "hidden";
 document.body.style.margin = "0";
 document.body.style.padding = "0";

 scene = new THREE.Scene();

 camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
 camera.position.z = 100;
 scene.add(camera);

 controls = new THREE.TrackballControls(camera, renderer.domElement);
 controls.dynamicDampingFactor = 0.5;
 controls.rotateSpeed = 3;

 var light = new THREE.PointLight(0xffffff, 1, Infinity);
 camera.add(light);

 stats = new Stats();
 stats.domElement.style.position = 'absolute';
 stats.domElement.style.top = '0';
 document.body.appendChild(stats.domElement);

 resize();
 window.onresize = resize;

 createTri();

 animate();
}

function resize() {
 WIDTH = window.innerWidth;
 HEIGHT = window.innerHeight;
 if (renderer && camera && controls) {
  renderer.setSize(WIDTH, HEIGHT);
  camera.aspect = WIDTH / HEIGHT;
  camera.updateProjectionMatrix();
  controls.handleResize();
 }
}

function render() {
 renderer.render(scene, camera);
}

function animate() {
  rotateTri(); // rotation method
 requestAnimationFrame(animate);
 render();
 controls.update();
 stats.update();
}

function threeReady() {
 init();
}

(function () {
 function addScript(url, callback) {
  callback = callback || function () { };
  var script = document.createElement("script");
  script.addEventListener("load", callback);
  script.setAttribute("src", url);
  document.head.appendChild(script);
 }

 addScript("https://threejs.org/build/three.js", function () {
  addScript("https://threejs.org/examples/js/controls/TrackballControls.js", function () {
   addScript("https://threejs.org/examples/js/libs/stats.min.js", function () {
    threeReady();
   })
  })
 })
})();

three.jsr85