void addTriangle (uint i0, uint i1, uint i2) {
uint ic = atomicCounterIncrement(indirectIndexCount);
meshIndices[ic*3+0] = i0;
meshIndices[ic*3+1] = i1;
meshIndices[ic*3+2] = i2;
}
生成网格后,它使用glDrawElementsIndirect绘制。上面代码中的indirectIndexCount是GL_DRAW_INDIRECT_BUFFER中位置0处的atomic_uint计数器(请参阅名为DrawElementsIndirectCommand的结构)。现在该计数器显然太小了三倍,因为每个三角形仅增加了一次。目前,我在发出绘画调用之前将其乘以3。
(目前,这是通过映射缓冲区并在CPU上乘以完成的,这当然是胡说八道,但是表明整个事情基本上都能正常工作。一切都正确绘制。我可以通过调用一个1x1x1x1x1x1计算着色器来做到这一点,但这似乎只不过稍微傻了一点。)
如何摆脱这种多余的乘法步骤?
由于每当生成具有可变索引数的网格时,这似乎是一个明显的问题,我想一定有一些我忽略的简单解决方案?
#1 楼
如果可以使用glsl 4.3+(或glsl ES 3.1),则可以使用atomicAdd下一个选项是在计算中生成所有顶点之后使用
barrier()
,然后将其值乘以计数器:main(){
// generate vertices
barrier();
if(gl_localInvocationID == vec3(0)){
indirectCount = atomicCounter(indirectIndexCount)*3;
}
}
这模拟运行另一个1x1x1计算着色器来乘以索引。
否则,您可以使用第二个原子来保存顶点数:
void addTriangle (uint i0, uint i1, uint i2) {
uint ic = atomicCounterIncrement(indirectIndex);
meshIndices[ic*3+0] = i0;
meshIndices[ic*3+1] = i1;
meshIndices[ic*3+2] = i2;
atomicCounterIncrement(indirectIndexCount);
atomicCounterIncrement(indirectIndexCount);
atomicCounterIncrement(indirectIndexCount);
}
indirectIndex
和indirectIndexCount
均被初始化为0,而indirectIndexCount
则传递给glDrawElementsIndirect
。评论
$ \ begingroup $
我喜欢第二个想法,因为它明确表明我需要两个不同的东西:一种原子添加三角形的方法以及一种获取最终索引数的方法。不必是相同的机制。是的,我也会尝试atomicAdd。正如Nathan在上面的评论中所建议的那样,很有趣的是看看它是否真的更慢。我将报告调查结果。
$ \ endgroup $
–杯子
2015年10月13日14:33
$ \ begingroup $
可以确认在nvidia kepler上的这种使用情况下,atomicAdd确实并不慢(〜1.5k索引:0.1ms-可能需要更大的大小才能实现有意义的基准测试)。将间接命令缓冲区绑定为SSBO并写入位置0的uint可以正常工作。有时候,应该先尝试简单的解决方案...
$ \ endgroup $
–杯子
2015年10月13日在22:15
评论
您能将3原子加到计数器上而不是递增吗?不可以,原子计数器只能查询,增加(增加1)或减少(增加1)。请参阅opengl Wiki中的文章。它们与Images上的atomic Add等不同。您只有8个(或大约8个),并且它们在极频繁地访问时(例如,在生成(并计数)成千上万个...事物时)应该会快得多。
是的,我想您必须将其从“原子计数器”转换为SSBO中的变量。看看这实际上是否更慢(取决于硬件),可能会很有趣。除此之外,我唯一想到的就是按照您所说的做,然后运行计算着色器将值乘以3。
嗨,cupe,可以看看某处的代码吗?附:您是否也在检查多个条目?