Shader blending ( Get previous pixel )

Started by
15 comments, last by haegarr 10 years, 1 month ago

Hello.

I want to control the way opengl blend transparent surfaces.

Vertex shader


#version 120
varying vec2 texcoord;
 
void main()
{
    gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
    texcoord = gl_MultiTexCoord0.xy;
}

Fragment shader


#version 120
uniform sampler2D img;
varying vec2 texcoord;

void main() 
{
	vec4 tex = texture2D ( img, texcoord );
	gl_FragColor = tex;
}

Those are my basic texture rendering codes.
What i need is to get somehow the pixel what is behind that thing what is correctly in shader.

It would be so good to have control over it.
Also readed the basics of shaders, did not get any ideas how to do it.

Reading on internet, they said that opengl offers some blend functions. Already tried them.
Its nothing wrong with them but the way they act doesnt pleasure me. I really need to controll how pixels are blended.
Is there someone wise who have solution to my problem?
Thanks!

Advertisement

http://wiki.delphigl.com/index.php/glBlendFunc

You need to set "GL_ONE" for dfactor, and depending on how you want to apply the new pixel it will probably also bee "GL_ONE" for sfactor (the first param).

That is a really good source yet not exactly what i wanted.
Il give you code example:


#version 120
uniform sampler2D img;
varying vec2 texcoord;

void main() 
{
	vec4 tex = texture2D ( img, texcoord );
        vec4 behindpixel = ?
	gl_FragColor = (behindpixel * 0.5 ) + (tex * 0.5 );
}

In theory i can blend pixels without using glBlendFunc.
Getting the that pixel what is behind will give me so much control. I can make so many new nice blending types.

If i can somehow know where the pixel will be in screen ( the pixel origin in screen ( x, y coords ) )
Then i can store them and use them. Also the order will not matter ( if the back pixel is rendered first or the front one )
I can figure it out somehow.

AFAIK fragment shaders cannot read framebuffers directly. However, you can use an FBO with a texture attached as color target in a first pass, and bind those texture for sampling in a second pass. That should give you the access you need.

Just for curiosity, what are those kinds of blending you are not able to create with the standard blend-functions?

Nope, that can't be done. You can't read and write to the same texture due to how desktop GPUs work. It can however be done on tile based mobile GPUs.

AFAIK fragment shaders cannot read framebuffers directly. However, you can use an FBO with a texture attached as color target in a first pass, and bind those texture for sampling in a second pass. That should give you the access you need.

I'm familiar with that way and im afraid that it will be ineffective.
Not sure how fast the function is but still believe that there are some other ways, there must be something.

Just for curiosity, what are those kinds of blending you are not able to create with the standard blend-functions?

For example one is that if you are looking out of the window, pixels will be different color but the window texture will be white for example.

You can't read from the same target that you currently render to. In order to make what you want to work, you would need to use two rendertargets, and ping-pong between them. First write to #1, and in the next pass you set #1 as uniform sampler and write to #2, and so on.

However, are you sure you really need this? What you wrote here:


gl_FragColor = (behindpixel * 0.5 ) + (tex * 0.5 );

can be realised using glBlendFunc(GL_SRC_ALPHA, GL_ONE_MIN_SRC_ALPHA) and outputting


void main() 
{
	vec3 tex = texture2D ( img, texcoord ).rgb;
	gl_FragColor = vec4(tex, 0.5f);
}

I belive that for effects that only need the underlying pixel of the current operation and only want to modify that value in a way you posted, then glBlendFunc is all you need. Really look closely at the page I posted you and look at the available options, there is almost everything you could need. Otherwise, you can take my first suggestion.

EDIT:

I'm familiar with that way and im afraid that it will be ineffective.
Not sure how fast the function is but still believe that there are some other ways, there must be something.

Its as fast as switching input textures can be, FBOs are standard and used so widley for advanced graphical effects that the overhead is neglectible. Handling the swapping can be a little awkward to handle, thats all about it.

For example one is that if you are looking out of the window, pixels will be different color but the window texture will be white for example.

This looks like a standard-way for alpha blending, I even more belive now that you will be fine if you just use glBlendFunc correctly.

Untitled-1.png

That thing what make the wall yellow.
The color depens on that texture what is right now in the fragment shader.
As far, you guys have been really helpful, im glad you want to help me. Thank you so much!
Anyway, i'm really beginner, yet dont know the ways and functions.
I've tried all options of glBlendfunc yet did not succeed in creating the effect you see up, right in the corner.


I've tried all options of glBlendfunc yet did not succeed in creating the effect you see up, right in the corner.

Did you call glEnable(GL_BLEND) anywhere? This is definately doable with standard blending, people would have gotten insane if they required to pingpong rendertargets in order for simple glass effects.

The one ohter problem is:

2014-03-09_193421.png


// vertex shader

#version 120
varying vec2 texcoord;
 
void main()
{
    gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
    texcoord = gl_MultiTexCoord0.xy;
}

#version 120
uniform sampler2D img;
varying vec2 texcoord;

void main() 
{
	vec4 tex = texture2D ( img, texcoord );
	if( tex.r < 0.3 && tex.g < 0.3 && tex.b > 0.6 ) tex *= 0.0;
	else tex.a = 1.0;
	gl_FragColor = tex;
}


		glUniform1i(glGetUniformLocation(program,"img"),0);
		glBindTexture(GL_TEXTURE_2D, triangles[a].texture);
		glActiveTexture(GL_TEXTURE0);
		if(triangles[a].texture == 1) // The first texture is not supposed to be transparent
		{
			glDisable(GL_BLEND);
		}
		else
		{
			glEnable (GL_BLEND);
			glBlendFunc(GL_ONE, GL_ONE);
		}

	
		glBegin(GL_TRIANGLES);
		for( c = 0; c < 3; c++ )
		{
			glTexCoord2d(triangles[a].uvmap[c][0], -triangles[a].uvmap[c][1]);
			glNormal3d(triangles[a].normals[c][0], triangles[a].normals[c][1], triangles[a].normals[c][2]);
			glVertex3d(-triangles[a].vertex[c][1], triangles[a].vertex[c][2],triangles[a].vertex[c][0]);
		}
		glEnd();

The one reason why i really wanted to get that pixel what is behind.
Tried all those blending flags what are in the page you gave.

This topic is closed to new replies.

Advertisement