【问题标题】:Vertex attributes - using short instead of float for vertex positions顶点属性 - 顶点位置使用 short 而不是 float
【发布时间】:2016-08-14 23:01:19
【问题描述】:

目前我有以下设置,目前运行良好。

struct Vertex {
    glm::vec3 position;
    glm::vec3 normal;
    glm::vec2 texCoord;
}
std::vector<Vertex> vertices;

顶点属性:

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, Vertex::position)); 
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, Vertex::normal));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, Vertex::texCoord));

现在我想通过将顶点属性从浮动更改为短来提高我的性能。 我尝试从顶点位置开始。

OpenGL's Vertex Specification Best Practices 告诉我这个:

职位 [...] 为此,您需要重新排列模型空间数据,以便将所有位置打包在原点周围的 [-1, 1] 框中。您可以通过在所有位置中找到 XYZ 中的最小/最大值来做到这一点。然后从所有顶点位置中减去最小/最大框的中心点;然后将所有位置缩放最小/最大框的宽度/高度/深度的一半。您需要保持中心点和缩放因子。 当您构建模型到视图矩阵(或模型到任何矩阵)时,您需要在变换堆栈的顶部应用中心点偏移和缩放(所以在最后,就在您绘制之前)。

我也读过这个Thread

这就是为什么我添加了这个预处理步骤,将所有顶点映射到 [-1,1]

for (auto& v : vertices) {
    v.position = (v.position - center) * halfAxisLengths;
}

并在顶点着色器中重新调整

vec4 rescaledPos = vec4(in_pos, 1.0) * vec4(halfAxisLengths, 1.0) + vec4(center, 0.0);
gl_Position = P * V * M * rescaledPos;

我的顶点属性使用GL_SHORT而不是GL_FLOAT,并且规范化设置为GL_TRUE

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_SHORT, GL_TRUE, sizeof(Vertex), (void*) offsetof(Vertex, Vertex::position));

结果我只是得到一个三角形的混乱,但不是我的模型增加了 fps。

这是将顶点属性设置为短的正确方法吗?

或者我是否必须更改我的完整顶点结构? 如果是,那么最好的方法是什么(带短裤的 glm 向量?)。

一个可行的例子会很棒,我找不到。

【问题讨论】:

  • 这个问题暂且不论,但你考虑过半浮动吗?
  • @WilliamKappler 是的,GL_HALF_FLOAT 工作正常。但我想使用GL_SHORT/GL_UNSIGNED_SHORT(特别是对于texCoords)和GL_INT_2_10_10_10_REV作为法线。
  • "recale it in the vertex-shader" 你为什么不把它放在矩阵本身呢?这只是一个比例/翻译。矩阵可以做到这一点。
  • 我会这样做的。现在我处于“只是测试”状态。

标签: c++ opengl glsl glm-math vertex-attributes


【解决方案1】:

我调整了顶点缓冲区的数据结构:

struct newVertex {
    GLshort position[4]; // for GL_SHORT
    GLint normal; // for GL_INT_2_10_10_10_REV
    GLshort texCoord[2]; // for GL_SHORT
};

因此,我的性能提高了约 20%。

【讨论】:

    【解决方案2】:

    或者我是否必须更改我的完整顶点结构?

    是的,OpenGL 不会神奇地为您进行转换。但是,如果性能是您的目标……

    现在我想通过将顶点属性从浮动更改为短来提高性能。

    这实际上会损害性能。 GPU 已针对将向量作为浮点值进行处理进行了优化。这反过来会影响内存接口,该接口旨在为 32 位对齐访问提供最佳性能。通过提交为 16 位短整数,您将强制当前的 GPU 线执行次优的内存访问和中间转换步骤。

    如果性能是您的目标,请坚持使用单精度浮点数。如果你不相信我:对它进行基准测试。

    【讨论】:

    • 我可以使用第 4 个向量分量进行填充以填充 32 位吗?人们herehere 通过使用短裤获得更多性能。我认为更少的内存传输会更快,不是吗?
    • "如果你不相信我:给它做基准测试。" 你是一个声称可疑的自然的人,这与传统智慧背道而驰。所以我想说举证责任在你身上。但是您是对的,您必须将该位置填充为 4 元素位置。但它仍然为每个顶点节省了 32 位。通过以 10/10/10/2 格式压缩法线并将纹理坐标压缩为 16 位标准化短裤,您可以节省更多。这从 32-bytes-per-vertex 到 16. 数据大小的一半。我很确定任何转换步骤都会比内存访问更快。
    • @Mr.X:OpenGL-ES != OpenGL。在移动 GPU 上,例如 iPhone 中的 GPU,节省内存带宽实际上会提高性能。
    • @NicolBolas:我也这么认为,很长时间了。然后我两周前参加了一个 Khronos 活动,来自 NVidia 和 AMD 的 GPU 工程师在场并耐心地向我详细解释了为什么这些类型的转换会对现代 GPU 的齿轮产生影响。甚至到目前为止(至少就 AMD 而言),驱动程序可能决定实际重新编译着色器以获得不同的格式,并在他们认为合适的情况下进行原位格式转换。
    • "驱动程序可能决定为不同的格式重新编译着色器并进行原位格式转换" AMD 的驱动程序总是这样做,因为他们的 GCN 硬件不完全有顶点获取逻辑。这并没有改变降低内存带宽和 pre-T&L 缓存命中成本非常重要的事实。如果您有此活动的链接或一些类似信息,请分享。
    猜你喜欢
    • 1970-01-01
    • 2022-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-25
    • 1970-01-01
    • 1970-01-01
    • 2023-01-15
    相关资源
    最近更新 更多