Jump to content

Help understanding blendFunc


Recommended Posts

One thing I've never grasped, even after reading about it a lot, is blendFuncs. I'm sure I'm not alone... I need a thorough explanation of blendFunc logic, explained differently than the shader manual does it, so that I can freeform blendFunc my way through Jedi Knight.

 

How do the blendFuncs relate to the current stages vs previous stages? What is really the color buffer?

If you could also put it in a way that could let me understand how to do the following it would be very helpful:

 

-Have an unaltered texture to do tcMod operations on, such as scrolling a tiled texture. The texture's alpha channel (not scrolling) filters the visibility of the whole texture.

 

End result would be: A light with a gradient falloff, but with a slow scroll overlaying it based on the texture, not the alpha.

Link to comment

For what i see by try and error method doing shadering for my cathedral....

GL_ONE GL_ONE... -> full brightness shader, it's good for fire of glowing particles. in materials. it make they too brights, also in MD3. use it for glowing lighting texture, but not for MD3 or any kind of materials.

GL_ZERO GL_ZERO -> make completely dark and opaque the objects. 

GL_ONE GL_ZERO -> not change much of the brightness. it's good for make lighting diffuse of glm models.

GL_ONE GL_SRC_COLOR : .-> as GL_ONE GL_ZERO, but the model is little more bright and with a different RGB filter...

GL_SRC_ALPHA ETC -> with alphagen and alphaconst parms make the texture translucent... you can watch throught it.

GL_DST_COLOR GL_ZERO -> with rgbgen Identity, it's the better shadering for MD3 models. it's good also for the most of the materials of brushes

GL_DST_COLOR GL_SRC_COLOR -> make things with color little differnet and more light of GL_DST_COLOR GL_ZERO. i not like much because create strange kind of tonality and false colors... >.< it's not much good to see.

GL_SRC_ALPHA GL_ONE_:MINUS_SRC_ALPHA it's fine for MD3 translucent reflect tcgen enviroment effects. i make a marble reflex with this parameter. in tcgen enviroment stage.

 

rgbGen Lighting Diffuse -> On glm model, not on MD3, on MD3 make it blacks.

// Alphagen Lightingspecular-> good for making metal tcgen enviroment on blades and saber or metal surfaces like armors of GLM npcs or weapons. the tggen enviroment scroll the metal reflex at second of the camer view and moving of player.

rgnGen vertex : use it on planar and bidimensional surfaces, like flags or leathers or leaves...

 

if you use the $lightmap parameter, this affected about light diffusion and illumination of model or the brush, lightmap need to be followed by rgbgen parameter. using $lightmap on my md3 model i obtained morbid and soffuse lighting... :3

$whiteimage: apply a white filter on the textures... i not know much about this function... i try to use at the start of my shadering works, by after i change to lightmap because it make the MD3 too brights on Meta build of the map.

 

This is my experience with shadering,. i not know much other and i read too the Quake3 manual. atthe end, i used for many of my textures the DST_COLOR GL_ZERO, the lightmap for the stone textures of MD3 domes, and the SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA tcgen enviroment for the reflexes of my marble textures...

i think every one use a different combination at second of they necessity, many thing depend by your buld and your ambiental and worldspawn and sunny skybox parameters.

Link to comment

blendFunc is fairly simple to understand. All colours can be represented using 3 numbers, Red, Green, Blue, with a 4th number for transparency (the alpha) - in Photoshop or GIMP, you can use the colour picker to show you these numbers (or components) of the colour. These values are in the range 0 - 255. In graphics, you "normalize" these values, so they become 0.0 - 1.0.

 

blendFunc is a way to tell the graphics card how you want two colours to be blended, where the first colour is the source, and the second colour is the destination (i.e. what's already been drawn). Blending then happens like so...

sourceColor * srcBlendFunc + destinationColor * dstBlendFunc

So for example, you might write "blendFunc GL_ONE GL_ZERO". GL_ONE is your srcBlendFunc (source blend function), and GL_ZERO is your dstBlendFunc (destination blend function). GL_ONE GL_ZERO also happens to be the default blendFunc. The maths then works out like this:

final color = source color * 1 + destination color * 0

You can simplify this because 0 * x = 0.

final color = source color

Let's take another example... blending based on alpha transparency is pretty common. This is "blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA". The final colour is then calculated:

final color = source color * source color's alpha + destination color * (1 - source color's alpha)

