2016-12-02 120 views
2

我正在three.js中創建水,到目前爲止我還沒有在three.js中實現反射和折射的任何水示例,但是如果你這樣做,請鏈接。 在我被Slayvin在上Mirror.js的頂部建築工作的那一刻 https://threejs.org/examples/webgl_mirror.htmlMirror.js中的矩陣操作(三個j)

我的計劃是使用第二渲染目標渲染refractiontexture以類似的方式爲反射,然後混合兩種紋理着色器。

現在我有一個臨時折射rendertarget,我用於混合,它工作。然而,由於我沒有對紋理應用正確的矩陣乘法,因此此時的臨時折射被嚴重扭曲。它應該比我想象的鏡子容易得多,但是這不起作用,因爲我認爲它會。我怎麼知道最初的紋理矩陣應該設置爲什麼?

this.updateMatrixWorld(); 
this.camera.updateMatrixWorld(); 

// Update the texture matrix 
this.textureMatrixRefraction.set(0.5, 0.0, 0.0, 0.5, 
         0.0, 0.5, 0.0, 0.5, 
         0.0, 0.0, 0.5, 0.5, 
         0.0, 0.0, 0.0, 1.0); 

this.textureMatrixMirror.multiply(this.camera.projectionMatrix); 
this.textureMatrixMirror.multiply(this.camera.matrixWorldInverse); 

我試圖找出對鏡子裏的矩陣運算是如何工作的,因爲我失去了一些東西很重要。我試圖從這是上面的代碼做一個簡單的版本。代碼中的上限註釋是我的,所以如果你能解釋一些我認爲很好的問題標記。

