Jump to content
  • Advertisement
Sign in to follow this  
renanrosa

Put Textures in a Texture (MultiTextures)

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

Hello guys, I researched a little, but I found nothing, to know how to put a texture in a texture (what ? lol). example I got my map (a file . X) is a forest, so I have a great texture that goes on top, it has two colors, green and brown, then, i wanted to put grass texture where is green, and i wanted to put sand texture where is brown Anybody know how to do it? have a sample ? (I try this http://www.applicachia.com/HLSLTexBlend.zip but have error in compilation) thank guys :D

Share this post


Link to post
Share on other sites
Advertisement
This doesn't have to necessarly use a texture atlas (multiple textures in a texture), it is probably a good idea to go for multitexturing.

However, you are not clear on the data you have. You say you have a forest and a great texture to apply - by planar projection? - so, are you trying to mask the grass/sand textures by the first texture? Are texture cordinates otherwise available?

You may want then to try just alphablending the two such as taking the alpha from the first 'big' texture and use it as a lerp factor for the grass/sand textures.
In other words, working with values as 'green' and 'brown' is pretty ankward.

Share this post


Link to post
Share on other sites
Quote:
Original post by Krohm
This doesn't have to necessarly use a texture atlas (multiple textures in a texture), it is probably a good idea to go for multitexturing.

However, you are not clear on the data you have. You say you have a forest and a great texture to apply - by planar projection? - so, are you trying to mask the grass/sand textures by the first texture? Are texture cordinates otherwise available?

You may want then to try just alphablending the two such as taking the alpha from the first 'big' texture and use it as a lerp factor for the grass/sand textures.
In other words, working with values as 'green' and 'brown' is pretty ankward.


i dont understand, have a sample ?

Share this post


Link to post
Share on other sites
Having taken a cursory look at http://www.applicachia.com/HLSLTexBlend.zip, I don't think it will help you.

Seems like what you want is something like: (this is pseudo code, not HLSL)


type = groundDescriptionTexture.sample(coords)
if (type == green)
colour = grassTexture.sample(coords * scale)
else if (type == brown)
colour = sandTexture.sample(coords * scale)

Share this post


Link to post
Share on other sites
Quote:
Original post by ET3D
Having taken a cursory look at http://www.applicachia.com/HLSLTexBlend.zip, I don't think it will help you.

Seems like what you want is something like: (this is pseudo code, not HLSL)


type = groundDescriptionTexture.sample(coords)
if (type == green)
colour = grassTexture.sample(coords * scale)
else if (type == brown)
colour = sandTexture.sample(coords * scale)



sure, but how i do in C++ and how i use multi texture and more of 2 in a only place ?
have a code ?
see my code render map:

//i load the .x file
d3dxloadmeshfromx(...);
//aplly texture
device->setTexture..(..., GRASS);
mapX->DrawSubset(..);

//how i add multi texture and your coords ?



sorry the questions :)

hugs

Share this post


Link to post
Share on other sites
Besides multi-texturing, the term is also sometimes called "Texture Splatting" or "Terrain Splatting". The way to correctly generate the tiled/non-tiled U,V coordinates is quite specific to how your images and terrain mesh were created.

Here's a picture of terrain splatting from my current project:

Photobucket

Here's my HLSL if it helps you. It allows the caller of DrawIndexedPrimitive to splat the terrain using up to 4 blend maps each encoding the alpha percentage of up to 3 splat textures using their RGB channels (for a total of 12 splat textures per draw call, each one layered onto the other). Instead of replicating 12 different pixel shaders I combined them into a "super-shader" that uses boolean 0.0f/1.0f arrays to determine if a particular blend map or splat texture is bound to the draw call. You might choose to do it the other way (I've done both and couldn't tell the difference on three different machines including one that was fillrate limited, using a data set that was pretty layer-heavy).


#define MAX_BLENDS (4)
#define MAX_SPLATS (MAX_BLENDS * 3)

uniform extern int gPatchRow;
uniform extern int gPatchCol;
uniform extern float4x4 gViewProj;
uniform extern float4x4 gWorld;
uniform extern float3 gEyePosW;

uniform extern texture gSplatTex0;
uniform extern texture gSplatTex1;
uniform extern texture gSplatTex2;
uniform extern texture gSplatTex3;
uniform extern texture gSplatTex4;
uniform extern texture gSplatTex5;
uniform extern texture gSplatTex6;
uniform extern texture gSplatTex7;
uniform extern texture gSplatTex8;
uniform extern texture gSplatTex9;
uniform extern texture gSplatTex10;
uniform extern texture gSplatTex11;

uniform extern texture gBlendMap0;
uniform extern texture gBlendMap1;
uniform extern texture gBlendMap2;
uniform extern texture gBlendMap3;

