Tiles in 3D?

Started by
8 comments, last by Ilankt 20 years, 10 months ago
well, i got a question, how (in theory) i can make a tiles for an engine like in WC3 or SIMCITY 4? in 2D i know how to do it, but its kind of diffrent in 3D, right? so, any ideas?
How appropriate, you fight like a cow!
Advertisement
Ok... it's a bit longer but as I have already done this in a terrain engine (see http://www.sun-a-moon.org/index_proj.htm and there Race Tracks Unlimited)...

first of all you have a regular grid with quads (2 triangles making one quad).
Then you have 2 layer.

The first layer contains the base ground texture for an entire quad. Imagine that you have 4 ground types : sand, rock, grass and mud. You give them an order. ie :

a=rock
b=sand
c=mud
d=grass

your tiles now look like this :

 A   B   C   D   E0*---*---*---*---* | a | b | b | c |1*---*---*---*---* | a | c | c | c |2*---*---*---*---* | c | c | d | d |3*---*---*---*---* 


As you can see, the grid is regular and there are
always entire tiles with one (1) ground type in it.

Your tiles are then A0->B0->B1->A1 then B0->C0->C1->B1
and so on.

What you need now are the transitions between the different
underground types. It becomes a little bit more complicated
here :

A transition is done from a higher level ground type to a
lower level one. This means that you would draw the transition
from sand to rock but not from rock to sand.

In our example there are a lot of transitions. But let's take
only 2 or 3 :

The first 2 tiles on the upper left side are the tiles A0->B0->B1->A1 then B0->C0->C1->B1 and their contain underground a and
underground b.

Since b is higher level than a, we have to draw a transition in tile A0->B0->B1->A1.

A transition is again done on the entire tile. So we have to draw a tile A0->B0->B1->A1 that encodes the transition. To make a transition, we have to take a look at the corners of the tile and determine whether or not the adjacent tiles influence this one.

The tile is :
A     B *---* |   | *---*C     D 


we have to examine the corner A then B then C then D. We give each corner a bit and encode it into 4 bits : DCBA

We now do following :

Given our tile is at position X, Y we do (for eaxh underground
type != the tile underground) :

count=0bitfield=0for each X' = X-1 to X+1  if (X'==0) skip  for each Y' = Y-1 to Y+1    if (Y'==0) skip    if ( count == 0 )       count = 1    else       count << 1    if ( tile(X',Y') != tile underground )       bitfield |=count  end forend for 

in this way we encode for each underground type a bitfield for this type that encodes a value from 0 to 15.

If the value is 0 there is no need to render a tile with that
underground type.

if the value is 15 then the entire tile is covered by that
underground type and you should change the layer 1 underground
type to the current checked one

if the value is != 0 then you have an index to one of 14 textures
(or texture coordinates) that contains the corner GFX. Example

Value 1 :O---*|   |*---*Value 2 :*---O|   |*---*Value 3 :O---O|   |*---*Value 4 :*---*|   |*---OValue 5 :O---*|   |*---OValue 6 :*---O|   |*---Oand so on untilValue 14 :*---O|   |O---O 


You create like this all the tiles you need with the transitions.

I would create 2 textures :

Texture A with the complete tile underground types

Texture B with the transitions encode as mentioned above.

If you use a tiling size of 64x64 pixels then you could create
a Texture A with 512x512 pixels and therefore store 8 different underground types with 8 variations (ie. gras, gras with flower, gras with a stone, etc).

The transition texture would have to be double size (ie. 1024x512) to support the 14 transitions ie along the X Axis and the 8 underground types along the Y Axis.

I hope this helps... don't hesitate to ask if something isn't clear enough...

Metron

[edited by - Metron on June 18, 2003 9:43:23 AM]
----------------------------------------http://www.sidema.be----------------------------------------
I think I''ll dig out the source code... that should make it more clear... can''t do it yet... perhaps this evening...

----------------------------------------http://www.sidema.be----------------------------------------
THANKS!!!
btw nice screenshots!
How appropriate, you fight like a cow!
Metron, there should be more people like you.
-------homepage - email
I have a question Metron...

What I''m missing from your example is your tiles look like this :

 A   B   C   D   E0*---*---*---*---* | a | b | b | c |1*---*---*---*---* | a | c | c | c |2*---*---*---*---* | c | c | d | d |3*---*---*---*---* 


If "b" overrides tile "a" in A0,B1, what happens when you get to the "c" that is in B1,C2?

How do you handle cases like for B1,C2 where it is "c" and surrounded by "a", "b" and "d" types? How does the blend work since it seems you have to blend 4 types together to get a smooth transition?
Hi again...

I have to make a small correction. It has been some time since I've done it and I took a look at my code and my structures

First of all :

The terrain types aren't stored in the tiles but within the corners of the tile. If a tile is defined like this :

A     B *---* |   | *---*D     C   


then it's only possible to have 4 different terrain underground types per tile.

