Archived

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

Raloth

texture splatting question

Recommended Posts

Raloth    379
Here is the article http://www.cbloom.com/3d/techdocs/splatting.txt and screenshots: http://www.cbloom.com/3d/splatting/index.html Ok, now my question: To make textures blend, the author builds an alpha map. The thing I don''t understand is how does he actually get them to blend in to each other? Does he overlap the textures? Take the situation A A B A A B A A B Does he render A on top of the Bs and Bs on top of the middle As? This would take a lot of vertices if you have an involved terrain, but it''s the only thing I can think of. Can anyone who has implemented this technique give me some direction?

Share this post


Link to post
Share on other sites
noisecrime    817
Texture splatting is based on rendering the terrain within a set radius of the camera, once per a texture. That means several passes, or multi-texturing.

So you should have a single mesh, that is rendered once per a texture, with the alpha values determining the opacity of the texture being render. Each texture/pass can have different UV or scaling to others too.

Of course you can take it further, so if your terrain is split into chunks (quadtree for example), then you can apply texture splatting to only those chunks within a certain radius. Furthermore each chunk can hold information about how many textures it needs splattered, that way you don't have to limit yourself to always rendering x number of textures, but only those that are needed. In addition it means you could also have a large number of textures across the whole terrain, but each chunk might only have say 3 different textures max.

Hope that helps.


[edited by - noisecrime on August 11, 2003 11:17:30 PM]

Share this post


Link to post
Share on other sites
Raloth    379
So I render all the vertices for each texture? I wish this guy would say these things up front instead of making obscure references to them . Can you give me a quick overview of what I have to do to render everything?

Share this post


Link to post
Share on other sites
Chaucer    122
I''ve been working on this same thing for awhile. Please let me know if you get it working. I can''t get my alpha map to line up with my terrain (quadtree). I get sharp edges in lots of places and no matter how I try to stretch or move the alpha map, I can''t seem to get in the right position.

I''m not using the exact method of finding the weights as him. I''ve tried both a 2x2 alpha map where each pixel is the weight at one corner of a tile and a 1x1 alpha map where each pixel is the weight at the bottom left corner of each tile. The 2x2 alpha map gives me better results than the 1x1 but it''s still not right. Anyway, I''d love to hear how you got it working, if you do. Thanks

Share this post


Link to post
Share on other sites
jesterlecodeur    122
Use a bigger alpha map.
Between chunk you will have some edges, then you alpha map fonction must take care of edges values from neighbourhood.

Currently I use this method
where alphaMap is a array where each vertices has a materialID.

// Alpha Map generation
static const int ALPHA_MAP_SIZE = 32;
EcomPtr alphaTexture[3];
static uint8_t alphaMap[ALPHA_MAP_SIZE*ALPHA_MAP_SIZE];
for(int j = 1; j < 3; j++)
{
if(nb[j] == 0)
continue;
for(int v = 0; v < ALPHA_MAP_SIZE; v++)
for(int u = 0; u < ALPHA_MAP_SIZE; u++)
alphaMap[v * ALPHA_MAP_SIZE + u] = 0x00;

for(int y = 0; y < nbVertexPerRow; y++)
for(int x = 0; x < nbVertexPerRow; x++)
{
if(influenceMap[y*nbVertexPerRow + x] != j)
continue;
if(y > 0 && x > 0)
alphaMap[(y-1) * ALPHA_MAP_SIZE + x - 1] += 0xff/4;
if(y > 0 && x + 1 < nbVertexPerRow)
alphaMap[(y-1) * ALPHA_MAP_SIZE + x] += 0xff/4;
if(x > 0 && y + 1 < nbVertexPerRow)
alphaMap[y * ALPHA_MAP_SIZE + x - 1] += 0xff/4;
if(y + 1 < nbVertexPerRow && x + 1 < nbVertexPerRow)
alphaMap[y * ALPHA_MAP_SIZE + x] += 0xff/4;
}
mDisplay->CreateTexture(alphaMap, ALPHA_MAP_SIZE, ALPHA_MAP_SIZE,
0, Gfx::FormatA8,
Gfx::ITexture::IID, (void**)&alphaTexture[j]);
}

