【问题标题】:Rectangle instances with different texture UVs具有不同纹理 UV 的矩形实例
【发布时间】:2014-07-30 21:01:02
【问题描述】:

我是现代 OpenGL VBO/VAO 的新手,我为一件事而苦恼:我已经基于 this tutorial 编写了一个 RectangleAsset,但我不确定如何将有关纹理 UV 的信息移动到 RactangleAssetInstance(我的矩形可以有不同的纹理)。


我必须为其创建新的 VAO,还是可以通过其他方式传递 UV?或者为 UV 添加第二个 VBO?最重要的是:解决这个问题的最佳实践是什么?

struct RectangleAsset {
    GLuint VBO;
    GLuint VAO;
};

struct RectangleAssetInstance { //this is actually more complex class in my code
    RectangleAsset rect;        //but tried to extract the most imporatant code
    glm::mat4 transform;
    Texture * texture;
    void UpdateTransform(int,int,int,int);
private:
    int x,y,width,height;
};

以及加载 RectangleAsset 的函数:

void GUIRenderer::init()
{
    image = new Program ("vs.glsl", "fs.glsl");
    glGenVertexArrays(1, &rect.VAO);
    glBindVertexArray(rect.VAO);
    glGenBuffers(1, &rect.VBO);
    glBindBuffer(GL_ARRAY_BUFFER, rect.VAO);

    GLfloat vertexData[] = {
        //  X     Y     Z       U     V   
         0.0f, 0.0f, 0.0f,   0.0f, 0.0f,
         1.0f, 0.0f, 0.0f,   1.0f, 0.0f,
         0.0f, 1.0f, 0.0f,   0.0f, 1.0f,
         1.0f, 0.0f, 0.0f,   1.0f, 0.0f, 
         1.0f, 1.0f, 0.0f,   1.0f, 1.0f,
         0.0f, 1.0f, 0.0f,   0.0f, 1.0f,
    };
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);

    glEnableVertexAttribArray(image->attrib("vert"));
    glVertexAttribPointer(image->attrib("vert"), 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), NULL);

    glEnableVertexAttribArray(image->attrib("vertTexCoord"));
    glVertexAttribPointer(image->attrib("vertTexCoord"), 2, GL_FLOAT, GL_TRUE,  5*sizeof(GLfloat), (const GLvoid*)(3 * sizeof(GLfloat)));
    glBindVertexArray(0);
}

注意:我计划只在一个地方使用 RectangleAssetInstances,在一个 std::vector 中进行 GUI 渲染(非静态 gui)。将所有矩形合并到一个 VBO 和 VAO 中可能是个好主意(并在添加/删除 UIElement 时重新创建它)?
欢迎任何学习 OpenGL 最佳实践的建议。

【问题讨论】:

  • 我认为每个属性都需要 1 个 VBO。虽然,您可以在同一个 VAO 中拥有所有数据(顶点和纹理坐标),并使用 glVertexAttribPointerstride 参数来指定属性之间的跳转。我通常为每个属性设置 1 个 VBO 和 1 个 VAO。不过,我不知道最佳做法是什么。
  • 如果我理解正确的话,RectangleAssetInstance 应该同时具有 UV VBO 和 UV VAO(在构造函数中生成),对吧?那么合并呢,是不是有很多短缓冲区效率低下?
  • 你可以这样做。不过,如果您愿意,您可以为 verticestexture coordinates 使用相同的 VAO。这是如何工作的?我们可以在glVertexAttribPointer 上的每个属性的数据之间设置stride(jump)。对于顶点我会调用glVertexAttribPointer(start pos=0, size=3, stride=2) 和UV glVertexAttribPointer(start pos=2, size=2, stride=3。类似的东西。
  • 我认为,这就是资产教程中的内容。好吧...我想如果 UV 和 Vert 缓冲区都在 RectangleAssetInstance 中,那么保留 RectangleAsset 是没有意义的。

标签: c++ opengl vbo opengl-3 vao


【解决方案1】:

VAO 存储输入数据的格式和输入数据的来源位置。这实际上是两个不同的概念。如果你想改变 UV 的来源,你必须再次调用 glVertexAttribPointer。此调用类似于 glVertexAttribPointer(uvLoc, GL_FLOAT, false, sizeof(float) * 5, (const GLvoid*)(sizeof(float) * 3)) 请注意,这不会更改您的位置信息来自的 VBO。

现在您提到您想要这样做是因为您的矩形实例可能具有不同的纹理。您无需更改 UV 即可实现此目的。通常位置、UV 和法线都是网格的一部分,您只需要它们的一份副本。要更改纹理,只需调用glActiveTexture(GL_TEXTURE0 + i),然后调用glBindTexture(GL_TEXTURE_2D, tex),然后在着色器中设置采样器统一以使用正确的图像单元和glUniform1i(samplerLoc, i)

还有 ARB_vertex_attrib_binding 扩展,它成为 OpenGL 4.3 的核心。这允许您将属性布局与数据位置分开。 OpenGL wiki 上的文章提供了有关如何执行此操作的信息,但同样最好使用相同的 UV 为给定网格创作所有纹理。

关于您关于将所有内容合并到一个 VAO 和 VBO 的问题:如果您只想要矩形,则不需要这样做,因为您可以使用具有非均匀缩放组件的仿射变换获得任何类型的矩形。这样你总共只需要一个VAO和一个VBO,不需要合并任何东西。

【讨论】:

  • 好吧,问题是,我想为(GUI)矩形使用纹理图集——这也意味着并非所有矩形都具有相同的 UV(isVertexAttribPointer 调用昂贵吗?)。关于你的最后一段,这正是我的想法——拥有 1,1 个矩形并对其进行缩放,但事实证明它比我想象的要复杂(UV 问题)。
  • 您可以对所有矩形使用相同的 UV,并通过制服将有关使用哪个图集的信息发送到着色器,然后根据您所在的图集在片段着色器中偏移 UV。跨度>
猜你喜欢
  • 2018-07-14
  • 1970-01-01
  • 2014-10-04
  • 2013-04-21
  • 2021-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多