glMultiDrawElementsIndirect自定义drawID,每个DrawElementsIndirectCommand

时间:2018-11-24 17:49:33

标签: opengl

如果我使用以下方法为每个实例数据设置了一个定制的递增整数drawID顶点缓冲流:

glVertexAttribDivisor(drawIDVertexStreamIdx, 1)

使用给定的glMultiDrawElementsIndirect():

struct DrawElementsIndirectCommand
{
    uint  count;
    uint  instanceCount;
    uint  firstIndex;
    uint  baseVertex;
    uint  baseInstance;
};

当将instanceCount设置为一个以上时,我困惑地看着旧笔记和网上关于将drawID传递给着色器的确切情况?

如果说有两个从一个glMultiDrawElementsIndirect()调用的DrawElementsIndirectCommand记录,第一个记录的instanceCount为3,第二个记录的instanceCount为1,则实例在着色器中实际看到了什么? (假设drawID顶点流包含0、1、2、3等)

他们是否应该为第一个DrawElementsIndirectCommand记录实例看到0,1,2,并为第二个DrawElementsIndirectCommand记录实例看到3,

我在网上可以找到的所有示例似乎都将instanceCount专门设置为一个,并依赖多个DrawElementsIndirectCommand记录,这使我现在怀疑这种理解是否正确?

const int CustomDrawIDIdx = 1;
const int VertexCount = 4;
DrawElementsIndirectCommand drawCallRecords[2] =
{
    { VertexCount, 3, 0, 0, 0 },
    { VertexCount, 1, 0, 0, 0 },
};

...
//  Attempt to set up custom drawID from a vertex attribute, where the vertex stream for it is a sequence of integers 0, 1, 2 etc
glVertexAttribIPointer(CustomDrawIDIdx, 1, GL_UNSIGNED_INT, 0, NULL);
glVertexAttribDivisor(CustomDrawIDIdx, 1);
...

glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, &drawCallRecords, 2, 0);

在顶点着色器中:

layout (location = 1) in uint customDrawID;

void main()
{
    bool match = (customDrawID== gl_InstanceID); 
    ...
}

因此,这应该引起4次实际的绘图调用,因为由glMultiDrawElementsIndirect()引起的实际绘图调用由DrawElementsIndirectCommand记录的数量及其包含的实例数确定。

对于每个绘制调用,gl_InstanceID应该从零开始并为每个实例计数,但是在处理了每个DrawElementsIndirectCommand记录后又回到零?

那么gl_InstanceID应该对drawCallRecords [0]做(0,1,2),然后对drawCallRecords [1]做(0)? customDrawID有什么作用?

我还是很好奇,还是不建议与使用来自顶点流的自定义drawID相比,在nVidia(GTX1070 +)上使用ARB_shader_draw_parameters?

***更新以反映非常耐心和乐于助人的Nicol Bolas的答案:

所以给定了:

DrawElementsIndirectCommand drawCallRecords[2] =
{
    { VertexCount, 3, 0, 0, 0 },
    { VertexCount, 1, 0, 0, 3 /*baseInstance will push us along in customDrawID vertex stream*/ },
};

然后,customDrawID将对multidrawindirect中的所有实例进行(0,1,2)和(3)。

这意味着在两次multidrawindirect调用中,两次绘制调用中的每个绘制实例以及绘制的3 + 1总实例(一个“对象”的3个实例,另一个“对象”的1个实例)可以引用完全唯一的变换例如矩阵。实质上,只要您为每个DrawElementsIndirectCommand记录不断增加baseInstance这样的值(独占和样式),就可以模拟gl_DrawID的功能。

每个DrawElementsIndirectCommand记录中的baseInstance会将偏移量推送到customDrawID顶点流中,从而提供一个customDrawID,该ID对于所有绘制的对象中的每个实例都是唯一的。

1 个答案:

答案 0 :(得分:3)

  

因此,这应该引起4次实际的绘图调用,因为由glMultiDrawElementsIndirect()引起的实际绘图调用由DrawElementsIndirectCommand记录的数量及其包含的实例数确定。

不。实例和“绘图调用”不是一回事。

定义一次绘图调用,就像通过调用glDraw*InstancedBaseVertexBaseInstance来定义;当系统从绘制数据数组中读取单个条目时,就会发生这种情况。单个绘图调用包括所有实例。实例化是在抽奖中发生的事情。

这也是为什么每个实例的值不能保证为dynamically uniform expressions的原因。

多绘制命令中的

单独绘制gl_DrawID放在一边,彼此完全分开。他们不互动。着色器为实例数组或gl_InstanceID获取的值与分别发出每个绘图调用没有什么不同。

您的“自定义drawID”根本不是绘图ID;它是一个实例数组值。因此,它遵循实例化规则,并且不关心什么所在的绘制调用。


bool match = (customDrawID== gl_InstanceID); 

否。

即使您用于馈送customDrawID的实际数组只是从零开始的整数索引,实例数组和gl_InstanceID的工作方式也不相同。

gl_InstanceID忽略基本实例。实例数组。这样,从任何实例数组中获取的实例值将始终始终先由基本实例偏移。

因此,如果您希望特定绘图调用的customDrawID从特定值开始,则可以将baseInstance设置为该特定值的实例索引。因此,给定一个从零开始的整数索引数组,如果希望特定的绘制调用使其第一个实例接收customDrawID的值“ 3”,则可以将baseInstance设置为3。