【问题标题】:How to store to texture in fragment shader如何在片段着色器中存储到纹理
【发布时间】:2019-09-05 00:04:42
【问题描述】:

你有一个简单的盒子,里面有一张图片。

你还有两个纹理,一个红色的,一个绿色的......

您从绿色纹理初始化您使用的纹理...

您的窗口首先显示您未更改的使用纹理:

阴影圆圈围绕鼠标显示纹理的一部分。

当你按下鼠标按钮时,阴影区域变为红色纹理,如下图所示:

到目前为止一切顺利。但是,我进行了很多搜索,但找不到将片段着色器的结果存储到显示的使用纹理的方法。总操作将加起来形成第一个和第二个纹理的混合。

这是我的相关片段着色器:

#version 120
uniform sampler2D red_texture, used_texture;
uniform bool isMouseClicked;
uniform float mousex, mousey;
uniform float radius; //the radius of the painting circle

void shadePixel(){ ... }

void main(){
   //calculate the distance from mouse origin
   float distance = sqrt(pow((gl_FragCoord.x - mousex), 2) + pow((gl_FragCoord.y - mousey), 2));

   if(distance<=radius && isMouseClicked){
    //used_texture <- red_tuxture
   }

   if(distance<=radius) shadePixel(); //make circle bound visible
   else gl_FragColor = texture2D(used_texture, gl_TexCoord[0].xy);
}

我想稍后将纹理检索到 ram 并作为图像保存到磁盘。

那么,有没有办法通过片段着色器来操作纹理?

【问题讨论】:

    标签: opengl glsl shader


    【解决方案1】:

    您可以执行“渲染到纹理”。

    1. 将图像渲染为纹理
    2. 将此纹理保存到磁盘
    3. 在窗口中显示。

    这是一个关于如何准备要渲染的纹理的示例:

    // create a texture "_textureId"
    glGenTextures(1, &_textureId);
    glBindTexture(TEXTURE_TARGET, _textureId);
    glTexParameteri(TEXTURE_TARGET, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(TEXTURE_TARGET, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(TEXTURE_TARGET, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(TEXTURE_TARGET, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(TEXTURE_TARGET, 0, YOUR_INTERNAL_FORMAT, width, height, 0, YOUR_FORMAT, GL_UNSIGNED_BYTE, 0);
    
    // create the framebuffer "_frameBuffer" and associate to the texture above
    glGenFramebuffers(1, &_frameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
    glBindTexture(TEXTURE_TARGET, _textureId);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _textureId, 0);
    GLenum drawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
    glDrawBuffers(1, drawBuffers);
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
        // error...
    }
    

    上面的代码基本上是创建了一对texture + framebuffer,所以渲染到关联的framebuffer就可以渲染到texture了。为此,您可以执行以下操作:

    // do your normal render here... is goes to the image
    glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
    
    // render whatever you want... glViewPort, glClear, glDrawArrays, etc...
    // ...
    
    // Switch back to the "default framebuffer" 0... it means, your window.
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    

    此时,您可以再次根据需要将纹理 _textureId 渲染到窗口...并可选择将纹理数据下载到 GPU...这可以通过以下方式完成:

    glBindTexture(TEXTURE_TARGET, _textureId);
    glGetTexImage(TEXTURE_TARGET, 0, YOUR_FORMAT, GL_UNSIGNED_BYTE, _data);
    

    _data 是一个缓冲区,其大小足以让您保存位图。

    【讨论】:

    • 谢谢,但我希望通过着色器来做到这一点。你知道这是否可能吗?
    • @FrustratedSoul:您可以在新硬件上使用计算着色器和imageStore 来实现。但我认为没有理由不使用 Wagner 所描述的通过渲染到纹理混合提供的硬件。
    • "但我希望通过着色器做到这一点:"好吧,你使用片段着色器计算你的图像(或任何你想要计算的东西)并将其输出到纹理,我不真正明白为什么你对这个解决方案不满意
    猜你喜欢
    • 2013-09-17
    • 1970-01-01
    • 1970-01-01
    • 2017-12-09
    • 1970-01-01
    • 2019-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多