local mesh rotation without geometry translate and

2019-08-18 05:16发布

问题:

I try to apply a "local rotation" to a mesh in THREEJS.

I want to rotation to be applied around the geometry center but it is applied around the geometry "origin" (0, 0, 0).

Assumption:

  1. I can not modify the geometry.

What I do right now:

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

Is the only solution to use a pivot somehow? I'd also like to avoid that as it changes the object children hierarchy...

Thanks

回答1:

To rotate about a point that isn't the object origin, this general order of operations applies:

  1. Subtract the point from the object position.
  2. Rotate.
  3. Add the original point to the object position.

In your case, the original point is the geometric center.

The example below is a triangle where the object origin and one corner is at the scene origin, but the triangle rotates about its geometric center. Change matRot = new THREE.Matrix4().makeRotationX(0.01); to use makeRotationY/makeRotationZ to see it working in other directions.

Note that these transformations are applied to the object's local matrix, so any child objects will be transformed as well, following their parent.

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.js r85