First some structures :
struct STerrainCorner{	AR::CMVector3D	m_vPosition;		// x-y-z position of the corner.	AR::CMVector3D	m_vNormal;			// normal vector of the corner.	ulong			m_uColor;			// color of the corner.		ulong			m_uTerrainType;		// Terrain type of the corner.};struct STerrainTile{	STerrainCorner	*m_pCorner[4];		// Maximum 4 corners per tile.	AR::CMVector3D	m_vNormal;			// normal vector of the tile.	ulong			m_uTerrainType;		// Dominant type of terrain for this tile.};    


Here now 2 functions. The first one calculates the terrain type dominance for a given tile:

// ----------------------------------------------------------// Calculate the terrain underground dominance.voidCTerrain::CalculateTerrainTypeTileDominance(STerrainTile* _pTerrainTile){	ASSERT( _pTerrainTile );	ulong	uCurCorner;	byte	uTerrainType;	byte	uDominant	= 255;		STerrainCorner** ppCorners = _pTerrainTile->m_pCorner;	// Determine the number of different corners and write them into a list.	for ( uCurCorner=0; uCurCorner<4; uCurCorner++)	{		uTerrainType = ppCorners[uCurCorner]->m_uTerrainType & 0x0f;		if ( uDominant > uTerrainType )		{			uDominant = uTerrainType;		}	}		// Fast case -> All the same.	_pTerrainTile->m_uTerrainType = uDominant;}    


The second one calculates the blending :

// ----------------------------------------------------------// Calculate the terrain underground dominance.ARMETHODIMP(ulong)CTerrain::CalculateTerrainTypeTileBlendings(STerrainTile* pTerrainTile, byte _byTerrainType[4], byte _byBlendIndices[4] ){	DynArray oDiffTerrains;	byte				uTerrainType;	byte				uDominant = 255;	ulong				uCurCorner, uCurElement;	STerrainCorner** ppCorners = pTerrainTile->m_pCorner;	// Determine the number of different corners and write them into a list.	for ( uCurCorner=0; uCurCorner<4; uCurCorner++)	{		uTerrainType = ppCorners[uCurCorner]->m_uTerrainType & 0x0f;		if ( uDominant > uTerrainType )		{			uDominant = uTerrainType;		}		oDiffTerrains.AddUniqueElement( uTerrainType );	}	// Only 1 then there is no need for blending.	if ( oDiffTerrains.GetNrElements() == 1 )	{		return 0;	}	// Remove the dominant element since this one will not be blendet.	oDiffTerrains.RemoveElement( uDominant );	byte byBlend = 0;	for ( uCurElement=0; uCurElement < oDiffTerrains.GetNrElements(); uCurElement++ )	{		_byBlendIndices[uCurElement] = 0;		for ( uCurCorner=0; uCurCorner<4; uCurCorner++ )		{			byBlend = 1< < uCurCorner;			uTerrainType = ppCorners[uCurCorner]->m_uTerrainType & 0x0f;			if ( uTerrainType == oDiffTerrains[uCurElement] )			{				_byBlendIndices[uCurElement] |= byBlend;				_byTerrainType[uCurElement] = uTerrainType;			}		}		if ( _byBlendIndices[uCurElement] )			_byBlendIndices[uCurElement] -= 1;	}#pragma todo("Do a dominance sort on the blendings.")	return oDiffTerrains.GetNrElements();}	    


I think this also replies to the question Zarmax has. Since the terrain types are defined in the corners and not in the tiles themself the overlapping is done automatically.

But yes, if you have 4 different underground types in one tile then you have multiple blendings (1 normal rendering for the dominant underground (underground with lowest id) and 3 blendings with the other underground types).

Kind regards,
Metron

[edited by - Metron on June 19, 2003 5:07:39 AM]

[edited by - Metron on June 19, 2003 5:08:58 AM]
----------------------------------------http://www.sidema.be----------------------------------------
Thanks Metron, good answer.

I was trying something out using mutli-texturing with up to 4 blend stages and driven by a vertex shader to do the blends, you''ve given me a good way to figure out what the blend values need to be. Only problem now is to best figure out how to opimize texture swaps.



Well... that can be reduced to 1 swap :

You put all you base underground types and their variation into one texture.
You put all the blending types for the underground types into a second texture.

You then first draw all the complete tiles without blending (using texture #1).
Then you render all the blending tiles with the second texture. Like this you don''t need to swap the texture...

Metron
----------------------------------------http://www.sidema.be----------------------------------------
Just wanted to say thanks, you solved a few problems I have been having with texture tiling. I can finally get rid of the one big texture/detail texture method I have been using.

I''ve tried about 4-5 other methods with things like texture splatting, volume textures, multi-texture blends, overlapping textures, etc. I think this tiling method will finally solve the problem.

One enhancement that I was thinking about that would require an additional texture stage would be to use an alpha map for blending instead of vertex blends in that you can do the alpha map at 2 or 3 times the size of the terrain patch and get a smoother blend by adding a little noise to the blend. I may have to try that one out as I already am thinking I need a minimum of three stages for blending, (two tiles + lightmap), so I might as well throw in an alphamap to add a more irregular blend. With a vertex shader I could probably pack the alphamap into the same texture as the lightmap...hmm...

There also might be a nice way to wrap it all up into a vertex shader to cut back on the number of texture coords needed.

This topic is closed to new replies.

Advertisement