threejs获取模型坐标_Threejs倒影实现解析
倒影是在自然界中非常常見的一種現象,例如水面倒影、鏡子。我們都知道,眼睛之所以能夠看到某個物體,是因為物體本身能夠發光或者物體能夠反射其它的物體所發的光,這些光進入到我們的眼里就形成了該物體影像。倒影形成也是一種光學的現象,其原理是物體發射或者反射的光經過倒影平面的反射后進入到我們的眼里,我們所看到的在倒影平面形成的虛像就是該物體的倒影。
不管是做數據可視化還是游戲,我們經常需要在3D場景中來實現這種自然現象,給水面、鏡面等物體增加倒影的效果,來提高視覺效果。那么在3D渲染中這種效果是怎么實現的那?WebGL的渲染引擎threejs給我們提供了一個很好的倒影實現的封裝,通過對threejs提供的代碼進行分析,希望能夠和大家一起學習一下。
大概的思路是:構建一個虛擬的相機對需要倒影的物體進行渲染,然后將渲染的結果當作紋理映射到倒影平面上,這樣就可以實現倒影的效果了。這里面我們需要解決兩個問題,第一個是如何構建這個虛擬的相機,第二個是怎么將通過紋理相機渲染出來的結果正確的映射到倒影平面上。
使用threejs來實現倒影我們只需要引入threejs的倒影引擎(該文件位于threejs項目example/js/objects目錄下),然后創建一個接受倒影的幾何體,其他的交給threejs來完成就可以來,這里我們創建了一個圓形來接收陰影。
<script src="js/objects/Reflector.js"></script>var geometry = new THREE.CircleBufferGeometry(40, 64); var groundMirror = new THREE.Reflector(geometry, {textureWidth: WIDTH * window.devicePixelRatio,textureHeight: HEIGHT * window.devicePixelRatio });第一步:構建虛擬的相機
得到倒影面和真實相機的位置
reflectorWorldPosition.setFromMatrixPosition( scope.matrixWorld ); cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld );得到反射面的旋轉矩陣
rotationMatrix.extractRotation( scope.matrixWorld );先定義一個默認的法向量,乘以上一步得到的反射面的旋轉向量得到反射面現在的法向量
normal.set( 0, 0, 1 ); normal.applyMatrix4( rotationMatrix );計算相機位置
// 計算相機位置到反射平面位置到向量 view.subVectors( reflectorWorldPosition, cameraWorldPosition ); // 當向量與反射面當法向量夾角說明相機在反射面的背面,則直接返回不進行倒影的渲染 if ( view.dot( normal ) > 0 ) return; // 得到反射向量的反向量 view.reflect( normal ).negate(); // 投影面位置加上該向量得到虛擬相機的位置 view.add( reflectorWorldPosition );與計算相機位置類似的步驟計算相機的視點位置
rotationMatrix.extractRotation( camera.matrixWorld ); lookAtPosition.set( 0, 0, - 1 ); lookAtPosition.applyMatrix4( rotationMatrix ); lookAtPosition.add( cameraWorldPosition );target.subVectors( reflectorWorldPosition, lookAtPosition ); target.reflect( normal ).negate(); target.add( reflectorWorldPosition );根據計算的相機位置和相機視點位置構建虛擬相機
virtualCamera.position.copy( view ); virtualCamera.up.set( 0, 1, 0 ); virtualCamera.up.applyMatrix4( rotationMatrix ); virtualCamera.up.reflect( normal ); virtualCamera.lookAt( target ); virtualCamera.far = camera.far; virtualCamera.updateMatrixWorld(); virtualCamera.projectionMatrix.copy( camera.projectionMatrix );第二步:如何將虛擬相機的渲染結果映射到投影面上
初始化一個默認矩陣,這是初始化的矩陣主要是為了把屏幕坐標和[-1, 1]映射到[0, 1]的紋理坐標
textureMatrix.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 );然后將該矩陣乘以模型、視圖、投影矩陣,經過模型、視圖、投影矩陣變換的坐標為屏幕坐標,再經過上述矩陣后就可以映射為紋理坐標了
textureMatrix.multiply( virtualCamera.projectionMatrix ); textureMatrix.multiply( virtualCamera.matrixWorldInverse ); textureMatrix.multiply( scope.matrixWorld );將該矩陣在著色器中使用,可以得到倒影面各坐標點對應的紋理坐標,這樣就可以把渲染結果正確的映射到投影平面上
vUv = textureMatrix * vec4( position, 1.0 );進一步的完善
調整虛擬相機渲染時的投影矩陣,將相機的近裁剪面重置為投影面,避免對倒影面下方對物體進行投影,clipBias參數是對裁剪面進行了一個偏移,具體對算法請參考:
Oblique View Frustum Near-Plane Clipping
http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
reflectorPlane.setFromNormalAndCoplanarPoint( normal, reflectorWorldPosition ); reflectorPlane.applyMatrix4( virtualCamera.matrixWorldInverse );clipPlane.set( reflectorPlane.normal.x, reflectorPlane.normal.y, reflectorPlane.normal.z, reflectorPlane.constant );var projectionMatrix = virtualCamera.projectionMatrix;q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ]; q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ]; q.z = - 1.0; q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ];clipPlane.multiplyScalar( 2.0 / clipPlane.dot( q ) );projectionMatrix.elements[ 2 ] = clipPlane.x; projectionMatrix.elements[ 6 ] = clipPlane.y; projectionMatrix.elements[ 10 ] = clipPlane.z + 1.0 - clipBias; projectionMatrix.elements[ 14 ] = clipPlane.w;最主要對幾個步驟在已經完成了,下面進行對就是通過構建對虛擬相機和新的投影矩陣對整個場景進行渲染,將渲染結果當作紋理映射到投影平面上就完成了。
總結
以上是生活随笔為你收集整理的threejs获取模型坐标_Threejs倒影实现解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql查看系统可用字符集_MySQL
- 下一篇: java在创建对象时必须_Java中5种