uniform extern float g_hasBlend[ MAX_BLENDS ];
uniform extern float g_hasSplat[ MAX_SPLATS ];
uniform extern float gTexScale[ MAX_SPLATS ];

struct DirLight
{
float4 ambient;
float4 diffuse;
float4 spec;
float3 dirW;
};
uniform extern DirLight gLight;

uniform extern float gFogRange;
static float4 gFogColor = {0.55f, 0.66f, 0.85f, 1.0f};
static float gFogStart = 1.0f;

sampler SplatTex0S = sampler_state
{
Texture = <gSplatTex0>;
MinFilter = ANISOTROPIC;
MagFilter = LINEAR;
MipFilter = LINEAR;
MaxAnisotropy = 8;
AddressU = WRAP;
AddressV = WRAP;
};
sampler SplatTex1S = sampler_state
{
Texture = <gSplatTex1>;
MinFilter = ANISOTROPIC;
MagFilter = LINEAR;
MipFilter = LINEAR;
MaxAnisotropy = 8;
AddressU = WRAP;
AddressV = WRAP;
};
sampler SplatTex2S = sampler_state
{
Texture = <gSplatTex2>;
MinFilter = ANISOTROPIC;
MagFilter = LINEAR;
MipFilter = LINEAR;
MaxAnisotropy = 8;
AddressU = WRAP;
AddressV = WRAP;
};
sampler SplatTex3S = sampler_state
{
Texture = <gSplatTex3>;
MinFilter = ANISOTROPIC;
MagFilter = LINEAR;
MipFilter = LINEAR;
MaxAnisotropy = 8;
AddressU = WRAP;
AddressV = WRAP;
};
sampler SplatTex4S = sampler_state
{
Texture = <gSplatTex4>;
MinFilter = ANISOTROPIC;
MagFilter = LINEAR;
MipFilter = LINEAR;
MaxAnisotropy = 8;
AddressU = WRAP;
AddressV = WRAP;
};
sampler SplatTex5S = sampler_state
{
Texture = <gSplatTex5>;
MinFilter = ANISOTROPIC;
MagFilter = LINEAR;
MipFilter = LINEAR;
MaxAnisotropy = 8;
AddressU = WRAP;
AddressV = WRAP;
};
sampler SplatTex6S = sampler_state
{
Texture = <gSplatTex6>;
MinFilter = ANISOTROPIC;
MagFilter = LINEAR;
MipFilter = LINEAR;
MaxAnisotropy = 8;
AddressU = WRAP;
AddressV = WRAP;
};
sampler SplatTex7S = sampler_state
{
Texture = <gSplatTex7>;
MinFilter = ANISOTROPIC;
MagFilter = LINEAR;
MipFilter = LINEAR;
MaxAnisotropy = 8;
AddressU = WRAP;
AddressV = WRAP;
};
sampler SplatTex8S = sampler_state
{
Texture = <gSplatTex8>;
MinFilter = ANISOTROPIC;
MagFilter = LINEAR;
MipFilter = LINEAR;
MaxAnisotropy = 8;
AddressU = WRAP;
AddressV = WRAP;
};
sampler SplatTex9S = sampler_state
{
Texture = <gSplatTex9>;
MinFilter = ANISOTROPIC;
MagFilter = LINEAR;
MipFilter = LINEAR;
MaxAnisotropy = 8;
AddressU = WRAP;
AddressV = WRAP;
};
sampler SplatTex10S = sampler_state
{
Texture = <gSplatTex10>;
MinFilter = ANISOTROPIC;
MagFilter = LINEAR;
MipFilter = LINEAR;
MaxAnisotropy = 8;
AddressU = WRAP;
AddressV = WRAP;
};
sampler SplatTex11S = sampler_state
{
Texture = <gSplatTex11>;
MinFilter = ANISOTROPIC;
MagFilter = LINEAR;
MipFilter = LINEAR;
MaxAnisotropy = 8;
AddressU = WRAP;
AddressV = WRAP;
};

sampler BlendMap0S = sampler_state
{
Texture = <gBlendMap0>;
MinFilter = Point;
MagFilter = Linear;
MipFilter = Point;
AddressU = Clamp;
AddressV = Clamp;
};
sampler BlendMap1S = sampler_state
{
Texture = <gBlendMap1>;
MinFilter = Point;
MagFilter = Linear;
MipFilter = Point;
AddressU = Clamp;
AddressV = Clamp;
};
sampler BlendMap2S = sampler_state
{
Texture = <gBlendMap2>;
MinFilter = Point;
MagFilter = Linear;
MipFilter = Point;
AddressU = Clamp;
AddressV = Clamp;
};
sampler BlendMap3S = sampler_state
{
Texture = <gBlendMap3>;
MinFilter = Point;
MagFilter = Linear;
MipFilter = Point;
AddressU = Clamp;
AddressV = Clamp;
};

