Texture Stages

Started by
7 comments, last by Kest 17 years, 7 months ago
Anyone have any suggestions for setting up texture stages for this operation? EnvResult = EnvTexture * CustomEnvColor; TexResult = DiffuseTexture * CustomDiffuseColor; FinalResult = TexResult + EnvResult; where * = D3DTOP_MODULATE + = D3DTEXOPCAPS_ADDSMOOTH This is what I have now. But it's not correct in the way the diffuse color modulates the environment texture and color. It uses my shader interface, but the calls should be pretty clear: FinalResult = EnvTexture * CustomEnvColor; FinalResult = FinalResult + DiffuseTexture; FinalResult = FinalResult * CustomDiffuseColor;
// Set textures
Shader->SetTexture( 0, env_tex );
Shader->SetTexture( 1, dif_tex );
Shader->SetRenderState( D3DRS_TEXTUREFACTOR, env_color );

// Combine Environment map with texture factor
Shader->SetTextureState( 0, D3DTSS_COLOROP,  D3DTOP_MODULATE );
Shader->SetTextureState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
Shader->SetTextureState( 0, D3DTSS_COLORARG2, D3DTA_TFACTOR );
Shader->SetTextureState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
Shader->SetTextureState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
Shader->SetTextureState( 0, D3DTSS_ALPHAARG2, D3DTA_TFACTOR );

