如何创建模糊着色器
How to create a blur shader
我正在按照以下着色器创建模糊效果。
OpenGL es 2.0 Gaussian blur on triangle
首先我生成帧缓冲区。
glGenTextures(2, texObj);
glGenFramebuffers(2, fbObj);
glActiveTexture(GL_TEXTURE0);
for (int i = 0; i < 2; i++)
{
glBindTexture(GL_TEXTURE_2D, texObj[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1920, 1080, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glGenerateMipmap(GL_TEXTURE_2D);
glBindFramebuffer(GL_FRAMEBUFFER, fbObj[i]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texObj[i], 0);
GLuint renderbuffer;
glGenRenderbuffers(1, &renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 1920, 1080);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
然后我按照这些步骤。
// first create a image of the scene
GLint drawFrameBuffer;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &drawFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, fbObj[0]);
ResourceManager::GetShader("BasicShader").Use();
//ResourceManager::GetShader("BasicShader").SetInteger("UseColorMap", false);
glDisable(GL_DEPTH_TEST);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT );
geom->draw();
// Set the Blur in X direction
glBindFramebuffer(GL_FRAMEBUFFER, fbObj[1]);
ResourceManager::GetShader("shaderTest").Use();
// Set the blur shader properties
ResourceManager::GetShader("shaderTest").SetFloat("u_sigma", intensity);
ResourceManager::GetShader("shaderTest").SetFloat("u_radius", blur);
ResourceManager::GetShader("shaderTest").SetVector2f("u_dir", glm::vec2(1.0, 0.0));
ResourceManager::GetShader("shaderTest").SetVector2f("u_textureSize", glm::vec2(1920.0, 1080.0));
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texObj[0]);
glGenerateMipmap(GL_TEXTURE_2D);
drawFullScreenQuad();
// Set the Blur in Y direction
glBindFramebuffer(GL_FRAMEBUFFER, fbObj[0]);
ResourceManager::GetShader("shaderTest").Use();
// Set the blur shader properties
ResourceManager::GetShader("shaderTest").SetFloat("u_sigma", intensity);
ResourceManager::GetShader("shaderTest").SetFloat("u_radius", blur);
ResourceManager::GetShader("shaderTest").SetVector2f("u_dir", glm::vec2(0.0, 1.0));
ResourceManager::GetShader("shaderTest").SetVector2f("u_textureSize", glm::vec2(1920.0, 1080.0));
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texObj[1]);
glGenerateMipmap(GL_TEXTURE_2D);
drawFullScreenQuad();
// Render the result to full screen.
glBindFramebuffer(GL_FRAMEBUFFER, drawFrameBuffer);
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE0);
ResourceManager::GetShader("Screen").Use();
glBindTexture(GL_TEXTURE_2D, texObj[0]);
glGenerateMipmap(GL_TEXTURE_2D);
drawFullScreenQuad();
ResourceManager::GetShader("BasicShader").Use();
这些是着色器。
#version 430 core
layout (location = 0) in vec2 aPos;
out vec2 pos;
void main()
{
pos = aPos;
gl_Position = vec4(aPos, 0.0 , 1.0);
}
////////////////////////////////////////// //////////////////////////////////////////////// /////////
#version 330 core
out vec4 FragColor;
in vec2 pos;
// texture sampler
uniform sampler2D u_texture;
uniform vec2 u_textureSize;
uniform float u_sigma;
uniform float u_radius;
uniform vec2 u_dir;
float CalcGauss( float x, float sigma)
{
if( sigma <= 0.0 )
return 0.0;
return exp( -(x * x) / ( 2.0 * sigma)) / ( 2.0 * 3.14157 * sigma);
}
void main()
{
vec2 texC = pos.st * 0.5 + 0.5;
vec4 texCol = texture2D( u_texture, texC );
vec4 gaussCol = vec4( texCol.rgb, 1.0 );
vec2 step = u_dir / u_textureSize;
float weight;
for ( int i = 1; i <= 16; ++ i )
{
weight = CalcGauss( float(i) / 16.0, u_sigma * 0.5 );
if ( weight < 1.0/255.0 )
break;
texCol = texture2D( u_texture, texC + u_radius * step * float(i) );
gaussCol += vec4( texCol.rgb * weight, weight );
texCol = texture2D( u_texture, texC - u_radius * step * float(i) );
gaussCol += vec4( texCol.rgb * weight, weight );
}
gaussCol.rgb = clamp( gaussCol.rgb / gaussCol.w, 0.0, 1.0 );
FragColor = vec4( gaussCol.rgb , 1.0 );
}
当 u_radius 和 u_sigma 的值为 1 时,模糊是平滑的。
当 u_sigma 为 10 且 u_radius 为 30 时,模糊看起来像这样。
由于该示例使用的是 webgl,而我使用的是 Opengl,结果会有所不同吗?
Rabbid76 给定值后的新图像。
在着色器的实现中,sigma 的值必须在 [0.0, 1.0] 范围内。 半径 30 似乎太大了。从 u_sigma = 0.5
和 u_radius = 10
.
开始
着色器效果看起来还是不对,因为alpha通道的计算是错误的。
您已经从 WebGL. WebGL by default uses premultiplied alpha, but your desktop application does not. See Straight versus premultiplied.
复制了着色器
跳过颜色通道的加权和除以 alpha 通道的加权和:
gaussCol.rgb = clamp( gaussCol.rgb / gaussCol.w, 0.0, 1.0 );
gaussCol.rgb = clamp(gaussCol.rgb, 0.0, 1.0);
我正在按照以下着色器创建模糊效果。
OpenGL es 2.0 Gaussian blur on triangle
首先我生成帧缓冲区。
glGenTextures(2, texObj);
glGenFramebuffers(2, fbObj);
glActiveTexture(GL_TEXTURE0);
for (int i = 0; i < 2; i++)
{
glBindTexture(GL_TEXTURE_2D, texObj[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1920, 1080, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glGenerateMipmap(GL_TEXTURE_2D);
glBindFramebuffer(GL_FRAMEBUFFER, fbObj[i]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texObj[i], 0);
GLuint renderbuffer;
glGenRenderbuffers(1, &renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 1920, 1080);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
然后我按照这些步骤。
// first create a image of the scene
GLint drawFrameBuffer;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &drawFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, fbObj[0]);
ResourceManager::GetShader("BasicShader").Use();
//ResourceManager::GetShader("BasicShader").SetInteger("UseColorMap", false);
glDisable(GL_DEPTH_TEST);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT );
geom->draw();
// Set the Blur in X direction
glBindFramebuffer(GL_FRAMEBUFFER, fbObj[1]);
ResourceManager::GetShader("shaderTest").Use();
// Set the blur shader properties
ResourceManager::GetShader("shaderTest").SetFloat("u_sigma", intensity);
ResourceManager::GetShader("shaderTest").SetFloat("u_radius", blur);
ResourceManager::GetShader("shaderTest").SetVector2f("u_dir", glm::vec2(1.0, 0.0));
ResourceManager::GetShader("shaderTest").SetVector2f("u_textureSize", glm::vec2(1920.0, 1080.0));
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texObj[0]);
glGenerateMipmap(GL_TEXTURE_2D);
drawFullScreenQuad();
// Set the Blur in Y direction
glBindFramebuffer(GL_FRAMEBUFFER, fbObj[0]);
ResourceManager::GetShader("shaderTest").Use();
// Set the blur shader properties
ResourceManager::GetShader("shaderTest").SetFloat("u_sigma", intensity);
ResourceManager::GetShader("shaderTest").SetFloat("u_radius", blur);
ResourceManager::GetShader("shaderTest").SetVector2f("u_dir", glm::vec2(0.0, 1.0));
ResourceManager::GetShader("shaderTest").SetVector2f("u_textureSize", glm::vec2(1920.0, 1080.0));
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texObj[1]);
glGenerateMipmap(GL_TEXTURE_2D);
drawFullScreenQuad();
// Render the result to full screen.
glBindFramebuffer(GL_FRAMEBUFFER, drawFrameBuffer);
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE0);
ResourceManager::GetShader("Screen").Use();
glBindTexture(GL_TEXTURE_2D, texObj[0]);
glGenerateMipmap(GL_TEXTURE_2D);
drawFullScreenQuad();
ResourceManager::GetShader("BasicShader").Use();
这些是着色器。
#version 430 core
layout (location = 0) in vec2 aPos;
out vec2 pos;
void main()
{
pos = aPos;
gl_Position = vec4(aPos, 0.0 , 1.0);
}
////////////////////////////////////////// //////////////////////////////////////////////// /////////
#version 330 core
out vec4 FragColor;
in vec2 pos;
// texture sampler
uniform sampler2D u_texture;
uniform vec2 u_textureSize;
uniform float u_sigma;
uniform float u_radius;
uniform vec2 u_dir;
float CalcGauss( float x, float sigma)
{
if( sigma <= 0.0 )
return 0.0;
return exp( -(x * x) / ( 2.0 * sigma)) / ( 2.0 * 3.14157 * sigma);
}
void main()
{
vec2 texC = pos.st * 0.5 + 0.5;
vec4 texCol = texture2D( u_texture, texC );
vec4 gaussCol = vec4( texCol.rgb, 1.0 );
vec2 step = u_dir / u_textureSize;
float weight;
for ( int i = 1; i <= 16; ++ i )
{
weight = CalcGauss( float(i) / 16.0, u_sigma * 0.5 );
if ( weight < 1.0/255.0 )
break;
texCol = texture2D( u_texture, texC + u_radius * step * float(i) );
gaussCol += vec4( texCol.rgb * weight, weight );
texCol = texture2D( u_texture, texC - u_radius * step * float(i) );
gaussCol += vec4( texCol.rgb * weight, weight );
}
gaussCol.rgb = clamp( gaussCol.rgb / gaussCol.w, 0.0, 1.0 );
FragColor = vec4( gaussCol.rgb , 1.0 );
}
当 u_radius 和 u_sigma 的值为 1 时,模糊是平滑的。
当 u_sigma 为 10 且 u_radius 为 30 时,模糊看起来像这样。
由于该示例使用的是 webgl,而我使用的是 Opengl,结果会有所不同吗?
Rabbid76 给定值后的新图像。
在着色器的实现中,sigma 的值必须在 [0.0, 1.0] 范围内。 半径 30 似乎太大了。从 u_sigma = 0.5
和 u_radius = 10
.
着色器效果看起来还是不对,因为alpha通道的计算是错误的。
您已经从 WebGL. WebGL by default uses premultiplied alpha, but your desktop application does not. See Straight versus premultiplied.
复制了着色器
跳过颜色通道的加权和除以 alpha 通道的加权和:
gaussCol.rgb = clamp( gaussCol.rgb / gaussCol.w, 0.0, 1.0 );
gaussCol.rgb = clamp(gaussCol.rgb, 0.0, 1.0);