2014-02-24 34 views
0

有幾個這樣的問題,但我還沒有真正理解。我在10年前編寫了OpenGL,注意到進入現代OpenGL有多困難。當涉及到示例時,OpenGL.org頁面是一個可怕的混亂,你永遠不知道它是什麼版本,任何版本似乎都混合在各種代碼示例中。 好吧,我有一箇舊代碼,我想至少更新到OpenGL> 3。所以我做的第一件事是從glVertex3fv繼續前進,最後使用glVertexAttribPointer(在glVertexPointer的一個步驟之前,直到我讀到這個步驟現在也被棄用)。這種精細的作品出來,而是試圖把紋理時我得到了迅速卡住,我以爲這是因爲錯誤的定位,我想擺脫的C++代碼:替換爲gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

glMatrixMode(GL_PROJECTION); 
glLoadIdentity(); 
glFrustum(-RProjZ, +RProjZ, -Aspect*RProjZ, +Aspect*RProjZ, 1.0, 32768.0); 

,並把它畫

// bind vertex buffer 
glBindBuffer(GL_ARRAY_BUFFER, VertBuffer); 
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * size, verts, GL_STATIC_DRAW); 

// enable arrays 
glEnableVertexAttribArray(0); 

// set pointers 
glVertexAttribPointer(0,3,GL_FLOAT, GL_FALSE, sizeof(float) * floatsPerVertex, 0); 

// render ComplexSurface 
glDrawArrays(GL_TRIANGLE_FAN, 0, size); 
glDisableVertexAttribArray(0); 

與在vertexshader

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 

而且一切工作神奇。現在不要誤解我的意思,我是一個很有魅力的粉絲,但是...... 然後我發現了幾個矩陣轉換,它可以用來獲得一個矩陣來代替glFrustum,但是每當我嘗試替換它時,它失敗了(儘管我認爲我理解了glFrustum背後的數學和轉化爲矩陣)。

什麼嘗試是像

buildPerspProjMat(g_ProjView,FovAngle,Aspect,1.0,32768.0); 

glUseProgram(g_program); 
glUniformMatrix4fv(g_programFrustum, 1, GL_FALSE, g_ProjView); 
glUseProgram(0); 

,並利用以上投影MATIX從緩衝區着色器中的位置,但是這不奏效的。

所以我現在還不明白的是在哪裏替換這個以及與着色器中的內容。我不知道glMatrixMode發生在哪一點,「何時」用一些統一的矩陣替換它(通過統一的參數不是這裏的問題)。 我不能計算我已經閱讀了多少個教程,但我總是對所有混合版本感到困惑。我總是對一些代碼示例感到高興,但請使用OpenGL 3或更高版本。

將是一個glTexCoord2f替代紋理下,但是這是一個不同的故事:)

+0

現在有另一種意見在這一點上有相當多的信息,但是幾分鐘前被刪除,而一個-1代替,但我沒有找到時間複製鏈接並閱讀所有信息。我在原來的問題中增加了更多信息,它被刪除了,因爲我認爲這不適合我的問題。 – Gnampf

回答

12

我發現在思考現代OpenGL時,最好忘記glMatrixMode曾經存在過。

考慮到這一點,讓我們回顧一下最基本的繪製操作所需要的:代替gl_ModelViewProjectionMatrix。顧名思義,這是3種不同矩陣的組合:模型矩陣,視圖矩陣和投影矩陣。

所以你需要在你的着色器中容納這個是3個統一的變量,類型爲mat4。你會這樣使用:

uniform mat4 projMat; 
uniform mat4 viewMat; 
uniform mat4 modelMat; 

layout (location = 0) in vec3 position; 

void main() 
{ 
    gl_Position = projMat * viewMat * modelMat * vec4(position, 1.0); 
} 

這一點的着色器代碼執行相同的功能,你在上面。什麼改變是內置的gl_ModelViewProjectionMatrix被3個統一變量取代(如果你確保在傳入C++端時自己將它們相乘,可以將它們組合爲一個變量)。內置的gl_Vertex被輸入變量替換。

在C++方面,你需要做2件事情。首先,您需要獲得位置爲這些制服:

GLuint modelMatIdx = glGetUniformLocation(shaderProgId, "modelMat"); 
GLuint viewMatIdx = glGetUniformLocation(shaderProgId, "viewMat"); 
GLuint projMatIdx = glGetUniformLocation(shaderProgId, "projMat"); 

而與此在手,你可以在每個均勻權值使用glUniformMatrix4fv繪製前傳現在。

