Sign in to follow this  
Swatter555

Texture staging question

Recommended Posts

I am attempting to blend 3 textures together. The bottom layer is a map texture with landmasses. The middle layer is the detail texture. The top layer is the water the surrounds the landmasses from texture one. The top layer is loaded colorkeying out everything but the water. Now, the following code handles the first two textures(bot,mid):
device->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); 
device->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); 
device->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_CURRENT ); 
device->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_TEXTURE ); 
device->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_ADDSIGNED ); 

All of these state enumerations just make me want to tear my eyes out. Could someone show me how to put the third texture in there correctly? I would rather sort of work backwards and figure out why it works, rather than figuring out why it doesnt work. Thanks in advance :) Also, could someone direct me to their favorite tutorial on texture stage stuff.

Share this post


Link to post
Share on other sites
Textures stages are fairly simple once you understand what they do. Every stage must have both a colorop and an alphaop.

The COLOROP and ALPHAOP are operations, such as add, multiply, etc.

The COLORARG1, ARG2, ARG0, and ALPHAARG1, ARG2, ARG0 are the arguments to the operation. The number of arguments depends on the operation.

An ARG of CURRENT means use the output of the previous stage. On stage 0 it's the same as DIFFUSE.

An ARG of DIFFUSE means use the vertex diffuse color. If lighting is disabled, this is the color stored in the vertex structure. If lighting is enabled, this is the output from the lighting equations. COLORVERTEXENABLE, and DIFFUSEMATERIALSOURCE render states control where lighting chooses colors from.

An ARG of TEMP means to use the value that a previous stage wrote to the temporary output.

An ARG of TFACTOR means to use the color stored in render state TEXTUREFACTOR.

An ARG of TEXTURE means to use a texture lookup. TEXCOORDINDEX must also be set to choose which set of UVs to use, or to calculate UVs. TEXTURETRANSFORMFLAGS can also be used to enable a transformation matrix on the UVs before the texture lookup happens.

A stage can write to two places, CURRENT, or TEMP, set via RESULTARG.

examples:
COLOROP = SELECTARG1, COLORARG1 = TEXTURE, TEXCOORDINDEX = 0 means
current = texture (using first set of UV coordinates)

COLOROP = MODULATE, COLORARG1 = TEXTURE, COLORARG2 = DIFFUSE, TEXCOORDINDEX = 1 means
current = texture * diffuse (using second set of UV coordinates)

Your final stage should be set to DISABLED

Share this post


Link to post
Share on other sites
Thanks for the reply. I closely read your post and played with the ops for a few hours. I just cannot seem to accomplish the goal. The more I play with it, the greater I believe I understand it, but it certainly seems very tricky at the moment. Any other help you or anyone else can offer?

Share this post


Link to post
Share on other sites
The MSDN documentation suggests the use of a macro along the lines of
#define ColorStage(i, arg1, op, arg2)     \ 
Device->SetTextureStageState(i, D3DTSS_COLOROP, op); \
Device->SetTextureStageState(i, D3DTSS_COLORARG1, arg1); \
Device->SetTextureStageState(i, D3DTSS_COLORARG2, arg2)

#define AlphaStage(i, arg1, op, arg2) \
Device->SetTextureStageState(i, D3DTSS_ALPHAOP, op); \
Device->SetTextureStageState(i, D3DTSS_ALPHAARG1, arg1); \
Device->SetTextureStageState(i, D3DTSS_ALPHAARG2, arg2)

I find it rather helpful when visualising tricky blending operations.

Disclaimer: I wouldn't want anybody to think I'm condoning the use of preprocessor macros - I highly recommend you convert this into the equivalent inline function [rolleyes].

Regards
Admiral

Share this post


Link to post
Share on other sites
Thanks Admiral, that really solidifies what name said.

I have been trying lots of ops, but still the solution to the above problem alludes me. I need the third texture (which has everything but the water colorkeyed out) to solidly be placed on top of the result of the previous stages.

Ah, Ill continue my experimentation.

Share this post


Link to post
Share on other sites
I don't have too much experience with colour-keying. If you are using a 1-bit alpha channel to mask the transparent areas, how about
Device->SetTextureStageState(2, D3DTSS_COLORARG1, D3DTA_CURRENT); // Blend the current colour
Device->SetTextureStageState(2, D3DTSS_COLORARG2, D3DTA_TEXTURE); // with the texture colour
Device->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA ); // according to the texture's alpha value

Device->SetTextureStageState(2, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); // Set the final alpha
Device->SetTextureStageState(2, D3DTSS_ALPHAOP, D3DTA_SELECTARG1); // to the vertex interpolated alpha

If you're using alpha testing, I'm not entirely sure what to suggest. No doubt somebody will, though.

Regards
Admiral

Share this post


Link to post
Share on other sites
Sorry it's taken so long to get back to this thread... I've been busy. I only really covered part of what I wanted to in my previous post, but I figured something was better than nothing, and might help you along.

Anyway...

So, I covered how a COLOROP and it's ARGs and an ALPHAOP and it's ARGs are kind of like a line of simple code.

The stage number is the order these operations are done. Always set both color and alphaops on all stages. Finish with a stage set to disabled. The output of the last stage then goes through specular addition, fog, alpha testing and alpha blending, and then is written to the framebuffer/render target. Note that specular is automagically added, so you don't need to refer to D3DTA_SPECULAR anywhere in your texture stages.

I'm going to use this shorthand... it seems simple and compact.
[stage] [color op, color args] [alphaop, alphaargs] [texcoordindex]

So, the defaults are:
[0] [modulate, texture, diffuse] [selectarg1, texture] [0]
[1] [disable] [disable]
which translates to:
current.rgb = texture * diffuse;
current.a = texture;

Now, lets add a spherical environment map onto that
[0] [modulate, texture, diffuse] [selectarg1, texture] [0]
[1] [add, texture, current] [selectarg1, current] [D3DTSS_TCI_SPHEREMAP]
[2] [disable] [disable]

which translates to:
current.rgb = texture * diffuse;
current.a = texture;
current.rgb = texture + current
current.a = current.a

Notice how we're generating UVs to lookup the spheremap. These UVs make the same part of the texture face the camera, based on the normals in your mesh. Change stage 1's TEXCOORDINDEX to 0 to use the same UVs as the regular texture, and notice how it behaves that way.

Also, see how it's behaving as a small program.

Lets change the spheremap so that it is affected by lights
[0] [selectarg1, texture] [selectarg1, texture] [0]
[1] [add, texture, current] [selectarg1, current] [D3DTSS_TCI_SPHEREMAP]
[2] [modulate, current, diffuse] [selectarg1, current] [0]
[3] [disable] [disable]
current.rgb = texture;
current.a = texture;
current.rgb = texture + current
current.a = current.a
current.rgb = current.rgb * diffuse
current.a = current.a

By multiplying with diffuse later, we've made the spheremap be affected by lights too.

Now on to your specific case:
tex0 = land
tex1 = detail
tex2 = water w/ colorkey (ensure alpha in colorkey is set of 255!)
I'm assuming all 3 stages use the same set of UV coordinates, ensure you actually set TEXCOORDINDEX because it doesn't default to 0! Also, ensure you set the address modes (to clamp, wrap, or whatever you are expected) on each stage. Also set the filtering modes (likely to LINEAR) for min, mag, and mip filters.

[0] [selectarg1, texture] [selectarg1, current] [0]
[1] [addsigned, current, texture] [selectarg1, current] [0]
[2] [blendtexturealphapm, texture, current] [selectarg1, current] [0]
[3] [modulate, current, diffuse] [selectarg1, current] [0]
[4] [disable] [disable]
current.rgb = texture;
current.a = current;
current.rgb = current + (texture - 0.5)
current.a = current.a
current.rgb = texture.rgb + texture.a * current.rgb
current.a = current.a
current.rgb = current * diffuse
current.a = current.a

blendtexturealphapm blends between arg1 (water texture) and arg2 (mix of land and detail) based on the alpha in the current stage's texture (your water's colorkey makes an alpha). Regular blendtexturealpha would produce some artifacts along the edges of the water, as colorkey replaces the old pixel with transparent black. This is kinda technical, but it's a good thing to know.

Lets say your hardware sampled the texture halfway beween a water texel and a transparent texel. It would filter between the two colors, resulting in watercolor/2, alpha=0.5. If you blend that in with blendtexturealpha you'd get (alpha*watercolor/2) + (land * (1-alpha)), or, in other words, land/2 + watercolor/4. Oops. That's not a 50% blend.

Premultiplied alpha means that the texture contains color*alpha in RGB, and alpha. When the alpha=0, the color is black. Hey, that's what the colorkey does. blendtexturealphapm skips the alpha multiply on arg1, resulting in (watercolor/2) + (land * (1-alpha)), or, in other words, land/2 + watercolor/2, which is what we want, and nice 50% blend.

Share this post


Link to post
Share on other sites

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

Sign in to follow this