opengl - 如何在片段着色器中存储纹理

标签 opengl glsl shader

您有一个简单的盒子,里面显示了一个图像。

您还有两种纹理,一种是红色的,另一种是绿色的......

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

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

enter image description here

阴影圆圈位于鼠标周围,用于显示纹理的一部分。

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

enter image description here

到目前为止一切顺利。然而,我已经搜索了很多,但我找不到一种方法将片段着色器的结果存储到显示的、使用的纹理中。总的操作将形成第一和第二纹理的混合。

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

#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 并作为图像保存到磁盘。

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

最佳答案

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

  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...
}

上面的代码基本上创建了一对纹理+帧缓冲区,因此如果渲染到关联的帧缓冲区,则可以渲染到纹理。为此,您可以执行以下操作:

// 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是一个缓冲区,其大小足以保存位图。

关于opengl - 如何在片段着色器中存储纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42172169/

相关文章:

c++ - 几何着色器输出可能用最接近的值填充 Z-Buffer? (DirectX)

c++ - 调整窗口倾斜显示 (OpenGL)

OpenGL GL_SELECT 或手动碰撞检测?

c++ - GLSL 日志返回未定义的结果

javascript - webgl 试图画一个三 Angular 形

glsl - THREE.js 在着色器中重复包装纹理

java - 使用 JOGL 调整 GLJPanel 的大小会导致我的模型消失

c++ - OpenGL:无法绘制由存储在 SSBO 中的计算着色器生成的顶点

opengl - GLSL:无法从 FBO 读取纹理并使用片段着色器渲染到另一个 FBO

opengl - 着色器语言之间是否存在重大差异?