2016-12-02 118 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); 

...并前进到投影矩阵计算。