如何使用多个对象的不同变换进行实例绘制

How to instance draw with different transformations for multiple objects

我在使用 glDrawArraysInstanced() 时遇到一点问题。

现在我正在尝试用棋子画棋盘。

我已正确加载所有模型。

我试过只用实例绘图来绘制 pawn 并且成功了。我会通过制服将带有转换 vec3s 的数组发送到着色器,然后使用 gl_InstanceID

移动数组

这将通过这个 for 循环完成(每个模型的单独绘制调用):

for (auto& i : this->models) {
    i->draw(this->shaders[0], count);
}

最终导致:

glDrawArraysInstanced(GL_TRIANGLES, 0, vertices.size(), count);

其中顶点着色器是:

#version 460

layout(location = 0) in vec3 vertex_pos;
layout(location = 1) in vec2 vertex_texcoord;
layout(location = 2) in vec3 vertex_normal;

out vec3 vs_pos;
out vec2 vs_texcoord;
out vec3 vs_normal;
flat out int InstanceID;

uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

uniform vec3 offsets[16];

void main(void){
    vec3 offset = offsets[gl_InstanceID];  //saving transformation in the offset 

    InstanceID = gl_InstanceID; //unimportant

    vs_pos = vec4(modelMatrix * vec4(vertex_pos + offset, 1.f)).xyz; //using the offset

    vs_texcoord = vec2(vertex_texcoord.x,1.f-vertex_texcoord.y);

    vs_normal = mat3(transpose(inverse(modelMatrix))) * vertex_normal;

    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(vertex_pos + offset,1.f); //using the offset
}

现在我的问题是我不知道如何以这种方式绘制多个对象并更改它们的转换,因为 gl_InstanceID 在每次绘制调用时从 0 开始,因此我的转换数组将再次使用开始(这只会在棋子位置上绘制下一块)。

任何帮助将不胜感激。

你有两个问题。或者更确切地说,你有一个问题,但自然的解决方案会给你带来第二个问题。

您的问题的自然解决方案是使用 base-instance rendering functions 之一,例如 glDrawElementsInstancedBaseInstance。这些允许您为实例化渲染调用指定起始实例。

这将引发第二个问题:gl_InstanceID 尊重基础实例。它总是在 [0, instancecount) 范围内。只有 instance arrays 尊重基础实例。因此,您 必须 使用实例数组呈现,而不是使用制服来提供每个实例的数据。这意味着将每个实例数据存储在缓冲区对象中(无论如何你都应该这样做)并通过 VS 输入访问它,其 VAO 指定特定属性被实例化。

这还有一个好处,即不会将您的实例数限制在 uniform 限制内。

OpenGL 4.6/ARB_shader_draw_parameters 允许访问 gl_BaseInstance 顶点着色器输入,它提供绘制命令指定的 baseinstance 值。因此,如果您不想 to/can 不使用实例化数组(例如,对于属性限制,每个实例的数据量太大),您将不得不依赖 extension/4。 6 功能。最近的桌面 GL 驱动程序提供了此功能,因此如果您的硬件相当新,您应该可以使用它。