How can I match the rotation of one Object3D to another (different parents, different coords)?

后端 未结 1 456
有刺的猬
有刺的猬 2021-01-23 11:57

I want to match the rotation of a reference object in three.js. The object3d I want to rotate and the reference object might have different parents in different local transforms

相关标签:
1条回答
  • 2021-01-23 12:03

    Note: I'd normally ask what you have tried so far, because it sounds like a fairly easy thing to accomplish. But when I tried it myself, I wasn't able to make it work, and I had to jump through several hoops to make it work correctly.

    In the example code below, I start with two Groups, each containing a cube. Each Group also has its own transformation/rotation. This makes the cubes initially face in different directions.

    In the animate function, you can see when the "Spin" checkbox is checked, I tear apart (decompose) the redCube's world matrix, saving its quaternion (used for rotation) into tempQ. I do the same thing to greenCube. I then re-build (compose) greenCube's world matrix, using its original translation and scale, but using redCube's quaternion. (And remember, this is the world quaternion, so it's not affected by local transformations.)

    This works because I took a direct shortcut to the most important part of transforming the object: its world matrix. I disabled updating matrices across the board, which removes a lot of the convenience of three.js, but it allowed me to work directly with the world matrices without anything overwriting them.

    Here's hoping someone can find a more elegant solution for you.

    var renderer, scene, camera, controls, stats, redCube, greenCube, t, q, tempQ, s;
    
    var WIDTH = window.innerWidth,
    	HEIGHT = window.innerHeight,
    	FOV = 35,
    	NEAR = 1,
    	FAR = 1000;
    
    var doUpdates = false;
    var spinBox = document.getElementById("spin");
    spinBox.addEventListener("change", function(){
      doUpdates = spinBox.checked;
    });
    
    function populateScene(){
    
      var axis = new THREE.Vector3();
      var pos = new THREE.Vector3();
      var cubeGeo = new THREE.BoxBufferGeometry(10, 10, 10);
    
      axis.set(Math.random(), Math.random(), Math.random());
      pos.set(-10, 0, 0);
      var p1 = new THREE.Group();
      p1.matrixWorld.makeRotationAxis(axis, Math.random());
      p1.matrixWorld.setPosition(pos);
    	redCube = new THREE.Mesh(cubeGeo, new THREE.MeshPhongMaterial({ color: "red" }));
    	p1.add(redCube);
      redCube.updateMatrixWorld(true);
      
      scene.add(p1);
      
      axis.set(Math.random(), Math.random(), Math.random());
      pos.set(10, 0, 0);
      var p2 = new THREE.Group();
      p2.matrixWorld.makeRotationAxis(axis, Math.random());
      p2.matrixWorld.setPosition(pos);
    	greenCube = new THREE.Mesh(cubeGeo, new THREE.MeshPhongMaterial({ color: "green" }));
    	p2.add(greenCube);
      greenCube.updateMatrixWorld(true);
      
      scene.add(p2);
    }
    
    function init() {
    	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();
      scene.autoUpdate = false;
    
    	camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
    	camera.position.z = 50;
    	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;
    
    	populateScene();
      
      t = new THREE.Vector3();
      q = new THREE.Quaternion();
      tempQ = new THREE.Quaternion();
      s = new THREE.Vector3();
    
    	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() {
    	requestAnimationFrame(animate);
      camera.updateMatrixWorld(true);
      
      if(doUpdates){
        redCube.rotation.x += 0.01;
        redCube.rotation.y += 0.02;
        redCube.rotation.z += 0.03;
        redCube.updateMatrixWorld(true);
        
        redCube.matrixWorld.decompose(t, tempQ, s);
        greenCube.matrixWorld.decompose(t, q, s);
        greenCube.matrixWorld.compose(t, tempQ, s);
      }
      
    	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();
    			})
    		})
    	})
    })();
    <label style="display: block; float: right; width: 200px;">Spin:<input type="checkbox" id="spin" /></label>

    0 讨论(0)
提交回复
热议问题