Game Development Community

Getting triangles from terrain

by Keith Johnston · in Torque Game Engine · 12/20/2002 (8:07 pm) · 3 replies

What is the best way to get all the triangles for a given region for the current terrain block?

I tried using buildPolyList on the terrain block, passing in a Box3F - and it seems to work with some terrains, but crashes with others.

Has anyone found a way to do this that works consistently?

Thanks,
Keith

#1
12/21/2002 (6:36 am)
I found a workaround.

The crash was in this loop.

// Add the missing points
         U32 vi[5];
         for (int i = 0; i < 4 ; i++) {
            S32 dx = i >> 1;
            S32 dy = dx ^ (i & 1);
            U32* vp = &vb[dy][x - xStart + dx];
            if (*vp == U32_MAX) {
               Point3F pos;
               pos.x = (x + dx) * squareSize;
               pos.y = (y + dy) * squareSize;
               pos.z = fixedToFloat(getHeight(xi + dx, yi + dy));
               *vp = polyList->addPoint(pos);
            }
            vi[i] = *vp;
         }

Since the end result is to make a copy of the polygons, I just got rid of the use of the vb buffer and had the loop create every single point. I suppose this is slower, since none of the points will be reused. But I only call this once per level.

// Add the missing points
         U32 vi[5];
         for (int i = 0; i < 4 ; i++) {
            S32 dx = i >> 1;
            S32 dy = dx ^ (i & 1);
            //U32* vp = &vb[dy][x - xStart + dx];
			U32 vp;
            if (true) {
               Point3F pos;
               pos.x = (x + dx) * squareSize;
               pos.y = (y + dy) * squareSize;
               pos.z = fixedToFloat(getHeight(xi + dx, yi + dy));
               vp = polyList->addPoint(pos);
            }
            vi[i] = vp;
         }
#2
03/24/2004 (3:49 pm)
Now, first of all, I know that this is an old thread, but I just had the same problem today and since some other people were trying to get the polys to get ODE to work, I thought I'd have a look at this. Here are the results:

In terrCollision.cc, the buildPolyList method uses an array to reuse vertices, so when a vertex is used several times, only one index is needed by the polylist. This happens a lot in the TerrainBlock, caused by grid setup of the terrain. This array is cleared right at the start of this method. Only a small part of the array is cleared, just as big as the x-extent of the Box3F that was specified as a parameter. This x-extent used to clear the array has a maximum size:

S32 xExt = xEnd - xStart;
if (xExt > MaxExtent)
   xExt = MaxExtent;

MaxExtent is a constant defined as the following right at the top of the file:

static const U32 MaxExtent = 100;

The big problem with this is, that this maximum size of 100 'memory units' is not enough for even half of the terrain. This causes the method to read memory positions that have not been cleared nor reserved, leading to unpredictable results == wrong vertex indices. Normally, the method is used with much smaller parts of the terrain, so this problem doesn't happen.

To correct it, set MaxExtent to 256, which is the BlockSize:

static const U32 MaxExtent = 256;

or replace MaxExtent with BlockSize. This should correct the problem and avoid crashes. It might still happen if you use the terrains bounding box as the Box3F in the buildPolyList query, since this is set to very large values, so the terrain is always in scope:

mObjBox.min.set(-1e8, -1e8, -1e8);
mObjBox.max.set( 1e8,  1e8,  1e8);

The 'real' extents of the TerrainBlock is squareSize * BlockSize.
#3
05/07/2006 (8:41 am)
Yes, Stefan's idea worked for me.

In terrCollision.cc, I changed line 12 from
static const U32 MaxExtent = 100;
to
static const U32 MaxExtent = TerrainBlock::BlockSize;

Then I wanted to extract the triangles for the terrain within the missionarea. I did the following. I don't know if there is a better way to determine the min/max height of the terrain (i'm not sure what I did is correct---comments welcome).

//determine the min and max x and y bounds
MissionArea * pMissionArea = dynamic_cast<MissionArea*>(Sim::findObject("MissionArea"));
const RectI &missionArea = pMissionArea->getArea();
F32 minX = missionArea.point.x;
F32 maxX = missionArea.point.x + missionArea.extent.x;
F32 minY = missionArea.point.y;
F32 maxY = missionArea.point.y + missionArea.extent.y;
//determine the min and max z bounds
TerrainBlock * pTerrain = dynamic_cast<TerrainBlock*>(Sim::findObject("Terrain"));
GridSquare * gSquare = pTerrain->findSquare(TerrainBlock::BlockShift, Point2I(0,0));
F32 minZ = fixedToFloat(gSquare->minHeight);
F32 maxZ = fixedToFloat(gSquare->maxHeight);
Box3F queryBox(minX,minY,minZ,maxX,maxY,maxZ);
Point3F center = (queryBox.min + queryBox.max) * 0.5f;
VectorF radius = queryBox.max - center;
SphereF querySphere(center,radius.len());
//now get the terrain polys in the mission area
ConcretePolyList cpl;
pTerrain->buildPolyList(&cpl,queryBox,querySphere);
// etc...