Damn SetTextureStageState() (DX9)

Started by
8 comments, last by Evil Steve 20 years, 8 months ago
Ok, I don't even know if this is possible to do efficiently (but to be honest it doesn't really matter). I have these three tiles: (If the image is broken, #1 is a mask (magenta & black), and #2 & #3 are normal textures [grass & sand]). I'd really like to be able to blend the second and third textures using the first as a mask of some sort, but i really don't know how to go about it. At the moment is have this:

m_pDevice->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_MODULATE);
m_pDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);
m_pDevice->SetTextureStageState(0,D3DTSS_ALPHAARG2,D3DTA_CURRENT);

m_pDevice->SetTextureStageState(1,D3DTSS_ALPHAOP,D3DTOP_MODULATE);
m_pDevice->SetTextureStageState(1,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);
m_pDevice->SetTextureStageState(1,D3DTSS_ALPHAARG2,D3DTA_CURRENT);

m_pDevice->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_ADD);
m_pDevice->SetTextureStageState(1,D3DTSS_COLORARG1,D3DTA_TEXTURE);
m_pDevice->SetTextureStageState(1,D3DTSS_COLORARG2,D3DTA_CURRENT);
Which produces an image like this: (Ignore the window title - its a work in progress ) But i don't know what to do next... Someone suggested something to do with the stencil buffer that sounds over-complicated to me. Is this the only way to do it? How do terrain engines do this? Terrain engines blend 2 textures into one another (e.g. grass & rock), which is what i'm doing - except with only 1 bit of alpha (effectively 0.0 or 1.0) Any suggestions? Cheers, Steve [edited by - Evil Steve on August 12, 2003 8:07:55 AM]
Advertisement
If your card supports fancy features like >2 texture stages, temp registers and lerp commands, try something like this:

m_pDevice->SetTexture( 0, m_mask );
m_pDevice->SetTexture( 1, m_sand );
m_pDevice->SetTexture( 2, m_grass );

m_pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
m_pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE );
m_pDevice->SetTextureStageState( 0, D3DTSS_RESULTARG1, D3DTA_TEMP );

m_pDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
m_pDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pDevice->SetTextureStageState( 1, D3DTSS_RESULTARG1, D3DTA_CURRENT );

m_pDevice->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_LERP );
m_pDevice->SetTextureStageState( 2, D3DTSS_COLORARG0, D3DTA_TEMP );
m_pDevice->SetTextureStageState( 2, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pDevice->SetTextureStageState( 2, D3DTSS_COLORARG2, D3DTA_CURRENT );
m_pDevice->SetTextureStageState( 2, D3DTSS_RESULTARG1, D3DTA_CURRENT );


otherwise go multi-pass:

m_pDevice->SetTexture( 0, m_sand );

m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );

m_pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
m_pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );

m_pDevice->SetTexture( 0, m_grass );
m_pDevice->SetTexture( 1, m_mask );

m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
m_pDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
m_pDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );

m_pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
m_pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );

m_pDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
m_pDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
m_pDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_CURRENT );
m_pDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_TEXTURE );
Excellent, multi-pass works perfectly.

Thanks!
Ok, one more question.
I''ve tried to implement both methods in my game, so that i can use single-pass if its supported. When i did this, i got 950 fps, an increase of 100fps, so i reckon its worthwhile.
Anyway, to determine if the graphics card supports it, i do this:
if((m_theCaps.PrimitiveMiscCaps & D3DPMISCCAPS_TSSARGTEMP) &&   (m_theCaps.TextureOpCaps & D3DTEXOPCAPS_LERP))   m_bRenderWithLerp = true;else   m_bRenderWithLerp = false;

However, i seem to be missing something because although this works on my server (with only onboard graphics), it doesn''t work on my sisters GeForce2. All i get is a black screen. If i skip that step and set m_bRenderWithLerp to false, it works fine. So i guess there must be another cap that i need to test against.
Anyone know what it is?

Cheers,
Steve
Although the GeForce2 accepts lerp, it may not support 3 textures. You''ll need to check the maximum number of textures a card supports.

If someone has a link describing all cards feature sets, I''d love to have it, as I''m sure many others would too. If anyone has such a beast, post a new thread (more likely to be seen by interested parties).
D''oh that was it. The GeForce 2 can only handle 2 textures at once.

Thanks for the help
The GeForce 2 can only handle 2 textures at once.

How to check this value? Is it under (Caps Viewer)

D3D Device Types\HAL\Caps\

"MaxTextureBlendStages" or
"MaxSimultaneousTextures" ?




Sorry again, in that "multi-pass" option, isn't the
second "SetTexutre(0, m_grass)" over-writin' the first "SetTexture(0, m_sand)"? Some kind of DrawPrimitive() is
needed in between them, am I right?

m_pDevice->SetTexture( 0, m_sand );
m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );

m_pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
m_pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );

// Some kind of DrawPrimitive() here...

m_pDevice->SetTexture( 0, m_grass );
m_pDevice->SetTexture( 1, m_mask );

etc...






[edited by - HaywireGuy on August 17, 2003 9:50:59 PM]
Q1) I check MaxSimultaneousTextures
Q2) Yes:
m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE);m_pDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_SELECTARG1);m_pDevice->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);// For each tile:   m_theScene.SetTexture(0,m_vTiles[pTile->wTile].pTexture);   m_pDevice->DrawPrimitive(D3DPT_TRIANGLEFAN,(y*m_sizeView.cx+x)*4,2);m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);m_pDevice->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_SELECTARG1);m_pDevice->SetTextureStageState(1,D3DTSS_ALPHAOP,D3DTOP_SELECTARG2);m_pDevice->SetTextureStageState(1,D3DTSS_COLORARG1,D3DTA_CURRENT);m_pDevice->SetTextureStageState(1,D3DTSS_ALPHAARG2,D3DTA_TEXTURE);// For each tile:   m_theScene.SetTexture(0,m_vTiles[pTile->wOverlayTile].pTexture);   m_theScene.SetTexture(1,m_vMasks[pTile->wMask].pTexture);   m_pDevice->DrawPrimitive(D3DPT_TRIANGLEFAN,(y*m_sizeView.cx+x)*4,2);


[edited by - Evil Steve on August 19, 2003 10:33:25 AM]
Cool, that makes better sense. Thanks!

This topic is closed to new replies.

Advertisement