GLSL 图像处理

xiaoxiao2021-02-28  47

文章转载于:https://r3dux.org/2011/06/glsl-image-processing/

Image Processing Vertex Shader

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #version 330   // Read-only uniform values shared across all vertexes uniform mat4 mvpMatrix ;   // Incoming per-vertex values in vec4 vVertex ; in vec2 vTexCoord0 ;   // Outgoing interpolated values smooth 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 (mean 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]); } // Divide by the number of samples to get our mean 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]; } } } 1 2 3 4 5 6 7 8 9 10 11 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 #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 (mean 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 ] ) ; }   // Divide by the number of samples to get our mean 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):

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 // Set up texture sampling offset storage const GLint tcOffsetColumns = 5 ; const GLint tcOffsetRows      = 5 ; GLfloat texCoordOffsets [ tcOffsetColumns * tcOffsetRows * 2 ] ;   // Calculate texture coordinate offsets for kernel convolution effects void 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 quad projectionMatrix.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(); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 // *** Draw the original geometry to a FBO here ***   // Now draw our full-screen quad projectionMatrix . 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.

转载请注明原文地址: https://www.6miu.com/read-81970.html

最新回复(0)