【问题标题】:Compute Shader write to texture计算着色器写入纹理
【发布时间】:2015-02-14 04:22:05
【问题描述】:

我已经实现了将投影纹理复制到 3d 对象上的更大纹理的 CPU 代码,如果你愿意的话,“贴花烘焙”,但现在我需要在 GPU 上实现它。为此,我希望使用计算着色器,因为在我当前的设置中添加 FBO 非常困难。

Example image from my current implementation

这个问题更多的是关于如何使用计算着色器,但对于任何感兴趣的人,这个想法是基于我从用户 jozxyqk 那里得到的答案,在这里看到:https://stackoverflow.com/a/27124029/2579996

写入的纹理在我的代码中称为_texture,而投影的纹理是_textureProj

简单的计算着色器

const char *csSrc[] = {
    "#version 440\n",
    "layout (binding = 0, rgba32f) uniform image2D destTex;\
     layout (local_size_x = 16, local_size_y = 16) in;\
     void main() {\
           ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);\
           imageStore(destTex, storePos, vec4(0.0,0.0,1.0,1.0));\
    }"
};

如您所见,我目前只想将纹理更新为任意(蓝色)颜色。

更新功能

void updateTex(){ 
    glUseProgram(_computeShader);
    const GLint location = glGetUniformLocation(_computeShader, "destTex"); 
    if (location == -1){
        printf("Could not locate uniform location for texture in CS");
    }
    // bind texture
    glUniform1i(location, 0); 
    glBindImageTexture(0, *_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
    // ^second param returns the GLint id - that im sure of. 

    glDispatchCompute(_texture->width() / 16, _texture->height() / 16, 1); 
    glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);

    glUseProgram(0);
    printOpenGLError(); // reports no errors.
}

问题 如果我在主程序对象之外调用updateTex(),我会看到 zero 效果,而如果我在其范围内调用它,如下所示:

 glUseProgram(_id); // vert, frag shader pipe
  updateTex();
  // Pass uniforms to shader 
  // bind _textureProj & _texture (latter is the one im trying to update) 
 glUseProgram(0);

然后在渲染时我看到了这个:

问题: 我意识到在主程序对象范围内设置更新方法不是正确的方法,但它是获得任何视觉结果的唯一方法。在我看来,发生的事情是它几乎消除了片段着色器并绘制到屏幕空间......

我该怎么做才能让它正常工作? (我的主要重点是能够将任何东西写入纹理并更新)

如果需要发布更多代码,请告诉我。

【问题讨论】:

  • 我不确定您所说的“主程序对象范围”是什么意思。 _programObject->activate(); 是做什么的?
  • 您的“主程序范围”是否在单独的线程上?当您在线程之间进行调用时,OpenGL 将无法正常/根本无法运行。
  • @GuyRT - 哦,对不起,也许我在那里用错了词。 _programObject->activate() 本质上是调用 glUseProgram(id) ,其中 id 是 GLint,我将编辑我的问题。
  • @newObjekt 它不在单独的线程上,我可能在那里使用了错误的术语,我的意思是在 glUseProgram() 中

标签: opengl glsl map-projections compute-shader


【解决方案1】:

我相信在这种情况下,FBO 会更简单、更快捷,我会推荐它。但是这个问题本身还是很有道理的。

我很惊讶看到一个球体,因为您正在向整个纹理写入蓝色(如果纹理大小不是 16 的倍数,则减去任何边缘位)。我猜这是来自其他地方的代码。

无论如何,您的主要问题似乎是能够从设置代码之外的计算着色器写入纹理以进行常规渲染。 我怀疑这与您绑定destTex 图像的方式有关。我不确定您的 TexUnitactivate 方法是做什么的,但是要将 GL 纹理绑定到图像单元,请执行以下操作:

int imageUnitIndex = 0; //something unique
int uniformLocation = glGetUniformLocation(...);
glUniform1i(uniformLocation, imageUnitIndex); //program must be active
glBindImageTexture(imageUnitIndex, textureHandle, ...);

见:

最后,由于您使用的是image2D,所以GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 是使用的障碍。 GL_SHADER_STORAGE_BARRIER_BIT 代表storage buffer objects

【讨论】:

  • 感谢您的快速回复。我实际上已经尝试过明确地这样做(根据您的建议编辑了我的帖子)。我对格式没有完全确定,但在检查时,它的 GL_RGB 似乎不受加载/存储方法的支持。所以,当我没有得到 GL_RGBA32F 的 glError 时,我假设它是要走的路。此外,您现在看到 im 使用布局限定符显式绑定到 0 - 仍然不起作用。我怀疑它要么与格式(应该)有关,要么与纹理的加载方式有关。
  • 继续:看起来我已经完成了“教科书”的实现,所以我将再次尝试使用 FBO(并在另一个线程中发布问题),但我会保留这段代码,并发表评论。让我知道我是否应该为此发布更多代码,现在我对为什么它没有做它应该做的事情有点不知所措。也许我省略了关键代码,请告诉我(谢谢!)。
  • 哦,还有一件事:我们看到“蓝色”球体的原因只是因为我在 glUseProgram() 调用中插入了 updateTex() 方法 - 即 - 看起来它删除了片段着色器。我现在知道颜色是基于投影的垂直着色器vec4 position,这就是为什么它的蓝色 - 运行时间和它根据投影仪与表面的角度改变颜色 - 完全错误,但这是我看到任何相关的唯一方法计算着色器... :(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多