Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411432 Posts in 69363 Topics- by 58417 Members - Latest Member: gigig987

April 20, 2024, 05:12:18 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)glBlendFunc parameters for subtractive texture blending [SOLVED]
Pages: [1]
Print
Author Topic: glBlendFunc parameters for subtractive texture blending [SOLVED]  (Read 11512 times)
Tycho Brahe
Level 10
*****

λx.x


View Profile
« on: November 02, 2010, 09:37:58 AM »

HI.

Got a small opengl question to all you opengl wizards out there.

Say I had a large, black opaque texture; what parameters should I use in glBlendFunc so that I can effectively "cut out" parts of it by drawing to it.

I already know how to draw to a texture, and what I'm really looking for (I guess) is a way to set the alpha values of the pixels, possibly using a blend function...

The effect I'm going for should be something like this (excuse the programmer art):


Is this possible using just the blend function? or am I missing something substantial...
« Last Edit: November 03, 2010, 02:15:54 PM by 14113 » Logged
slembcke
Level 3
***



View Profile WWW
« Reply #1 on: November 02, 2010, 09:50:59 AM »

The simplest way to get that effect is to draw the scene normally, then draw a texture with a circular gradient that fades to white in the middle over the top of the scene using multiplicative blending. In which case your blend function would be: glBlendFunc(GL_DST_COLOR, GL_ZERO)

edit: spelling
« Last Edit: November 02, 2010, 12:54:45 PM by slembcke » Logged

Scott - Howling Moon Software Chipmunk Physics Library - A fast and lightweight 2D physics engine.
Glaiel-Gamer
Guest
« Reply #2 on: November 02, 2010, 10:54:22 AM »

right, the effect you're going for is multiply not subtract, but if you want to subtract

glBlendEquationEXT(GL_FUNC_SUBTRACT_EXT)
or glBlendEquation(GL_FUNC_SUBTRACT) in openGL 2.0

changes the blend function to be used [add is default]

still need to set parameters in glBlendFunc though
Logged
Tycho Brahe
Level 10
*****

λx.x


View Profile
« Reply #3 on: November 03, 2010, 12:16:09 PM »

Thanks all!

slembcke: the main reason I wanted to know, is so I can remove more than one circle at a time, and simply removing the alpha channel seemed to be the simplest option.

glaiel: Thanks! I'll try that out as soon as I can.
Logged
Tycho Brahe
Level 10
*****

λx.x


View Profile
« Reply #4 on: November 03, 2010, 12:49:13 PM »

aahhh. It doesnt quite work how I'd like:

It successfully erases the alpha, unfortunately I'm getting this effect when I'm drawing more than one:



Is there some blend function modifier that I should be using or something...

[edit]

oops, almost forgot to say:

this is the code to draw the "lights", onto the texture, the background (which the texture is being drawn onto) is white.
Code:
void draw_light(float x, float y, float rad)
{
   float nx,ny;
   glBegin(GL_TRIANGLE_FAN);
   glColor4f(0,1,0,0);
   glVertex2f(x,y);
   glColor4f(0,0,0,1);
   for (float ang = (2*pi)+(pi/24);ang>=0;ang-=pi/24)
   {
       nx = (rad*sin(ang))+x;
       ny = (rad*cos(ang))+y;
       glVertex2f(nx,ny);
   }
   glEnd();
}

and when Its drawn to the texture:
Code:
 glBlendEquationEXT(GL_FUNC_SUBTRACT_EXT);
 draw_light(256,256,200);
 draw_light(100,100,56);
 glBlendEquationEXT(GL_FUNC_ADD_EXT);

« Last Edit: November 03, 2010, 12:58:17 PM by 14113 » Logged
slembcke
Level 3
***



View Profile WWW
« Reply #5 on: November 03, 2010, 01:19:26 PM »

If you want more than one, it gets a bit more complicated. You need to create a render texture where you add all the "lights" together using glBlendFunc(GL_ONE, GL_ONE). Then you multiply that over the top of your scene using the blending mode from before.

I came up with a solution using the stencil buffer a few years ago because I thought render textures were scary and complicated. Ultimately it was just more complicated and meant I could only use hard cut alpha.
Logged

Scott - Howling Moon Software Chipmunk Physics Library - A fast and lightweight 2D physics engine.
Tycho Brahe
Level 10
*****

λx.x


View Profile
« Reply #6 on: November 03, 2010, 01:29:59 PM »

Hmm, I'm not quite sure I follow, do you mean that you render to a texture, all the lights ( using glBlendFunc(GL_ONE, GL_ONE)) then render that texture using the function before?

