週一到週五,天天一篇,北京時間早上7點準時更新~數組
In Chapter 2, 「Our First OpenGL Program,」 you were briefly introduced to the vertex array object (VAO). During that discussion, we explained how the VAO represented the inputs to the vertex shader—though at the time, we didn’t use any real inputs to our vertex shaders and opted instead for hard-coded arrays of data. Then, in Chapter 3 we introduced the concept of vertex attributes, but we discussed only how to change their static values. Although the vertex array object stores these static attribute values for you, it can do a lot more. Before we can proceed, we need to create a vertex array object to store our vertex array state and bind it to our context so that we can use it:ide
在第二章中,咱們已經接觸過VAO了,在那裏,咱們已經解釋過VAO如何給shader輸入數據了-雖然那時候咱們沒有真的使用VAO而是使用了硬編碼的數據。 在第三章,咱們介紹了頂點屬性的概念,但咱們僅僅是討論瞭如何改變他們靜態的值。VAO不只能夠爲你存儲那些靜態屬性,它還能夠作更多事情。在咱們開始以前,咱們須要建立一個VAO的對象 去存儲咱們頂點數組的狀態,而且把它綁定到咱們的上下文中,這樣咱們才能使用它函數
GLuint vao;
glCreateVertexArrays(1, &vao);
glBindVertexArray(vao);
Now that we have our VAO created and bound, we can start filling in its state. Rather than using hard-coded data in the vertex shader, we can instead rely entirely on the value of a vertex attribute and ask OpenGL to fill it automatically using the data stored in a buffer object that we supply. Each vertex attribute gets to fetch data from a buffer bound to one of several vertex buffer bindings. To set the binding that a vertex attribute uses to reference a buffer, call the glVertexArrayAttribBinding() function:fetch
如今咱們建立了VAO了,咱們能夠幹大事了。此次咱們使用緩衝區對象提供數據而不是使用硬編碼。每一個頂點屬性都須要從緩衝區對象綁定到的節點上去獲取數據。 爲了讓頂點屬性知道本身去哪裏緩衝區的那個節點上拿數據,咱們調用glVertexArrayAttribBinding去設置ui
void glVertexArrayAttribBinding(GLuint vaobj,GLuint attribindex,GLuint bindingindex);
The glVertexArrayAttribBinding() function tells OpenGL that when the vertex array object named vaobj is bound, the vertex attribute at the index specified in attribindex should source its data from the buffer bound at bindingindex. To tell OpenGL which buffer object our data is in and where in that buffer object the data resides, we use the glVertexArrayVertexBuffer() function to bind a buffer to one of the vertex buffer bindings. We use the glVertexArrayAttribFormat() function to describe the layout and format of the data, and finally we enable automatic filling of the attribute by calling glEnableVertexAttribArray(). The prototype of glVertexArrayVertexBuffer() isthis
這個函數就告訴OpenGL,當vaobj這個VAO被綁定到上下文的時候,在attribindex上的頂點屬性去緩衝區的那個bindingindex上拿數據。 爲了告知OpenGL數據在哪一個緩衝區裏以及數據在那個緩衝區裏的內存格局,咱們使用glVertexArrayVertexBuffer去設置這些。咱們使用glVertexArrayAttribFormat去描述數據的格式,也就是內存分佈啦。 不清楚內存分佈的同窗能夠看看咱們的C++ Tricks課程,不講C++基礎語法,只經過一些小的例子來加深對C++的理解。而且最終,咱們調用glEnableVertexAttribArray函數去啓動讓OpenGL 自動的去把緩衝區裏的數據按照設置的模式發送給shader處理。glVertexArrayVertexBuffer的函數以下:編碼
void glVertexArrayVertexBuffer(GLuint vaobj,
GLuint bindingindex,
GLuint buffer,
GLintptr offset,
GLsizei stride);
Here, the first parameter is the vertex array object whose state you’re modifying. The second parameter, bindingindex, is the index of the vertex buffer, which matches the parameter sent to glVertexArrayAttribBinding(). The buffer parameter specifies the name of the buffer object that we’re binding. The last two parameters, offset and stride, tell OpenGL where in the buffer object the attribute data lies. offset says where the first vertex’s data starts and stride says how far apart each vertex is. Both are measured in bytes. Next, we have glVertexArrayAttribFormat(), whose prototype isprototype
這裏,第一個參數是VAO,第二個參數是緩衝區對象的索引,這個索引與glVertexArrayAttribBinding裏面設置的那個一一對應。第三個參數是緩衝區對象。 最後倆參數offset和stride告訴OpenGL這些數據的內存格局,offset告訴OpenGL數據的起始位置,stride告訴OpenGL同一個屬性之間的數據間隔,大小都是字節。翻譯
void glVertexArrayAttribFormat(GLuint vaobj,
GLuint attribindex,
GLint size,
GLenum type,
GLboolean normalized,
GLuint relativeoffset);
For glVertexArrayAttribFormat(), the first parameter is again the vertex array whose state we’re modifying. attribindex is the index of the vertex attribute. You can define a large number of attributes as input to a vertex shader and then refer to them by their index, as explained in the 「Vertex Attributes」 section in Chapter 3. size is the number of components that are stored in the buffer for each vertex and type is the type of the data, which would normally be one of the types in Table 5.3.code
glVertexArrayAttribFormat的第一個參數是VAO,attribindex是頂點屬性的索引。你能夠定義不少屬性,而後試用索引來引用他們。 size參數是是指每個頂點有多少個組成部分,類型指的是數據的類型,通常來講就是指表5.3裏的那些。
The normalized parameter tells OpenGL whether the data in the buffer should be normalized (scaled between 0.0 and 1.0) before being passed to the vertex shader or if it should be left alone and passed as is. This parameter is ignored for floating-point data, but for integer data types, such as GL_UNSIGNED_BYTE or GL_INT, it is important. For example, if GL_UNSIGNED_BYTE data is normalized, it is divided by 255 (the maximum value representable by an unsigned byte) before being passed to a floating-point input to the vertex shader. The shader will therefore see values of the input attribute between 0.0 and 1.0. However, if the data is not normalized, it is simply cast to floating-point values and the shader will receive numbers between 0.0 and 255.0, even though the input to the vertex shader consists of floating-point data. The stride parameter tells OpenGL how many bytes are between the start of one vertex’s data and the start of the next, but you can set this parameter to 0 to let OpenGL calculate it for you based on the values of size and type. Finally, relative offset is the offset from the vertex’s data where the specific attribute’s data starts. This all seems pretty complex, but the pseudocode to compute the location in a buffer object is fairly simple:
normalized參數告訴OpenGL,數據是否須要在傳給shader前被縮放到0~1之間去。對於GL_FLOAT類型來講,這個參數會被OpenGL忽略,可是對於GL_UNSIGNED_BYTE或者GL_INT類型的數據來講,這個參數 很重要。對於GL_UNSIGNED_BYTE來講,若是你傳入的數據是255,若是這裏告訴OpenGL須要縮放,那麼shader裏收到的數據是1.0,若是你告訴OpenGL不須要縮放,那麼shader裏收到的數據是255.0這樣一個浮點數。 stride參數告訴OpenGL數據間隔。最後相對偏移指示了某一個屬性數據的數據在頂點全部數據中的偏移位置。雖然這些概念看起來很複雜,可是計算偏移的僞代碼很簡單:
location = binding[attrib.binding].memory + // Start of data store in memory
binding[attrib.binding].offset + // Offset of vertex attribute in buffer
binding[attrib.binding].stride vertex.index + // Start of this* vertex
vertex.relative_offset; // Start of attribute relative to vertex
Finally, glEnableVertexAttribArray() and the converse glDisableVertexAttribArray() have the prototypes:
最後,使用glEnableVertexAttribArray和相反的操做glDisableVertexAttribArray有以下的函數申明:
void glEnableVertexAttribArray(GLuint index);
When a vertex attribute is enabled, OpenGL will feed data to the vertex shader based on the format and location information you’ve provided with glVertexArrayVertexBuffer() and glVertexArrayAttribFormat(). When the attribute is disabled, the vertex shader will be provided with the static information you provide with a call to glVertexAttrib(). Listing 5.4 shows how to use glVertexArrayVertexBuffer() and glVertexArrayAttribFormat() to configure a vertex attribute. Notice that we also call glEnableVertexArrayAttrib() after setting up the offset, stride, and format information. This tells OpenGL to use the data in the buffer to fill the vertex attribute rather than using data we provide through one of the glVertexAttrib() functions.
當一個頂點屬性啓用以後,OpenGL將會根據咱們前面設置的那些來給shader發送參數.若是頂點屬性被禁用了,那麼OpenGL則會給shader發送你使用glVertexAttrib那些函數設置的一些固定的數據。 清單5.4展現瞭如何使用glVertexArrayVertexBuffer和glVertexArrayAttribFormat去配置頂點屬性。注意到,咱們一樣在設置offset、stride以及format的信息後調用了glEnableVertexArrayAttrib。 這是在告訴OpenGL,咱們使用緩衝區裏的數據做爲shader輸入參數俄入世glVertexAttrib那些函數設置的東西。
// First, bind a vertex buffer to the VAO
glVertexArrayVertexBuffer(vao, // Vertex array object
0, // First vertex buffer
binding
buffer, // Buffer object
0, // Start from the beginning
sizeof(vmath::vec4)); // Each vertex is one vec4
// Now, describe the data to OpenGL, tell it where it is, and turn on automatic
// vertex fetching for the specified attribute
glVertexArrayAttribFormat(vao, // Vertex array object
0, // First attribute
4, // Four components
GL_FLOAT, // Floating-point data
GL_FALSE, // Normalized - ignored for floats
0); // First element of the vertex
glEnableVertexArrayAttrib(vao, 0);
Listing 5.4: Setting up a vertex attribute
After Listing 5.4 has been executed, OpenGL will automatically fill the first attribute in the vertex shader with data it has read from the buffer that was bound to the VAO by glVertexArrayVertexBuffer(). We can modify our vertex shader to use only its input vertex attribute rather than a hardcoded array. This updated shader is shown in Listing 5.5.
當清單5.4倍執行了以後,OpenGL將會自動使用glVertexArrayVertexBuffer綁定在VAO上的緩衝區的數據去填充shader裏的第一個屬性。咱們如今來修改shader,讓shader去使用這樣的輸入數據,而不是硬編碼數據。 清單5.5展現了咱們最新版本的shader代碼該如何寫
#version 450 core
layout (location = 0) in vec4 position;
void main(void)
{
gl_Position = position;
}
Listing 5.5: Using an attribute in a vertex shader
As you can see, the shader of Listing 5.5 is greatly simplified over the original shader shown in Chapter 2. Gone is the hard-coded array of data. As an added bonus, this shader can be used with an arbitrary number of vertices. You can literally put millions of vertices’ worth of data into your buffer object and draw them all with a single command such as a call to glDrawArrays(). If you are done using data from a buffer object to fill a vertex attribute, you can disable that attribute again with a call to glDisableVertexAttribArray(), whose prototype is
如你所見,清單5.5比起之前那個shader簡單多了。刪除了硬編碼的數據。這個shader能夠使用任意數量的頂點。能夠說,你能夠在緩衝區裏放上百萬的數據,而後使用一個繪製指令就將他們畫出來。 若是你使用完畢了緩衝區裏的頂點屬性,你能夠使用glDisableVertexAttribArray禁用這個屬性。
void glDisableAttribArray(GLuint index);
Once you have disabled the vertex attribute, it goes back to being static and passing the value you specify with glVertexAttrib*() to the shader.
當你禁用了這個屬性後,將來調用shader的時候,傳給shader的數據又是那些使用glVertexAttrib*函數設置的數據了。
本日的翻譯就到這裏,明天見,拜拜~~
第一時間獲取最新橋段,請關注東漢書院以及圖形之心公衆號
東漢書院,等你來玩哦