Ok I'm just testing out something and I'm very confused about the whole blendFunc thing.

I have my level which I just render (did not touch blendFunc yet), with let's say color(0.3f, 0.3f, 0.3f, 1f);. Pretty dark...

Then this guy comes:

Now I want that cool looking light-effect, so I set the blendFunc to what exactly? GL_SRC_ALPHA, GL_DST_ALPHA?

Reading about blendFunc, I feel I'm getting only more confused. Why is it even possible to set something like GL_DST_* in the src part of the blendFunc? Shouldn't the src part only allow for GL_SRC_* stuff? Does it even make a difference?

Explain Like I'm 5 Version:When a mommy pixel loves a daddy pixel, they sometimes make a baby pixel.This might get confusing, let's try another approach

Explained How I Understand it:The Blend Function, as you may have guessed, is a function which defines how two colors combine to make the final color.It helps if you think of this as a per-pixel process. So don't think of the entire image in the buffer, just consider one pixel.

First off we need to understand which parts of the functions apply to which color.

Source Color: This is the color you want to draw to the surface (the one you're currently drawing with).Destination Color: This is the color which already exists on the surface.

So we have the basic idea:Source Color + Destination Color = Baby-I mean Final Color.

Blend FunctionWell, the above is great and all, but simply adding two colors together isn't always going to produce the results we want. Thus along comes the Blend Function.Instead of just adding the two colors together, we're now going to mangle both colors and then add them together to create the final result. So we're going to define a functionfor how we're going to mangle each pixel, by using the blend function.

Let's assume all the colors under the light are dark blue. ThusDestination = (0, 0, 0.3)

Since we're making a light, we obviously want to make the dark blue color a lighter shade of blue. So how should we do this?Easy enough, just slap those two bad boys together with an add function and BAM instant lighting.How do we tell OpenGL to do this? Well, we us the blending parameter called GL_ONE.

glBlendFunc(GL_ONE, GL_ONE);

This means the source and the destination are going to be multiplied by 1.And here's essentially what happens:

Note: This actually answers your question about which blend function to use for your lighting. Also, you can change the color and strength of the lightby manipulating the Source Color elements. IE: change to (0,1,0) if you want a really strong green light etc...I recommend you play with it to get the effect you want, but start with lower numbers and work your way up. Once a color goes out of the 0 to 1 range, it's clamped to either 0 or 1.

In this example, we'll use RGBA format. And we'll tackle a common question when trying to do transparencies.How do you draw a transparent object on top of a scene?You're going to need a transparency value (the alpha element of course). Keep in mind the destination color does not need an alpha value, but the source does.I think the magic of this one is easier understood by just looking at an example.The function we'll use is

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

This means we're going to multiply the Source Color by the value of the Alpha channel on the source value.Then we're going to take 1 and subtract the Source Color Alpha channel. The result is then multiplied against the Destination Color.

So let's say we want to blend a dark red over a blue Scene. But we only want to blend it by half (in other words, 50% transparency).Source = (0.3, 0, 0, 0.5)Destination = (0, 0, 0.3)

The end result is a purple-ish looking color.If the final destination doesn't contain alpha values, then to the best of my understanding the alpha channel of the final color is taken to a farm out in the country where it lives therest of its days - and wasn't by any means taken out back and shot.

Other Blend Function ParametersThere are a lot of other parameters you can set. To be honest, you'll likely see the above two example used the most.The reason you can use things like GL_DST_ALPHA in the Source parameter, is because sometimes you feel life just isn't hard enough. No no no, that can't be right.I haven't run into a case where I've needed a value from the destination channel, so I can't really provide an example. But I'm sure there are specific cases where it comes in useful.

And thats all. It works but...the result is kinda sad. Besides, the "light" is not very "transparent" and I guess that depends of the alpha of the "light_back" previously rendered. Here's a pic:

Im not sure what I have to do exactly but, I guess that what I need is to render the "light1" and get a final pixel color with alpha equal to "light1", independently of the previously alpha of the pixel. Tried a lot of things and combinations of the BlengFunc but i always get the same result (or worst).

I think I understand what you are doing and why you're getting the less than stellar lighting result.Unfortunately the end answer isn't a simple solution.

The problem with using a flat color as a light is what you're seeing. It's prone to saturation and really not good for main lighting.That being said, I think you've done a pretty nice job mangling it to a point where it's not too bad.

I left it out of my above explanation, but the way to do lighting is a bit more complex. Instead of blanketing the light area with a single color, you actually want to use the exact color of every pixel for every pixel in the lit area.Take your light as an example. The steps would be roughly1.) Copy pixels covered by the light and save them.2.) Draw your shadow texture3.) Draw the pixels you saved back to the main screen using glBlend(GL_ONE, GL_ONE).

The end result is a perfectly round circle with all the pixels accurately lit without saturation.But now you have a new problem. It's all lit, but now you're missing the nice feathered lighting. So in order to apply the attenuation, you'll either need to redraw a dark circle over the light, or get down into the shader code and apply an attenuation calculation based on the position of the light. The later being the optimal of course.

This approach is similar to something called a G-Buffer, where you draw parts of your scene to a off screen textures called Frame Buffers. For example, you'd draw all the objects to something named a diffuse buffer (note: I'm simply naming it diffuse), which contains everything without any lighting or shadowing. Then you can easily sample from the diffuse buffer and apply it to your output.Think of it similar to a copy paste approach. Only the user never sees the source picture and when you paste the picture to the main view port, you can make it paste in special ways.

