OpenGL:使用指向静态数据的指针数组传递缓冲区数据
OpenGL: Passing buffer data using array of pointers to static data
在构造网格时,我将所有可能的法线数组保存在另一个 const static GLfloat[6][12]
数组中。网格将仅由立方体的正方形面组成,因此只有六个可能的法线。当我向网格添加面时,我将静态数组中相应子数组中的数据复制到std::vector<GLfloat>
,完成后,我使用glBufferData
将数据从矢量传递到顶点缓冲区。
静态数组:
static constexpr GLfloat facenormals[6][12] = {
{
0.0f, 1.0f, 0.0f, // TOP
// Each sub-array has four identical 3-part vectors, I only included one of each.
},
{
0.0f, -1.0f, 0.0f, // BOTTOM
},
{
0.0f, 0.0f, 1.0f, // FRONT
},
{
0.0f, 0.0f, -1.0f, // BACK
},
{
1.0f, 0.0f, 0.0f, // RIGHT
},
{
-1.0f, 0.0f, 0.0f, // LEFT
}
};
使用以下方法复制到载体中:
normals.insert(normals.end(), CubeData::facenormals[direction], CubeData::facenormals[direction] + 12);
传递到顶点缓冲区:
glBufferData(GL_ARRAY_BUFFER, chunkmesh.normals.size() * sizeof(GLfloat), chunkmesh.getnormals(), GL_STATIC_DRAW);
像这样,向量只是一个连续的内存块,按照索引缓冲区指定的顺序包含法线。
是否有可能和/或理智地用指向数组中静态数据的指针填充向量并将指针传递给顶点缓冲区,并通过这样做减少从网格构建时间复制数据所需的时间。
我测量了构建网格所需的时间,包括随机生成,使用 Visual Studios 调试工具,以及数据复制占用了 40% 以上的 CPU 时间、位置、法线和纹理坐标。
所以当然下面的代码更适合 2D 绘图,但这是我的方法。
-1. 创建一个可以调用顶点的对象。
typedef struct{
float x, y;
float r, g, b;
float tex_coordx, tex_coordy;
}Vertex;
-2. 定义顶点对象的静态数组
Vertex square[6] = {{0, 0, 1, 1, 1, 0, 1},
{1, 0, 1, 1, 1, 1, 1},
{0, 1, 1, 1, 1, 0, 0},
{0, 1, 1, 1, 1, 0, 0},
{1, 1, 1, 1, 1, 1, 0},
{1, 0, 1, 1, 1, 1, 1}};
正如我之前所说,此代码用于 2D 绘图,您可以在顶点调用 y 中自由添加新的浮点数(或者如果您更喜欢 GLfloat)变量。
-3. 将指针传递给 glBufferData,而无需将数组复制到另一个不需要的 std::vector 对象中。
glBufferData(GL_ARRAY_BUFFER, sizeof(square), square, GL_STATIC_DRAW);
我希望这对你有用。
听起来好像您想知道如何在整个立方体上重用 6 个法线作为节省空间的措施? 即为法线和顶点提供单独的索引?如果是这种情况,那么您可以采用两种节省空间的措施。
最简单的方法是简单地将缓冲区转换为半精度(16 位浮点数)。然后稍后使用 GL_HALF_FLOAT 指定数据。
#include <emmintrin.h>
typedef uint16_t half;
inline half toHalf(float f) { return _cvtss_sh(f, _MM_FROUND_CUR_DIRECTION); }
如果要对顶点和法线使用单独的索引,则可以将法线索引作为 uint16 或 uint32 数组上传(使用 glVertexAttribIFormat 或 glVertexArrayAttribIFormat!! 指定数据)。法线需要作为着色器存储缓冲区上传,然后法线索引将成为每个顶点的属性。使这项工作的最小着色器如下所示:
#version 450
in uint vs_normalIndex;
layout(std430, binding = 0) buffer Normals
{
float normals[];
};
void main()
{
uint index = vs_normalIndex * 3;
vec3 normal = vec3(normals[index], normals[index + 1], normals[index + 2]);
}
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 如何在没有数据拷贝的情况下从指针创建一个Eigen VectorXd对象
- 如何使用数据对象上的常量指针初始化类
- int数据类型的指针指向的是什么,如果是一个类的私有数据成员,我们创建了该类的两个对象?
- 将矢量的数据复制到<MyStruct>矢量<MyStruct>的指针
- 使用指针访问数组中的对象数据成员
- CURLOPT_INTERLEAVEFUNCTION回调函数始终接收 nullptr 作为用户数据指针
- C++中纹理数据指针的联合
- 什么是成员数据指针的正确赋值语句
- EIGEN地图 - 它是否占数据指针的所有权
- C 11 STD :: Promise返回STD :: String从线程中返回String,数据指针看起来已复制
- 为什么函数指针和数据指针在 C/C++ 中不兼容
- 带有数据指针的可变模板模板
- 为什么我在尝试将opencv图像数据指针转换为char*时出错
- 通过在CGAL中传递高度、宽度、深度和数据指针来创建Image_3实例
- read() 缓冲区有无效数据(指针问题?
- 在用SWIG编译的c和lua模块之间共享数据指针
- 具有原始数据指针和刻字的对象
- 对openCV的数据指针进行类型转换
- Lua用户数据指针的生存期