Archived

This topic is now archived and is closed to further replies.

how to set up multitexturing?

This topic is 5617 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

i have this vertex: struct terrain_vertex{ FLOAT x, y, z; // The untransformed position for the vertex. FLOAT nx,ny,nz; FLOAT tu, tv; // The texture coordinates FLOAT weight; //the info for multitexturing the terrain, allows for 3 textures DWORD matrixIndices; FLOAT weight2; DWORD matrixIndices2; FLOAT weight3; DWORD matrixIndices3; }; and this fvf for it: #define TERRAINVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1|D3DFVF_XYZB3) now how do i use this setup? i got this far reading the dx documentation, but i can''t figure out how to use it. i realise it may be a larger than postable topic/tutorial, but does anyone know of a tutorial that teachs this?

Share this post


Link to post
Share on other sites
Are you doing it with a shader or using texture stages? Even with a shader, you shouldn''t need that much information in your vstructure. If you''re planning to blend three textures with different texture coords, then all you need if your regular vertex structure but with three tex coords. No weights or matrix indices are needed. For multitexturing, I have no need for shaders so I base my code off of the multitexturing code found at www.Direct3D.net. Maybe you can find some use out of it.

---
My Site
Come join us on IRC in #directxdev @ irc.afternet.org

Share this post


Link to post
Share on other sites
No, he has the blending stuff to specify how much of each texture to use at each vertex e.g 50% grass, 25%snow, 25% lava.
Leastwise, that''s what I figure from your earlier post. Let me know if you figure this out - I''m not getting anywhere!



Read about my game, project #1



John 3:16

Share this post


Link to post
Share on other sites
What you seem to be trying to do in your code is indexed vertex blending. Unfortunately I think this is not what you actually want to do (weight-dependant texture stage blending). Indexed vertex blending modifies the vertex positions according to matrices you have set up.

In any case, the FVF you have specified is incompatible with the struct you have defined (I won''t explain now why unless you want me too ).

Right now I can only think of doing what you want to do is by using the specular register to pass on the blending factors for your textures to a vertex shader. The vertex shader can then pass this on to the pixel shader (it will have iterated it across the shape you are rendering as it would a diffuse colour). In the pixel shader you should then be able to use these factors to determine how much of each texture to use. The only thing about this is that you would have to be very careful to make sure that your three blending factors add up to 1.0f. Anything less and it would appear a bit transparent, anything more and you would see unexpected results as one of the textures would be masked out by the other textures.

Rory.

Share this post


Link to post
Share on other sites
This topic shows the steps necessary to initialize and use a simple vertex shader that uses a position and multiple texture coordinates for multiple textures.

The first step is to declare the structures that holds the position and color as shown in the code example below.

struct XYZBuffer
{
float x, y, z;
};

struct Tex0Buffer
{
float tu, tv;
};

struct Tex1Buffer
{
float tu2, tv2;
};

The next step is to create a vertex shader declaration as shown in the code below.

DWORD decl[] =
{
D3DVSD_STREAM( 0 ),
D3DVSD_REG( D3DVSDE_POSITION, D3DVSDT_FLOAT3 ),
D3DVSD_STREAM( 1 ),
D3DVSD_REG( D3DVSDE_TEXCOORD0, D3DVSDT_FLOAT2 ),
D3DVSD_STREAM( 2 ),
D3DVSD_REG( D3DVSDE_TEXCOORD1, D3DVSDT_FLOAT2 ),
D3DVSD_END()
};

The next step is to call the IDirect3DDevice8::CreateVertexShader method to create the vertex shader.

g_d3dDevice->CreateVertexShader( decl, NULL, &vShader, 0);

Passing NULL to the second parameter of CreateVertexShader tells Direct3D that this vertex shader will use a fixed function pipeline.

After creating the vertex buffer and vertex shader, they are ready to use. The code example below shows how to set the vertex shader, set the stream source, and then draw a triangle list that uses the new vertex shader.

g_d3dDevice->SetVertexShader( vShader );
g_d3dDevice->SetStreamSource( 0, xyzbuf, sizeof(XYZBuffer) );
g_d3dDevice->SetStreamSource( 1, tex0buf, sizeof(Tex0Buffer) );
g_d3dDevice->SetStreamSource( 2, tex1buf, sizeof(Tex1Buffer) );
g_d3dDevice->SetIndices( pIB, 0 );
g_d3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, max - min + 1, 0, count / 3 );

what about this taken from the sdk documentation? it appears to do what i want, i think.

Share this post


