Mirror.js中的矩阵运算(三个js)

时间:2016-12-02 16:38:44

标签: javascript three.js linear-algebra matrix-multiplication

我正在努力在three.js中创造水,到目前为止,我还没有看到三个实现反射和折射的水中的水样例,但如果你这样做,请链接。 目前我正在Slayvin的Mirror.js上工作 https://threejs.org/examples/webgl_mirror.html

我的计划是使用第二个rendertarget以与反射类似的方式渲染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 个答案:

答案 0 :(得分: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 );

...然后进行投影矩阵计算。