2011-01-06 36 views
3

我想知道我們是否可以從窗口座標獲得對象表面上的法線。 gluUnProject()函數將窗口座標轉換爲3D空間中的對象座標。同樣,我需要一個函數來給出鼠標指針所在表面的法線。如果我們有一個可以賦予它的opengl函數,我會非常高興。我不想用射線和物體(表面三角形)的交點來做到這一點。尋找正常的OpenGL

回答

2

我不認爲這是可能的。爲什麼opengl會存儲所有像素的所有法線?它不需要它,所以你不可能檢索它。恐怕真不容易。

您可以編寫一個着色器來繪製編碼爲rgb的法線,而不是臉部顏色。如果您使用着色器重新繪製場景,則會繪製所有法線。然後你可以簡單地查看你想要的顏色並獲得正常的顏色。

+0

別那麼一定有關!例如,渲染方法(如延遲着色)使用所謂的幾何緩衝區,該緩衝區還包含每個像素的屏幕空間法向,以便在屏幕空間中完成照明計算。 – datenwolf 2011-01-06 14:07:40

+1

@datenwolf,關於延期着色的好處,但不是Ishtar所說的? OpenGL不會「自己」存儲法線,但很容易爲其製作着色器。 – Kos 2011-01-06 14:11:30

0

如果你有三點,數學並不難。我建議看看OpenGL超級聖經第四版MacintoshWindows代碼示例。共享目錄中的math3d。*爲您提供執行此操作的代碼,並搜索m3dFindNormal。

至於存儲法線,這將取決於你。

1

首先澄清一下:gluUnProject做了OpenGL固定功能流水線的逆向投影。如果涉及到着色器,事情會變得複雜。但是,作爲gluUnProject的起點,通常會在所需的位置檢索深度緩衝區值(使用glReadPixels)。讀取深度值的整個塊(例如3x3陣列)並且不進行投影是很平常的,給你9點,其中一個在中心。使用這些點向左和向上已經產生了一個有效的法線(理論上2x2數組就足夠了),但讓我們通過考慮整個鄰域來過濾它。

讓我們數它們這種方式,根據陣列他們來自:

1 8 7 
2 0 6 
3 4 5 

所有你所要做的就是計算平面定義三角形的法線(0,1,2),(0 ,2,3),...(0,7,8),(0,8,1)取法向和(可能是樣本距離的倒數)和,並歸一化結果向量。你確定了選定點的世界空間法線。爲了回到對象空間中,與對象矩陣的轉置逆相乘(爲什麼轉置的反向,好的法線由模型視圖矩陣的反轉轉置進行轉換,請參閱OpenGL編程指南附錄以解釋原因以及反轉那是......好吧,我認爲你知道了)。

0

有幾種方法我可以考慮這樣做。

可能性1

用戶點擊窗口中的空間,所以現在你有鼠標點擊(X,Y)的窗口座標。現在,在X方向(x + 1 /寬度,y)上添加一個像素,並在y方向上添加一個像素(x,y + 1 /高度),其中寬度和高度是顯示器的像素尺寸。在所有這三個矢量上使用gluUnProject,那麼在對象空間{A,B,C}中有三個點。一旦物體空間有三點,正常計算相對簡單:

A = ObjectCoordinates(x+1/width, y) 
B = ObjectCoordinates(x, y) 
C = ObjectCoordinates(x, y+1/height) 
BA = (A-B)/|A-B| 
BC = (C-B)/|C-B| 
N = BA cross BC 

其中| X |是矢量X 的大小和正常是N

這可能不是很快,這將有問題,當A,B和C不上相同的三角所有土地(如果你是這種情況可能發生點擊一個非常遠的物體)。但它應該得到一個好的近似結果。

可能性2

現在這個未來的可能性,我也不是很肯定的,但在這裏不用。創建片段着色器和頂點着色器。你將不得不創建一個兩遍渲染系統。第一遍使用這些新創建的着色器,第二遍實際渲染你的場景。這可能會顯着減慢程序執行速度,因爲您必須每幀進行兩次全景渲染。

在第一遍,你的頂點着色器將頂點正常傳遞到您的片段着色器。然後,將片段(r,g,b)的顏色分配給從頂點着色器(x,y,z)傳入的法線座標。然後,您的第一遍將使用這些着色器渲染到紋理。你的第二遍將渲染到幀緩衝區。當用戶點擊時,您會得到一組窗口空間座標,您可以將其轉換爲(u,v)紋理座標,以便從第一遍渲染創建的紋理中進行採樣。

此外,該解決方案將是顯著慢,但它最有可能讓你根據你使用的紋理尺寸更精確的數據。

Here是一個稍微過時的,但免費的GLSL OpenGL着色語言書,它描述瞭如何將這些着色器放在一起。

Here是加載和編譯着色器的教程。

Here是用於計算正常僞代碼。

乾杯, 斯內德