Link to post
Share on other sites
i am 99% sure i can do what i want with texturestages, i want each vertex to have a blend weight of 3 textures, and then draw them interpolating the blend weight across the triangles. i do not want to use shaders, as they aren''t supported on my friends card. i know its possible, i''ve seen it done in lots of games on my old voodoo3, obviously not using shaders. i''m pretty sure i would just do something like this:
pD3DDv->SetTexture(0, t_grass);
pD3DDv->SetTexture(1, t_rock);
pD3DDv->SetTexture(2, t_dirt);

i know i''m obviously missing a lot of code, but i only need some blend weights in the vertexes and some SetTextureStageStates, right?

Share this post


Link to post
Share on other sites
quote:

i know i''m obviously missing a lot of code,


Absolutely...

quote:

but i only need some blend weights in the vertexes and some SetTextureStageStates, right?



No... You don''t need blend weights in the vertices... or if you insist, place it in the alpha component of the vertex diffuse colour and do a multipass render (not multitexture in single pass!).

What you are talking about is vertex based blending or alpha interpolation on vertices!!! You can achieve this only by using the alpha component of the diffuse colour in the vertex (you mentioned you don''t want to use shaders!).
Textures are set for the entire triangle and cannot have different properties for each vertex (unless ofcourse if u use a shader)...

what you need to do is to understand the SetTextureStageState thoroughly...you may be able to use these in some places...

Share this post


Link to post
Share on other sites
Yeah. That sounds right. I'm just not sure how you can set some kind of blending using SetTextureStageState and the vertex information.

OK. Having read the docs, I think I see what you need to be doing. Unfortunately I'm still not totally sure it can be done for three textures in one pass. Two textures in one pass is simple, but three is much harder.

Basically you will be needing to use the lerp texture operation for the alpha op in your 2nd and third stages. ie

SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_LERP);

This uses the factor that you send in to D3DTSS_COLORARG0 to determine how to blend the stages. The only problem is that you will need to find a way to set this value to something useful. It can only be things like the vertex's diffuse colour, or the specular colour. So basically you'll need to specify the blending factors by putting them in the diffuse and specular colours I think.

For texture stage 0, you just set the texture straight away to 100% your first texture (eg grass). Then for texture stage 1 (your snow), you use LERP as the alpha operation, and specify D3DTA_DIFFUSE as your D3DTSS_COLORARG0. So you use the diffuse colour to determine the blending factor.

So for a vertex who's (pretend) colour is white, it will use all of the grass texture, if it is black, it will use all snow texture, and if it is grey, it will blend between them.

So finally for your texture stage 2 (rock or whatever), use LERP again as the operation, but this time use D3DTA_SPECULAR as the D3DTSS_COLORARG0. Now you use your vertex specular in the same way to blend between the grassy-snowy texture and the rock.

Here's a pseudo-code snippet (off the top of my head so might not be perfect).


    
IDirect3DDevice8* pDevice;

// Set the textures for each stage

pDevice->SetTexture(0, grass);
pDevice->SetTexture(1, snow);
pDevice->SetTexture(2, rock);

// Stages. Leave the ColorArg1 and 2 as defaults. This uses

// the current stage's texture as colorarg1, and the previous

// stage's output as colorarg2


// Stage 0. Just output the grass texture

pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);

// Stage 1. Use the vertex diffuse colour to determine the blend

pDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_LERP);
pDevice->SetTextureStateState(1, D3DTSS_COLORARG0, D3DTA_DIFFUSE);

// Stage 2. Use vertex specular colour to determine the blend

pDevice->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_LERP);
pDevice->SetTextureStateState(2, D3DTSS_COLORARG0, D3DTA_SPECULAR);


You might want to see what exactly the D3DTA_TEMP flag does (in place of D3DTA_SPECULAR and D3DTA_DIFFUSE). That looks like it might help you out, but the docs are very sparse.

I'm sure you might get some funny effects depending on you settings, but to get (roughly) a mix of all three textures you would set the vertex diffuse colour to (0.5, 0.5, 0.5, 0.5) and the specular colour to (0.3, 0.3, 0.3, 0.3) or something like that. I guess you would have to play around with it for a while. One coll thing about this system is that you can blend the colours separately. So if you want to make the rock appear blue, just use (I am using ARGB format) (0.0, 0.0, 0.0, 0.3)

I think this is enough to get you going for a bit. I am pretty sure this is a step in the right direction. You will probably be able to modify this to be a lot better with experience (as I have almost none with the fixed function pipeline!)

Rory.


[edited by - protopornopants on July 26, 2002 9:47:53 AM]

Share this post