Thinking about this intuitively, if the source colour's alpha = 1, then none of the destination colour is shown, and you effectively get the same as GL_ONE GL_ZERO. If source colour's alpha = 0, then you're fully transparent, and you see the destination colour in full as you would expect. Fractional values in the source colour's alpha will make the source colour more or less transparent.

 

All of the blendFunc names are pretty named very well so you can work out what they do by plugging them into the first formula I gave. The last important piece of information is that the final colour that's calculated is the destination colour for the next shader stage.

 

Hopefully that's clear enough. I'm writing this at work so my post isn't as detailed as I'd like it to be, but I think it's enough to go on. Let me know if you need any more explanation and I'll try my best :)

 

EDIT: Didn't read your post properly, so I missed a point. The colour buffer is the "texture" that gets drawn to your screen. However, you won't see the results of your calculations until it gets "presented" to the display. This way, you can overwrite/blend/clear existing colour pixels without you seeing any of the intermediate results.

 

EDIT2: I've been wanting to write a simple WebGL application that lets you play with blend functions in a web browser, but have never gotten around to doing it. It would be great if someone could do this as seeing how the blend functions works in action can make understanding a lot easier.

Link to comment

I've been trying to write this post for soon one and a half hour, and I'm nearly psyched out. I'm trying to think of the logical way to have one texture scroll and then be hidden/filtered by the same texture's alpha channel.

My crumbling logic:

 

Stage 1 must draw nothing but the alpha channel, because if you draw the full color there will be no blendFunc in the second stage, in the destination part, to subtract again. So you will just end up with more and more.

But the most logical thing for me would be to somehow draw the full color and do scroll and stuff on that - and then in the second stage take the texture's alpha channel and subtract everything else. But I feel like you can't do that.

 

Stage 1:

map etc/textureWithAlphaChannel

 

Draw the alpha channel of the texture (GL_SRC_ALPHA) and add nothing more (GL_ZERO).