For each "tile" and each material I add 25% of opacity for the material at this tile for each neighbouring vertex which have this material.

It''s not the best way I think, but for now I have good result.

PS: Sorry for my english.

_______________

Jester, studient programmer
The Jester Home in French

Share this post


Link to post
Share on other sites
Chaucer    122
Hmm. I''m not sure if I follow you exactly.

If I move my alpha map to a 3x3, then I should be able to have a weight for each vertex and each edge of the tile. If that is what you''re telling me to do, I''m afraid it may be too inefficient. It would then take a very long time to load the terrain, having to generate so many values on the alpha map.

I''ve seen screenshots where people have done it with a 1x1 alpha map and it looks right to me. There must be something else I''m doing wrong.

Share this post


Link to post
Share on other sites
noisecrime    817
Chaucer,

I''m not sure what you''re trying to do, but its not the classic terrain splattering that I understand. You appear to be focusing on a purely tile based environemnt, like old 2D games.

The concept of Terrain splattering as asked by the orginal poster was in terms of an entire landscape, where several textures are ''tiled'' across it. In these terms the alpha component is not per a tile, but per the whole landscape (or chunks if divided up).

For example,

1. Terrain mesh based of a 256x256 hieght map
2. 3 tilable textures (grass, mud, stone) of say 512x512 depending upon how detailed you want the texture to be (i.e. how close the camera is going to get to them)
3. 3 alpha textures of 256x256 i.e. 1 pixel per a vertex in the hieghtmap

So the textures may be tiled say 10 times across the terrain mesh, that is 1 tile per 25 vertices. Yet the alpha texture is only tiled once across the whole terrain, giving an alpha value (weight) 1 per a vertex.

This allows you to control the detail level of each texture (its pixel size), the number of times it is physically tiled across the terrain mesh, and each cell/quad of the hieght map can have any mix of the 3 textures.

Using an alpha of a 1:1 ratio with the number of vertices across the terrain means you can simply assign the alpha component as a weight to each vertex, so i don''t think its necessary to actually render it. However if you want finer control then you''d use a larger size alpha map, and actually render the alpha with the texture.

Share this post


Link to post
Share on other sites
Chaucer    122
Right. That is the way I'm doing it now. I have an alpha map for each type of texture I use (1 for grass, 1 for rock, etc.)

I render using multiple passes...
For each pass I do

1. Render texture using texcoord1
2. Render alpha map using texcoord2
3. Render lightmap using texcoord2

To calculate texcoord1 and texcoord2, I do

------------------------------------------------------

for(int z=0;z<m_Size;z++)
{
for(int x=0;x<m_Size;x++)
{

float X = (float)x;
float Z = (float)z;

m_pVertices[vertCount].tex1 = D3DXVECTOR2(X,Z);
m_pVertices[vertCount].tex2 = D3DXVECTOR2(X/m_Size, Z/m_Size);

}
}

------------------------------------------------------
To calculate alpha map, I do

for(int j=0;j<m_NumTexture;j++)
CreateAlphaMap(j, m_Size-1);

for(int z=0;z<m_Size-1;z++)
{
for(int x=0;x<m_Size-1;x++)
{

//Since the pixel cooresponds to the bottom left vertex, I find //the four vertices around it by doing this:


int current = GetTextureType(x,z);
int left = GetTextureType(x-1,z);
int bottomleft = GetTextureTYpe(x-1,z-1);
int bottom = GetTextureType(x,z-1);

for(int j=0;j<m_NumTextures;j++)
{
float percent=0.0f;
if(j == current || j == left || j == bottomleft || j == bottom)
{
if(j == current) percent+=1.0f;
if(j == left) percent+=1.0f;
if(j == bottomleft) percent+=1.0f;
if(j == bottom) percent+=1.0f;
percent/=4.0f;
}
AlphaMapTexture[j]->SetAlphaMapPixel(percent);
}
}
}