// Add texture to result
Shader->SetTextureState( 1, D3DTSS_COLOROP,  D3DTEXOPCAPS_ADDSMOOTH );
Shader->SetTextureState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
Shader->SetTextureState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT );
Shader->SetTextureState( 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
Shader->SetTextureState( 1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
Shader->SetTextureState( 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT );

// Modulate diffuse with result
Shader->SetTextureState( 2, D3DTSS_COLOROP,  D3DTOP_MODULATE );
Shader->SetTextureState( 2, D3DTSS_COLORARG1, D3DTA_DIFFUSE );
Shader->SetTextureState( 2, D3DTSS_COLORARG2, D3DTA_CURRENT );
Shader->SetTextureState( 2, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
Shader->SetTextureState( 2, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
Shader->SetTextureState( 2, D3DTSS_ALPHAARG2, D3DTA_CURRENT );

// Disable further stages
Shader->SetTextureState( 3, D3DTSS_COLOROP, D3DTOP_DISABLE);





Is it possible to modulate seperate results and then add those together? Thanks for any help.
Advertisement
Have a look at D3DTSS_RESULTARG in SetTextureStageState. It allows you to save the results of an operation into a temporary register, which you can later use with D3DTA_TEMP.

Hope this helps.
Sirob Yes.» - status: Work-O-Rama.
Quote:Original post by sirob
Have a look at D3DTSS_RESULTARG in SetTextureStageState. It allows you to save the results of an operation into a temporary register, which you can later use with D3DTA_TEMP.

Hope this helps.

Thanks very much for pointing that out. Would you say this would be the best way to achieve the effect?

Are you aware of any performance issues? From my understanding, normal blending routines could avoid creating temporary data to blend to the result. But this will absolutely require a copy to be created. Would the hardware create pixel copies as it performs blending, or would it create an entire temporary texture space?

Thanks again [smile]
Quote:Original post by Kest
Would you say this would be the best way to achieve the effect?

As far as I know, other than shaders, this is the only way to achieve this. Shaders would be the better solution, of course, but this would probably do if your looking for a realistic solution [smile].

Quote:Original post by Kest
Are you aware of any performance issues? From my understanding, normal blending routines could avoid creating temporary data to blend to the result. But this will absolutely require a copy to be created. Would the hardware create pixel copies as it performs blending, or would it create an entire temporary texture space?

The copy is only created for a very short time. It creates it after performing the first op, and uses in on of the next stages. Since this is a per-pixel operation, that's only performed on up to 48 pixel at a time (on the high-end card), this is actually very little space. If you consider a SM2 card has room for 256 of these per pixel, that's no big issue at all.
I'm not sure if it'll be free, but impact should be minimal.

Hope this helps.
Sirob Yes.» - status: Work-O-Rama.
The hardware would just convert this to a suitable pixel shader, which is likely to have the same number of instructions (one multiplication, one mad, plus the texture accesses).

In fact, I'd suggest just using a pixel shader. Virtually all graphics cards sold over the past couple of years have them, including integrated chips, so it's not as if you're limiting your audience significantly by not using them. It's not that texture stages are bad, but whenever you want to do something a little complicated, pixel shaders are more straightforward (and can do a lot of stuff that texture stages simply can't).
I started my project with a card that didn't support pixel shaders. Well, it had some support, but the performance was ridiculous. Even though I use and completely rely on vertex shaders, I haven't touched the pixel side of it yet.

But it's very useful/helpful to hear that texture operations work in the same way. That was my assumption, but it's nice to get confirmation.

Thanks to both of you.
I have one other question about this if anyone with knowledge about the internal operation of this has a minute to answer.

Does it matter which order this operation should be placed?

Current = Texture * Diffuse;
Temp = EnvTex * EnvColor;
Current = Current * Temp;

OR

Temp = EnvTex * EnvColor;
Current = Texture * Diffuse;
Current = Current * Temp;

With the first, the 'temp' data is used in the very next stage, but 'current' must be kept stable while calculating 'temp'. With the second, 'current' doesn't need kept through the temp calculation, but 'temp' does need kept through the 'current' calculation. Are there any differences whatsoever, concerning portability between cards, performance, or any other issues at all? I only ask because it will work exactly the same for me either way. So even the smallest difference would be worth swapping the order.

Thanks for any information.
"D3DTEXOPCAPS_ADDSMOOTH" is not a texture operation. It's a caps bit used in D3DCAPS9 for your app to detect if D3DTOP_ADDSMOOTH is supported. Using it as an operation is going to do the wrong thing.

D3DTEXOPCAPS_ADDSMOOTH = 0x400
D3DTOP_ADDSMOOTH = 11

I have no idea what the driver will make of a value of 0x400. The debug runtimes would likely be screaming at you quite loudly.


This can be done in 2 stages if you don't really need addsigned.

modulate diffuse and texture
multiplyadd tfactor, texture, and current.

I can never remember if it adds ARG0 or ARG2 (or even ARG1). Since the docs refer to args1-3, and the stages support args0-2.


If you need addsigned, you'll need the use temp. As for the temp method, I've never trusted drivers to interpret a CURRENT correctly after a stage writes to TEMP. I'm not sure the documentation even describes what should happen, or if the WHQL tests check that cards match the spec. As such I've always ordered the math to work like:

temp = diffuse * texture
current = tfactor * texture
current = current + temp

your sample code does this:
a = texture * tfactor
b = texture + a
c = diffuse * b
or
c = diffuse * (texture + (texture * tfactor) )

which isn't what you want.

Finally, the following should do the trick.
0, modulate, texture, diffuse (result = temp)
1, modulate, texture, tfactor
2, addsigned, current, temp

Quote:Original post by Namethatnobodyelsetook
"D3DTEXOPCAPS_ADDSMOOTH" is not a texture operation. It's a caps bit used in D3DCAPS9 for your app to detect if D3DTOP_ADDSMOOTH is supported. Using it as an operation is going to do the wrong thing.

Oops. Copied and pasted the wrong value. Here's what I have:
Display.SmoothAddOpp = ( Caps.TextureOpCaps & D3DTEXOPCAPS_ADDSMOOTH ) ? D3DTOP_ADDSMOOTH : D3DTOP_ADD;
Then I use Display.SmoothAddOpp for the operation type. In my haste, I copied the flag value from the conditional statement to post here.

Quote:This can be done in 2 stages if you don't really need addsigned.

modulate diffuse and texture
multiplyadd tfactor, texture, and current.

I can never remember if it adds ARG0 or ARG2 (or even ARG1). Since the docs refer to args1-3, and the stages support args0-2.

Addsigned? Do you mean addsmooth? Add-signed causes a 0-1 addition to be ranged between -0.5 to +0.5. Add-Smooth just changes the 0-1 addition to be non-linear.

Quote:If you need addsigned, you'll need the use temp. As for the temp method, I've never trusted drivers to interpret a CURRENT correctly after a stage writes to TEMP.

And for good reason. My card is definitely doing something funky when I order it this way. Something that causes everything to become much brighter. I assumed it would be safer to trust that temp wouldn't change while modifying current, but the fact that it is named temp had me worried.

edit: I later realize this is likely because I forgot to swap texture coordinate indices in my vertex shader.

Quote:Finally, the following should do the trick.
0, modulate, texture, diffuse (result = temp)
1, modulate, texture, tfactor
2, addsigned, current, temp

This is what I have now, which is basically the same deal:

0, modulate, texture, tfactor (result = temp)
1, modulate, texture, diffuse
2, addsmooth, current, temp

Now I'm adding a detail texture mode on top of that, so it will have..

0, modulate, texture, tfactor (result = temp)
1, modulate, texture, diffuse
2, modulate, current, texture
3, addsmooth, current, temp

Then normal maps combined with that will follow, but I don't want to think about that yet.

Thanks for your help.

[Edited by - Kest on September 18, 2006 12:52:27 AM]

This topic is closed to new replies.

Advertisement