texture blending using vertex alpha

Started by
5 comments, last by Namethatnobodyelsetook 18 years, 11 months ago
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
JSoft@coder.hu
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.
Sincerely,Arto RuotsalainenDawn Bringer 3D - Tips & Tricks
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.
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?
JSoft@coder.hu
For blending inside texture stages, ALPHABLENDENABLE and ALPHATESTENABLE do nothing. Those are solely for blending with the frame buffer.

Just turn ALPHABLENDENABLE to false, and you should be set.
Thanks, that worked. Anybody something about non fvf vertex buffers?
JSoft@coder.hu
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.

This topic is closed to new replies.

Advertisement