溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Feeding Vertex Shaders from Buffers從緩沖區(qū)給shader輸入數(shù)據(jù)

發(fā)布時間:2020-08-10 13:27:31 來源:網(wǎng)絡 閱讀:403 作者:萌谷王 欄目:游戲開發(fā)

周一到周五,每天一篇,北京時間早上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:

在第二章中,我們已經(jīng)接觸過VAO了,在那里,我們已經(jīng)解釋過VAO如何給shader輸入數(shù)據(jù)了-雖然那時候我們沒有真的使用VAO而是使用了硬編碼的數(shù)據(jù)。 在第三章,我們介紹了頂點屬性的概念,但我們僅僅是討論了如何改變他們靜態(tài)的值。VAO不僅可以為你存儲那些靜態(tài)屬性,它還可以做更多事情。在我們開始之前,我們需要創(chuàng)建一個VAO的對象 去存儲我們頂點數(shù)組的狀態(tài),并且把它綁定到我們的上下文中,這樣我們才能使用它

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:

現(xiàn)在我們創(chuàng)建了VAO了,我們可以干大事了。這次我們使用緩沖區(qū)對象提供數(shù)據(jù)而不是使用硬編碼。每個頂點屬性都需要從緩沖區(qū)對象綁定到的節(jié)點上去獲取數(shù)據(jù)。 為了讓頂點屬性知道自己去哪里緩沖區(qū)的那個節(jié)點上拿數(shù)據(jù),我們調用glVertexArrayAttribBinding去設置

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() is

這個函數(shù)就告訴OpenGL,當vaobj這個VAO被綁定到上下文的時候,在attribindex上的頂點屬性去緩沖區(qū)的那個bindingindex上拿數(shù)據(jù)。 為了告知OpenGL數(shù)據(jù)在哪個緩沖區(qū)里以及數(shù)據(jù)在那個緩沖區(qū)里的內(nèi)存格局,我們使用glVertexArrayVertexBuffer去設置這些。我們使用glVertexArrayAttribFormat去描述數(shù)據(jù)的格式,也就是內(nèi)存分布啦。 不清楚內(nèi)存分布的同學可以看看我們的C++ Tricks課程,不講C++基礎語法,只通過一些小的例子來加深對C++的理解。并且最終,我們調用glEnableVertexAttribArray函數(shù)去啟動讓OpenGL 自動的去把緩沖區(qū)里的數(shù)據(jù)按照設置的模式發(fā)送給shader處理。glVertexArrayVertexBuffer的函數(shù)如下:

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 is

這里,第一個參數(shù)是VAO,第二個參數(shù)是緩沖區(qū)對象的索引,這個索引與glVertexArrayAttribBinding里面設置的那個一一對應。第三個參數(shù)是緩沖區(qū)對象。 最后倆參數(shù)offset和stride告訴OpenGL這些數(shù)據(jù)的內(nèi)存格局,offset告訴OpenGL數(shù)據(jù)的起始位置,stride告訴OpenGL同一個屬性之間的數(shù)據(jù)間隔,大小都是字節(jié)。

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.

glVertexArrayAttribFormat的第一個參數(shù)是VAO,attribindex是頂點屬性的索引。你可以定義很多屬性,然后試用索引來引用他們。 size參數(shù)是是指每一個頂點有多少個組成部分,類型指的是數(shù)據(jù)的類型,一般來說就是指表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參數(shù)告訴OpenGL,數(shù)據(jù)是否需要在傳給shader前被縮放到0~1之間去。對于GL_FLOAT類型來說,這個參數(shù)會被OpenGL忽略,但是對于GL_UNSIGNED_BYTE或者GL_INT類型的數(shù)據(jù)來說,這個參數(shù) 很重要。對于GL_UNSIGNED_BYTE來說,如果你傳入的數(shù)據(jù)是255,如果這里告訴OpenGL需要縮放,那么shader里收到的數(shù)據(jù)是1.0,如果你告訴OpenGL不需要縮放,那么shader里收到的數(shù)據(jù)是255.0這樣一個浮點數(shù)。 stride參數(shù)告訴OpenGL數(shù)據(jù)間隔。最后相對偏移指示了某一個屬性數(shù)據(jù)的數(shù)據(jù)在頂點所有數(shù)據(jù)中的偏移位置。雖然這些概念看起來很復雜,但是計算偏移的偽代碼很簡單:

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有如下的函數(shù)申明:

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將會根據(jù)我們前面設置的那些來給shader發(fā)送參數(shù).如果頂點屬性被禁用了,那么OpenGL則會給shader發(fā)送你使用glVertexAttrib那些函數(shù)設置的一些固定的數(shù)據(jù)。 清單5.4展示了如何使用glVertexArrayVertexBuffer和glVertexArrayAttribFormat去配置頂點屬性。注意到,我們同樣在設置offset、stride以及format的信息后調用了glEnableVertexArrayAttrib。 這是在告訴OpenGL,我們使用緩沖區(qū)里的數(shù)據(jù)作為shader輸入?yún)?shù)俄入世glVertexAttrib那些函數(shù)設置的東西。

// 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倍執(zhí)行了之后,OpenGL將會自動使用glVertexArrayVertexBuffer綁定在VAO上的緩沖區(qū)的數(shù)據(jù)去填充shader里的第一個屬性。我們現(xiàn)在來修改shader,讓shader去使用這樣的輸入數(shù)據(jù),而不是硬編碼數(shù)據(jù)。 清單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簡單多了。刪除了硬編碼的數(shù)據(jù)。這個shader可以使用任意數(shù)量的頂點。可以說,你可以在緩沖區(qū)里放上百萬的數(shù)據(jù),然后使用一個繪制指令就將他們畫出來。 如果你使用完畢了緩沖區(qū)里的頂點屬性,你可以使用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的數(shù)據(jù)又是那些使用glVertexAttrib*函數(shù)設置的數(shù)據(jù)了。

本日的翻譯就到這里,明天見,拜拜~~

第一時間獲取最新橋段,請關注東漢書院以及圖形之心公眾號

東漢書院,等你來玩哦

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI