Multitexturing with alpha channels and masks

There are a lot of neat effects you can do using a base texture and an overlying texture with an alpha channel or mask.

If I had a metal texture with an alpha map, and it had transparent parts through which you could see an underlying cube map…would that have to be done in 2 passes, or can it be done with multitexturing?

If I use GL_ALPHA_TEST for mask or GL_BLEND for alpha channel, the entire surface will be masked or alpha-blended, when I only want the top texture to be blended…with the underlying texture.

I did these kinds of effects in Blitz3D, which supports multitexturing, and I had to use multipass rendering for things like this.

if you look into the OpenGL Spec 1.5 you will find info about multitexture and texture envmodes in chapter 3.8

ActiveTextureARB and ClientActiveTextureARB are the commands to switch between texture units and with TexEnvi/f you can tell each stage how to behave

look into following extensions for getting a greater variety of control

http://oss.sgi.com/projects/ogl-sample/registry/ARB/texture_env_combine.txt
http://oss.sgi.com/projects/ogl-sample/registry/ARB/texture_env_crossbar.txt
http://oss.sgi.com/projects/ogl-sample/registry/ARB/texture_env_add.txt
http://oss.sgi.com/projects/ogl-sample/registry/NV/texture_env_combine4.txt
http://oss.sgi.com/projects/ogl-sample/registry/ATI/texture_env_combine3.txt

Thanks, but I don’t really get the blend modes. I can tweak the blend modes and mess with them for different effects, but I am having trouble finding the right one, for this specific effect.

I have one base texture, and a second texture with an alpha channel. I want the second texture to cover the first, but transparent according to alpha value per texel, so that the underlying texture shows through in some spots.

The only way I can get alpha to even show up is using a blend mode or alpha func, which I don’t want. I cannot get texture alpha to display at all with multitexturing.

I try this:

texture0
glTexEnvf GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE
glTexEnvi GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_MODULATE
glTexEnvi GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_TEXTURE

texture1
glTexEnvf GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE
glTexEnvi GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_INTERPOLATE
glTexEnvi GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_PREVIOUS
glTexEnvi GL_TEXTURE_ENV,GL_SOURCE1_RGB,GL_TEXTURE
glTexEnvi GL_TEXTURE_ENV,GL_SOURCE2_RGB,GL_PRIMARY_COLOR
glTexEnvi GL_TEXTURE_ENV,GL_OPERAND2_RGB,GL_SRC_ALPHA

…but it just gives me solid texture0. Texture1 is an RGBA texture. GL_BLEND is disabled.

I have tried a lot of things for texture1. The only results I get are either standard modulate blending, or solid texture1:
glTexEnvf GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE
glTexEnvi GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_INTERPOLATE
glTexEnvi GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_PREVIOUS
glTexEnvi GL_TEXTURE_ENV,GL_SOURCE1_RGB,GL_TEXTURE
glTexEnvi GL_TEXTURE_ENV,GL_SOURCE0_ALPHA,GL_PREVIOUS
glTexEnvi GL_TEXTURE_ENV,GL_SOURCE1_ALPHA,GL_TEXTURE

You can do this in one pass using multitexturing but you’re going to have to write a fragment shader for the texture application.

 
//......------=========================================================------......
//	Augmented GL_MODULATE: (fragColor *= textureColor)
//	Preserves underlying fragments alpha value and modulates only texture
//	samples where alpha > 0.0.
//====================================================================
vec3 Blend(in vec3 fragColor, in vec3 textureColor, in float alpha)
{
	vec3 blend;
	blend = vec3(fragColor*(1.0-alpha) + fragColor*textureColor*alpha);
	return blend;
}

 

I wrote the above bit of fragment code to achieve just that.

it takes the rgb vector of the texture sample and modulates it with the underlying fragment using the samples alpha value.

I’m not interested in methods that require a pixel shader card. If someone can confirm this can’t be done in one pass with regular methods, I will happily use a multipass system.

You can ignore the typical “You must use a fragment program”. It’s the standard response to any suggestion these days.

What you are trying to do should be possible using ARB_texture_env_combine. You might have to use an extra texture unit.

The interpolation formula is…

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

That means that with your first attempt, you were multiplying Tex0 by Tex1 and adding the constant colour multiplied by 1 minus Tex 1.

You might get an acceptable result by swapping your Source1 and Source2 (Tex1 and Primary Color), but I think you may end up with areas that are correctly shaded (with respect to lighting) and areas that are “luminous”.

(ac)+b(1-c)

I would want A to equal the color of the pixel for texture1.
C equals the alpha value of the pixel for texture1.
B equals the color of the pixel for texture0.

That way a pixel with alpha=1.0 would only show the texture1 pixel color, and a pixel with alpha=0.0 would be 100% the underlying texture0 pixel color.

How does that translate into actual commands?

I got it working! Now my texture1 alpha’d layer is full-bright, though.

glTexEnvi GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_INTERPOLATE
glTexEnvi GL_TEXTURE_ENV,GL_SOURCE2_RGB,GL_TEXTURE
glTexEnvi GL_TEXTURE_ENV,GL_SOURCE1_RGB,GL_PREVIOUS
glTexEnvi GL_TEXTURE_ENV,GL_SOURCE0_ALPHA,GL_TEXTURE

It seems like 0 and 2 should be switched for the equation, but it doesn’t work if I do that:
A=Source0Operand0
B=Source1
Operand1
C=Source2*Operand2

pixel=(ac)+b(c-1)

The lights not working on the alpha’d texture1 layer makes sense. I told it not to blend with what is underneath, and it can’t get the surface light color without getting the texture0 pixels I don’t want. This is a problem I had in Blitz3D.

So unless anyone can suggest otherwise, I am assuming this requires a multipass render…then the alpha-faded pixels would be blended with the plain (lit) surface underneath.

Thanks for your suggestions.

Even on a GeForce 2, you can set it up as such:

  1. interpolate(texture 1,texture0,texture 1.alpha)
  2. modulate(diffuse vertex color)

All this requires is texture_env_combine and texture_env_crossbar, or the equivalent NVIDIA register_combiner extension (which implies that crossbar will work, even though crossbar isn’t exposed). I e, the above code will work on any card made in the last 4 years or so. (We’re using it in a shipping game)

Wouldn’t that method make texture0 full-bright?

both tex0 and tex1 would be “full bright” in 0)
but in 1) he modulates the result (ie the full surface) with the primary color and that way gives lighting back to everything

because “previous” does not mean the previous texture, but the result of the previous combiner

Okay, my material editor can accomodate this, and it means I don’t have to mess with it right now. Maybe I will post it here later.