THREE.Water.prototype.updateTextureMatrixMirror = function() { 

    //UPDATE TO CURRENT WORLD AND CAMERA FOR MIRROROBJECT 
this.updateMatrixWorld(); 
this.camera.updateMatrixWorld(); 
//COPY VALUES FROM WORLD AND CAMERA, GETTING TRANSFORMATIONS IN WORLD 
this.mirrorWorldPosition.setFromMatrixPosition(this.matrixWorld); 
this.cameraWorldPosition.setFromMatrixPosition(this.camera.matrixWorld); 

this.rotationMatrix.extractRotation(this.matrixWorld); 
//SET NORMAL AND APPLY ROTATION 
this.normal.set(0, 0, 1); 
this.normal.applyMatrix4(this.rotationMatrix); 
//CREATE NEW CAMERA VIEW, THIS IS ONLY RELEVANT FOR THE REFLECTION 
var view = this.mirrorWorldPosition.clone().sub(this.cameraWorldPosition); 
view.reflect(this.normal).negate(); //tHIS IS NOT NEEDED FOR REFRACTION? 
view.add(this.mirrorWorldPosition); 

this.rotationMatrix.extractRotation(this.camera.matrixWorld); 
//SET LOOKAT... NOT REALLY GRASPING WHAT IT CHANGES? 
this.lookAtPosition.set(0, 0, -1); 
this.lookAtPosition.applyMatrix4(this.rotationMatrix); 
this.lookAtPosition.add(this.cameraWorldPosition); 
//TARGET, ALSO TROUBLY UNDERSTANDING WHAT IT CHANGES 
var target = this.mirrorWorldPosition.clone().sub(this.lookAtPosition); 
target.reflect(this.normal).negate(); //WHAT HAPPENS HERE?? 
target.add(this.mirrorWorldPosition); 

this.up.set(0, -1, 0); //CHANGING TO NEG Y 
this.up.applyMatrix4(this.rotationMatrix); 
this.up.reflect(this.normal).negate(); // IS THIS NEEDED? 

//MIRRORCAMERA COPIES THE GENERATED VALUES AND UPDATES 
this.mirrorCamera.position.copy(view); 
this.mirrorCamera.up = this.up; 
this.mirrorCamera.lookAt(target); 

this.mirrorCamera.updateProjectionMatrix(); 
this.mirrorCamera.updateMatrixWorld(); 
this.mirrorCamera.matrixWorldInverse.getInverse(this.mirrorCamera.matrixWorld); // IS THIS NEEDED FOR REFRACTION? 
//THIS IS WHERE THE MAGIC HAPPENS, TEXTURE MATRIX IS UPDATED 
// Update the texture matrix 
this.textureMatrixMirror.set(0.5, 0.0, 0.0, 0.5, 
         0.0, 0.5, 0.0, 0.5, 
         0.0, 0.0, 0.5, 0.5, 
         0.0, 0.0, 0.0, 1.0); 
//USE THE GENERATED MIRRORCAMERA TO GET MATRIX MULTIPLICATIONS 
this.textureMatrixMirror.multiply(this.mirrorCamera.projectionMatrix); 
this.textureMatrixMirror.multiply(this.mirrorCamera.matrixWorldInverse); 

// AS I UNDERSTAND, THIS PART DEALS WITH THE CLIPPING USING OBLIQUE FRUSTUMS 
// Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html 
// Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf 
this.waterPlane.setFromNormalAndCoplanarPoint(this.normal, this.mirrorWorldPosition); 
this.waterPlane.applyMatrix4(this.mirrorCamera.matrixWorldInverse); 

this.clipPlane.set(this.waterPlane.normal.x, this.waterPlane.normal.y, this.waterPlane.normal.z, this.waterPlane.constant); 

var q = new THREE.Vector4(); 
var projectionMatrix = this.mirrorCamera.projectionMatrix; 

q.x = (Math.sign(this.clipPlane.x) + projectionMatrix.elements[ 8 ])/projectionMatrix.elements[ 0 ]; 
q.y = (Math.sign(this.clipPlane.y) + projectionMatrix.elements[ 9 ])/projectionMatrix.elements[ 5 ]; 
q.z = - 1.0; 
q.w = (1.0 + projectionMatrix.elements[ 10 ])/projectionMatrix.elements[ 14 ]; 

// Calculate the scaled plane vector 
var c = new THREE.Vector4(); 
c = this.clipPlane.multiplyScalar(2.0/this.clipPlane.dot(q)); 

// Replacing the third row of the projection matrix 
projectionMatrix.elements[ 2 ] = c.x; 
projectionMatrix.elements[ 6 ] = c.y; 
projectionMatrix.elements[ 10 ] = c.z + 1.0 - this.clipBias; 
projectionMatrix.elements[ 14 ] = c.w; 

更新:所以我得到了一個半血統的視覺效果,但是,也有一些錯誤,我知道我不能正常產生,因爲錯誤的矩陣變換的折射質感。此外,我正努力爲我已經實現的dudv-map的偏移量獲得良好的流量,目前我正在使用正弦函數,但這會導致搖擺運動,看起來非常不自然,儘管它可以避免一個「跳躍切割」,只是用剩餘的分割值循環rippleMoveFactor。看到當前結果和全碼:Demo

回答

1

這裏有一些解釋:

的「lookatPosition」部分好像沒用,但它可以讓我在前面得到的位置1個單位遠(Z軸)當前視圖:

this.lookAtPosition.set(0, 0, -1); // -1 unit on Z (depth axis) 
this.lookAtPosition.applyMatrix4(this.rotationMatrix); // applying camera rotation to that lookat vector, so they are both the same 
this.lookAtPosition.add(this.cameraWorldPosition); // adding that vector to the camera position 

這一立場被用於進一步的計算和純粹是任意的,它可能是從相機-10或-0.5單位了,沒關係,只要它是一個衆所周知的位於相機軸線上的位置。我選擇了'-1',因此更容易處理。因此,我們知道相機的位置,我們現在知道相機正在看的至少一個空間點,並且我們也知道鏡子的位置和方向。 所以,現在是時候來計算我們的鏡像視圖的方向:

var target = this.mirrorWorldPosition.clone().sub(this.lookAtPosition); 
target.reflect(this.normal).negate(); 
target.add(this.mirrorWorldPosition); 

首先我創建目標載體,它是目標和後視鏡位置之間的差異。
然後沿反射鏡法線反射該矢量,然後反轉(否定)它,以便現在可以將其添加到反射鏡位置,並且現在可以獲得鏡像目標的最終位置。

最後,我設置鏡像相機正確起來,目標和位置...

this.mirrorCamera.position.copy(view); 
this.mirrorCamera.up = this.up; 
this.mirrorCamera.lookAt(target); 

...並前進到投影矩陣計算。