OpenGL:使用指向静态数据的指针数组传递缓冲区数据

OpenGL: Passing buffer data using array of pointers to static data

本文关键字:数据 指针 数组 缓冲区 静态 OpenGL      更新时间:2023-10-16

在构造网格时,我将所有可能的法线数组保存在另一个 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]);
}