also, I'm just wondering how feasible it would be to render a series of white "lights" to an empty, transparent texture (ie, texture rgba all = 0, light main colour rgba = 1) normally (ie glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA )), then invert the colours of the texture, so the unlit texture RGBA = 1, and the lights colour RGBA = 0, and render it. or was that what you were suggesting.
Logged
Tycho Brahe
Level 10
*****

λx.x


View Profile
« Reply #7 on: November 03, 2010, 02:14:14 PM »

Double post again, yay!

I think I've got it working guys;



now, I'm drawing this to the texture for each light:
Code:
void draw_light(float x, float y, float rad)
    {
        float nx,ny;
        glBegin(GL_TRIANGLE_FAN);
        glColor4f(1,1,1,0.8);
        glVertex2f(x,y);
        glColor4f(1,1,1,0);
        for (float ang = (2*pi)+(pi/24);ang>=0;ang-=pi/24)
        {
            nx = (rad*sin(ang))+x;
            ny = (rad*cos(ang))+y;
            glVertex2f(nx,ny);
        }
        glEnd();
    }

with normal alpha, and additive

when it comes to drawing the texture, I use glBlendFunc( GL_SRC_ALPHA, GL_SRC_ALPHA ); to invert the texture and draw it. Problem solved!
Logged
Glaiel-Gamer
Guest
« Reply #8 on: November 03, 2010, 03:03:42 PM »

just render white lights on a black background with a screen blend mode
screen = (ONE, ONE_MINUS_SRC_COLOR)

then render that texture on the screen with multiply
Logged
slembcke
Level 3
***



View Profile WWW
« Reply #9 on: November 03, 2010, 04:31:05 PM »

The "screen" blending mode is not commutative, so the light changes based on the order the lights are drawn. I guess you probably won't notice as long as the light order doesn't change however.
Logged

Scott - Howling Moon Software Chipmunk Physics Library - A fast and lightweight 2D physics engine.
Glaiel-Gamer
Guest
« Reply #10 on: November 03, 2010, 04:47:44 PM »

The "screen" blending mode is not commutative, so the light changes based on the order the lights are drawn. I guess you probably won't notice as long as the light order doesn't change however.

screen is algebraically identical to 1-((1-a)*(1-b))


