btHeightfieldTerrainShape giving a flat terrain

dumbo2007
Posts: 66
Joined: Sun Jan 30, 2011 8:46 pm

btHeightfieldTerrainShape giving a flat terrain

Post by dumbo2007 »

Hi,


I modified the TerrainDemo example to load my own raw values. I am trying to generate raw sine wave values and generate the sine wavy terrain from these values. Here are the modified sections :

An extra case called case eFile: was added to getRawHeightfieldData

Code: Select all

static byte_t *
getRawHeightfieldData
(
eTerrainModel model,
PHY_ScalarType type,
btScalar& minHeight,
btScalar& maxHeight
)
{
//	std::cerr << "\nRegenerating terrain\n";
//	std::cerr << "  model = " << model << "\n";
//	std::cerr << "  type = " << type << "\n";

	long nElements = ((long) s_gridSize) * s_gridSize;
//	std::cerr << "  nElements = " << nElements << "\n";

	int bytesPerElement = getByteSize(type);
//	std::cerr << "  bytesPerElement = " << bytesPerElement << "\n";
	btAssert(bytesPerElement > 0 && "bad bytes per element");

	long nBytes = nElements * bytesPerElement;
//	std::cerr << "  nBytes = " << nBytes << "\n";
	byte_t * raw = new byte_t[nBytes];
	btAssert(raw && "out of memory");

	// reseed randomization every 30 seconds
//	srand(time(NULL) / 30);

	// populate based on model
	switch (model) {
	case eRadial:
		setRadial(raw, bytesPerElement, type);
		break;

	case eFractal:
		for (int i = 0; i < nBytes; i++)
		{
			raw[i] = 0;
		}
		setFractal(raw, bytesPerElement, type, s_gridSize - 1);
		break;

	case eFile:
		for (int i = 0; i < nBytes; i++)
		{
			raw[i] = 20.f + 20.f*sin(float(i));
		}		
		break;

	default:
		btAssert(!"bad model type");
	}

	if (0) {
		// inside if(0) so it keeps compiling but isn't
		// 	exercised and doesn't cause warnings
//		std::cerr << "final grid:\n";
		dumpGrid(raw, bytesPerElement, type, s_gridSize - 1);
	}

	// find min/max
	for (int i = 0; i < s_gridSize; ++i) {
		for (int j = 0; j < s_gridSize; ++j) {
			float z = getGridHeight(raw, i, j, type);
			printf("i=%d, j=%d,  z=%f\n" , i, j, z);

			// update min/max
			if (!i && !j) {
				minHeight = z;
				maxHeight = z;
			} else {
				if (z < minHeight) {
					minHeight = z;
				}
				if (z > maxHeight) {
					maxHeight = z;
				}
			}
		}
	}

	if (maxHeight < -minHeight) {
		maxHeight = -minHeight;
	}
	if (minHeight > -maxHeight) {
		minHeight = -maxHeight;
	}

//	std::cerr << "  minHeight = " << minHeight << "\n";
//	std::cerr << "  maxHeight = " << maxHeight << "\n";

	return raw;
}
I also modified the initialization routine :

Code: Select all

void TerrainDemo::initialize(void)
{
//	std::cerr << "initializing...\n";

	// set up basic state
	m_upAxis = 1;		// start with Y-axis as "up"
	m_type = PHY_FLOAT;
	m_model = eFile;//eFractal;
	m_isDynamic = true;

	// set up the physics world
	m_collisionConfiguration = new btDefaultCollisionConfiguration();
	m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
	btVector3 worldMin(-1000,-1000,-1000);
	btVector3 worldMax(1000,1000,1000);
	m_overlappingPairCache = new btAxisSweep3(worldMin,worldMax);
	m_constraintSolver = new btSequentialImpulseConstraintSolver();
	m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_overlappingPairCache,m_constraintSolver,m_collisionConfiguration);

	// initialize axis- or type-dependent physics from here
	this->resetPhysics();
}
and the grid size is set to a lower value :

Code: Select all

static const int s_gridSize			= 8 + 1;  // must be (2^N) + 1
Resetting of physics is the same, for reference here it is :