Link to post
Share on other sites
Yeah, looked in the SDK docas, and the blending stuff is for matrices. Think we''re stuck with single passes or

TextureState1:
Texture=Grass.
ColourArg=Texture.
AlphaArg=constant (set to be completely solid)

TextureState2:
Texture=Rock.
ColourArg=Texture.
AlphaArg=VertexDiffuseColour

TextureState3:
Texture=Snow.
ColourArg=Texture.
AlphaArg=VertexSpecularColour

This does what you want I think, and CAN be done in a single pass. Sorry about lack of proper code, you know where to look
You can also still use the colour components of diffuse and specular for lighting or whatever I think if you''re careful not to screw with the alpha.

Does result in a large vertex FVF (3 texcoord sets, diffuse & specular), but if you build vertices dynamically this isn''t such a problem. I think you want the first texture to be solid, otherwise it''ll blend with the background colour you clear the backbuffer to.

What does anyone think to this method? Ok? Completely flawed?



Read about my game, project #1



John 3:16

Share this post


Link to post
Share on other sites
Hmm well I''ve looked at single-pass multitexturing and sure you can do it, but on which graphics cards - thats the question.
Geforce 2 MX etc will only do 2 textures at once, so you would need a multipass backup there.
Also different graphics cards have different limitations of what texturestagestates can be used at each level, so you wanna check that too.
I wanted to blend 2 textures and a vertex color in 1 pass and the extra color info just made in impossible - a 2 pass render made it simpler and cleaner.
The vertex shader solution though looks cool - anyone used this?
A

Share this post


Link to post
Share on other sites
The two stage weighted texture blending using pixel shaders I''m sure is used fairly frequently in games (pretty much all the games we do here at Climax use that). I still can''t quite see why someone would really need three stage weighted blending though. We can achieve a really nice look which artists are happy with using two stages. Plus on the Xbox that leaves two more stages (one for detail usually, plus maybe bump mapping?).

This solution using the vertex alpha looks nice especially on large, well tiled terrains. You can achieve so many nice blends between sand/grass or tarmac/grass or whatever. When you couple this will a good detail texture it really looks nice.

Rory.

Share this post


Link to post
Share on other sites
quote:
Original post by ProtoPornoPants
The two stage weighted texture blending using pixel shaders I'm sure is used fairly frequently in games (pretty much all the games we do here at Climax use that). I still can't quite see why someone would really need three stage weighted blending though. We can achieve a really nice look which artists are happy with using two stages. Plus on the Xbox that leaves two more stages (one for detail usually, plus maybe bump mapping?).

This solution using the vertex alpha looks nice especially on large, well tiled terrains. You can achieve so many nice blends between sand/grass or tarmac/grass or whatever. When you couple this will a good detail texture it really looks nice.

Rory.

ok, but don't i need three stages if i want three textures? i don't need detail or bumpmapping, as this is a VERY ametuer game by a dumb 15 year old

EDIT: i deleted my plea for help because i didn't see the VERY useful 4 posts above this one , only this last one

[edited by - billybob on July 26, 2002 8:11:43 AM]

Share this post


Link to post
Share on other sites
ok, would this be something close to what we want? i was going off of d000hg''s post, but i''m kind of new to this, so i''m not sure if i did what he said right

pD3DDv->SetTexture(0, grass);
pD3DDv->SetTexture(1, snow);
pD3DDv->SetTexture(2, rock);// Stages. Leave the AlphaArg1 and 2 as defaults. This uses
// the current stage''s texture as alphaarg1, and the previous
// stage''s output as alphaarg2
// Stage 0. Just output the grass texture
pD3DDv->SetTextureStageState(0, D3DTSS_COLORARG0, D3DTA_TEXTURE);
pD3DDv->SetTextureStageState(1, D3DTSS_COLORARG0, D3DTA_TEXTURE);
pD3DDv->SetTextureStateState(1, D3DTSS_ALPHAARG0, D3DTA_DIFFUSE);// Stage 2. Use vertex specular colour to determine the blend
pD3DDv->SetTextureStageState(2, D3DTSS_COLORARG0, D3DTA_TEXTURE);
pD3DDv->SetTextureStateState(2, D3DTSS_ALPHAARG0, D3DTA_SPECULAR);

is that what we want? or did i mess it up already...

Share this post


Link to post
Share on other sites
ok, why does this cause a crash?!?!

D3DXMatrixRotationY(&rot_y_matrix,0);
D3DXMatrixRotationX(&rot_x_matrix,0);

//Combine the 2 matrices to get our final Rotation Matrix
D3DXMatrixMultiply(&rot_matrix,&rot_x_matrix,&rot_y_matrix);