(quick algebra shows:
1-(1-a)(1-b)
1-(1-a-b+ab)
1-1+a+b-ab
a+b-ab
a+b(1-a) //a*ONE+b*ONE_MINUS_SRC_COLOR



1-(1-a)(1-b)

is commutative. Swap a and b and the result is the same.


EDIT: if you meant associative, which is

(a screen b) screen c === a screen (b screen c)

then we want to show

(a+b(1-a)) + c*(1-(a+b(1-a)) === a+(b+c*(1-b))(1-a)

expanding both sides

a+b-ab+ c*(1-(a+b-ab)) === a+(b+c-bc)(1-a)

a+b-ab+c*(1-a-b+ab) === a+b-ab+c-ca-bc+abc

a+b-ab+c-ca-bc+abc == a+b-ab+c-ca-bc+abc

which shows its associative too


HENCE it doesnt matter WHAT order you draw lights in, or even if you group lights together and draw layers at a time


Do NOT bash the screen blending mode. It's one of the MOST important ones you should know. It brightens without ever oversaturating
« Last Edit: November 03, 2010, 05:03:13 PM by Glaiel-Gamer » Logged
slembcke
Level 3
***



View Profile WWW
« Reply #11 on: November 03, 2010, 08:10:53 PM »

I remember running into a problem with it a couple of years ago, but it must have been some other issue. You are correct on both accounts, I did mean associative, and the math definitely works out fine.

So I take back what I said earlier, definitely use (ONE, ONE_MINUS_SRC_COLOR). As Glaiel-Gamer said, it has the huge advantage that it never oversaturates anything.
Logged

Scott - Howling Moon Software Chipmunk Physics Library - A fast and lightweight 2D physics engine.
dcarrigg
Level 0
***

Software Neurosurgeon


View Profile WWW
« Reply #12 on: November 07, 2010, 11:27:50 PM »

Hey guys, this is pretty cool...

I haven't been able to successfully replicate this. Can someone recap exactly how to do this, as there are multiple proposed solutions and none of them are described terribly well. This is actually something I've tried looking for a tutorial on in the past and have completely come up empty handed, so it may be worth making a post to the Tutorials forum.

Another question...   if you wanted to have colored lights, or even textured lights, how feasible would this be? I'm thinking something where you have a "lighting" layer which starts as a solid black texture, render other textures to it which subtract away alpha and add color, then finally render it on top of the scene with regular blending, glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)?

-Dave
Logged

Check it out! www.retroaffect.com
Tycho Brahe
Level 10
*****

λx.x


View Profile
« Reply #13 on: November 08, 2010, 03:48:47 AM »

Hi, the soloution I've come to is to draw the light to a normal blank texture with RGBA (1,1,1,0) with the light having a colour of (0,0,0,1) and then drawing this texture with a blend function of glBlendFunc( GL_SRC_ALPHA, GL_SRC_ALPHA );

Basically, when drawing this inverts all the colours in the texture, so all the parts which are (0,0,0,1) become (1,1,1,0), ie white with no alpha, and all the parts which are (1,1,1,0) become (0,0,0,1), ie black and opaque.

I hope this is a good enough answer. I can post some source code if you want, but I'm in the midst of sorting it out so it might take some time...
Logged
slembcke
Level 3
***



View Profile WWW
« Reply #14 on: November 08, 2010, 06:08:58 AM »

Colored lights work just fine with additive or the screen blending mode that Glaiel-Gamer and I were discussing. You don't really have to do anything special other than set the color before drawing.
« Last Edit: November 08, 2010, 06:26:02 AM by slembcke » Logged

Scott - Howling Moon Software Chipmunk Physics Library - A fast and lightweight 2D physics engine.
dcarrigg
Level 0
***

Software Neurosurgeon


View Profile WWW
« Reply #15 on: November 08, 2010, 02:14:16 PM »

I'd like to use the method that you were talking about, which would also support color.

Let me see if I can recap what I'm doing, because it's not quite working for me...

I'm rendering to a new texture, and I start by making it all black:
Code:
        glColor(0.0, 0.0, 0.0, 1.0);

The next step is to draw all of the lights onto it:
Code:
        glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_COLOR );
        glColor4f( 1.0f, 1.0f, 1.0f, 0.5f ); // White
        glBegin(GL_TRIANGLE_FAN);
        glVertex2f(250, -250);
        glColor4f( 1.0f, 1.0f, 1.0f, 0.0f ); // White
        for (float angle = 0; angle <= 6.28; angle+=0.1) {
            glVertex2f(sin(angle) * 250 + 250, cos(angle) * 250 - 250);
        }
        glVertex2f(sin(3.14159*2) * 250 + 250, cos(3.14159*2) * 250 - 250);
        glEnd();

Finally, I render this new texture onto the screen using:
Code:
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

...this seems to give me solid white circles. I'm thinking either the blend mode isn't correct, I've missed something, or there's an error with my code some where.

Any thoughts?
Logged

Check it out! www.retroaffect.com
Tycho Brahe
Level 10
*****

λx.x


View Profile
« Reply #16 on: November 08, 2010, 02:28:52 PM »

personally, I start by making it black, transparent:
Code:
glClearColor(0.0,0.0,0.0,0.0);
then to draw the lights:
       
Code:
float nx,ny;
        glBegin(GL_TRIANGLE_FAN);
        glColor4f(1,1,1,1);
        glVertex2f(x,y);
        glColor4f(1,1,1,0);
        for (float ang = (2*pi)+(pi/24);ang>=0;ang-=pi/24)
        {
            nx = (rad*sin(ang))+x;
            ny = (rad*cos(ang))+y;
            glVertex2f(nx,ny);
        }
        glEnd();

then to render the texture:
Code:
glBlendFunc( GL_SRC_ALPHA, GL_SRC_ALPHA );
it seems to work ok. I'll upload a picture once my internet speed goes above 9k.

Logged
slembcke
Level 3
***



View Profile WWW
« Reply #17 on: November 08, 2010, 02:36:19 PM »

You should be ignoring the alpha when blending to or from the lights texture. You just want to be blending the intensity and color of the light. Transparency makes no sense in this case, and you don't even need to allocate the alpha channel for the texture.

Set the center of your triangle fan to the desired color and intensity of the light, and make the edges black. When blending the lights texture over your scene, use the multiplicative blending mode (DST_COLOR, ZERO) instead of the usual alpha blending mode.
Logged

Scott - Howling Moon Software Chipmunk Physics Library - A fast and lightweight 2D physics engine.
dcarrigg
Level 0
***

Software Neurosurgeon


View Profile WWW
« Reply #18 on: November 08, 2010, 10:37:28 PM »

Sweet, that worked perfectly.

Thanks.
-Dave
Logged

Check it out! www.retroaffect.com
ANN-Tech.
TIGBaby
*


View Profile
« Reply #19 on: September 18, 2011, 03:52:54 PM »

...

then to render the texture:
Code:
glBlendFunc( GL_SRC_ALPHA, GL_SRC_ALPHA );
it seems to work ok. I'll upload a picture once my internet speed goes above 9k.


Hey, what texture do you render here exactly, that's the only part I am not clear with.
Can you please post more detailed Pseudo code here or the c++ code. If it is not a problem for you of course.

I would appreciate it.
« Last Edit: September 18, 2011, 04:03:05 PM by ANN-Tech. » Logged
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic