2017-07-06 66 views
4

我需要幫助將網格定位到根據本地座標給定的特定點。我創建了高度爲0.1的粉紅色圓柱體,以展示我想要互相觸及的立方體的局部點。在Three.js中定位基於局部向量的子網格

另外我想讓cube2成爲cube1的孩子,但那不是一個交易斷路器。

預期結果:立方體與特定角落接觸並正確旋轉 - 粉紅色柱體應該像素完美地覆蓋彼此。

我試圖解決這個問題:

cube2.position.copy(cube_position.clone().add(cube2_position)) 
cube2.rotation.setFromVector3(cube_rotation.clone().add(cube2_rotation)) 

,但是這不是那樣工作的預期。我應該使用某種矩陣變換嗎?

const scene = new THREE.Scene(); 
 
const camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 1000); 
 
camera.position.set(25, 25, 12); 
 
// setup cubes 
 

 
var geometry = new THREE.CubeGeometry(6, 6, 6); 
 
var material = new THREE.MeshLambertMaterial({ 
 
    color: 0x00fff0 
 
}); 
 
var cube = new THREE.Mesh(geometry, material); 
 
scene.add(cube); 
 

 
cube.position.set(0.3, 1, -2); 
 
cube.rotation.set(Math.PI/3, Math.PI/2, 1) 
 

 
var geometry2 = new THREE.CubeGeometry(4, 4, 4); 
 
var material2 = new THREE.MeshLambertMaterial({ 
 
    color: 0x0fff00 
 
}); 
 
var cube2 = new THREE.Mesh(geometry2, material2); 
 
cube.add(cube2); 
 

 
cube_position = new THREE.Vector3(3, 3, 3) 
 
cube_rotation = new THREE.Vector3(Math.PI/3, Math.PI/4, 0) 
 
cube2_position = new THREE.Vector3(2, -2, 2) 
 
cube2_rotation = new THREE.Vector3(Math.PI/2, Math.PI/2, 0) 
 

 
// visualize points 
 
vmat = new THREE.MeshLambertMaterial({ 
 
    color: 0xFF00FF, 
 
    opacity: 0.5, 
 
    transparent: true 
 
}); 
 
v1 = new THREE.Mesh(new THREE.CylinderGeometry(1, 1, 0.1, 10), vmat); 
 
cube.add(v1) 
 
v1.position.copy(cube_position) 
 
v1.rotation.setFromVector3(cube_rotation) 
 

 
v2 = new THREE.Mesh(new THREE.CylinderGeometry(1, 1, 0.1, 10), vmat); 
 
cube2.add(v2) 
 
v2.position.copy(cube2_position) 
 
v2.rotation.setFromVector3(cube2_rotation) 
 

 
// BUG: connect cube with cube2 on specified points 
 

 
cube2.position.copy(cube_position.clone().add(cube2_position)) 
 
cube2.rotation.setFromVector3(cube_rotation.clone().add(cube2_rotation)) 
 

 
// setup rest 
 
var pointLight = new THREE.PointLight(0xFFFFFF); 
 
pointLight.position.x = 10; 
 
pointLight.position.y = 50; 
 
pointLight.position.z = 130; 
 
scene.add(pointLight) 
 

 
const renderer = new THREE.WebGLRenderer({ 
 
    antialias: true 
 
}); 
 
renderer.setSize(window.innerWidth, window.innerHeight); 
 
renderer.setClearColor(0x20252f); 
 
renderer.setPixelRatio(window.devicePixelRatio); 
 
document.body.appendChild(renderer.domElement); 
 

 
const controls = new THREE.OrbitControls(camera, renderer.domElement); 
 

 
animate(); 
 

 
function animate() { 
 
    requestAnimationFrame(animate); 
 
    render(); 
 
} 
 

 
function render() { 
 
    renderer.render(scene, camera); 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r82/three.js"></script> 
 
<script src="https://yume.human-interactive.org/examples/buffer-geometry/OrbitControls.js"></script>

回答

1

所以,Matrix是真正強大的解決旋轉問題。我分兩步設置cube2旋轉和位置。

  • 旋轉

    的關係之間cube1cube2v1v2是: enter image description here 我們要的是v2世界旋轉等於v1相反的世界旋轉。當兩個物體具有相同的旋轉時,它們具有相同的旋轉矩陣(世界矩陣)。我們有這些公式:

    V1opposite.w = V2.w 
    V1opposite.l * C1.w = V2.l * C2.l * C1.l 
    V1opposite.l = V2.l * C2.l 
    C2.l = V1opposite.l * V2.l(-1) 
    

    凡V1opposite.w意味着v1相反的世界矩陣,V2.w是v2世界矩陣,C表示cube,V2.l(-1)表示v2局部矩陣的逆矩陣。現在,我們可以計算出cube2旋轉矩陣。

  • 位置

    我們需要的是使v1v2世界上的地位一樣什麼。下面是顯示座標空間的圖表:enter image description here 由於v2cube2的子項,因此我們需要移動cube2。在世界空間,我們應該從v2cube2的距離轉換成v1,現在我們得到了cube2世界上的地位,cube2cube1孩子,只是採用的cube1逆矩陣,以獲得cube2局部位置。

這是一個jsfiddle example

希望它有幫助。

更新

我寫了一個功能,你可以使用它沒有v1v2

//connect obj1 and obj2 on obj1's point1 and obj2's point2. 
function connect(obj1,obj2,point1,point2) 
{ 
    var point1World = new THREE.Vector3().copy(point1).applyMatrix4(obj1.matrixWorld); 
    var point2World = new THREE.Vector3().copy(point2).applyMatrix4(obj2.matrixWorld); 
    var translation = new THREE.Vector3().subVectors(point1World,point2World); 
    var obj2World = new THREE.Vector3().copy(obj2.getWorldPosition()); 
    obj2World.add(translation); 
    if(obj2.parent !== null) 
    { 
     var inverseMatrix = new THREE.Matrix4().getInverse(obj2.parent.matrixWorld); 
     obj2World.applyMatrix4(inverseMatrix); 
    } 
    obj2.position.copy(obj2World); 
} 

我還添加了一個爺爺立方體包含cube1cube2jsfiddle

+0

好吧,它有幫助,v1和v2只是爲了演示,所以他們不應該用來解決這個問題。另外我不能在中間計算中使用渲染。我試圖解決這個問題,所以我可以在我的應用中使用你的解決方案,但似乎不可能 – Patryk

+0

我渲染,因爲我需要更新v2和cube2的位置,我認爲這很方便,如果你不想做那個,你可以讓他們的位置應用變換矩陣。除了使用,你想要解決它的方式?任何約束?我可以繼續幫忙。 –

+0

我在我的實際應用程序中實現了您的解決方案,並且當它是孫兒(第一個立方體的孩子的孩子)時,一切都有奇怪的偏移。這讓我瘋狂,我不知道如何正確實施它。 – Patryk