D3DXMatrixTranslation(&trans_matrix,0.0f,0.0f, 0.0f);

D3DXMatrixMultiply(&matWorld,&rot_matrix,&trans_matrix);

pD3DDv->SetTransform(D3DTS_WORLD,&matWorld );
pD3DDv->SetVertexShader(D3D8T_CUSTOMVERTEX);
pD3DDv->SetStreamSource(0, v_Terrain, sizeof(D3D8T_CUSTOMVERTEX));
pD3DDv->SetTexture(0, t_grass);
pD3DDv->SetTextureStageState(0, D3DTSS_COLORARG0, D3DTA_TEXTURE);
pD3DDv->DrawPrimitive(D3DPT_TRIANGLELIST,0,100);

i see nothing wrong with it, i know its the drawPrimitive, so there must be something wrong with my vertex buffer(?)

[edited by - billybob on July 26, 2002 9:16:36 AM]

Share this post


Link to post
Share on other sites
You do realize that most graphics cards only support two textures, right? The recent GeForce4 Ti and not-so-recent GeForce3 support 4 apparently, and the Radeon 8500 supports a whopping 6. All before that, plus the GeForce4 MX and Go series only support 2.

I''m pretty sure you can pull it off with two stages, though, in which case you can use diffuse alpha. (from the material or wherever)

- hillip@xenoage.de''>JQ
Full Speed Games. Period.

Share this post


Link to post
Share on other sites
quote:
Original post by JonnyQuest
You do realize that most graphics cards only support two textures, right? The recent GeForce4 Ti and not-so-recent GeForce3 support 4 apparently, and the Radeon 8500 supports a whopping 6. All before that, plus the GeForce4 MX and Go series only support 2.

I''m pretty sure you can pull it off with two stages, though, in which case you can use diffuse alpha. (from the material or wherever )

- JQ
Full Speed Games. Period.

i can do it in two passes, there is hardly anything else in the game other than the terrain and cars. so it can afford the speed hit. but those few things in the game need to look good. ' Target=_Blank>Link

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
On a similar note. I have a small landscape that consists of 32x32 vertices. When I render the landscape with a single texture I get around 500 fps (1024x768x32), but when I activate a second texture the frame rate drops by 50%. I have a GeForce 3. Shouldn''t the hardware be able to work with two textures without a drop in the frame rate, or am I mistaken?

Share this post


Link to post
Share on other sites
quote:
Original post by billybob
ok, would this be something close to what we want? i was going off of d000hg''s post, but i''m kind of new to this, so i''m not sure if i did what he said right

pD3DDv->SetTexture(0, grass);
pD3DDv->SetTexture(1, snow);
pD3DDv->SetTexture(2, rock);// Stages. Leave the AlphaArg1 and 2 as defaults. This uses
// the current stage''s texture as alphaarg1, and the previous
// stage''s output as alphaarg2
// Stage 0. Just output the grass texture
pD3DDv->SetTextureStageState(0, D3DTSS_COLORARG0, D3DTA_TEXTURE);
pD3DDv->SetTextureStageState(1, D3DTSS_COLORARG0, D3DTA_TEXTURE);
pD3DDv->SetTextureStateState(1, D3DTSS_ALPHAARG0, D3DTA_DIFFUSE);// Stage 2. Use vertex specular colour to determine the blend
pD3DDv->SetTextureStageState(2, D3DTSS_COLORARG0, D3DTA_TEXTURE);
pD3DDv->SetTextureStateState(2, D3DTSS_ALPHAARG0, D3DTA_SPECULAR);

is that what we want? or did i mess it up already...


Have a look at the post I put up with the source up above. I think that this is exactly what you want to do. Have a go!

Rory.

Share this post


Link to post
Share on other sites
Wow, is my method actually useful?
Yeah, many cards only support two textures but that means you can do it in 2 passes rather than 1 - perfect if you add a bump texture or light map. Some of the previous generation ATI cards (7000/7500?) have 3 texture units, as mentioned in my thread here. To avoid having to bloat your FVF with specular colour, you might choose to do it in 2 stages anyway. btw, you could always use effects.
billybob I want a link to a screenshot/demo of your app as soon as you get this method working



Read about my game, project #1



John 3:16

Share this post


Link to post
Share on other sites
quote:
Original post by d000hg
Wow, is my method actually useful?
Yeah, many cards only support two textures but that means you can do it in 2 passes rather than 1 - perfect if you add a bump texture or light map. Some of the previous generation ATI cards (7000/7500?) have 3 texture units, as mentioned in my thread here. To avoid having to bloat your FVF with specular colour, you might choose to do it in 2 stages anyway. btw, you could always use effects.
billybob I want a link to a screenshot/demo of your app as soon as you get this method working



