1. 程式人生 > >小白入門opengl(二)畫出三角形

小白入門opengl(二)畫出三角形

在opengl中任何事物都在3D空間中,而螢幕與視窗確實2D的,由3D座標轉化為2D的處理過程是opengl的圖形渲染管線管理的。可以被劃分為兩個主要部分,第一部分把你的3D座標轉化為2D座標,第二部分則是把2D座標轉化為有顏色的畫素。 在圖形渲染管線上執行各自的小程式,從而圖形渲染管線魯艾蘇處理你的資料,這樣的小程式叫做著色器。 有些著色器允許開發者自己配置,可以讓我們更加細緻的控制渲染管線的特定部分。 影象渲染管線每個階段的展示 在現代OpenGL中,我們必須至少定義一個頂點著色器和一個片段著色器, 1.頂點輸入 float vertices[]={ -0.5f,-0.5f,0.0f, 0.5f,-0.5f,0.0f, 0.0f,0.5f,0.0f }; 由於我們渲染的是一個2d圖形,所以我們將它頂點的z座標設定為0.0。 定義了以上的頂點資料後,我們會把它作為輸入傳送給圖形渲染管線的第一個處理階段。 我們通過頂點緩衝物件來管理這個記憶體,會在GPU記憶體中儲存大量的頂點,好處就是可以一次性的傳送大量的資料至顯示卡的記憶體中。頂點著色器能夠立即訪問到頂點。 我們可以使用glGenBuffers函式和一個緩衝ID來生成一個VBO物件,頂點緩衝物件的緩衝型別是GL_ARRAY_BUFFER,然後呼叫glBufferData來將之前定義的頂點資料複製到緩衝的記憶體中:

unsigned int VBO;
glGenBuffers(1,&VBO);
glBindBuffer(GL_ARRAY_BUFFER,VBO);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);

glBufferData的第四個引數由三種形式,用於告訴顯示卡如何去管理給定的資料

  • GL_STATIC_DRAW:資料不會或者幾乎不會改變很多
  • GL_DYNAMIC_DRAW:資料會被改變很多
  • GL_STREAM_DRAW:資料每次繪製的時候都會改變 現在我們已經把頂點的資料儲存到了顯示卡中了。 2頂點著色器和片段著色器 首先,我們使用GLSL(OpenGL Shading Language)編寫頂點著色器,,然後編譯此著色器。 每個著色器都起始於一個版本宣告,例如(GLSL 420 對應OpenGL4.2) 下一步使用in關鍵字,在頂點著色器中輸入頂點屬性,現在我們只關心Position資料,所以我們只需要一個頂點屬性,GLSL有一個向量資料型別,包含1到4個float分量,通過layout(location =0)設定輸入變數的位置值。 編譯著色器,但是為了能夠讓OpenGL使用它,我們必須在執行時動態的編譯它的原始碼。 首先我們要做的就是要建立一個物件,注意還是用id來引用的,所以我們儲存這個頂點著色器為unsigned int,然後用glCreateShader來建立這個著色器,同樣類似的還有片段著色器
//將其儲存在vertexShaderSource 字串中
#version 330 core
layout (location = 0) in vec3 aPos;

void main()
{
    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}

然後就是編譯該著色器。

unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
//下面是檢查檔案是否編譯成功,如果編譯不成功就是輸出一些相關資訊
int  success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if(!success)
{
    glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
    std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}

片段著色器與之類似,不過引數改為了GL_FRAGMENT_SHADER 然後建立一個著色器程式,將其連線到用來渲染的著色器程式。

int shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glLinkProgram(shaderProgram);
	// check for linking errors
	glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
	if (!success) {
		glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
		std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
	}
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);

opengl解釋頂點屬性 這裡寫圖片描述 位置資料被儲存為32位(4位元組)浮點值。 每個位置包含3個這樣的值。 在這3個值之間沒有空隙(或其他值)。這幾個值在陣列中緊密排列(Tightly Packed)。 資料中第一個值在緩衝開始的位置。 有了這些資訊我們就可以使用glVertexAttribPointer函式告訴OpenGL如何解析頂點函式。

glVertexAttritPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void)*0);
glEnableVertexAttribArray(0);//以頂點屬性位置值作為引數,啟用頂點屬性

在OpenGL中繪製一個物體,程式碼會像如下所示那樣

// 0. 複製頂點陣列到緩衝中供OpenGL使用 glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 1. 設定頂點屬性指標 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // 2. 當我們渲染一個物體時要使用著色器程式 glUseProgram(shaderProgram); // 3. 繪製物體 someOpenGLFunctionThatDrawsOurTriangle();

頂點陣列物件(VAO)

OpenGL的核心模式要求我們使用VAO,所以它知道該如何處理我們的頂點輸入。如果我們繫結VAO失敗,OpenGL會拒絕繪製任何東西。

一個頂點陣列物件會儲存下面的東西,

  • glEnableVertexAttribArray和glDisableVertexAttribArray的呼叫。
  • 通過glVertexAttribPointer設定的頂點屬性配置。
  • 通過glVertexAttribPointer呼叫與頂點屬性關聯的頂點緩衝物件。 這裡寫圖片描述 建立一個VAO與VBO很類似的
unsigned int VAO;
glGenVertexArrays(1,&VAO);

要想使用VAO,要做的是使用glBindVertexArray繫結VAO。繫結之後起,繫結和配置對應的VBO和屬性指標,之後解綁VAO供之使用,在繪製一個物體前,將VAO繫結到希望的設定上去。

// ..:: 初始化程式碼(只執行一次 (除非你的物體頻繁改變)) :: ..
// 1. 繫結VAO
glBindVertexArray(VAO);
// 2. 把頂點陣列複製到緩衝中供OpenGL使用
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 3. 設定頂點屬性指標
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

[...]

// ..:: 繪製程式碼(渲染迴圈中) :: ..
// 4. 繪製物體
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
someOpenGLFunctionThatDrawsOurTriangle();