(1 * x) + (1 * 0)  = x. (Second stage's destination value).

 

So we have the alpha channel, but haven't drawn the full color anywhere.

 

Stage 2:

map etc/textureWithAlphaChannel

 

Draw the full color (GL_ONE) but also add.. add? I want less, not more. zxfdkjfk, I can't.. do it.

Draw nothing again (GL_ZERO) but add stage 1 (GL_ONE) = no change. I need an example, and another explanation :(

Link to comment

I started trying to write more about blendFuncs but it wasn't particularly coherent, but here's something that *might* do what you want. Untested, tcmod scroll values will need adjusting.

 

 

textures/boothand/foggy_lamp
{
    qer_editorimage textures/boothand/fog
    qer_trans 0.5
    surfaceparm noimpact
    surfaceparm nomarks
    surfaceparm nonsolid
    surfaceparm nonopaque
    surfaceparm trans
    q3map_nolightmap
    {
        map textures/boothand/fog
        alphaGen vertex
        tcMod scroll 5 5
        blendFunc GL_SRC_ALPHA GL_ONE
    }
}

 

textures/boothand/fog would just be some kind of foggy image (no alpha channel!).

to get the alpha stuff working properly you could use alphamod volume brushes to force the vertex alpha (as used by alphaGen vertex) to 1 by the lamp and 0 away from it.

Link to comment

You want to make a fading light... :\ i cannot help because i never make shaders of fading light...
i see a tutorial about the light fading of sun by the windows, but i not know if can help you.
 

models/map_objects/cda/marble2
{
    qer_editorimage    models/map_objects/cda/marble2
    surfaceparm    nonopaque
    q3map_material    marble
    q3map_onlyvertexlighting
     {
        map $lightmap
        rgbGen identity
    }
    {
        map models/map_objects/cda/marble2
        blendFunc GL_ONE GL_ZERO
        detail
        rgbGen identity
        tcMod scale 2 2
    }
    {
        map models/map_objects/cda/marble_env
         blendFunc  GL_DST_COLOR GL_ZERO
        alphaGen const 0.5
        tcGen environment
        tcMod scale 2 2
    }
}


 
for what i can understand, you need to add the enter value and the exit value...
the value make additions...
so, for example GL_ONE GL_ZERO is like Texture total rgb value + 0 = Texture total rgb value.
 
i used this for glasses of windows, following the tutorials about shadering of windows here on openjk forum
models/map_objects/cda/stainedglass1

{
//    polygonOffset
// this will stop the game from rendering shadows and burnmarks on the decal//
    q3map_material    glass
    surfaceparm    nomarks
    surfaceparm    trans
    nopicmip
    q3map_nolightmap
    q3map_novertexshadows
    {
// This is an optional line of code, that will make the texture more opague//

        map models/map_objects/cda/stainedglass1
        blendFunc GL_DST_COLOR GL_SRC_COLOR
        alphaGen const 0.7
    }
}


 
A marble part with enviroment:
 

models/map_objects/cda/marbleparts2c <- shader name
{
    qer_editorimage    models/map_objects/cda/marbleparts2c <- name of shader image used in radiant for apply shader to brush
    q3map_material    marble <- material (affected footstep sounds when you build map with q3map2.)
    q3map_onlyvertexlighting <- this make better the graphical quality of the shader, also if not know why
    {
        map $lightmap
        rgbGen    identity
    }
   {
         map models/map_objects/cda/marbleparts2c <- texture field
         blendFunc GL_ONE GL_SRC_COLOR <- GL_ONE + GL_SRC_COLOR the color are mixed.
         detail
        rgbGen identity
      }
   {
          map models/map_objects/cda/marble_env2 <- enviroment textures
         blendFunc  GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA <- trans blendfunc
         alphaGen const 0.05 <- trans value of this texture
         tcGen environment <- enviroment function
    }
}


 
can we see a screenshot of what you want to do? :)

Link to comment

Just to clarify - this thread is dedicated entirely to understanding how blendFunc works :D The example I used (a fading light) is not what I'm here to get help with, as I could find workarounds for this particular issue using possibly better solutions than a scrolling overlay as well.

 

(On a sidenote, @@redsaurus, alphamod brushes? Are they related to the alpha brushes used for terrain blending? It sounds interesting either way and would want to play around with that).

 

So my goal is to learn how blendFuncs work, especially when there are multiple stages, so that I can make my own shaders using only logic. I would need some kind of example probably and a technical step by step description of each step...!

Asgarath83 likes this
Link to comment

I've been trying to write this post for soon one and a half hour, and I'm nearly psyched out. I'm trying to think of the logical way to have one texture scroll and then be hidden/filtered by the same texture's alpha channel.

My crumbling logic:

 

Stage 1 must draw nothing but the alpha channel, because if you draw the full color there will be no blendFunc in the second stage, in the destination part, to subtract again. So you will just end up with more and more.

But the most logical thing for me would be to somehow draw the full color and do scroll and stuff on that - and then in the second stage take the texture's alpha channel and subtract everything else. But I feel like you can't do that.

 

Stage 1:

map etc/textureWithAlphaChannel

 

Draw the alpha channel of the texture (GL_SRC_ALPHA) and add nothing more (GL_ZERO).

(1 * x) + (1 * 0)  = x. (Second stage's destination value).

 

So we have the alpha channel, but haven't drawn the full color anywhere.

 

Stage 2:

map etc/textureWithAlphaChannel

 

Draw the full color (GL_ONE) but also add.. add? I want less, not more. zxfdkjfk, I can't.. do it.

Draw nothing again (GL_ZERO) but add stage 1 (GL_ONE) = no change. I need an example, and another explanation :(

 

The flaw in understanding here is that GL_SRC_ALPHA means drawing alpha only, that's not what happens.

 

In your stage 1 example, you can use the fomula Xycaleth talked about to understand how blending would work there.

FinalColour.RGB = SourceColour.RGB * SourceColour.A + DestinationColour.RGB * 0
... which simplifies into ...
FinalColour.RGB = SourceColour.RGB * SourceColour.A

Things to note here:

  • GL_SRC_ALPHA as the source blend func means the source RGB colours (texture RGB) are multiplied by the source Alpha channel (texture Alpha).
  • SourceColour.A is a single number between 0.0 and 1.0, corresponding to the alpha channel of that particular point in the texture.
  • Multiplying by anything that's less than 1.0 means that the RGB colours will be darkened, because the resulting values will be less than the original.
  • Where the alpha is 0.0 in your texture, the final colour will be black. Where the alpha is 1.0 in your texture, the final colour will be the original RGB colours.

Your stage 1 will basically result in a fully opaque surface whose colours will blend between black and their original colours depending on the alpha channel at the particular point on the texture.

 

Your stage 2 would be this:

FinalColour.RGB = SourceColour.RGB * 1 + DestinationColour.RGB * 0
... which simplifies into ...
FinalColour.RGB = SourceColour.RGB

So here, you're completely ignoring the result of the first stage (because you're multiplying destination colour by 0), and instead you're simply using the full RGB colour of the original texture (And it'll still be fully opaque over whatever's behind the surface).

So your shader essentially just does the default blending because the second stage is GL_ONE GL_ZERO.

 

I don't understand what technique you're trying to aim at in your post though. You want one stage to have a scrolling texture with RGB, while another stage is staying still and just acting as a sort of transparency mask?

Boothand likes this
Link to comment

Thanks for those clarifications. I think a lot of my confusion comes from trouble in imagining how adding the sources and destinations together looks like. A WebGL app like @@Xycaleth mentioned would be really useful indeed!

 

 I don't understand what technique you're trying to aim at in your post though. You want one stage to have a scrolling texture with RGB, while another stage is staying still and just acting as a sort of transparency mask?

 

Yeah. It might not be very useful in this particular case, but I used it as an example of something I can't figure out how to do. I tried to do something similar when helping a friend with a shader, but couldn't figure it out. He had a texture with an alpha channel, and he wanted to see the whole texture and then add another texture scrolling over only the white parts of the alpha channel, as an overlay. I feel it's in the same catecory.

 

Maybe I'll soon post an example shader that already works, and post my version of its logic, and you guys can tell me where it's flawed still :P

Link to comment

As far as I'm aware, it's not possible to do that sort of masking in the Quake 3 engine where you have a stage that uses the alpha information of the stage below it to figure out how to blend with the surfaces underneath.

Boothand likes this
Link to comment

Here's an online demo of the different blending options you have: http://www.andersriggelsen.dk/glblendfunc.php

 

The "Blend equation" option should be kept at GL_FUNC_ADD (Addition), since that's the only blending mode available in Quake 3 (as far as I know; maybe @@Xycaleth knows better).

The "Premultiply" checkbox on the page is an advanced topic that concerns texture filtering, it's best to leave that Off as it would involve extra steps when exporting assets for the game.

Edited by Didz
Boothand likes this
Link to comment
He had a texture with an alpha channel, and he wanted to see the whole texture and then add another texture scrolling over only the white parts of the alpha channel, as an overlay. I feel it's in the same catecory.

It's possible to do this, but the solution isn't obvious - you draw them in reverse order. Let's call your 'background texture', texture A, and your scrolling texture, texture B.

 

Stage 1: Draw texture B as usual, with default blendFunc and scrolly fun.

Stage 2: Draw texture A, with blendFunc GL_ONE_MINUS_SRC_ALPHA GL_SRC_ALPHA

 

Your scrolling texture get's drawn first, and is the destination texture for stage 2.

In stage 2, you multiply texture A's RGB values by (1 - alpha of texture A). So where the alpha is white (1), you get texture A RGB * 0, so none of texture A is used, but then you add on texture B RGB * 1 (which is the full colour of texture B ). When the alpha is black (0), the opposite happens. You get the full colour of A, and none of B.

 

It just takes experience and some creativity to figure out what to do with your blendFuncs but if you understand the basic concepts of how the blending works, then you should get there eventually :)

Boothand, DT85 and Asgarath83 like this
Link to comment
  • 3 years later...

It's possible to do this, but the solution isn't obvious - you draw them in reverse order. Let's call your 'background texture', texture A, and your scrolling texture, texture B.

 

Stage 1: Draw texture B as usual, with default blendFunc and scrolly fun.

Stage 2: Draw texture A, with blendFunc GL_ONE_MINUS_SRC_ALPHA GL_SRC_ALPHA

 

Your scrolling texture get's drawn first, and is the destination texture for stage 2.

In stage 2, you multiply texture A's RGB values by (1 - alpha of texture A). So where the alpha is white (1), you get texture A RGB * 0, so none of texture A is used, but then you add on texture B RGB * 1 (which is the full colour of texture B ). When the alpha is black (0), the opposite happens. You get the full colour of A, and none of B.

 

It just takes experience and some creativity to figure out what to do with your blendFuncs but if you understand the basic concepts of how the blending works, then you should get there eventually :)

