2015-10-10 96 views
0

我使用OpenGL緩衝區和一大堆GLfloats作爲頂點緩衝區,一切都很好。 GLfloats的格式爲[x1, y1, z1, x2, y2, z2, ...]OpenGL如何填充緩衝區並將其讀回?

但隨後,在遵循this tutorial,它告訴我使用glm::vec3代替:

glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), &vertices[0], GL_STATIC_DRAW); 

glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW); 

下面這段代碼是有效的,我不知道怎麼會OpenGL的知道如何與GLM緩衝區填滿:: VEC3而不是GLfloats。那麼我想知道,當我從緩衝區中讀取的數據後面,使用:

std::vector<glm::vec3> data; 
glGetBufferSubData(mTarget, offset, vertexCount * sizeof(glm::vec3), &data[0]);` 

這樣會令一堆GLM的:: VEC3?所以問題是,OpenGL如何用glm::vec3填充緩衝區,並且(如果是的話,它是怎樣)將其讀回的?

回答

5

根據OpenGL's documentationglBufferData()需要的指針data(即一個陣列,即頂點的座標)。

我們先來看看glm::vec3的實現。

如果檢查出glm's Github repo,你會看到,取決於你的編譯標誌glm::vec3typedef of highp_vec3這是一個typedef of tvec3<float, highp>

tvec3type_vec3.hpp(由vec3.hpp包括)聲明和類(模板)方法在type_vec3.inl定義。

特別地,operator[]'s definition是:

template <typename T, precision P> 
GLM_FUNC_QUALIFIER T & tvec3<T, P>::operator[](typename tvec3<T, P>::length_type i) 
{ 
    assert(i >= 0 && static_cast<detail::component_count_t>(i) < detail::component_count(*this)); 
    return (&x)[i]; 
} 

鑑於一段代碼,人們會認爲x是含有glm::vec3座標的「陣列」的第一個元素。然而,當我們回到type_vec3.h,我們發現:

union { T x, r, s; }; 
union { T y, g, t; }; 
union { T z, b, p; }; 

所以xyz單獨的屬性。但是由於how class/struct members are laid out,它們可以被看作是從&x開始的單個陣列。

我們現在知道,glm::vec3(實際上是tvec3)以連續的方式存儲座標。但它是否也存儲其他屬性?

好了,我們可以繼續深入到代碼,或使用一個簡單的程序來給我們答案:

#include <iostream> 
#include <ios> 

#include <glm/vec3.hpp> 

int main() 
{ 
    const glm::vec3 v; 

    const size_t sizeof_v = sizeof(v); 
    const size_t sizeof_xyz = sizeof(v.x) + sizeof(v.y) + sizeof(v.z); 

    std::cout << "sizeof(v) : " << sizeof_v << std::endl; 
    std::cout << "sizeof(xyz): " << sizeof_xyz << std::endl; 

    std::cout << "sizeof(v) == sizeof(xyz) : " << std::boolalpha << (sizeof_v == sizeof_xyz) << std::endl; 
} 

它打印,我的機器上:

sizeof(v) : 12 
sizeof(xyz): 12 
sizeof(v) == sizeof(xyz) : true 

因此,glm::vec3商店只有(x, y, z)座標。現在

,如果我們創建一個std::vector<glm::vec3> vertices;,它是安全地說,數據的佈局由&vertices[0]指出(在C++ 11 vertices.data())是:

vertices == [vertice1 vertice2 ...] 
     == [vertice1.x vertice1.y vertice1.z vertice2.x vertice2.y vertice2.z ...] 

回過頭來看看這個原來的問題 - glBufferData()的要求:正如預期glBufferData()當你通過&vertices[0]你實際上傳遞data的地址(即指針)。同樣的邏輯適用於glGetBufferSubData()

+0

太棒了!這非常有幫助。就像獎金一樣,你可以將「任何東西」傳遞給OpenGL緩衝區嗎?說一個類的實例的數組。我在猜測,當你將數據讀回來時,它不是很好用,還是會呢? – fordcars

+0

這取決於什麼GL反對你_ [綁定](https://www.opengl.org/sdk/docs/man3/xhtml/glBindBuffer.xml)_來。但以我的經驗,如果你要上傳的頂點,你將不得不使用本教程中提到的方法(即將原料陣列或GLM :: VEC3等等...基本上,'x的連續結構,所以如果你創建了一個自定義類,它只有**'x,y,z'的定義,就像'glm'(或者一個大小爲3的數組)一樣,你應該好好傳遞一個向量,包含大量的實例 – 865719

+1

@fordcars:好了,GL緩衝對象只是與特定大小的內存一個連續的區域所以,你可以把你喜歡的任何東西,也可以讀回不過,如果你打算。使用緩衝液作爲OpenGL本身輸入,則需要mathc一些限制,這取決於正在使用的緩衝液的類型。頂點屬性可以是某些數據類型的1至4維向量,和頂點數組需要與進行佈局在連續的元素之間保持連續的不斷變化,把對象的實例放在那裏可能會起作用,但是你可能會浪費一些內存。 – derhass

1

glm :: vec3只是一個結構中的三個浮點數。因此,將glm :: vec3的地址有效地傳遞給gl函數與將地址傳遞給float數組的第一個元素相同。 GLfloat只是float btw的一個typedef。

從gl讀取數據時適用同樣的原理。內存中glm :: vec3的x元素數組相當於具有3x元素的GLfloat(float)數組。