------------------------------------------------------

So I have one alpha pixel per each vertex in the terrain or chunk or whatever. I can post a screenshot if you'd like to see the effect I'm getting. I basically get a really good blend sometimes but other times I get a hard edge. I've tried moving the alpha map to fit properly on the terrain since it's 2^N and the terrain is 2^N+1 but its still not working.

Thanks for the help.




[edited by - Chaucer on August 13, 2003 5:49:59 PM]

Share this post


Link to post
Share on other sites
jesterlecodeur    122
I do it the same way as you.
The SetAlphaMapPixel(percent); seem strange as you don''t give where to put the percent in the alpha map but anyway.

The difference is that I use chunk of 32*32 tiles (33*33 vertices) so I use a 32*32 alphamap for each chunk. But if your chunk is 1*1 tiles OK.

I have hardedge to, but it''s very rare, and it''s between chunk, certainly billinear filtering of the alpha map, I need to fix it.

_______________

Jester, studient programmer
The Jester Home in French

Share this post


Link to post
Share on other sites
Raloth    379
Hmm that''s not the way I interpreted it. I have a chunk of 32x32 tiles, which should be 32x32x4 vertices. The reason is texcoord0 is your terrain texture and is on a 0,1 basis, while texcoord1 is on a x/32 basis. The alpha stretches over the entire section but the tile textures are repeated every tile. Bleh, I don''t know how to explain it. Maybe someone should right an article about this .

Share this post


Link to post
Share on other sites
Chaucer    122
Here's my writepixel function

void WritePixel(D3DLOCKED_RECT rect, BYTE **ppData, int x, int y, D3DXCOLOR pixel)
{
int index = (y*rect.Pitch)+(x*4);
(*ppData)[index++] = (BYTE)(pixel.b*255);
(*ppData)[index++] = (BYTE)(pixel.g*255);
(*ppData)[index++] = (BYTE)(pixel.r*255);
(*ppData)[index++] = (BYTE)(pixel.a*255);
}

My chunk is 33x33 vertices and my alpha map is 32x32. The alpha map SHOULD be stretched across the entire chunk since the values for each map is determined on a per chunk basis. ie there's a 32x32 map for a 33x33 vertices chunk. The tile textures have to be repeated in-order for the terrain to work. I'm not going to draw one tile at a time.. Instead, my index buffers are split up into triangle lists for each type of texture. SO i render the geometry for a texture, apply alpha map, move on to next texture. I don't render the geometry for every texture on the list, just the first one. Maybe I should re-write it to just simply do a triangle strip across the entire chunk since multiple textures are used, but I still don't see how one texture would want to be applied over an entire 33x33 chunk.

[edited by - Chaucer on August 13, 2003 12:28:30 AM]

Share this post


Link to post
Share on other sites
Raloth    379
Ah! I was doing it a different way . Your way seems much better - dramatically reduces the number of vertices you need. Forget what I said! Even better is your alpha map generation, which is the one thing I can''t quite get to work,other than a really weird index buffer problem which I can ignore for now. See my other post in the DirectX forum if you think you can help. Do you mind if I base my code off of yours? (the pitch thing kind of confuses me)

Share this post


Link to post
Share on other sites
Chaucer    122
Yeah that''s fine with me. Especially if you can help me figure out the hard edge problem

Well to make it simple, you can just think of the pitch as the width of the texture. However, the pitch is not equal to the width of the texture but the width of the memory the texture is using. Maybe that didn''t make sense.

The pitch is used to find the correct spot in memory since the memory usage of a texture is not necessarily equal to the width of the texture. Luckily, you don''t have to worry about calculating the pitch or anything, since it''s done for you. You just have to say rect.Pitch the way i''ve done it when you want to specify a pixel.

Share this post


Link to post
Share on other sites
Chaucer    122
jesterlecodeur,
so what you''re telling me is that you stretch one texture across your entire chunk? Wouldn''t this give a very low detail of the texture?

Share this post


Link to post
Share on other sites