Hi Xycaleth.

Please write an example of this shader. (Two textures, one of which is an alpha mask).

(The first texture should scroll, and the alpha channel of the second texture should make the first texture transparent or invisible near the edges, (depending on the alpha channel).)

 

I need to get the following result:

Texture1 (which will scroll).

TEXTURE1.jpg

Texture2 Alpha Channel - (which will not scroll).

TEXTURE2-ALPHA.jpg

Result.

RESULT.jpg

Link to comment

Hi Xycaleth.

Please write an example of this shader. (Two textures, one of which is an alpha mask).

(The first texture should scroll, and the alpha channel of the second texture should make the first texture transparent or invisible near the edges, (depending on the alpha channel).)

 

I need to get the following result:

Texture1 (which will scroll).

TEXTURE1.jpg

Texture2 Alpha Channel - (which will not scroll).

TEXTURE2-ALPHA.jpg

Result.

RESULT.jpg

so you want to render only the white parts of the first texture with the alpha channel of the second texture?

Link to comment

so you want to render only the white parts of the first texture with the alpha channel of the second texture?

AshuraDX, Yes. :)

I would like to get the result as on the third picture, (+ scrolling).

RESULT1-anim.gif

 

 

 

If there are several ways to get a similar result, please write.

(One texture moves, and the other texture does not move and makes that texture transparent or invisible in the right places.)