struct DAOCSplatOutputVS
{
float4 posH : POSITION0;
float2 tiledTexC : TEXCOORD0;
float2 nonTiledTexC : TEXCOORD1;
float shade : TEXCOORD2;
float fogLerpParam : TEXCOORD3;
};

DAOCSplatOutputVS DAOCSplatTerrainVS( float3 posW : POSITION0,
float2 tex0 : TEXCOORD0,
float1 height : TEXCOORD1,
float3 normalW : NORMAL0,
uniform int patchRow,
uniform int patchCol
)
{
// Zero out our output.
DAOCSplatOutputVS outVS = (DAOCSplatOutputVS)0;

//
// Just compute a grayscale diffuse and ambient lighting
// term: terrain has no specular reflectance. The color
// comes from the texture.
//
outVS.shade = saturate(max(0.0f, dot(normalW, -gLight.dirW)));

// Adjust the vertex height based on the second stream's data
float4 posT = mul(float4(posW, 1.0f), gWorld);
posT.y += height;

// Transform to homogeneous clip space.
outVS.posH = mul(posT, gViewProj);

// Pass on texture coordinates to be interpolated in rasterization.
outVS.nonTiledTexC = tex0; // Blend map not tiled.
tex0.x = (tex0.x * (1.0f / 8.0f)) + (patchRow / 8.0f);
tex0.y = (tex0.y * (1.0f / 8.0f)) + (patchCol / 8.0f);
outVS.tiledTexC = tex0; // Scale tex-coord to tile.

// Compute vertex distance from camera in world space for fog calculation.
float dist = distance(float3(posT.xyz), gEyePosW);
outVS.fogLerpParam = saturate((dist - gFogStart) / gFogRange);

// Done--return the output.
return outVS;
}

float4 DAOCSplatTerrainPS12( float2 tiledTexC : TEXCOORD0,
float2 nonTiledTexC : TEXCOORD1,
float shade : TEXCOORD2,
float fogLerpParam : TEXCOORD3) : COLOR
{
//
// Layer maps are tiled
//
float3 c0 = tex2D(SplatTex0S, tiledTexC * gTexScale[ 0 ]).rgb;
float3 c1 = tex2D(SplatTex1S, tiledTexC * gTexScale[ 1 ]).rgb * g_hasSplat[ 1 ];
float3 c2 = tex2D(SplatTex2S, tiledTexC * gTexScale[ 2 ]).rgb * g_hasSplat[ 2 ];

float3 c3 = tex2D(SplatTex3S, tiledTexC * gTexScale[ 3 ]).rgb * g_hasSplat[ 3 ];
float3 c4 = tex2D(SplatTex4S, tiledTexC * gTexScale[ 4 ]).rgb * g_hasSplat[ 4 ];
float3 c5 = tex2D(SplatTex5S, tiledTexC * gTexScale[ 5 ]).rgb * g_hasSplat[ 5 ];

float3 c6 = tex2D(SplatTex6S, tiledTexC * gTexScale[ 6 ]).rgb * g_hasSplat[ 6 ];
float3 c7 = tex2D(SplatTex7S, tiledTexC * gTexScale[ 7 ]).rgb * g_hasSplat[ 7 ];
float3 c8 = tex2D(SplatTex8S, tiledTexC * gTexScale[ 8 ]).rgb * g_hasSplat[ 8 ];

float3 c9 = tex2D(SplatTex9S, tiledTexC * gTexScale[ 9 ]).rgb * g_hasSplat[ 9 ];
float3 c10 = tex2D(SplatTex10S, tiledTexC * gTexScale[ 10 ]).rgb * g_hasSplat[ 10 ];
float3 c11 = tex2D(SplatTex11S, tiledTexC * gTexScale[ 11 ]).rgb * g_hasSplat[ 11 ];

//
// Blendmaps are not tiled.
//
float3 B0 = tex2D(BlendMap0S, nonTiledTexC).rgb;
float3 B1 = (tex2D(BlendMap1S, nonTiledTexC).rgb) * g_hasBlend[ 1 ];
float3 B2 = (tex2D(BlendMap2S, nonTiledTexC).rgb) * g_hasBlend[ 2 ];
float3 B3 = (tex2D(BlendMap3S, nonTiledTexC).rgb) * g_hasBlend[ 3 ];

//
// INVSRC ALPHA blend + fog + light
//
float3 color = (c0 * shade);
color = (B0.g * c1) + (1 - B0.g) * color;
color = (B0.b * c2) + (1 - B0.b) * color;

color = (B1.r * c3) + (1 - B1.r) * color;
color = (B1.g * c4) + (1 - B1.g) * color;
color = (B1.b * c5) + (1 - B1.b) * color;

color = (B2.r * c6) + (1 - B2.r) * color;
color = (B2.g * c7) + (1 - B2.g) * color;
color = (B2.b * c8) + (1 - B2.b) * color;

color = (B3.r * c9) + (1 - B3.r) * color;
color = (B3.g * c10) + (1 - B3.g) * color;
color = (B3.b * c11) + (1 - B3.b) * color;

return (lerp(float4(color, 1.0f), gFogColor, fogLerpParam));
}