At this point, you're probably thinking "Wow... that's a lot of shi-" yes, it is.Of course this isn't the only approach, but it's an effective one which mirrors the way many modern 3D games handle lighting.

Fortunately, you appear to be using LibGDX and davedes has done a nice job of pulling up some tutorials which should make your life a lot easier.I don't use LibDGX, so I can't say for sure, but I believe the second link is more similar to my above approach. Only it's made easier through LibGDX (lucky you).

I think I understand what you are doing and why you're getting the less than stellar lighting result.Unfortunately the end answer isn't a simple solution.

The problem with using a flat color as a light is what you're seeing. It's prone to saturation and really not good for main lighting.That being said, I think you've done a pretty nice job mangling it to a point where it's not too bad.

I left it out of my above explanation, but the way to do lighting is a bit more complex. Instead of blanketing the light area with a single color, you actually want to use the exact color of every pixel for every pixel in the lit area.Take your light as an example. The steps would be roughly1.) Copy pixels covered by the light and save them.2.) Draw your shadow texture3.) Draw the pixels you saved back to the main screen using glBlend(GL_ONE, GL_ONE).

The end result is a perfectly round circle with all the pixels accurately lit without saturation.But now you have a new problem. It's all lit, but now you're missing the nice feathered lighting. So in order to apply the attenuation, you'll either need to redraw a dark circle over the light, or get down into the shader code and apply an attenuation calculation based on the position of the light. The later being the optimal of course.

This approach is similar to something called a G-Buffer, where you draw parts of your scene to a off screen textures called Frame Buffers. For example, you'd draw all the objects to something named a diffuse buffer (note: I'm simply naming it diffuse), which contains everything without any lighting or shadowing. Then you can easily sample from the diffuse buffer and apply it to your output.Think of it similar to a copy paste approach. Only the user never sees the source picture and when you paste the picture to the main view port, you can make it paste in special ways.

At this point, you're probably thinking "Wow... that's a lot of shi-" yes, it is.Of course this isn't the only approach, but it's an effective one which mirrors the way many modern 3D games handle lighting.

Fortunately, you appear to be using LibGDX and davedes has done a nice job of pulling up some tutorials which should make your life a lot easier.I don't use LibDGX, so I can't say for sure, but I believe the second link is more similar to my above approach. Only it's made easier through LibGDX (lucky you).

Yeah, all this with alpha mask to use as light sounds weird and also not pretty nice on the end (at least what I'm capable of get).

Your approach its interesting, but Im starting to believe that Lighting and shaders are like cousins . The results of light effects using shaders its very good. For the moment, I will not look into shaders but in the near future, if I really want to implement light, I believe that I should look into shaders directly. :/

Seem that coding it's like life, it gets more and more complicated at every step LOL

Shaders are not too difficult to learn, they are just intimidating when you first look at them. IMHO it's pretty crucial to learn how they work if you want to make some "fancy" graphics (lighting, VFX, etc) rather than just a simple sprite game.

It seems you might already have seen this links given the placeholder graphics you're working with, but if not...

Shaders are not too difficult to learn, they are just intimidating when you first look at them. IMHO it's pretty crucial to learn how they work if you want to make some "fancy" graphics (lighting, VFX, etc) rather than just a simple sprite game.

It seems you might already have seen this links given the placeholder graphics you're working with, but if not...

Hehe yep been looking at them. Are pretty cool and very well explained. I understand shaders a bit more now, but I still have to do some tests, moving from lwjgl-basics to normal api and then yes, I'll be able to use shaders

But I have some problems with it. Im triying to reproduce some effects in a libgdx app. Probably Im doing something wrong but, for example, the combination of: GL_ZERO and GL_ONE_MINUS_SRC_ALPHA doesn't seems to work as expected.

Try using spriteBatch.setBlendFunction(...) and spriteBatch.enableBlending() instead of directly calling Gdx.gl.glBlendFunc and Gdx.gl.glEnable.

Alternatively, you can set SpriteBatch's blend function to (-1, -1) and use your own glBlendFunc calls.

If you are using spriteBatch.setBlendFunction, you won't need to flush the batch (it will call flush() for you, if necessary). And you only need to flush the batch before setting a different blend function.

Try using spriteBatch.setBlendFunction(...) and spriteBatch.enableBlending() instead of directly calling Gdx.gl.glBlendFunc and Gdx.gl.glEnable.

Alternatively, you can set SpriteBatch's blend function to (-1, -1) and use your own glBlendFunc calls.

If you are using spriteBatch.setBlendFunction, you won't need to flush the batch (it will call flush() for you, if necessary). And you only need to flush the batch before setting a different blend function.

Doing this:

1 2 3 4 5 6 7 8 9 10 11 12 13

batch.begin();

batch.enableBlending();batch.setBlendFunction(GL10.GL_ZERO, GL10.GL_ONE_MINUS_SRC_ALPHA); //GL10 or GL20, same resultGdx.gl20.glBlendEquation(GL20.GL_FUNC_ADD); //with or without this, same result

//Backgroundbatch.draw(bg, 0, 0);

//Ballbatch.draw(sprite, 0, 0);

batch.end();

I get an entirely black screen Tried setting batch.setBlendFunction(-1, -1) and then calling to Gdx.gl.setBlendFunction(...) and got same result.

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org