我有一个 3D 纹理,我在其中写入数据并以这种方式将其用作片段着色器中的体素:
#extension GL_ARB_shader_image_size : enable
...
layout (binding = 0, rgba8) coherent uniform image3D volumeTexture;
...
void main(){
vec4 fragmentColor = ...
vec3 coords = ...
imageStore(volumeTexture, ivec3(coords), fragmentColor);
}
纹理是这样定义的
glGenTextures(1, &volumeTexture);
glBindTexture(GL_TEXTURE_3D, volumeTexture);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, volumeDimensions, volumeDimensions, volumeDimensions, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
然后在我必须使用它的时候使用它
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, volumeTexture);
现在我的问题是,我想要这个的 mipmapped 版本并且不使用 opengl 函数,因为我注意到它非常慢。所以我想同时在所有级别写入 3D 纹理,例如,最大分辨率为 512^3,当我在该 3dtex 中写入 1 体素 VALUE 时,我也为 256^3 写入 0.125*VALUE体素和 0.015625*VALUE 用于 126^3 等。因为我使用的是 imageStore,它使用原子性,所有值都将被写入并使用这些权重,我会自动获得平均值(不完全像插值,但我可能会得到一个令人满意的结果反正)。 所以我的问题是,拥有多个 3d 纹理并同时写入所有 3d 纹理的最佳方法是什么?
最佳答案
我相信硬件 mipmap 的速度与您所能达到的差不多。我一直认为尝试自定义 mipmap 会比较慢,因为您必须依次手动绑定(bind)和光栅化到每个层。原子将引起巨大的争论,而且速度会非常慢。即使没有原子,您也会否定 mipmap 的 O(log n) 构造。
在访问顺序和缓存方面,您必须非常小心 imageStore
。我将从这里开始并尝试一些不同的索引(例如行/列与列/行)。
您可以尝试以旧方式绘制纹理,方法是将其绑定(bind)到 FBO 并使用 glDrawElementsInstanced
绘制全屏三角形(覆盖视口(viewport)的大三角形)。在几何着色器中,将 gl_Layer
设置为实例 ID。光栅化器为 x/y 创建片段,图层给出 z。
最后,即使按照今天的标准,512^3 也只是一个巨大的纹理。也许找出你的理论最大 gpu 带宽来了解你有多远。例如。假设您的 GPU 可以达到 200GB/s。无论如何,在好的情况下你可能只会得到 100。你的 512^3 纹理是 512MB,所以你可以在 ~5ms 内写入它(imo 这看起来非常快,也许我犯了一个错误)。预计管道的其余部分会产生一些开销和延迟,产生和执行线程等。如果您正在编写复杂的东西,那么内存带宽不是瓶颈,我的估计超出了范围。所以先尝试只写零。然后尝试更改 coords
xyz
顺序。
更新:除了使用片段着色器来创建线程,还可以使用顶点着色器,理论上可以避免光栅化器开销,尽管我已经看到它表现不佳的情况。您 glEnable(GL_RASTERIZER_DISCARD)
,glDrawArrays(GL_POINTS, 0, numThreads)
并使用 gl_VertexID
作为您的线程索引。
关于c++ - 在片段着色器 OpenGL 中写入多个 3d 纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24431205/