2015-10-10 3 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 documentation, glBufferData() необходим указатель на data (то есть в массив, то есть координаты вершин).

Давайте сначала рассмотрим реализацию glm::vec3.

Если вы заканчивали glm's Github repo, вы увидите, что, в зависимости от ваших флагов компиляции, glm::vec3 является typedef of highp_vec3, который является typedef of tvec3<float, highp>.

tvec3 заявлено в type_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; }; 

Так x, y и z являются отдельными атрибутами. Но благодаря 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() Требования: при передаче &vertices[0] вы фактически передаете адрес (то есть указатель) data, как и ожидалось glBufferData(). Та же логика применяется к glGetBufferSubData().

+0

Отлично! Это очень полезно. Как бонус, можете ли вы передать «что-нибудь» в буфер OpenGL? Произнесите массив экземпляров класса. Я предполагаю, что когда вы прочтете данные назад, это совсем не работает, или не так ли? – fordcars

+0

Это зависит от того, какой объект GL вы _ [binding] (https://www.opengl.org/sdk/docs/man3/xhtml/glBindBuffer.xml) _ to. Но, по моему опыту, если вы хотите загрузить вершины, вам придется использовать метод, упомянутый в учебнике (например, передать необработанный массив или glm :: vec3 и т. Д.), В основном, непрерывную структуру 'x, y, z'.Так что если вы создадите собственный класс, который имеет ** только ** 'x, y, z', определенный как в' glm' (или массив размера 3), вы должны хорошо передать вектор, который содержит ряд его экземпляров. – 865719

+1

@fordcars: Ну, объект буфера GL - это просто непрерывный регион памяти с указанным размером. Таким образом, вы можете разместить все, что вам там нравится, и можете также прочитать его. Однако, если вы планируете для использования буфера в качестве входных данных для самого OpenGL, вам нужно ограничить некоторые ограничения, в зависимости от используемого типа буфера. Атрибуты вершины могут быть от 1 до 4 размерных векторов определенных типов данных, а массивы вершин должны быть выложены с помощью постоянное смещение между последовательными элементами. Помещение экземпляров объектов может работать, но вы можете потерять некоторую память. – derhass

1

glm :: vec3 всего лишь три поплавка в структуре. Таким образом, передача адреса glm :: vec3 в функцию gl фактически делает то же самое, что передать адрес первому элементу массива float. GLfloat - это всего лишь typedef of float btw.

Тот же принцип применяется при чтении данных с gl. Массив x элементов glm :: vec3 в памяти эквивалентен массиву GLfloat (float) с 3x элементами.

 Смежные вопросы

  • Нет связанных вопросов^_^