Mirror.js中的矩阵运算(三个js)
Matrix operations in Mirror.js (Three js)
我正在努力在 three.js 中创建水,到目前为止我还没有在 three.js 中看到任何同时实现反射和折射的水示例,但是如果您这样做了,请 link.
目前,我正在 Slayvin 的 Mirror.js 之上进行构建
https://threejs.org/examples/webgl_mirror.html
我的计划是使用第二个渲染目标以与反射类似的方式渲染折射纹理,然后在着色器中混合这两个纹理。
现在我有一个用于混合的临时折射渲染目标,效果很好。但是,由于我没有对纹理应用正确的矩阵乘法,目前这种临时折射严重变形。它应该比我认为的镜子更容易,但这并不像我想象的那样有效。我怎么知道应该将初始纹理矩阵设置为什么?
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 获得一个很好的偏移量,目前我正在使用正弦函数但这会导致摇摆运动并且看起来非常不自然,尽管它避免了"jump cut" 只是循环 rippleMoveFactor 并保留除法值。查看当前结果和完整代码:Demo
这里有一些解释:
'lookatPosition' 部分似乎没用,但它允许我在当前视图前面(在 Z 轴上)获得 1 个单位的位置:
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”,这样更容易使用。
所以,我们知道相机的位置,我们现在至少可以确定 space 中相机正在注视的一个点,而且我们还知道镜子的位置和方向。
所以现在是时候计算镜像视图的方向了:
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 );
...然后进行投影矩阵计算。
我正在努力在 three.js 中创建水,到目前为止我还没有在 three.js 中看到任何同时实现反射和折射的水示例,但是如果您这样做了,请 link. 目前,我正在 Slayvin 的 Mirror.js 之上进行构建 https://threejs.org/examples/webgl_mirror.html
我的计划是使用第二个渲染目标以与反射类似的方式渲染折射纹理,然后在着色器中混合这两个纹理。
现在我有一个用于混合的临时折射渲染目标,效果很好。但是,由于我没有对纹理应用正确的矩阵乘法,目前这种临时折射严重变形。它应该比我认为的镜子更容易,但这并不像我想象的那样有效。我怎么知道应该将初始纹理矩阵设置为什么?
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 获得一个很好的偏移量,目前我正在使用正弦函数但这会导致摇摆运动并且看起来非常不自然,尽管它避免了"jump cut" 只是循环 rippleMoveFactor 并保留除法值。查看当前结果和完整代码:Demo
这里有一些解释:
'lookatPosition' 部分似乎没用,但它允许我在当前视图前面(在 Z 轴上)获得 1 个单位的位置:
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”,这样更容易使用。
所以,我们知道相机的位置,我们现在至少可以确定 space 中相机正在注视的一个点,而且我们还知道镜子的位置和方向。 所以现在是时候计算镜像视图的方向了:
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 );
...然后进行投影矩阵计算。