В соответствии с 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()
.
Отлично! Это очень полезно. Как бонус, можете ли вы передать «что-нибудь» в буфер OpenGL? Произнесите массив экземпляров класса. Я предполагаю, что когда вы прочтете данные назад, это совсем не работает, или не так ли? – fordcars
Это зависит от того, какой объект GL вы _ [binding] (https://www.opengl.org/sdk/docs/man3/xhtml/glBindBuffer.xml) _ to. Но, по моему опыту, если вы хотите загрузить вершины, вам придется использовать метод, упомянутый в учебнике (например, передать необработанный массив или glm :: vec3 и т. Д.), В основном, непрерывную структуру 'x, y, z'.Так что если вы создадите собственный класс, который имеет ** только ** 'x, y, z', определенный как в' glm' (или массив размера 3), вы должны хорошо передать вектор, который содержит ряд его экземпляров. – 865719
@fordcars: Ну, объект буфера GL - это просто непрерывный регион памяти с указанным размером. Таким образом, вы можете разместить все, что вам там нравится, и можете также прочитать его. Однако, если вы планируете для использования буфера в качестве входных данных для самого OpenGL, вам нужно ограничить некоторые ограничения, в зависимости от используемого типа буфера. Атрибуты вершины могут быть от 1 до 4 размерных векторов определенных типов данных, а массивы вершин должны быть выложены с помощью постоянное смещение между последовательными элементами. Помещение экземпляров объектов может работать, но вы можете потерять некоторую память. – derhass