technique DAOCSplatTech
{
pass P0
{
//////////////////////////////////////////////////
VertexShader = compile vs_2_0 DAOCSplatTerrainVS( gPatchRow, gPatchCol );
PixelShader = compile ps_2_0 DAOCSplatTerrainPS12( );
//////////////////////////////////////////////////
CullMode = CCW;
//////////////////////////////////////////////////
StencilEnable = false;
AlphaBlendEnable = false;
AlphaTestEnable = false;
ZWriteEnable = true;
//////////////////////////////////////////////////
ZFunc = Less;
SrcBlend = SrcAlpha;
DestBlend = InvSrcAlpha;
AlphaRef = 0x0000005A;
AlphaFunc = Greater;
//////////////////////////////////////////////////
}
}



How to use the above technique/shaders.

You will need to set the following uniform externs in C++ before making a DrawIndexedPrimitive(DIP) call:

gLight structure containing information about the directional light affecting the terrain.
gWorld and gViewProj will contain the WVP matrices.
gEyePosW is used for exponential fogging and describes the camera's position in world space coordinates.
gFogRange is the saturation limit of the exponential fog in world coordinates.
A float array of four 0.0f/1.0f boolean values identifying which blend maps are set (g_hasBlend[]).
A float array of twelve splat texture tiling scales, which indicates how many times across the entire terrain to tile the splat texture (gTexScale[]).
A float array of twelve 0.0f/1.0f boolean values identifying which splat textures are set (g_hasSplat[]).
The "patch" row and column of the patch being drawn by this DIP call (gPatchRow, gPatchCol).

Then you need to SetTexture for each blend map (gBlendMap0..3) and splat texture (gSplatTex0..11) you want to use for this terrain patch.

The vertex buffer input to the vertex shader is as follows:

// Stream 0
D3DXVECTOR3 xyzPosition;
D3DXVECTOR2 tex0;
// Stream 1
float height;
D3DXVECTOR3 normalVector;

You will need two vertex stream sources. The first one will have the information about a completely flat MxN terrain patch (i.e. height == 0.0f) with procedurally generated (u,v) coordinates.

The second stream contains a single float per-vertex describing that vertices height as well as a normal vector per vertex.

In my implementation I divided my overall terrain into 8x8 patches with each patch being 32x32 rows and columns.

The input to the pixel shader is provided by the HLSL above. The (u,v) coordinates were generated to span a patch, not the entire terrain and are re-computed to span the entire terrain in the vertex shader (this made streaming huge terrains from disk easier for me).

Share this post


Link to post
Share on other sites
oh shit, :)
this is very hard :)
but I realized I need to study more.
I will leave aside a little, and i go study anymore.
thank

and nice project :)
hugs

Share this post


Link to post
Share on other sites
Nice to see someone is getting some use out of my website. The reason you're most likely getting compilation errors is because I wrote that code 4 years ago and there is some stuff that no longer works. Open up the file TextureBlending.fx, and change these 2 lines from:

vertexshader = compile vs_1_1 VS();
pixelshader = compile ps_1_1 PS();

to this:

vertexshader = compile vs_2_0 VS();
pixelshader = compile ps_2_0 PS();

That should fix your compilation errors.

Share this post


Link to post
Share on other sites
Quote:
Original post by bengaltgrs
Nice to see someone is getting some use out of my website. The reason you're most likely getting compilation errors is because I wrote that code 4 years ago and there is some stuff that no longer works. Open up the file TextureBlending.fx, and change these 2 lines from:

vertexshader = compile vs_1_1 VS();
pixelshader = compile ps_1_1 PS();

to this:

vertexshader = compile vs_2_0 VS();
pixelshader = compile ps_2_0 PS();

That should fix your compilation errors.


oh shit worked, this site is your ?
very nice nice * 99999999, your site helped me a lot,
collision of .x meshs and textures :)
congratulations for the site
i'm brazilian and i said the site for all
thank you very much much :)

Share this post


Link to post
Share on other sites
Quote:
Original post by bengaltgrs
Nice to see ...



Hi, sorry,
how i desable light of the texture in this file ? :(
in directx/c++:
Quote:

g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, D3DCOLOR_XRGB(50,50,50) );

thank :)

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!