Pixel Corruption From Neighboring Pixels with gl_FragCoord

I’m trying to create a color filter array demosaicing fragment shader for raw capture from a color camera with color bayer filter. In order to properly decode the image, I require acces to clean neighboring texels without any averaging from neighboring texels. Since I’m not using TEXTURE_RECTANGLE textures, I’m a little nervous. I also have to know the exact x/y offset of the main pixel in the shader.

Here is a partial simple shader that implements the RGB values from a red pixel of the color bayer filter array:

 #extension GL_EXT_gpu_shader4 : enable [SIZE=2]//Required For Integer Modulus Operation (%)

uniform sampler2D BayerCaptureSampler;
uniform [/SIZE][SIZE=2]float[/SIZE] captureImageWidth;
uniform [SIZE=2]float[/SIZE] captureImageHeight;

[SIZE=2]void[/SIZE] main([SIZE=2]void[/SIZE])
{
[SIZE=2]float[/SIZE] step_w;
[SIZE=2]float[/SIZE] step_h;
[SIZE=2]float[/SIZE] fragOffsetFloatX;
[SIZE=2]float[/SIZE] fragOffsetFloatY
[SIZE=2]int[/SIZE] fragOffsetIntX;
[SIZE=2]int[/SIZE] fragOffsetIntY;
vec2 redOffset[4];
vec2 greenOffset[4];
vec2 blueOffset[4];
[SIZE=2]int[/SIZE] evenOddX;
[SIZE=2]int[/SIZE] evenOddY;
[SIZE=2]float[/SIZE] Sum;
 
[SIZE=2]//Example: ASSUME ORIGINAL SOURCE BUFFER OF 2048 x 1536

[/SIZE][SIZE=2]//Calculate Single Texel Normalized Offset From Original capture buffer resolution
[/SIZE]step_w = 1.0/captureImageWidth;           [SIZE=2]//Should return 1.0/2048.0 = 0.00048828125
[/SIZE]step_h = 1.0/captureImageHeigh;            [SIZE=2]//Should return 1.0/1536.0 = 0.00065104166

[/SIZE][SIZE=2]//Retrieve the Current Texel Offset (In Host Buffer Integer Coordinates From Corner (0,0)
[/SIZE]fragOffsetIntX = gl_FragCoord.x;             [SIZE=2]//Should Return Integer Value 0 to 2047
[/SIZE]fragOffsetIntY = gl_FragCoord.y;             [SIZE=2]//Should Return Integer Value 0 to 1535

[/SIZE][SIZE=2]//Determine if this is an even or odd pixel on horizontal and vertical offsets from bottom right corner texel
[/SIZE]evenOddX = fragOffsetIntX%2;               [SIZE=2]//Should Return 0 for even, or 1 for odd
[/SIZE]evenOddY = fagOffsetIntY%2;                [SIZE=2]//Should Return 0 for even, or 1 for odd
 
[/SIZE][SIZE=2]//*************************Sample Code For A Red Pixel Decocing******************//
[/SIZE][SIZE=2]if[/SIZE](evenOddX==0) [SIZE=2]//Width Offset = Even Texel
[/SIZE]{
[SIZE=2]if[/SIZE] {evenOddY==0) [SIZE=2]//Height Offset = Even Texel
[/SIZE]{
[SIZE=2]//Retrieve Red Texel
[/SIZE]glFragColor.r = texture2D(BayerCaptureSampler,vec(gl_TextCoord[0].st)).r;
[SIZE=2]//Calculate Green Pixel Offsets
[/SIZE][SIZE=2]//THESE NEED TO BE IDENTICAL PIXEL VALUE FROM THE ORIGINAL BUFFER THAT WAS LOADED INTO
[/SIZE][SIZE=2]//TEXTURE WIHTOUT ANY MIXTURE OR AVERAGING OF PIXELS ONCE INSIDE THE TEXTURE
[/SIZE] greenOffset[0] = vec2(step_w,step_h);
  greenOffset[1] = vec2(0.0,step_h);
  greenOffset[2] = vec2(-step_w,0.0);
  greenOffset[3] = vec2(0.0,-step_h);
[SIZE=2]//Retrieve and Average Neighboring Green Pixels
[/SIZE] sum = 0.0;
  sum += texture2D(BayerCaptureSampler,vec2(gl_TexCoord[0].st + greenOffset[0];
  sum += texture2D(BayerCaptureSampler,vec2(gl_TexCoord[0].st + greenOffset[1];
  sum += texture2D(BayerCaptureSampler,vec2(gl_TexCoord[0].st + greenOffset[2];
  sum += texture2D(BayerCaptureSampler,vec2(gl_TexCoord[0].st + greenOffset[3];
[SIZE=2]//Assign Final Calculated Green Texel
[/SIZE]glFragColor.g = sum/4.0;
[SIZE=2]//Calculate Blue Pixel Offsets
[/SIZE][SIZE=2]//THESE NEED TO BE IDENTICAL PIXEL VALUE AS DESCRIBED ABOVE
[/SIZE] greenOffset[0] = vec2(step_w,step_h);
  greenOffset[1] = vec2(-step_w,step_h);
  greenOffset[2] = vec2(step_w,-step_h);
  greenOffset[3] = vec2(-step_w,-step_h);
[SIZE=2]//Retrieve and Average Neighboring Blue Pixels
[/SIZE] sum = 0.0;
  sum += texture2D(BayerCaptureSampler,vec2(gl_TexCoord[0].st + blueOffset[0];
  sum += texture2D(BayerCaptureSampler,vec2(gl_TexCoord[0].st + blueOffset[1];
  sum += texture2D(BayerCaptureSampler,vec2(gl_TexCoord[0].st + blueOffset[2];
  sum += texture2D(BayerCaptureSampler,vec2(gl_TexCoord[0].st + blueOffset[3];
[SIZE=2]//Assign Final Calculated Blue Texel
[/SIZE]glFragColor.b = sum/4.0;
   }
}
[SIZE=2]//Assign 1 to Alpha Channel
[/SIZE]glFragColor.a = 1.0
}

My questions are:

  1. How do I implement the layout qualifier “pixel_center_integer” with this version of OpenGL? I need the offsets to be the actual integer values, not with 0.5 offsets.

  2. Will my greenOffset[] and blueOffset[] texel offsets return me the original buffer pixels without any sub-pixel neighbor averaging? The color demosaicing will not work if the pixel values are in any way mixed.

Thanks for your help!

[QUOTE=Rennie Johnson;1243170]1) How do I implement the layout qualifier “pixel_center_integer” with this version of OpenGL? I need the offsets to be the actual integer values, not with 0.5 offsets.

  1. Will my greenOffset[] and blueOffset[] texel offsets return me the original buffer pixels without any sub-pixel neighbor averaging? The color demosaicing will not work if the pixel values are in any way mixed.[/QUOTE]

Often a simpler way to deal with this is to just use glFragCoord and texelFetch.

The integer offset of the current pixel (in window coordinates):

[SIZE=-1]ivec2 tcoord = ivec2( gl_FragCoord.xy ); // This is in (0,0) … (xres,yres)

[/SIZE]
then:

texelFetch( tex, tcoord, 0 ).rgb;

If you’re reading from a multisample texture, you can just plug the sample index in place of the third argument.

Also with texelFetch, there’s explicitly no filtering, so you don’t have to worry about that creeping in.

Hey, thanks Dark Photon!!

Do I need to declare a higher version of OpenGL or an extension to use “texelFetch”?

If so, could you type out the line for me?

Also, since you still used glFragCoord(), don’t I still have to deal with the 0.5 pixel offset?

Thanks again.

I was just reading up on textlFetch. How do I specify the offsets for my neighboring pixel access?

Can I use integer offsets, i.e.:

ivec2 offset;
offset = ivec2(1,-1);
ivec2 tcoord = ivec2( gl_FragCoord.xy );
texelFetch(TruesenseCaptureSampler, (tcoord + offset), 0 ).r;

or do I have to use Normalized offsets, like in my code example;

Again, do I have to implement the layout qualifier “pixel_center_integer” in this example, and what is the correct syntax to do that?

Thanks for your help.

p.s. Can someone explain how to post code on a reply? I can’t find the box to do that.

[QUOTE=Rennie Johnson;1243178]Hey, thanks Dark Photon!!

Do I need to declare a higher version of OpenGL or an extension to use “texelFetch”?[/QUOTE]

Depends on which version you are declaring now. May already be supported. Heck, it’s been in GLSL since v1.3. So anything greater than or equal to #version 130 should pull it in.

Alternatively, you’ll probably just get it with the #extension GL_EXT_gpu_shader4 : enable you’ve got in there now, though you’ll likely need to call texelFetch2D() instead of texelFetch() (for 2D textures anyway). GLSL 1.3 did away with all the sampler type suffixes from the names of the sampling functions, eliminating a lot of needless function list bloat.

The issue with declaring 1.3 right now if you’re using 1.2 (the default IIRC) is that the built-in identifiers (fixed-function shader shims) go away. Which may or may not be more code rework than you want to bite off right now.

Also, since you still used glFragCoord(), don’t I still have to deal with the 0.5 pixel offset?

I cast to an int (ivec2), which (just as in C/C++) whacks the fractional portion.

Yes! You’ve got it. That’s one of the nice things about using this for single texel access.

Again, do I have to implement the layout qualifier “pixel_center_integer” in this example, and what is the correct syntax to do that?

No idea what you’re talking about here. This does not occur in your code. If you want no interpolation on interpolators, declare them flat. You have to do this when passing integral values anyway.

p.s. Can someone explain how to post code on a reply? I can’t find the box to do that.

Surround your code with [noparse]

 ... 

[/noparse] tags.

OK, I’ll try all this and report back.

Seems a bit rude to whack fractions, but I guess I’ve got no choice.

Thanks again to Dark Photon.

p.s. I’m not sure what the origin of your profile photo is (looks like a cross between Darth Vader and a Dalek, but you might be interested to know I that attended the first showing of STAR WARS (1977) in San Jose. It was the greatest experience (female company excluded) of my life!

Ssssspace ballssss !!!

Dear Dark Photon:

Everything works great! Just the way you told me to do. However, I’ve got a new problem:

Apparently, moving up to OpenGL 1.3 (Wow, I’m state-of-the-art now!) has obsoleted my drawing code which…NO LONGER WORKS!!!



[SIZE=2]void[/SIZE] DiGlConfig_RJ::UpdateScannerFrameBufferColorBayer()
{
wglMakeCurrent(m_deviceContextHandle_01,m_renderContextHandle);
SetScannerShader(SCANNER_SHADER_MASTER_COLOR_BAYER);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fboObject);
glUseProgramObjectARB(m_shaderGl->m_scannerColorBayerProgram);
glViewport(0-(m_maxTextureSize-m_FramebufferWidth)/2,
0-(m_maxTextureSize-m_FramebufferHeight)/2,m_maxTextureSize,m_maxTextureSize);
 
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.0,0.0,0.0,1.0);
glClear(GL_COLOR_BUFFER_BIT);
 
glPushMatrix();
glTranslatef(m_offsetX,m_offsetY,0.0);
glRotatef(m_rotation,0.0,0.0,1.0);
glScalef(m_scaleX*m_geometryFlopFactor,m_scaleY*m_geometryInvertFactor*m_fboInvertFactor,0.0);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE,GL_ZERO);
glBegin(GL_QUADS);
glTexCoord2f(0.0,0.0); 
glVertex2f(-1.0,-1.0);
glTexCoord2f(1.0,0.0); 
glVertex2f( 1.0,-1.0);
glTexCoord2f(1.0,1.0); 
glVertex2f( 1.0, 1.0);
glTexCoord2f(0.0,1.0); 
glVertex2f(-1.0, 1.0);
glEnd();
glDisable(GL_BLEND);
glPopMatrix();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
glUseProgramObjectARB(0);
}

So, none of the scaling works, and the image isn’t drawn in the correct offset to the texture I’m rendering to (the texture is larger), so that means that the glViewport() command isn’t working, either.

I suppose you’re going to tell me I have to do all of this in a vertex shader now.

HELP!!!

Living in the past,
Rennie

p.s to Cy Bo Rg:I met Mel Brooks at Metrocolor lab in 1986 when he was color timing the negative on SPACEBALLS.

Hmmmm… I think this may be my fault… Looking into it. News at 11:00

[QUOTE=Rennie Johnson;1243214]Everything works great! Just the way you told me to do. However, I’ve got a new problem:

Apparently, moving up to OpenGL 1.3 (Wow, I’m state-of-the-art now!) has obsoleted my drawing code which…NO LONGER WORKS!!! [/quote]

Yeah, that’s what I meant by “the built-in identifiers go away” in GLSL 1.3. Which is why I suggested:

Alternatively, you’ll probably just get it with the #extension GL_EXT_gpu_shader4 : enable you’ve got in there now, though you’ll likely need to call texelFetch2D() instead of texelFetch() (for 2D textures anyway). GLSL 1.3 did away with all the sampler type suffixes from the names of the sampling functions, eliminating a lot of needless function list bloat.

The issue with declaring 1.3 right now if you’re using 1.2 (the default IIRC) is that the built-in identifiers (fixed-function shader shims) go away. Which may or may not be more code rework than you want to bite off right now.

p.s to Cy Bo Rg:I met Mel Brooks at Metrocolor lab in 1986 when he was color timing the negative on SPACEBALLS.

Ah yes! Der Schwartz lives on!

No, it’s not what you think. It’s much, much worse!

Yogurt! Yogurt! I hate Yogurt! Even with Strawberries.

Ah, buckle this! LUDICROUS SPEED! GO!

Thanks again. texelFetch2D() is very happy, but I still have the transformation problem.

Is it possible that by using textureFetch2D() I have circumvented the transformation by not using glFragCoord[0]?

This is getty verrrry weird! It seems if I declare OpenGL 1.3 in one shader, it screws up other shaders, AND I’m not even getting paid for this project. So much for having your own business!

Even after I solve this crap, I can see there will be a new issue:

In order for the Fragment shader I’ve just created (with Dark Photon’s help) to work properly, there cannot be any geometric transformation applied in advance. I have to work directly on the original host buffer pixels.

Soooo, is there an way to apply a scale/translate/rotate operation to the target rFBO render texture after the Fragment shader has completed it’s work.

I don’t ever attach multiple shaders, but can you attach a vertex shader after a Fragment shader and transform the output of the Fragment shader.

May the Farce be with you!

“You’ll laugh. You’ll cry. YOU’LL KISS THREE BUCKS GOODBYE.”

Well, I’ve discovered that I can attach a Vertex Shader after the Fragment Shader, but all it does it manipulate a black matte over a non-moving image:

Just a test shader:


void main(void)
{
float offsetX = 0.0;
float offsetY = 0.0;
float xScale = 2.0;
float yScale = 1.0;
float rotation = 0.0;
 
vec4 scale;
vec4 offset;
float rotationRadians = rotation  -0.0174532925 ;
offset.x = offsetX;
offset.y = offsetY;
offset.z = 0.0;
offset.w = 0.0;
scale.x = xScale;
scale.y = yScale;
scale.z = 1.0;
scale.w = 1.0;
mat3 rotationMatrix = mat3( vec3( cos(rotationRadians), sin(rotationRadians), 0.0), vec3(-sin(rotationRadians), cos(rotationRadians), 0.0), vec3( 0.0, 0.0, 1.0) );
gl_Position = gl_ModelViewProjectionMatrix  gl_Vertex;
gl_Position += offset;
gl_Position *= scale;
gl_Position.xyz *= rotationMatrix;
}


How can I get the post-fragment vertex shader to scale the image? Or am I taking a stupid approach and should go to bed?

p.s. I just figured out that your photo is from SPACEBALLS. I catch on fast, don’t I???

Well, I’ve discovered that I can attach a Vertex Shader after the Fragment Shader

That’s not possible. Not in the way you seem to think it means, at least.

The order you call glAttachShader is irrelevant; the vertex shader happens first. It always happens first. You can attach two vertex shader objects to a program at the same time and link them; if both of them have a main function, the linker will complain, but otherwise, the vertex shader will still happen first.

So it’s not clear what it is that you actually did. Show us the code you use to “attach a Vertex Shader after the Fragment Shader”.

Well that explains the behavior. No need to post the code.Can you answer me:1) Is there a way to apply translate/rotate/scale transformations from the output of a fragent shader? I’m just doing a texture accessed render to FBO texture. Would that require two separate shader operations?2) If I’m using texelFetch2D() instead of texture2d(), do I lose the effects of glScalef() ,glTranslatef() and glRotatef() in a glBegin(GL_QUADS) drawing routine?If you require code, I’ll try to organize that thoughtfully and post tomorrow.Thanks very much.