Jump to content
  • Advertisement
Sign in to follow this  
spe

texture blending using vertex alpha

This topic is 4835 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all, I have two questions regarding the subject. 1: How do I have to set the texture stages to blend two (or more) textures together? 2: I need this for a terrain engine where I have a big vertex buffer for all the data. But if I want to blend more textures together I'd have to use more vertex buffers to store the alpha. In the dx sdk I read that it is possible to use more vertex buffers to seperate the vertex data, and this buffers are interleaved for rendering. Unfortunetly there are no examples on how to do it, so does someone know? And is this method slower then normal vertex buffers? Spe

Share this post


Link to post
Share on other sites
Advertisement
1) There are many ways to do that really, it is done by setting texture stages, little example of using base + detail texture:

// Base texture (1 layer)
D3DDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE);
D3DDevice->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);
D3DDevice->SetTextureStageState(0,D3DTSS_COLORARG2,D3DTA_DIFFUSE);

D3DDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTOP_MODULATE);
D3DDevice->SetTextureStageState(0,D3DTSS_ALPHAARG2,D3DTA_TEXTURE);
D3DDevice->SetTextureStageState(0,D3DTSS_RESULTARG,D3DTA_DIFFUSE);

// Detail texture (2 layer)
D3DDevice->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_ADDSIGNED);
D3DDevice->SetTextureStageState(1,D3DTSS_COLORARG1,D3DTA_TEXTURE);
D3DDevice->SetTextureStageState(1,D3DTSS_COLORARG2,D3DTA_CURRENT);

D3DDevice->SetTextureStageState(1,D3DTSS_ALPHAARG1,D3DTOP_MODULATE);
D3DDevice->SetTextureStageState(1,D3DTSS_ALPHAARG2,D3DTA_TEXTURE);
D3DDevice->SetTextureStageState(1,D3DTSS_RESULTARG,D3DTA_CURRENT);





Also remember that DirectX can only handle 8 texture layers at time.
For more flags check DirectX SDK Documentation.

2) Well I wouldn't use vertex alpha to blend texture, but there are many ways to do it, some ways:

- Use one big base texture for whole terrain.
- Use one/many alpha textures (what texture is used and where)
- Use tiles (base + slope), this requires that you know the texture area edges.

Share this post


Link to post
Share on other sites
Well presume you have a customvertex like this:


typedef struct
{
D3DXVECTOR3 position; // The 3D position for the vertex
D3DCOLOR color; //Diffuse Color 0x00FFFFFF=Transparent 0xFFFFFFFF=Opaque
D3DXVECTOR2 tex; //Texture coords
}CUSTOMVERTEX;

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)




All vertex that are Transparent will be use to blend the second texture (in my example the texture in stage 1).


if( SUCCEEDED(g_pd3dDevice->BeginScene()))
{
SetupMatrices();
//SetupLights();
g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetIndices(g_pIB);
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);

// Texture crap here
g_pd3dDevice->SetTexture(0, g_pTB1);// First Texture
g_pd3dDevice->SetTexture(1, g_pTB2);// Second Texture

g_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);//Use the first set of texture coords
g_pd3dDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 0);//Use the first set of texture coords


SetTSS(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); // select arg1
SetTSS(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); // arg1 is texture color
SetTSS(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); // select arg1, which is diffuse by default

SetTSS(1, D3DTSS_COLOROP, D3DTOP_BLENDDIFFUSEALPHA); // Use alpha from stage last stage to blend texture 2
SetTSS(1, D3DTSS_COLORARG1, D3DTA_CURRENT); // take the color output from operation in stage zero
SetTSS(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); // Just keep alpha stage active
SetTSS(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT);// take alpha output from operation in stage zero

g_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,
0, 0,
(MapX + 1) * (MapY + 1), // Number of Verticals
0,
2 * MapX * MapY); // Number of Triangles

g_pd3dDevice->EndScene();
}




Maybe this sample was enough for you to figure out how texture blending works.

<href="www.32Bits.co.uk"/> Has some nice tutorials which I recommer to look at.

Share this post