Read about my game, project #1



John 3:16


i haven''t gotten it working yet because i can''t figure out what to put in the vertex structure and the FVF define. can someone help me with that? i found the problem though, i was setting the sizeof my stream vertice to my FVF define, DOH! now, all i need to know is what to put in my vertex struct to get those diffuse and specular things. that is the last piece, someone tell me!!!

Share this post


Link to post
Share on other sites
Your fvf should have

D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_SPECULAR|D3DFVF_TEX3|D3DFVF_TEXCOORDSIZE2(0)|D3DFVF_TEXCOORDSIZE2(1)|D3DFVF_TEXCOORDSIZE2(2)

and your struct is


struct CUSTOMVERTEX
{
FLOAT x, y, z; // Position
FLOAT nx, ny, nz; // Normals
DWORD diffuse; // Diffuse colour
DWORD specular; // Specular colour
FLOAT tu1, tv1; // Texture coords
FLOAT tu2, tv2;
FLOAT tu3, tv3;
};


Rory.

Share this post


Link to post
Share on other sites
do i still need three sets of texture coordinates even if they will be the same? it seems like such a waste when its going to be put into a pretty large array.

also, how do i set the r or the g or the b of a DWORD? i know you have to do something with bit masks, but i never understood that totally. how do i say, set the Diffuse red to 1.0f?

EDIT: also, 90% of the terrain will not be multitextured, like it will be 100% of one texture. will the video card see that it will not have an effect and discard it, or render it anyway with 0% alpha? that would be a huge waste

[edited by - billybob on July 26, 2002 11:01:02 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by billybob
do i still need three sets of texture coordinates even if they will be the same? it seems like such a waste when its going to be put into a pretty large array.

also, how do i set the r or the g or the b of a DWORD? i know you have to do something with bit masks, but i never understood that totally. how do i say, set the Diffuse red to 1.0f?

EDIT: also, 90% of the terrain will not be multitextured, like it will be 100% of one texture. will the video card see that it will not have an effect and discard it, or render it anyway with 0% alpha? that would be a huge waste

[edited by - billybob on July 26, 2002 11:01:02 AM]


You need the same number of texture coords as texture stages for the fixed function pipeline as far as I am aware.

There is a macro, D3DCOLOR_ARGB which does the colour masking for you.

If you are not using multiple textures for particular sections of the terrain then I would suggest rendering those sections separately and let them use a reduced vertex format (pos, normal and 1 set of tex coords).

Rory.

Share this post


Link to post
Share on other sites
quote:
do i still need three sets of texture coordinates even if they will be the same? it seems like such a waste when its going to be put into a pretty large array.


Of course not. We assumed that the tex coords and textures used will be different sizes but if they arn't, then go ahead and use the same ones. One thing I will recommend though when setting up your coords is make them wrap so that you don't get one small grass texture stretched across a large terrain. Make it wrap across so that you can keep the detail. Edit: note, to tell which tex coords are being used, look into the settexturestagestate values, I'm sure it's one of them.

quote:
also, how do i set the r or the g or the b of a DWORD? i know you have to do something with bit masks, but i never understood that totally. how do i say, set the Diffuse red to 1.0f?


Most people use the D3DCOLOR_ARGB macro but if you want to set individual colors, you'll have to do a bit of bit shifting. I havn't tried these and I'm writing them off the top of my head but they MIGHT work. If they don't work, let me know and I'll try and make them work:

#define SetAlpha(c,v) (((v&0xff)<<24)|c)
#define SetRed(c,v) (((v&0xff)<<16)|c)
#define SetGreen(c,v) (((v&0xff)<<8)|c)
#define SetBlue(c,v) ((v&0xff)|c)

quote:
also, 90% of the terrain will not be multitextured, like it will be 100% of one texture. will the video card see that it will not have an effect and discard it, or render it anyway with 0% alpha? that would be a huge waste


It will do what you tell it to. If you tell it to linear interpolate between the colors with 100% of one, it will still do the math. A better solution maybe would be to group it into groups which arn't 100% of one and a group of which are. Then render the multitextured ones using texture stages and for the rest just set the texture needed and render. It would proble speed things up a bit.



---
My Site
Come join us on IRC in #directxdev @ irc.afternet.org

[edited by - RapidStunna on July 26, 2002 11:31:06 AM]

Share this post


Link to post
Share on other sites