For example, such a shader:

The first texture. (Scroll, rotate ...) Has an image and an alpha channel. The light and dark parts of the image are displayed. The alpha channel of the first texture makes some places of the texture transparent or invisible.

The second texture. (Does not scroll.) Has an alpha channel that makes the first texture transparent or invisible in some places.

Texture1.

TEXTURE1.jpg

 

Texture1-Alpha.

TEXTURE1-ALPHA.jpg

 

Texture2-Alpha.

TEXTURE2-ALPHA.jpg

 

Result.

RESULT2-anim.gif

 

 

Link to comment

@@Bad Dancer the first one is definitely possible, not sure about the second one.

 

Here's a possible solution for the first shader:

 

textures/example/texture

{

{

map textures/example/texture2

alphaFunc GE128

blendFunc GL_ONE GL_ONE

depthWrite

rgbGen identity

}

{

map textures/example/texture1

alphaFunc GE128

blendFunc GL_ONE GL_ONE

depthFunc equal

tcMod scroll 0.25 0

}

}

 

For this to work your texture2 is expected to have all black RGB channels with your black and white alpha in the alpha channel.

 

Texture1 does not need any alpha, it will appear transparent based on brightness.

 

I did not have the time to try that shader yet, but it should work.

Link to comment

@@Bad Dancer the first one is definitely possible, not sure about the second one.

 

Here's a possible solution for the first shader:

 

textures/example/texture

{

{

map textures/example/texture2

alphaFunc GE128

blendFunc GL_ONE GL_ONE

depthWrite

rgbGen identity

}

{

map textures/example/texture1

alphaFunc GE128

blendFunc GL_ONE GL_ONE

depthFunc equal

tcMod scroll 0.25 0

}

}

 

For this to work your texture2 is expected to have all black RGB channels with your black and white alpha in the alpha channel.

 

Texture1 does not need any alpha, it will appear transparent based on brightness.

 

I did not have the time to try that shader yet, but it should work.

Thank you! :) It really works. :winkthumb:

 

But there are two problems:

1 - Very sharp edges of the Alpha Channel. (There is no smooth transition from white to black.)

2 - Transparency of other effects. (Explosions, fire ...) When I look through this effect to other effects, they become transparent in those places where this effect should be transparent.

 

I am very interested in solving these problems. Especially solving problem number 2.

Can you help me with this?

TR1.jpg

TR2.jpg

TR3.jpg

Link to comment

In theory there is another method to achieve this that'd actually solve the issues you have with the current version.

The problem is that it doesn't work on most graphics cards in the vanilla version of the game.

 

I'm also not 100% sure if you can actually get the same visual result with this alteration. I'll dig into it later.

Bad Dancer likes this
Link to comment

In theory there is another method to achieve this that'd actually solve the issues you have with the current version.

The problem is that it doesn't work on most graphics cards in the vanilla version of the game.

 

I'm also not 100% sure if you can actually get the same visual result with this alteration. I'll dig into it later.

I got some idea about this ... Maybe this idea is silly, but I dared to ask ... :)

 

Maybe we need to add a texture 3 to this shader, with some settings? Then the alpha channel will only affect texture 2, and will not affect the transparency of other effects?

 

P.S.
This is my mercenary model.

I create this model for Jedi Academy with Rend2 (GL2).

I create weapons for this mercenary. For the effects of his weapon will also need that shader.

Csom-d.png

Langerd likes this
Link to comment

I seem to be having trouble with this lately as well. If I am trying to make a text decal, like a sign that says ARENA or something on a wall, that has an alpha transparent background, which blendfunc should I use that doesn't make the text like full bright? Maybe it's an issue with the lightmap function I have in my shader?

 

 
textures/mapname/sign
{
qer_editorimage textures/mapname/sign
polygonOffset
q3map_nolightmap
q3map_onlyvertexlighting
    {
        map textures/mapname/sign
        blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
    }
}
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...