一個特別容易使用的庫是glm。例如,要獲得相同的投影矩陣在你的榜樣,你會怎麼做:

glm::mat4 projMat = glm::frustum(-RProjZ, +RProjZ, -Aspect*RProjZ, +Aspect*RProjZ, 1.0, 32768.0); 

,你會在它傳遞像這樣:

glUniformMatrix4fv(projMatIdx, 1, GL_FALSE, glm::value_ptr(projMat)); 

現在你知道怎麼了,我想解決「什麼時候」的問題。你說你不清楚矩陣模式的東西,這讓我回到我以前的「忘掉它」的說法。矩陣模式在那裏,以便您可以告訴opengl哪些內置應該受到OpenGL矩陣操作(如glTranslate,glFrustum等)的調用的影響,但現在所有這些都消失了。您現在負責管理涉及的(可能很多)矩陣。所有你需要做的就是在你畫畫之前把它們傳進去(正如我上面所顯示的那樣),你會好起來的。在嘗試修改制服之前,確保程序已經綁定。

下面是一個工作示例(如果您驚訝於gl :: ...而不是gl ...這是因爲我使用的是由glLoadGen生成的opengl頭文件,它將所有的opengl API函數放入gl命名空間)。

GLuint simpleProgramID; 
// load the shader and make the program 

GLuint modelMatIdx = gl::GetUniformLocation(simpleProgramID, "modelMat"); 
GLuint viewMatIdx = gl::GetUniformLocation(simpleProgramID, "viewMat"); 
GLuint projMatIdx = gl::GetUniformLocation(simpleProgramID, "projMat"); 

GLuint vaoID; 
gl::GenVertexArrays(1, &vaoID); 
gl::BindVertexArray(vaoID); 

GLuint vertBufferID, indexBufferID; 
gl::GenBuffers(1, &vertBufferID); 
gl::GenBuffers(1, &indexBufferID); 

struct Vec2 { float x, y; }; 
struct Vec3 { float x, y, z; }; 
struct Vert { Vec3 pos; Vec2 tex; }; 

std::array<Vert, 8> cubeVerts = {{ 
    { { 0.5f, 0.5f, 0.5f }, { 1.0f, 0.0f } }, { { 0.5f, 0.5f, -0.5f }, { 1.0f, 1.0f } }, 
    { { 0.5f, -0.5f, -0.5f }, { 0.0f, 1.0f } }, { { 0.5f, -0.5f, 0.5f }, { 0.0f, 0.0f } }, 
    { { -0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f } }, { { -0.5f, 0.5f, -0.5f }, { 0.0f, 1.0f } }, 
    { { -0.5f, -0.5f, -0.5f }, { 1.0f, 1.0f } }, { { -0.5f, -0.5f, 0.5f }, { 1.0f, 0.0f } } 
}}; 

std::array<unsigned int, 36> cubeIdxs = {{ 
    0, 2, 1, 0, 3, 2, // Right 
    4, 5, 6, 4, 6, 7, // Left 
    0, 7, 3, 0, 4, 7, // Top 
    1, 6, 2, 1, 5, 6, // Bottom 
    0, 5, 1, 0, 4, 5, // Front 
    3, 7, 6, 3, 6, 2 // Back 
}}; 

// Vertex buffer 
gl::BindBuffer(gl::ARRAY_BUFFER, vertBufferID); 
gl::BufferData(gl::ARRAY_BUFFER, sizeof(Vert) * cubeVerts.size(), cubeVerts.data(), gl::STATIC_DRAW); 
gl::EnableVertexAttribArray(0); // Matches layout (location = 0) 
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE_, sizeof(Vert), 0); 
gl::EnableVertexAttribArray(1); // Matches layout (location = 1) 
gl::VertexAttribPointer(1, 2, gl::FLOAT, gl::FALSE_, sizeof(Vert), (GLvoid*)sizeof(Vec3)); 

// Index buffer 
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, indexBufferID); 
gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * cubeIdxs.size(), cubeIdxs.data(), gl::STATIC_DRAW); 
gl::BindVertexArray(0); 

glm::mat4 projMat = glm::perspective(56.25f, 16.0f/9.0f, 0.1f, 100.0f); 
glm::mat4 viewMat = glm::lookAt(glm::vec3(5, 5, 5), glm::vec3(0, 0, 0), glm::vec3(0, 0, 1)); 
glm::mat4 modelMat; // identity 

