2011-12-05 45 views
4

我在基於Apple示例代碼的OpenGL-ES中製作了一些相當基本的形狀。他們使用了一系列點,第一個數組中有一系列索引,每個三個索引都創建一個多邊形。這非常棒,我可以製作我想要的形狀。要正確遮蔽形狀,我相信我需要爲每個多邊形上的每個頂點計算法線。起初這些形狀是立方形的,所以非常容易,但是現在我正在製作(稍微)更高級的形狀,我想自動創建這些法線。如果我得到一個多邊形的兩個邊(這裏所有的多邊形都是三角形)的矢量並且將它們的叉積用於該多邊形上的每個頂點似乎很容易。之後,我使用下面的代碼來繪製形狀。自動計算GLKit/OpenGL-ES中的法線數

glEnableVertexAttribArray(GLKVertexAttribPosition); 
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 0, triangleVertices); 

glEnableVertexAttribArray(GLKVertexAttribColor); 
glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, 0, triangleColours); 

glEnableVertexAttribArray(GLKVertexAttribNormal); 
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 0, triangleNormals); 

glDrawArrays(GL_TRIANGLES, 0, 48); 

glDisableVertexAttribArray(GLKVertexAttribPosition); 
glDisableVertexAttribArray(GLKVertexAttribColor); 
glDisableVertexAttribArray(GLKVertexAttribNormal); 

我無法理解的是爲什麼我必須手動執行此操作。我敢肯定,有些情況下,除了垂直於表面的矢量以外,還需要其他東西,但我也確定這是迄今爲止最流行的用例,所以不應該有更簡單的方法嗎?我錯過了明顯的東西嗎? glCalculateNormals()會很好。

//這裏是一個答案 傳入一個GLKVector3 [],你希望用你的法線填充,另一個用頂點(每三個分組成多邊形),然後是頂點的數量。

- (void) calculateSurfaceNormals: (GLKVector3 *) normals forVertices: (GLKVector3 *)incomingVertices count:(int) numOfVertices 
{ 

    for(int i = 0; i < numOfVertices; i+=3) 
    { 
     GLKVector3 vector1 = GLKVector3Subtract(incomingVertices[i+1],incomingVertices[i]); 
     GLKVector3 vector2 = GLKVector3Subtract(incomingVertices[i+2],incomingVertices[i]);   
     GLKVector3 normal = GLKVector3Normalize(GLKVector3CrossProduct(vector1, vector2)); 
     normals[i] = normal; 
     normals[i+1] = normal; 
     normals[i+2] = normal; 
    } 
} 

回答

2

次的答案是:OpenGL是既不場景同治庫,也不是幾何庫,而只是一個繪圖API繪製漂亮的照片在屏幕上。對於照明,它需要法線,並將其作爲法線。就這樣。爲什麼它應該計算法線,如果這可以由用戶完成,並且與實際繪圖無關?

通常你不會在運行時計算它們,而是從文件中加載它們。有很多方法可以計算法線。你想要每面法線或每頂點法線嗎?你需要任何特定的硬邊或任何特定的平滑補丁嗎?如果你想平均臉法線得到頂點法線,你想如何平均這些?

隨着着色器的出現以及在較新的OpenGL版本中刪除內置的普通屬性和光照計算,無論如何,這整個問題都變得過時了,因爲您可以以任何想要的方式進行照明,並且不再需要傳統法線。

順便說一句,這聽起來像你現在使用的是每面法線,這意味着每個面的頂點都具有相同的法線。這創造了一個非常刻面的模型,具有堅硬的邊緣,並且與索引一起使用效果不佳。如果你想要一個光滑的模型(我不知道,也許你真的想要一個多面的外觀),你應該平均相鄰面的面法線爲每個頂點計算每個頂點法線。這實際上是更常見的使用情況而不是每面法線。

所以,你可以做這樣的事僞代碼:

for each vertex normal: 
    intialize to zero vector 

for each face: 
    compute face normal using cross product 
    add face normal to each vertex normal of this face 

for each vertex normal: 
    normalize 

,產生平滑的每個頂點的法線。即使在實際的代碼中,這應該導致10到20行代碼之間的東西,這並不是很複雜。

+0

我原以爲我的案子是多數案件,但如果不是通常的做法,那麼我可以理解它是一項手工工作。我主要想要塊,所以我可能會堅持我的系統。用平均的平均頂點法線方法描述瞭如何告訴OpenGL,雖然我有12個多邊形和36個頂點,但我只計算了8個法線?我是否需要一個包含36個法線的數組來匹配頂點,並將法線放置在相同的順序中?這意味着當有兩個多邊形共享一個頂點時,有些會重複,或者有一種方法可以鏈接法線和頂點? – Craig

+0

@Craig每個頂點總是有一個法線。如果計算法線,則必須爲每個面的每個頂點重複每個面的法向(每個面)。如果計算每個頂點法線,則每個頂點法線將重複用於頂點所屬的每個面,就像頂點實際一樣。從概念上講,頂點是其所有屬性的全部,而不僅僅是位置,在OpenGL中,這不幸也稱爲頂點。 –

+0

@Craig但是每個頂點法線(關於存儲效率)的優點是,您可以使用索引數組(和'glDrawElements')並完全減少重複,因爲每個唯一頂點具有相同的法線。對於每面法線,指數不會爲您購買任何東西,因爲您無論如何都需要複製頂點,因爲每個具有唯一位置的頂點可能有多個不同的法線。 –