Link to post
Share on other sites
I tryed it like this :


D3D.GetD3DDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE,true);
D3D.GetD3DDevice()->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
D3D.GetD3DDevice()->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
D3D.GetD3DDevice()->SetRenderState(D3DRS_BLENDOP,D3DBLENDOP_ADD);

D3D.GetD3DDevice()->SetTexture(0,t2.BaseTexture);
D3D.GetD3DDevice()->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE);
D3D.GetD3DDevice()->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);
D3D.GetD3DDevice()->SetTextureStageState(0,D3DTSS_COLORARG2,D3DTA_DIFFUSE);

D3D.GetD3DDevice()->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_SELECTARG1);
D3D.GetD3DDevice()->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_DIFFUSE);

D3D.GetD3DDevice()->SetTexture(1,t2.DetailTexture);
D3D.GetD3DDevice()->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_BLENDDIFFUSEALPHA);
D3D.GetD3DDevice()->SetTextureStageState(1,D3DTSS_COLORARG1,D3DTA_CURRENT);
D3D.GetD3DDevice()->SetTextureStageState(1,D3DTSS_COLORARG2,D3DTA_TEXTURE);

D3D.GetD3DDevice()->SetTextureStageState(1,D3DTSS_ALPHAOP,D3DTOP_SELECTARG1);
D3D.GetD3DDevice()->SetTextureStageState(1,D3DTSS_ALPHAARG1,D3DTA_DIFFUSE);


Now the 2 textures blend together but I can see through the polys. How can I avoid this?

Share this post


Link to post
Share on other sites
Thanks, that worked. Anybody something about non fvf vertex buffers?

Share this post


Link to post
Share on other sites
If you can limit yourself to 4 textures active at once, you don't need more storage, as there are some tricks you can do... Now, not necessarily 4 for the entire landscape, but draw with one set of 4, draw again with another set of 4, etc. Only 4 active on one chunk of terrain. For best performance you'll want to render sections that use 1 texture with just the 1 texture, section that use 2 textures, with just the two. We had a 4 textures everywhere system on our last game, and really, it's a huge waste shader and memory bandwidth to mix in 3 textures at 0%, 80% of the time. Nearly 50% of our frame time was spent drawing ground.

If you're using a shader capable card, you'll have 4 texture available at once (GeForce3+). In this case simply mix one texture by diffuse.a, and one by diffuse.b using blue replicate (ps 1.1 shader supports this), then use a DP3 with 1,0,0,0 to get your diffuse.r into an alpha channel, mix with that, and use DP3 with 0,1,0,0 to get diffuse.g into an alpha channel and mix with that.

If you need more that 4 textures, you're looking at cards which support ps.2.0 anyway. Simply put more data into the VB as color1 (aka specular), a texture coord, or whatever you want. Blending more textures with the fixed pipeline will likely be more trouble than it's worth. You will no longer need to use DP3 tricks to get at .r and .g, as I think ps.2.0 allows arbitrary swizzling.

If you're using a pre-shader card you can expect 2 texture units to be available, though often more than 2 texture stages. Texture 0 can be 100%, and texture 1 can be blended via diffuse alpha, then you can mix lighting/vertex color in stage 2.

If you're aiming for shader capable cards and using the fixed pipeline, you should be able to use the DP3 tricks and using D3DTA_CONSTANT. Any card with shaders should (I haven't checked, so just SHOULD) support constants per stage in the fixed pipeline. You can use D3DTSS_RESULTARG, and D3DTA_TEMP to calculate the DP3 into a register that won't clobber the color. You lose blue replicate this way, needing an extra dp3. So you'd do something like this

select tex0
blenddiffusealpha tex1 current into temp
dp3 constant, diffuse (select r, g, or b)
blendcurrentalpha tex2, temp, into temp
dp3 constant, diffuse (select r, g, or b)
blendcurrentalpha tex3, temp, into temp
dp3 constant, diffuse (select r, g, or b)
blendcurrentalpha tex4, temp, into temp
disable

Remember to set the resultargs back to current when you're done rendering.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!