Code: Select all

/// called whenever key terrain attribute is changed
void TerrainDemo::resetPhysics(void)
{
	// remove old heightfield
	clearWorld();

	// reset gravity to point in appropriate direction
	m_dynamicsWorld->setGravity(getUpVector(m_upAxis, 0.0, -s_gravity));

	// get new heightfield of appropriate type
	m_rawHeightfieldData =
	    getRawHeightfieldData(m_model, m_type, m_minHeight, m_maxHeight);
	btAssert(m_rawHeightfieldData && "failed to create raw heightfield");

	bool flipQuadEdges = false;
	btHeightfieldTerrainShape * heightfieldShape =
	    new btHeightfieldTerrainShape(s_gridSize, s_gridSize,
					  m_rawHeightfieldData,
					  s_gridHeightScale,
					  m_minHeight, m_maxHeight,
					  m_upAxis, m_type, flipQuadEdges);
	btAssert(heightfieldShape && "null heightfield");

	// scale the shape
	btVector3 localScaling = getUpVector(m_upAxis, s_gridSpacing, 1.0);
	heightfieldShape->setLocalScaling(localScaling);

	// stash this shape away
	m_collisionShapes.push_back(heightfieldShape);

	// set origin to middle of heightfield
	btTransform tr;
	tr.setIdentity();
	tr.setOrigin(btVector3(0,-20,0));

	// create ground object
	float mass = 0.0;
	localCreateRigidBody(mass, tr, heightfieldShape);
}
I am directly setting the raw values using raw = 20.f + 20.f*sin(float(i));
But this gives me only a flat terrain. It seems that something is wrong in the values I set in raw[] as this section in getRawHeightfieldData() always gives z=0 and consequently m_minHeight and m_maxHeight are both 0 in resetPhysics()

Code: Select all

// find min/max
	for (int i = 0; i < s_gridSize; ++i) {
		for (int j = 0; j < s_gridSize; ++j) {
			float z = getGridHeight(raw, i, j, type);
			printf("i=%d, j=%d,  z=%f\n" , i, j, z);

			// update min/max
			if (!i && !j) {
				minHeight = z;
				maxHeight = z;
			} else {
				if (z < minHeight) {
					minHeight = z;
				}
				if (z > maxHeight) {
					maxHeight = z;
				}
			}
		}
	}
There are functions in the demo which generate fractal and radial heightfields. I cannot understand how differently they are setting the raw values so that the m_minHeight and m_maxHeight are reported correctly. Do I need to align the values I set in raw[] in someway ?

Thanks
dumbo2007
Posts: 66
Joined: Sun Jan 30, 2011 8:46 pm

Re: btHeightfieldTerrainShape giving a flat terrain

Post by dumbo2007 »

Any idea about this anyone....has anyone tried reading heightmap values or modifying the TerrainDemo to read in heightmap values ?
Dave Driesen
Posts: 1
Joined: Mon Jun 13, 2011 11:23 am

Re: btHeightfieldTerrainShape giving a flat terrain

Post by Dave Driesen »

Hi,

In your getRawHeightfieldData function, your data has an incorrect alignment:

Code: Select all

case eFile:
      for (int i = 0; i < nBytes; i++)
      {
         raw[i] = 20.f + 20.f*sin(float(i));
      }      
      break;
You are writing to raw which will be byte-aligned; raw is declared as byte_t*.
Use the convertFromFloat function, and correct your alignment (multiplying i by bytesPerElement, or alternatively changing your loop-expression).

Try this:

Code: Select all

case eFile:
      for (int i = 0; i < nElements; i++) {
		// simple triangle waveform
		float z=(i % 2) * 3.0f;
		convertFromFloat(&raw[i*bytesPerElement], z, type);
	}
Doesn't use your sine wave as I'm not sure of the actual effect you desire, but it does show you how to fill up the heightfield data.

Happy coding,
Dave
dumbo2007
Posts: 66
Joined: Sun Jan 30, 2011 8:46 pm

Re: btHeightfieldTerrainShape giving a flat terrain

Post by dumbo2007 »

Thanks Dave. Yes it work now :D