打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
GLSL Image Processing | r3dux.org
I had a play around doing some image processing earlier using GLSL shaders from chapter 17 of theOpenGL SuperBible (4th Edition, I’m not seeing them in the 5th) and the results aren’t too shabby. I’m rendering the skybox plus torus’ with ambient/diffuse/specular lighting and cubemap texture lookup to a FBO, then rendering a full-screen quad textured with the result of the previous pass, and it’s this full-screen quad that I’m processing to get these effects.Pretty easy & kinda fun – next up depth of field
Image Processing Vertex Shader
#version 330 // Read-only uniform values shared across all vertexesuniform mat4 mvpMatrix; // Incoming per-vertex valuesin vec4 vVertex;in vec2 vTexCoord0; // Outgoing interpolated valuessmooth out vec2 vTex; void main(void){ // Pass through the texture coordinates vTex = vTexCoord0;  // Transform the geometry gl_Position = mvpMatrix * vVertex;}
Image Processing Fragment Shader
#version 330 uniform sampler2D quadTexture;uniform int filterNumber;uniform vec2 tcOffset[25]; // Texture coordinate offsets in vec2 vTex; out vec4 vFragColour; void main(void){ // Standard if (filterNumber == 0) { vFragColour = texture2D(quadTexture, vTex); }  // Greyscale if (filterNumber == 1) { // Convert to greyscale using NTSC weightings float grey = dot(texture2D(quadTexture, vTex).rgb, vec3(0.299, 0.587, 0.114));  vFragColour = vec4(grey, grey, grey, 1.0); }  // Sepia tone if (filterNumber == 2) { // Convert to greyscale using NTSC weightings float grey = dot(texture2D(quadTexture, vTex).rgb, vec3(0.299, 0.587, 0.114));  // Play with these rgb weightings to get different tones. // (As long as all rgb weightings add up to 1.0 you won't lighten or darken the image) vFragColour = vec4(grey * vec3(1.2, 1.0, 0.8), 1.0); }  // Negative if (filterNumber == 3) { vec4 texMapColour = texture2D(quadTexture, vTex);  vFragColour = vec4(1.0 - texMapColour.rgb, 1.0); }  // Blur (gaussian) if (filterNumber == 4) { vec4 sample[25];  for (int i = 0; i < 25; i++) { // Sample a grid around and including our texel sample[i] = texture(quadTexture, vTex + tcOffset[i]); }  // Gaussian weighting: // 1 4 7 4 1 // 4 16 26 16 4 // 7 26 41 26 7 / 273 (i.e. divide by total of weightings) // 4 16 26 16 4 // 1 4 7 4 1  vFragColour = ( (1.0 * (sample[0] + sample[4] + sample[20] + sample[24])) + (4.0 * (sample[1] + sample[3] + sample[5] + sample[9] + sample[15] + sample[19] + sample[21] + sample[23])) + (7.0 * (sample[2] + sample[10] + sample[14] + sample[22])) + (16.0 * (sample[6] + sample[8] + sample[16] + sample[18])) + (26.0 * (sample[7] + sample[11] + sample[13] + sample[17])) + (41.0 * sample[12]) ) / 273.0;  }  // Blur (median filter) if (filterNumber == 5) { vFragColour = vec4(0.0);  for (int i = 0; i < 25; i++) { // Sample a grid around and including our texel vFragColour += texture(quadTexture, vTex + tcOffset[i]); }  vFragColour /= 25; }  // Sharpen if (filterNumber == 6) { vec4 sample[25];  for (int i = 0; i < 25; i++) { // Sample a grid around and including our texel sample[i] = texture(quadTexture, vTex + tcOffset[i]); }  // Sharpen weighting: // -1 -1 -1 -1 -1 // -1 -1 -1 -1 -1 // -1 -1 25 -1 -1 // -1 -1 -1 -1 -1 // -1 -1 -1 -1 -1  vFragColour = 25.0 * sample[12];  for (int i = 0; i < 25; i++) { if (i != 12) vFragColour -= sample[i]; } }  // Dilate if (filterNumber == 7) { vec4 sample[25]; vec4 maxValue = vec4(0.0);  for (int i = 0; i < 25; i++) { // Sample a grid around and including our texel sample[i] = texture(quadTexture, vTex + tcOffset[i]);  // Keep the maximum value maxValue = max(sample[i], maxValue); }  vFragColour = maxValue; }  // Erode if (filterNumber == 8) { vec4 sample[25]; vec4 minValue = vec4(1.0);  for (int i = 0; i < 25; i++) { // Sample a grid around and including our texel sample[i] = texture(quadTexture, vTex + tcOffset[i]);  // Keep the minimum value minValue = min(sample[i], minValue); }  vFragColour = minValue; }  // Laplacian Edge Detection (very, very similar to sharpen filter - check it out!) if (filterNumber == 9) { vec4 sample[25];  for (int i = 0; i < 25; i++) { // Sample a grid around and including our texel sample[i] = texture(quadTexture, vTex + tcOffset[i]); }  // Laplacian weighting: // -1 -1 -1 -1 -1 // -1 -1 -1 -1 -1 // -1 -1 24 -1 -1 // -1 -1 -1 -1 -1 // -1 -1 -1 -1 -1  vFragColour = 24.0 * sample[12];  for (int i = 0; i < 25; i++) { if (i != 12) vFragColour -= sample[i]; } }}
The only other bit of code worth mentioning is the generation of the texture coordinate offsets, which is accomplished with the following C++ code (yes, it’s kinda ugly – no, I didn’t write it – yes, it works):
// Set up texture sampling offset storageconst GLint tcOffsetColumns = 5;const GLint tcOffsetRows = 5;GLfloat texCoordOffsets[tcOffsetColumns * tcOffsetRows * 2]; // Calculate texture coordinate offsets for kernel convolution effectsvoid genTexCoordOffsets(GLuint width, GLuint height, GLfloat step = 1.0f) // Note: Change this step value to increase the number of pixels we sample across...{ // Note: You can multiply the step to displace the samples further. Do this with diff values horiz and vert and you have directional blur of a sort... float xInc = step / (GLfloat)(windowWidth); float yInc = step / (GLfloat)(windowHeight);  for (int i = 0; i < tcOffsetColumns; i++) { for (int j = 0; j < tcOffsetRows; j++) { texCoordOffsets[(((i*5)+j)*2)+0] = (-2.0f * xInc) + ((GLfloat)i * xInc); texCoordOffsets[(((i*5)+j)*2)+1] = (-2.0f * yInc) + ((GLfloat)j * yInc); } }}
You can then draw your full-screen quad something like this:
// *** Draw the original geometry to a FBO here *** // Now draw our full-screen quadprojectionMatrix.PushMatrix();  projectionMatrix.LoadIdentity(); projectionMatrix.LoadMatrix(orthoMatrix);  modelViewMatrix.PushMatrix();  modelViewMatrix.LoadIdentity();  glDisable(GL_DEPTH_TEST);  glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, fboTexture); // Select the texture in our framebuffer  glUseProgram(r3dTextureProgram); glUniformMatrix4fv(locTexMVPMatrix, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix()); glUniform1i(locTexTextureMap, 0); glUniform1i(locTexFilterNumber, filterNumber); glUniform2fv(locTexTCOffsets, 25, texCoordOffsets); // Pass in 25 vec2s in our texture coordinate offset array  screenQuad.Draw();  glEnable(GL_DEPTH_TEST);  modelViewMatrix.PopMatrix(); projectionMatrix.PopMatrix();
Job’s a good ‘un.
No related posts.
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
OpenGL学习脚印: 纹理映射基础篇
Мобильный LiveInternet Texture | гилана
opengl 使用 texture2d 关键步骤
关于Shader着色器的使用(这个是GL通用的,用什么开发设置都一样) | Java与Ripple怎么玩?
Moai SDK 1.4p0 Released | Blog
Triplanar Mapping | Martin Palko
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服