# Terrain chunks and index arrays

## Recommended Posts

Hey there! I want to split my terrain into several pieces. It's working, actually... but I got some weird problem with the degenerated triangles, I guess.
//m_patchSize is a power of 2 digit
for(unsigned int patchZ = 0; patchZ < GetWidth(); patchZ += m_patchSize)
{
for(unsigned int patchX = 0; patchX < GetWidth(); patchX += m_patchSize)
{
TerrainPatch new_patch;

new_patch.m_vertexCount = m_patchSize*m_patchSize + m_patchSize*2;

flx_Vertex		*patchVertices	= new flx_Vertex[new_patch.m_vertexCount];
flx_TexCoord	        *patchTexCoords	= new flx_TexCoord[new_patch.m_vertexCount];
flx_Normal		*patchNormals	= new flx_Normal[new_patch.m_vertexCount];
//Note: m_pVertices is the array of the vertices from the unchunked terrain (which is rendering correct)
for(unsigned int z = 0; z < m_patchSize; ++z)
{
unsigned int x;
for(x = 0; x < m_patchSize; ++x)
{
patchVertices[x + z * m_patchSize].x = m_pVertices[(x + patchX ) + (z + patchZ) * GetWidth()].x;
patchVertices[x + z * m_patchSize].y = m_pVertices[(x + patchX) + (z + patchZ) * GetWidth()].y;
patchVertices[x + z * m_patchSize].z = m_pVertices[(x + patchX) + (z + patchZ) * GetWidth()].z;

patchTexCoords[x + z * m_patchSize].u = (float)((float)((x + patchX) * m_fOffsetX) / GetWidth());
patchTexCoords[x + z * m_patchSize].v = (float)((float)((z + patchZ) * m_fOffsetZ) / GetLength());

patchNormals[x + z * m_patchSize].x =  m_pNormals[(x + patchX) + (z + patchZ) * GetWidth()].x;
patchNormals[x + z * m_patchSize].y =  m_pNormals[(x + patchX) + (z + patchZ) * GetWidth()].y;
patchNormals[x + z * m_patchSize].z =  m_pNormals[(x + patchX) + (z + patchZ) * GetWidth()].z;
}
}

//create indices, incl. degenerated triangles
unsigned int indexPatchSize = m_patchSize;
for(int z = 0; z < indexPatchSize-1; z++)
{
if(z % 2)
{
int x;
for(x = indexPatchSize-1; x >= 0; x--)
{
new_patch.m_Indices.push_back((z + 1)*m_patchSize + x );
new_patch.m_Indices.push_back(x  + (z * m_patchSize) );

}
new_patch.m_Indices.push_back( (z+1)*m_patchSize );
new_patch.m_Indices.push_back( (z+1)*m_patchSize );
}
else
{
int x;
for(x = 0; x < indexPatchSize; x++)
{
new_patch.m_Indices.push_back( z*m_patchSize + x );
new_patch.m_Indices.push_back( (z+1)*m_patchSize + x );
}
new_patch.m_Indices.push_back( (z+2)*m_patchSize-1 );
new_patch.m_Indices.push_back( (z+2)*m_patchSize-1 );

}
}


This screen shows the problem: 1 row and 1 column are missing Thank you! [Edited by - starvinmarvin on May 4, 2009 10:42:39 AM]

##### Share on other sites
I don't want to annoy you, but I still haven't solved the problem myself :(

##### Share on other sites
rethan    149
You seem to have a stitching issue. Say the patch m_patchSize is 8, which means you keep track of 8x8 verts, where is the indexing for closing the gap between the right set of verts of one patch and the left set of verts of the next patch? If you want to use a vert buffer and indexing, then you will need to duplicate the verticies on the shared edge. So, for example, if you want 8x8 patches, you will actually need to store 9x9 verts the 9'th vert will = the 1'st vert of the patch it is next to.

Here is a simpler example of 9 total patches where you want "4x4". This requires that you store 5x5 verts for each patch. One way to do this is to include the right and bottom verts from the neighbor patches so the indexing can reference them:

. . . . o . . . o . . . .. . . . o . . . o . . . .. . . . o . . . o . . . .. . . . o . . . o . . . .o o o o o o o o o o o o o. . . . o . . . o . . . .. . . . o . . . o . . . .. . . . o . . . o . . . .o o o o o o o o o o o o o. . . . o . . . o . . . .. . . . o . . . o . . . .. . . . o . . . o . . . .. . . . o . . . o . . . .

the o's are shared, and the verts you would store for each patch would be like so:

. . . . o    o . . . o   o . . . .. . . . o    o . . . o   o . . . .. . . . o    o . . . o   o . . . .. . . . o    o . . . o   o . . . .o o o o o    o o o o o   o o o o o   o o o o o    o o o o o   o o o o o. . . . o    o . . . o   o . . . .. . . . o    o . . . o   o . . . .. . . . o    o . . . o   o . . . .o o o o o    o o o o o   o o o o o   o o o o o    o o o o o   o o o o o. . . . o    o . . . o   o . . . .. . . . o    o . . . o   o . . . .. . . . o    o . . . o   o . . . .. . . . o    o . . . o   o . . . .

To be explicit, if your global list of verts are numbered like so:

1  2  3  4  5  6  7  8  9 10 11 12 13.  .  .  .  o  .  .  .  o  .  .  .  .

these verts would show up like so in the top three patches:

1  2  3  4  5    5  6  7  8  9    9 10 11 12 13.  .  .  .  o    o  .  .  .  o    o  .  .  .  .

(And yes, this means you basically duplicate a lot of verts, which is one of the drawbacks, so picking a large enough m_patchSize is important to reduce the "# or verts per patch / duplicate verts per patch" ratio.

Hope that makes sense,
Val

[Edited by - rethan on May 4, 2009 4:30:42 PM]

##### Share on other sites
Thank you! But I already found out that I have to get the neighbour vertices too :). The problem is my piece of code which creates the indices.

Anyway, do you think splitting the terrain into patches is a bad idea (when implementing LOD sometime)?

##### Share on other sites
cameni    487
m_patchSize used in the routine should be a (2^n + 1) number, as rethan pointed out, because of the stitching. So you should use something like

//m_patchSize is a power of 2 digit//but patch contains (m_patchSize+1)^2 verticesunsigned int nvert = m_patchSize + 1;for(unsigned int patchZ = 0; patchZ < GetWidth(); patchZ += m_patchSize){	for(unsigned int patchX = 0; patchX < GetWidth(); patchX += m_patchSize)	{		TerrainPatch new_patch;				new_patch.m_vertexCount = nvert*nvert;		flx_Vertex *patchVertices = new flx_Vertex[new_patch.m_vertexCount];		flx_TexCoord *patchTexCoords = new flx_TexCoord[new_patch.m_vertexCount];		flx_Normal *patchNormals = new flx_Normal[new_patch.m_vertexCount];//Note: m_pVertices is the array of the vertices from the unchunked terrain (which is rendering correct)		for(unsigned int z = 0; z < nvert; ++z)		{			unsigned int x;			for(x = 0; x < nvert; ++x)			{				patchVertices[x + z * nvert].x = m_pVertices[(x + patchX ) + (z + patchZ) * GetWidth()].x;				patchVertices[x + z * nvert].y = m_pVertices[(x + patchX) + (z + patchZ) * GetWidth()].y;				patchVertices[x + z * nvert].z = m_pVertices[(x + patchX) + (z + patchZ) * GetWidth()].z;				patchTexCoords[x + z * nvert].u = (float)((float)((x + patchX) * m_fOffsetX) / GetWidth());				patchTexCoords[x + z * nvert].v = (float)((float)((z + patchZ) * m_fOffsetZ) / GetLength());				patchNormals[x + z * nvert].x =  m_pNormals[(x + patchX) + (z + patchZ) * GetWidth()].x;				patchNormals[x + z * nvert].y =  m_pNormals[(x + patchX) + (z + patchZ) * GetWidth()].y;				patchNormals[x + z * nvert].z =  m_pNormals[(x + patchX) + (z + patchZ) * GetWidth()].z;			}		}			//create indices, incl. degenerated triangles		unsigned int indexPatchSize = nvert;		for(int z = 0; z < indexPatchSize-1; z++)		{			if(z % 2)			{				int x;				for(x = nvert-1; x >= 0; x--)				{					new_patch.m_Indices.push_back((z + 1)*nvert + x );					new_patch.m_Indices.push_back(x  + (z * nvert) );											}				new_patch.m_Indices.push_back( (z+1)*nvert );				new_patch.m_Indices.push_back( (z+1)*nvert );			}			else			{				int x;				for(x = 0; x < indexPatchSize; x++)				{					new_patch.m_Indices.push_back( z*nvert + x );					new_patch.m_Indices.push_back( (z+1)*nvert + x );				}				new_patch.m_Indices.push_back( (z+2)*nvert-1 );				new_patch.m_Indices.push_back( (z+2)*nvert-1 );			}		}

Hope I got it right .. [smile]

##### Share on other sites
rethan    149
Quote:
 Original post by starvinmarvinThank you! But I already found out that I have to get the neighbour vertices too :). The problem is my piece of code which creates the indices.Anyway, do you think splitting the terrain into patches is a bad idea (when implementing LOD sometime)?

I think it depends on how you indend to use the patches. If you are using patches to not draw parts of the terrain that are not visible etc, then there will be a sweet spot for patch size based on what your GPU can do. The trade off there is if the patch size is too small, you're binding texture/indecies too often, and if they are too big, you will be including big chunks of terrain even if only a small bit is visible.

Another trick that you use (if not already) is that really you just need 1 index array that all the chunks can use since each chunk really uses the same indexing to draw and it's only the normals and vertex positions that change. You can also look into automatic texture coordinate generation if you are rendering a heightmap that is based on a regular grid (which you are doing). ie the glTexGeni() func and friends.

[Edited by - rethan on May 4, 2009 11:23:25 PM]

##### Share on other sites
Quote:
 Original post by camenim_patchSize used in the routine should be a (2^n + 1) number, as rethan pointed out, because of the stitching. So you should use something like*** Source Snippet Removed ***Hope I got it right .. [smile]

Thanks for the trouble! That's almost what I've got so far, but nverts is out of range of m_pVertices since it has the dimension of terrain_size^2. The reason for that is that I first build a vertice array like you would do without splitting the terrain.

@cameni, nverts in those lines doesn't seem right to me
new_patch.m_Indices.push_back( (z + 2) * m_patchSize-1 );

void GeometryTerrain::buildPatches(){	for(unsigned int patchZ = 0; patchZ < GetWidth(); patchZ += m_patchSize)	{		for(unsigned int patchX = 0; patchX < GetWidth(); patchX += m_patchSize)		{			TerrainPatch new_patch;			new_patch.m_vertexCount = (m_patchSize+1)*(m_patchSize+1);			flx_Vertex		*patchVertices	= new flx_Vertex[new_patch.m_vertexCount];			flx_TexCoord		*patchTexCoords	= new flx_TexCoord[new_patch.m_vertexCount];			flx_Normal		*patchNormals	= new flx_Normal[new_patch.m_vertexCount];			Vector3 tmax  = Vector3(-999999,-999999,-999999);			Vector3 tmin  = Vector3(999999,999999,999999);                        //fill the buffers/arrays of the patch with data			for(unsigned int z = 0; z < m_patchSize+1; ++z)			{				unsigned int x;				for(x = 0; x < m_patchSize+1; ++x)				{					//I do that because if x and y equal m_patchSize+1 they would be out of m_pVertices range					if(((tx + patchX) + (tz + patchZ) * GetWidth()) > GetWidth()*GetWidth()) continue;					patchVertices[x + z * m_patchSize].x = m_pVertices[(x + patchX) + (z + patchZ) * GetWidth()].x;					patchVertices[x + z * m_patchSize].y = m_pVertices[(x + patchX) + (z + patchZ) * GetWidth()].y;					patchVertices[x + z * m_patchSize].z = m_pVertices[(x + patchX) + (z + patchZ) * GetWidth()].z;						patchTexCoords[x + z * m_patchSize].u = (float)((float)((x + patchX) * m_fOffsetX) / GetWidth());					patchTexCoords[x + z * m_patchSize].v = (float)((float)((z + patchZ) * m_fOffsetZ) / GetLength());					patchNormals[x + z * m_patchSize].x =  m_pNormals[(x + patchX) + (z + patchZ) * GetWidth()].x;					patchNormals[x + z * m_patchSize].y =  m_pNormals[(x + patchX) + (z + patchZ) * GetWidth()].y;					patchNormals[x + z * m_patchSize].z =  m_pNormals[(x + patchX) + (z + patchZ) * GetWidth()].z;	                                //find corners of AABB					tmin.x = min(patchVertices[x + z * m_patchSize].x, tmin.x);					tmin.y = min(patchVertices[x + z * m_patchSize].y, tmin.y);					tmin.z = min(patchVertices[x + z * m_patchSize].z, tmin.z);					tmax.x = max(patchVertices[x + z * m_patchSize].x, tmax.x);					tmax.y = max(patchVertices[x + z * m_patchSize].y, tmax.y);					tmax.z = max(patchVertices[x + z * m_patchSize].z, tmax.z);				}								}			//set AABB min/max			new_patch.m_aabb.vecMax = tmax;			new_patch.m_aabb.vecMin = tmin;                        //create the indices + degenerate triangles			unsigned int indexPatchSize = m_patchSize;			for(int z = 0; z < indexPatchSize-1; z++)			{				if(z % 2)				{					int x;					for(x = indexPatchSize-1; x >= 0; x--)					{												new_patch.m_Indices.push_back(x + (z + 1) * m_patchSize);						new_patch.m_Indices.push_back(x + (z    ) * m_patchSize);												}						new_patch.m_Indices.push_back( (z + 1) * m_patchSize );						new_patch.m_Indices.push_back( (z + 1) * m_patchSize );				}				else				{					int x;					for(x = 0; x < indexPatchSize; x++)					{						new_patch.m_Indices.push_back(x + (z    ) * m_patchSize );						new_patch.m_Indices.push_back(x + (z + 1) * m_patchSize );					}						new_patch.m_Indices.push_back( (z + 2) * m_patchSize-1 );						new_patch.m_Indices.push_back( (z + 2) * m_patchSize-1 );				}			}			new_patch.VertexBuffer.setElementList(patchVertices, new_patch.m_vertexCount);			new_patch.TexCoordBuffer.setElementList(patchTexCoords, new_patch.m_vertexCount);			new_patch.NormalBuffer.setElementList(patchNormals, new_patch.m_vertexCount);			new_patch.VertexBuffer.build(GL_ARRAY_BUFFER, GL_VERTEX_ARRAY);			new_patch.TexCoordBuffer.build(GL_ARRAY_BUFFER, GL_TEXTURE_COORD_ARRAY);			new_patch.NormalBuffer.build(GL_ARRAY_BUFFER, GL_NORMAL_ARRAY);			m_vTerrainPatches.push_back(new_patch);			delete [] patchVertices; patchVertices = NULL;			delete [] patchTexCoords; patchTexCoords = NULL;			delete [] patchNormals; patchNormals = NULL;		}	}}

And what I got is:

As you can see the missing z row is now rendered, but the indices for the missing x row are messed up.

I'm sure the problem is the part where I create indices, because when I draw the AABBs now, they appear having the correct size (patchsize+1*patchsize+1).

I played for days with the loop which creates the indices, every try failed.

[Edited by - starvinmarvin on May 4, 2009 5:26:42 PM]

##### Share on other sites
rethan    149
Hey starvinmarvin,

What my first reply implied is that your patches should include shared verts. From your code, it looks like using power of two and not power of two +1 patch sizes would make a better fit from your big vertex data. To achieve this, your loop to copy the verticies from your big vertex buffer to your patches should be something like:

	for(unsigned int patchZ = 0; patchZ < GetWidth(); patchZ += (m_patchSize-1))	{		for(unsigned int patchX = 0; patchX < GetWidth(); patchX += (m_patchSize-1))		{			TerrainPatch new_patch;			new_patch.m_vertexCount = (m_patchSize)*(m_patchSize);			flx_Vertex		*patchVertices	= new flx_Vertex[new_patch.m_vertexCount];			flx_TexCoord		*patchTexCoords	= new flx_TexCoord[new_patch.m_vertexCount];			flx_Normal		*patchNormals	= new flx_Normal[new_patch.m_vertexCount];...

Note the:
patchZ += (m_patchSize-1)

in the for loop. This causes us to start copying on the shared vertex which should allow you to have power of two patch sizes which hopefully means the total width/height of the terrain is a multiple of the patch size and also means you shouldn't need:

if(((tx + patchX) + (tz + patchZ) * GetWidth()) > GetWidth()*GetWidth()) continue;

You may also have issues with how you do your indexing, I'm not quite sure what method you are using to compose the mesh. Are you using a single triangle strip? The way I would do a mesh is like so:

Verts:
 0  1  2  3 .  .  .  . 4  5  6  7 .  .  .  . 8  9 10 11 .  .  .  .12 13 14 15 .  .  .  .

Then i would index like so:

0 4 1 5 2 6 3 7 7 7 11 6 10 5 9 4 8 8 8 12 9 13 10 14 11 15 15 15 ...

But there are plenty of other ways.

##### Share on other sites
cameni    487
Quote:
 Original post by starvinmarvin@cameni, nverts in those lines doesn't seem right to menew_patch.m_Indices.push_back( (z + 2) * m_patchSize-1 );

There are m_patchSize+1 vertices in each row of the patch, so the z coords should be multiplied by (m_patchSize+1) row multiplier to get the correct index.

Then you should generate indices for the 2^n+1st vertex too, so the for cycles with x should be extended.
And I think there is a problem with the degenerate triangles in (z+2)*m_patchSize-1, why -1?

if(z % 2){	int x;	for(x = indexPatchSize; x >= 0; x--)	{		new_patch.m_Indices.push_back((z + 1)*nvert + x );		new_patch.m_Indices.push_back(x  + (z * nvert) );				}		new_patch.m_Indices.push_back( (z+1)*nvert );		new_patch.m_Indices.push_back( (z+1)*nvert );}else{	int x;	for(x = 0; x <= indexPatchSize; x++)	{		new_patch.m_Indices.push_back( z*nvert + x );		new_patch.m_Indices.push_back( (z+1)*nvert + x );	}		new_patch.m_Indices.push_back( (z+1)*nvert + indexPatchSize );		new_patch.m_Indices.push_back( (z+2)*nvert + indexPatchSize );}

##### Share on other sites
Thanks again to both of you. I tried your solutions, but unfortunately the results are getting even more weird :(

The problem is trivial, actually, but in the end it turns out that it's hard to be solved.

I made a little sketch to explain it a bit better, but I guess that's what you've already understood:

And yes, I'm using triangle strips.
I'm sure the problem is all about the indices.

##### Share on other sites
cameni    487
So please print the indices for the patch as you generate it, so we can see what it does (and which source version it is).

##### Share on other sites
Ok, I modified the indice generation loop.

unsigned int nvert = m_patchSize;		for(int z = 0; z < nvert-1; z++)			{				if(z % 2)				{					int x;                                        // x > = 1 is correct, not x >= 0					for(x = nvert-1; x >= 1; x--)					{												new_patch.m_Indices.push_back(x + (z + 1) * m_patchSize);						new_patch.m_Indices.push_back(x + (z    ) * m_patchSize -1);												}						new_patch.m_Indices.push_back( (z + 1) * m_patchSize );						new_patch.m_Indices.push_back( (z + 1) * m_patchSize );				}				else				{					int x;					for(x = 0; x < nvert; x++)					{						new_patch.m_Indices.push_back(x + (z    ) * m_patchSize );						new_patch.m_Indices.push_back(x + (z + 1) * m_patchSize );					}						new_patch.m_Indices.push_back( (z + 2) * m_patchSize-1 );						new_patch.m_Indices.push_back( (z + 2) * m_patchSize-1 );				}			}

Setting the terrain size to 4 and patch size to 4 too it's generating the Indices:
0 4 1 5 2 6 3 7 7 7 11 6 10 5 9 4 8 8 8 12 9 13 10 14 11 15 15 15
Which is correct.

When I set nvert to m_patchSize+1 (to get the missing rows) everything is messed up.

These are the indices for a 8x8 patch of a 16x16 terrain:

0 8 1 9 2 10 3 11 4 12 5 13 6 14 7 15 8 16 15 15 24 15 23 14 22 13 21 12 20 11 19 10 18 9 17 8 16 16 16 24 17 25 18 26 19 27 20 28 21 29 22 30 23 31 24 32 31 31 40 31 39 30 38 29 37 28 36 27 35 26 34 25 33 24 32 32 32 40 33 41 34 42 35 43 36 44 37 45 38 46 39 47 40 48 47 47 56 47 55 46 54 45 53 44 52 43 51 42 50 41 49 40 48 48 48 56 49 57 50 58 51 59 52 60 53 61 54 62 55 63 56 64 63 63 72 63 71 62 70 61 69 60 68 59 67 58 66 57 65 56 64 64

##### Share on other sites
cameni    487
Patch size 8 means that you are generating 9x9 vertex buffer, right?
So the sequence should go 0 9 1 10 2 ...

But you still use m_patchSize as row multiplier, and not nvert

##### Share on other sites
Quote:
 Original post by cameniPatch size 8 means that you are generating 9x9 vertex buffer, right?So the sequence should go 0 9 1 10 2 ...But you still use m_patchSize as row multiplier, and not nvert

Right!

Here are the indices after replacing m_patchSize with nvert:

0 9 1 10 2 11 3 12 4 13 5 14 6 15 7 16 8 17 17 17 26 16 25 15 24 14 23 13 22 12 21 11 20 10 19 9 18 18 18 27 19 28 20 29 21 30 22 31 23 32 24 33 25 34 26 35 35 35 44 34 43 33 42 32 41 31 40 30 39 29 38 28 37 27 36 36 36 45 37 46 38 47 39 48 40 49 41 50 42 51 43 52 44 53 53 53 62 52 61 51 60 50 59 49 58 48 57 47 56 46 55 45 54 54 54 63 55 64 56 65 57 66 58 67 59 68 60 69 61 70 62 71 71 71 80 70 79 69 78 68 77 67 76 66 75 65 74 64 73 63 72 72

Here's a screenshot:

##### Share on other sites
cameni    487
Ok, now the last triangle in row is .. 16 8 17
But after that should come degenerated triangles 17 26
and then the even-row sequence 26 17 25 16 ...

But you have there 26 16 25 15 ...
Can you post the whole code again how it looks now?

##### Share on other sites
void GeometryTerrain::buildPatches(){	for(unsigned int patchZ = 0; patchZ < GetWidth(); patchZ += m_patchSize)	{		for(unsigned int patchX = 0; patchX < GetWidth(); patchX += m_patchSize)		{			TerrainPatch new_patch;			new_patch.m_vertexCount = (m_patchSize+1)*(m_patchSize+1);			flx_Vertex		*patchVertices	= new flx_Vertex[new_patch.m_vertexCount];			flx_TexCoord	*patchTexCoords	= new flx_TexCoord[new_patch.m_vertexCount];			flx_Normal		*patchNormals	= new flx_Normal[new_patch.m_vertexCount];			Vector3 tmax  = Vector3(-999999,-999999,-999999);			Vector3 tmin  = Vector3(999999,999999,999999);			for(unsigned int z = 0; z < m_patchSize+1; ++z)			{				unsigned int x;				for(x = 0; x < m_patchSize+1; ++x)				{					unsigned int tx = x;					unsigned int tz = z;										if(((tx + patchX) + (tz + patchZ) * GetWidth()) > GetWidth()*GetWidth()) continue;					patchVertices[x + z * m_patchSize].x = m_pVertices[(x + patchX) + (z + patchZ) * GetWidth()].x;					patchVertices[x + z * m_patchSize].y = m_pVertices[(x + patchX) + (z + patchZ) * GetWidth()].y;					patchVertices[x + z * m_patchSize].z = m_pVertices[(x + patchX) + (z + patchZ) * GetWidth()].z;						patchTexCoords[x + z * m_patchSize].u = (float)((float)((x + patchX) * m_fOffsetX) / GetWidth());					patchTexCoords[x + z * m_patchSize].v = (float)((float)((z + patchZ) * m_fOffsetZ) / GetLength());					patchNormals[x + z * m_patchSize].x =  m_pNormals[(x + patchX) + (z + patchZ) * GetWidth()].x;					patchNormals[x + z * m_patchSize].y =  m_pNormals[(x + patchX) + (z + patchZ) * GetWidth()].y;					patchNormals[x + z * m_patchSize].z =  m_pNormals[(x + patchX) + (z + patchZ) * GetWidth()].z;					tmin.x = min(patchVertices[x + z * m_patchSize].x, tmin.x);					tmin.y = min(patchVertices[x + z * m_patchSize].y, tmin.y);					tmin.z = min(patchVertices[x + z * m_patchSize].z, tmin.z);					tmax.x = max(patchVertices[x + z * m_patchSize].x, tmax.x);					tmax.y = max(patchVertices[x + z * m_patchSize].y, tmax.y);					tmax.z = max(patchVertices[x + z * m_patchSize].z, tmax.z);				}								}			new_patch.m_aabb.vecMax = tmax;			new_patch.m_aabb.vecMin = tmin;							unsigned int nvert = m_patchSize+1;			int z;			for(z = 0; z < nvert-1; z++)			{				if(z % 2)				{					int x;					for(x = nvert-1; x >= 1; x--)					{												new_patch.m_Indices.push_back(x + (z + 1) * nvert);						new_patch.m_Indices.push_back(x + (z    ) * nvert -1);												}						new_patch.m_Indices.push_back( (z + 1) * nvert );						new_patch.m_Indices.push_back( (z + 1) * nvert );				}				else				{					int x;					for(x = 0; x < nvert; x++)					{						new_patch.m_Indices.push_back(x + (z    ) * nvert );						new_patch.m_Indices.push_back(x + (z + 1) * nvert );					}						new_patch.m_Indices.push_back( (z + 2) * nvert-1 );						new_patch.m_Indices.push_back( (z + 2) * nvert-1 );				}			}			FLX_LOGGER->Write(LOG_DEFAULT, "\n\n");			for(int i = 0; i < new_patch.m_Indices.size(); ++i)				FLX_LOGGER->Write(LOG_DEFAULT, "%d ", new_patch.m_Indices[i]);						new_patch.VertexBuffer.setElementList(patchVertices, new_patch.m_vertexCount);			new_patch.TexCoordBuffer.setElementList(patchTexCoords, new_patch.m_vertexCount);			new_patch.NormalBuffer.setElementList(patchNormals, new_patch.m_vertexCount);			new_patch.VertexBuffer.build(GL_ARRAY_BUFFER, GL_VERTEX_ARRAY);			new_patch.TexCoordBuffer.build(GL_ARRAY_BUFFER, GL_TEXTURE_COORD_ARRAY);			new_patch.NormalBuffer.build(GL_ARRAY_BUFFER, GL_NORMAL_ARRAY);			m_vTerrainPatches.push_back(new_patch);			delete [] patchVertices; patchVertices = NULL;			delete [] patchTexCoords; patchTexCoords = NULL;			delete [] patchNormals; patchNormals = NULL;		}	}}

Oh wait, I changed one line to "new_patch.m_Indices.push_back(x + (z ) * nvert -1);" the -1 there worked for nvert = m_patchSize

edit: The -1 wasn't the problem, but indices are know as you said they should be:

0 9 1 10 2 11 3 12 4 13 5 14 6 15 7 16 8 17 17 17 26 17 25 16 24 15 23 14 22 13 21 12 20 11 19 10 18 9 18 18 18 27 19 28 20 29 21 30 22 31 23 32 24 33 25 34 26 35 35 35 44 35 43 34 42 33 41 32 40 31 39 30 38 29 37 28 36 27 36 36 36 45 37 46 38 47 39 48 40 49 41 50 42 51 43 52 44 53 53 53 62 53 61 52 60 51 59 50 58 49 57 48 56 47 55 46 54 45 54 54 54 63 55 64 56 65 57 66 58 67 59 68 60 69 61 70 62 71 71 71 80 71 79 70 78 69 77 68 76 67 75 66 74 65 73 64 72 63 72 72

But still pixel chaos

##### Share on other sites
cameni    487
What will this do (copy the whole thing there):

if(z % 2){    int x;    for(x = nvert-1; x >= 0; x--)    {                new_patch.m_Indices.push_back(x + (z + 1) * nvert);        new_patch.m_Indices.push_back(x + (z    ) * nvert);                }        new_patch.m_Indices.push_back( (z + 1) * nvert );        new_patch.m_Indices.push_back( (z + 1) * nvert );}else{    int x;    for(x = 0; x < nvert; x++)    {        new_patch.m_Indices.push_back(x + (z    ) * nvert );        new_patch.m_Indices.push_back(x + (z + 1) * nvert );    }        new_patch.m_Indices.push_back( (z + 1) * nvert + m_patchSize );        new_patch.m_Indices.push_back( (z + 2) * nvert + m_patchSize );}

##### Share on other sites
It does:

0 9 1 10 2 11 3 12 4 13 5 14 6 15 7 16 8 17 17 26 26 17 25 16 24 15 23 14 22 13 21 12 20 11 19 10 18 9 18 18 18 27 19 28 20 29 21 30 22 31 23 32 24 33 25 34 26 35 35 44 44 35 43 34 42 33 41 32 40 31 39 30 38 29 37 28 36 27 36 36 36 45 37 46 38 47 39 48 40 49 41 50 42 51 43 52 44 53 53 62 62 53 61 52 60 51 59 50 58 49 57 48 56 47 55 46 54 45 54 54 54 63 55 64 56 65 57 66 58 67 59 68 60 69 61 70 62 71 71 80 80 71 79 70 78 69 77 68 76 67 75 66 74 65 73 64 72 63 72 72

... still pixel chaos

If you say it must be correct then the problem may be the vertices?

Notice this line: if(((tx + patchX) + (tz + patchZ) * GetWidth()) > GetWidth()*GetWidth()) continue;

##### Share on other sites
cameni    487
patchVertices[x + z * m_patchSize]

there too should be nvert multiplier

##### Share on other sites
cameni    487
Quote:
 Original post by starvinmarvinNotice this line: if(((tx + patchX) + (tz + patchZ) * GetWidth()) > GetWidth()*GetWidth()) continue;

Well skipping it means there will be undefined values. You should rather copy the last row & column values there in this case, or extend the source data to include that border values.

##### Share on other sites
Haha, true!

It's getting better (even without skipping):

##### Share on other sites
rethan    149
Not to add to the confusion, but be sure you are clear what m_patchSize means. It looks like you have the "fence post" problem in your numbering of verts in the "starting base grid" picture (left-most one).

If those numbers are the verts, then your base grid is missing another vert number. If you want 16 total verts per side, then you will end up with 15 total squares per side. If you want 16 total squares, you will then need 17 total verts per size of the grid. The grid you show as 16x16 actually has 17x17 verts per side. In this case, your patches would need to store 9x9 verts in order to have 8x8 squares.

Perhaps you should rename m_patchSize to something that is more telling like m_patchNumVerts or m_patchNumSquares so it is clear since "size" is ambiguous in this case.

##### Share on other sites
rethan    149
Also, do GetWidth() and GetHeight() return the number of squares per side or number of verts per side? I would also rename these to be more explicit like GetWidthNumSquares() or GetWidthNumVerts().

##### Share on other sites
Yay! Finally solved it now! Fixed the indice creation once again and the base grid is now (n+1)^2. Thanks to everybody! I'll post the code tomorrow if you're interested:)

##### Share on other sites
rethan    149
Nice! Don't forget a screenshot too :)