WebGL自學課程(13):獲得三維拾取向量
一個三維點最終展現在螢幕上要經過很多的矩陣變換,如果要根據螢幕上的2D點獲取對應的三維資訊,那麼就需要對3D到2D轉變的操作進行逆操作,我們先來看一下從3D到2D的具體的變換過程是怎麼樣的。
三維中一點要想展現在螢幕上需要經過這麼幾個重要的變換過程:模型變換->視點變換->投影變換->投影除法。
在頂點著色器中我們需要自己手動完成前三個變換過程(模型變換、視點變換、投影變換),如下所示:
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition,1.0);
模型變換:三維物件自身的模型矩陣乘以模型區域性座標中座標的過程稱作模型變換,經過模型變換後會將模型座標轉換為世界座標系中的座標,即世界座標,以齊次座標方式表示的世界座標中的第四個分量w為1。
視點變換:視點矩陣乘以世界座標的過程稱作視點變換,經過視點變換後會將世界座標轉換為攝像機座標系中的座標,即視座標,以其次座標方式表示的視座標中的第四個分量w為1。
投影變換:投影矩陣乘以視座標的過程稱作投影變換,經過投影變換後視座標將會轉換為裁剪座標gl_Position,以齊次座標方式表示的裁剪座標中的第四個分量w此時應該不為1。
投影除法:裁剪座標系中的w分量不為1,用裁剪座標系中的x、y、z依次除以w,得到新的座標(x/w,y/w,z/w),即歸一化座標(NDC),與視點座標系相比,z軸方向會翻轉,NDC座標系是左手座標系,NDC座標不再是齊次座標,而是3分量的三維座標。
需要特別注意的是在WebGL中,模型變換、視點變換以及投影變換都是要我們自己去手動實現的,得到的gl_Postion即為經過了上面三個變換之後的裁剪座標,其第四個分量的w不為1。在我們手動程式設計計算完gl_Position之後,進入GPU自身的流水管線,GPU會根據裁剪座標gl_Position中xyz分量與w分量絕對值的大小進行比較進行裁剪。具體的過程是:GPU依次將gl_Position中x、y、z的絕對值與w的絕對值分別比較,只要有一個分量的絕對值大於w的絕對值,GPU就認為該點不在視景體內,就會被裁減掉,也就是說裁剪的過程是GPU自己進行的,沒有被裁減掉的座標xyz分量的絕對值都小於w的絕對值。經過裁剪之後,GPU進行投影除法,具體的過程是:會將齊次座標轉換為普通的三元的座標(只有xyz,無w),會讓裁剪座標(裁剪座標也是齊次座標,包含w資訊)中的xyz依次除以w,得到新的xyz,新的xyz就是歸一化後的座標,即歸一化裝置座標(Normalized Device Coordinates),NDC座標存放於一個立方體座標系中。歸一化後的NDC座標中的x、y、z的取值範圍都是[-1,1],所表達的含義是將Canvas的中心點定位[0,0],左下為[-1,-1],右上為[1,1],x和y能夠表示出該點相對於Canvas中心原點的位置。NDC座標中的z表示了深度資訊,取值範圍也是[-1,1]。(從fs裡gl_DepthData取出來的應該是0-1),表示了深度資訊,近裁剪面near對應z=0,遠裁剪面far對應z=1。這樣就完成了3D到2D的轉變。
為了實現從2D到3D的逆變換,我們需要對上面的操作進行逆操作:
1.首先根據2D點座標計算出NDC座標,此時要把Canvas看成這樣一個座標系:原點在Canvas中心,並且左下為[-1,1],右上為[1,1],根據x和y的絕對座標計算出NDC中的x和y(二者範圍都是[-1,1])。NDC中的x和y雖然能計算了,但是深度值z是不確定的,我們可以在[0,1]之間任意取值,比如0.5,NDC中的w都為1,這樣構建了NDC中的座標[x,y,0.5,1]。
2.然後執行投影變換的逆操作,即先計算投影矩陣的逆矩陣,然後用該逆矩陣乘以NDC中的齊次座標,得到“視座標”。注意此處的視座標是打了引號的,為什麼呢?因為我們知道視座標中的w分量是1,而NDC座標經過投影變換的逆操作之後,w分量不再為1,我們需要將“視座標”中的四個分量都除以“視座標”中的w分量,這樣可以保證w為1了,從而得到真正的視座標。
3.然後執行視點變換的逆操作,即先計算視點變換的逆矩陣,然後用該逆矩陣乘以視座標即可得到世界座標。
4.注意,由於我們在第1步中的深度值z值是不固定的,可以在[0,1]之間任意取值,所以在第三步中得到的世界座標也應該是無窮多的,也就是說我們無法根據2D點獲取某個3D點,但是我們可以計算從攝像機出發沿著的單擊螢幕的那條射線的方向。該拾取向量的計算過程很簡單:獲取攝像機在世界座標系中的座標,又已知第三步中計算得到的單擊點的世界座標,根據這兩個世界座標中的點就可以得到世界座標系中的拾取向量。
具體的程式碼如下:
/**
* 已驗證正確
* 獲取滑鼠拾取向量(世界座標系中的向量)
* @param absoluteX 自左向右增大
* @param absoluteY 自上向下增大
* @return {*}
*/
World.PerspectiveCamera.prototype.getPickDirection = function(absoluteX,absoluteY){
var relativeCoords = World.Math.getPositionRelativeToCanvasCenter(absoluteX,absoluteY);
var relativeX = relativeCoords[0];
var relativeY = relativeCoords[1];
var ndcX = relativeX/(World.Canvas.width/2);
var ndcY = relativeY/(World.Canvas.height/2);
var ndcZ = 0.5;//深度值,可在0-1之間隨意取值
var ndcW = 1;
var columnNDC = [ndcX,ndcY,ndcZ,ndcW];//NDC歸一化座標
var inverseProj = this.projMatrix.getInverseMatrix();//投影矩陣的逆矩陣
var columnCameraTemp = inverseProj.multiplyColumn(columnNDC);//帶引號的“視座標”
var cameraX = columnCameraTemp[0]/columnCameraTemp[3];
var cameraY = columnCameraTemp[1]/columnCameraTemp[3];
var cameraZ = columnCameraTemp[2]/columnCameraTemp[3];
var cameraW = 1;
var columnCamera = [cameraX,cameraY,cameraZ,cameraW];//真實的視座標
var viewMatrix = this.getViewMatrix();
var inverseView = viewMatrix.getInverseMatrix();//視點矩陣的逆矩陣
var columnWorld = inverseView.multiplyColumn(columnCamera);//單擊點的世界座標
var verticeInWorld = new World.Vertice(columnWorld[0],columnWorld[1],columnWorld[2]);
var cameraPositon = this.getPosition();//攝像機的世界座標
var pickDirection = verticeInWorld.minus(cameraPositon);
pickDirection.normalize();
return pickDirection;
};
相關文章
- WebGL自學課程(14):WebGL使用Mipmap紋理Web
- WebGL自學課程(10):通過OpenStreetMap獲取資料繪製地球Web
- WebGL自學課程(15):WebGL在WebGIS上的應用——WebGlobeWeb
- WebGL自學課程(12):光照模型與渲染方式Web模型
- WebGL自學課程(8):WebGL+ArcGIS JS API實現TerrainMapWebJSAPIAI
- WebGL自學課程(9):WebGL框架World.js(0.3.5版本)Web框架JS
- WebGL自學課程(16):WebGlobe實現的基本演算法原理Web演算法
- WebGL自學課程(11):ELSL著色器程式設計中內建的運算子與函式Web程式設計函式
- WebGL-三維透視投影Web
- WebGL之繪製三維地球Web
- WebGL自學課程(7):WebGL載入跨域紋理出錯Cross-origin image load denied by Cross-Origin Resource Sharing policy.Web跨域ROS
- 微課|中學生可以這樣學Python(例7.2):三維向量類Python
- 使用IndexedDB快取給WebGL三維程式加速Index快取Web
- 0190-定義三維向量
- WebGL程式設計指南(5)進入三維世界Web程式設計
- osg三維場景中拾取滑鼠在模型表面的點選點模型
- c++ 一維向量,和二維向量的基本使用C++
- UI設計課程筆記(三)UI筆記
- Java工程師:非科班自學Java是如何獲得校招offer的Java工程師
- Andrew NG 深度學習課程筆記:梯度下降與向量化操作深度學習筆記梯度
- 微博收藏(機器學習課程與論文)(三)機器學習
- 龍哥盟-PMP-課程筆記-三-筆記
- 《專案思維心法》課程學習筆記筆記
- OCP課程13:SQL之使用資料字典檢視管理物件SQL物件
- WebGIS 利用 WebGL 在 MapboxGL 上渲染 DEM 三維空間資料Web
- 企業級實戰大資料課程(三)-尹成-專題視訊課程大資料
- OpenGL Android課程三:使用每片段照明Android
- 人工智慧第三次課程人工智慧
- 計算機課程第三週作業計算機
- 結合ReentrantLock獲得鎖分析AQS,lock過程分析ReentrantLockAQS
- oracle自定義過程來獲得完整的sql語句OracleSQL
- 學習Python課程選擇自學好不好?存在哪些煩惱?Python
- 林軒田機器學習技法課程學習筆記13 — Deep Learning機器學習筆記
- 獲得資料庫操作日誌的三種方式資料庫
- Java/JSP獲得客戶端網路卡MAC地址的三種方法解析(附:獲得真實IP)JavaJS客戶端Mac
- 如何從零基礎自學到獲得第一份程式設計工作?程式設計
- 讀過的書與自學的課
- 【課程筆記】中科大資訊理論(三)筆記