while (!glfwWindowShouldClose(window)) 
{ 
    gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT); 

    gl::UseProgram(simpleProgramID); 
    gl::UniformMatrix4fv(projMatIdx, 1, gl::FALSE_, glm::value_ptr(projMat)); 
    gl::UniformMatrix4fv(viewMatIdx, 1, gl::FALSE_, glm::value_ptr(viewMat)); 
    gl::UniformMatrix4fv(modelMatIdx, 1, gl::FALSE_, glm::value_ptr(modelMat)); 

    gl::BindVertexArray(vaoID); 
    gl::DrawElements(gl::TRIANGLES, 36, gl::UNSIGNED_INT, 0); 
    gl::BindVertexArray(0); 

    gl::UseProgram(0); 

    glfwSwapBuffers(window); 
    glfwPollEvents(); 
} 

相關頂點着色器:

//[VERTEX SHADER] 
#version 430 

uniform mat4 projMat; 
uniform mat4 viewMat; 
uniform mat4 modelMat; 

layout (location = 0) in vec3 in_position; // matches gl::EnableVertexAttribArray(0); 
layout (location = 1) in vec2 in_uv; // matches gl::EnableVertexAttribArray(1); 

out vec2 uv; 

void main() 
{ 
    gl_Position = projMat * viewMat * modelMat * vec4(in_position, 1.0); 
    uv = in_uv; 
} 

最後片段着色器:

//[FRAGMENT SHADER] 
#version 430 

in vec2 uv; 

out vec4 color; 

void main() 
{ 
    color = vec4(uv, 0.0, 1.0); 
} 

產生的圖像是:

enter image description here

+0

謝謝,這已經回答了很多東西。在我的例子中,我現在不確定的是: glm :: mat4 modelMat; //身份 - 我還閱讀了一些關於GLM的教程,我在一些簡單的測試程序中使用了它,但是我首先感覺到改變一種魔法對付另一種魔法(在我嘗試中至少擺脫gl_ModelViewProjectionMatrix),所以我想首先避免使用它。我想現在我明白爲什麼它不起作用。 – Gnampf

+0

謝謝你的支持!我花了太多時間試圖把所有這些東西都弄清楚。我沒有意識到我以前熟悉的OpenGL有多少已被棄用。試圖找出如何替換所有棄用的東西,我一直非常沮喪。 順便說一句,我得到的圖像是相反的,你的...任何想法,爲什麼這可能是? –

0

好吧,我同意大多數OpenGL教程混淆棄用,非過時的東西位。爲了讓你走向正確的方向,讓我解釋一下。

gl_ModelViewProjectionMatrixgl_ModeViewglMatrixMode()和矩陣堆棧glPushMatrix()glPopMatrix()被棄用。您需要將自己的矩陣定義爲統一變量,然後設置並使用glUniform*將它們傳遞給着色器。

gl_Vertex也被棄用,實際上整個固定的屬性名稱已被棄用。或者,您需要定義自己的屬性名稱並將其綁定到特定的位置。然後,您可以通過將屬性位置傳遞給它(Full explanation here),使用glVertexAttribPointer來設置它們的值。例如:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices); // for vertices 
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, color); // for color 

而對於shader代碼

layout (location = 0) in vec4 vertex; 
layout (location = 1) in vec4 color; 

uniform mat4 modelview; 
uniform mat4 projection; 

void main() 
{ 
gl_Position = projection* modelview* vertex; 
} 

對於屬性的地點,您可以從OpenGL的API使用glBindAttribLocation設置它們的着色器代碼和我一樣,或。

如果你習慣於舊的OpenGL全局變量,如gl_ModelView,我寫了一個article,希望可以幫助你管理大型項目的統一變量,管理統一變量可能會有些棘手。

+0

對同一主題有不同的看法總是好的,特別是在理解時,我認爲你的文章可能對我以後非常有用。太棒了,你把它加回來了。 – Gnampf

+0

啊! Khronos人有什麼問題?他們一次又一次地表明他們不明白「棄用」的含義。它應該是*當你有更好的替代功能的時候你會做的事情,*但是他們反覆使用它來讓事情變得更糟*我們反而把過去「只是工作」的東西和傾倒在我們的如果甚至可能的話,手動重新實施。 (例如,我仍然沒有看到'GL_QUADS'的好替代品) –

+0

@MasonWheeler GL_QUADS已棄用,因爲GPU的繪製速度更快,我通常做的是在兩個三角形上建立四邊形抽象,我將數據結構傳遞給OpenGL以繪製出三角形。是的,我想通過手動重新實現你的意思。 – concept3d