PhysX heightfield heightScale

plfiorini

06-01-2009 06:16:54

I know this has been discussed in other threads but the other threads was not that helpful for me.
I almost got the result I wanted, here's the code:


void PhysicsManager::registerTerrain(const ET::TerrainInfo& info)
{
// Set heightfield description
NxHeightFieldDesc desc;
desc.nbRows = info.getWidth();
desc.nbColumns = info.getHeight();
desc.convexEdgeThreshold = 0;
desc.thickness = -100;

// Print some terrain information
Ogre::LogManager::getSingleton().logMessage("[PhysicsManager] Terrain size " +
Ogre::StringConverter::toString(Ogre::Vector2(desc.nbRows, desc.nbColumns)));
Ogre::LogManager::getSingleton().logMessage("[PhysicsManager] Terrain extents " +
Ogre::StringConverter::toString(info.getExtents().getSize()));
Ogre::LogManager::getSingleton().logMessage("[PhysicsManager] Terrain scaling " +
Ogre::StringConverter::toString(info.getScaling()));
Ogre::LogManager::getSingleton().logMessage("[PhysicsManager] Terrain offset " +
Ogre::StringConverter::toString(info.getOffset()));

// Extent size
NxReal sizeX = info.getExtents().getSize().x;
NxReal sizeY = info.getExtents().getSize().y;
NxReal sizeZ = info.getExtents().getSize().z;

// Heightfield samples
desc.samples = new NxU32[desc.nbRows * desc.nbColumns];
desc.sampleStride = sizeof(NxU32);

// Set heightfield samples height
char* currentByte = (char*)desc.samples;
for (NxU32 row = 0; row < desc.nbRows; row++)
{
for (NxU32 column = 0; column < desc.nbColumns; column++)
{
NxHeightFieldSample* currentSample = (NxHeightFieldSample*)currentByte;
currentSample->height = info.at(row, column) * (2^15);
currentSample->materialIndex0 = 1;
currentSample->materialIndex1 = 1;
currentSample->tessFlag = 0;
currentByte += desc.sampleStride;
}
}

// Create heightfield
mHeightField = mPhysicsSDK->createHeightField(desc);

// Free heightfield samples because data has already been used
delete [] desc.samples;

// Terrain shape
NxHeightFieldShapeDesc shapeDesc;
shapeDesc.heightField = mHeightField;
shapeDesc.shapeFlags = NX_SF_FEATURE_INDICES;
if (gEnableDebugger)
shapeDesc.shapeFlags |= NX_SF_VISUALIZATION;
//shapeDesc.heightScale = sizeY / (2^15);
shapeDesc.heightScale = (sizeY * 0.5f) / (2^15);
shapeDesc.rowScale = sizeX / NxReal(desc.nbRows - 1);
shapeDesc.columnScale = sizeZ / NxReal(desc.nbColumns - 1);
shapeDesc.materialIndexHighBits = 0;
shapeDesc.holeMaterial = 3500;
//shapeDesc.localPose.t = NxVec3(info.getOffset().x, info.getOffset().y, info.getOffset().z);
Ogre::LogManager::getSingleton().logMessage("[PhysicsManager] Terrain shape: " +
Ogre::String("heightScale=") + Ogre::StringConverter::toString(shapeDesc.heightScale) + " " +
Ogre::String("rowScale=") + Ogre::StringConverter::toString(shapeDesc.rowScale) + " " +
Ogre::String("columnScale=") + Ogre::StringConverter::toString(shapeDesc.columnScale));

// Actor
NxActorDesc actorDesc;
actorDesc.shapes.pushBack(&shapeDesc);
actorDesc.density = 1.0f;
actorDesc.globalPose.t = NxVec3(info.getOffset().x, info.getOffset().y, info.getOffset().z);
mTerrainActor = mScene->createActor(actorDesc);
}


The log says:

07:13:23: [PhysicsManager] Terrain size 1025 1025
07:13:23: [PhysicsManager] Terrain extents 5000 1667 5000
07:13:23: [PhysicsManager] Terrain scaling 4.87805 1667 4.87805
07:13:23: [PhysicsManager] Terrain offset 0 0 0
07:13:23: [PhysicsManager] Terrain shape: heightScale=64.1154 rowScale=4.88281 columnScale=4.88281


I tried changing the heightScale some times but still no luck. I also took a look in this thread viewtopic.php?p=49677 and the NxOgre code.
All seems ok, but when I create some crates in my application they always fall under the ground.

Here's the update code in case there is something wrong there:


bool PhysicsManager::update(const Ogre::Real& elapsed)
{
mScene->simulate(elapsed);
mScene->flushStream();
mScene->fetchResults(NX_RIGID_BODY_FINISHED, true);

// TODO: Delete any actor that may have had request to release it from callbacks

// Move scene node associated to every actor
NxActor** actors = mScene->getActors();
const NxU32 nbActors = mScene->getNbActors();
for (NxU32 i = 0; i < nbActors; ++i)
{
NxActor* actor = actors[i];
Ogre::SceneNode* sceneNode = static_cast<Ogre::SceneNode*>(actor->userData);
if (sceneNode)
{
NxVec3 pos = actor->getGlobalPosition();
NxQuat ori = actor->getGlobalOrientationQuat();
sceneNode->setPosition(Ogre::Vector3(pos.x, pos.y, pos.z));
sceneNode->setOrientation(Ogre::Quaternion(ori.w, ori.x, ori.y, ori.z));
}
}

// Update controllers
if (mControllerManager)
mControllerManager->updateControllers();

return true;
}


Anyone with some PhysX experience had any luck?

plfiorini

06-01-2009 16:28:33

I made a screenshot of the VRD debugger and attached to this post.

I am wondering what that plain is which is not aligned to the terrain.

My code to update the camera on VRD is:


void updateCamera()
{
NxVec3 origin, target;

Ogre::Camera* camera = GraphicsManager::getSingleton().getCamera();
ogreToNx(camera->getPosition(), origin);
ogreToNx(camera->getRealDirection() * 10, target);

mSDK->getFoundationSDK().getRemoteDebugger()->writeParameter(origin, this, false, "Origin", NX_DBG_EVENTMASK_EVERYTHING);
mSDK->getFoundationSDK().getRemoteDebugger()->writeParameter(target, this, false, "Target", NX_DBG_EVENTMASK_EVERYTHING);
}


Don't care about Rows: 65 because it's a different terrain, the one I usually test is 1025.

plfiorini

18-01-2009 23:20:16

Perhaps I resolved, here's my code to get the heightfield out of a ET::TerrainInfo:


void registerTerrain(const ET::TerrainInfo& info)
{
const int matrixSize = 3;
const NxMaterialIndex matrix[9][3] =
{
// {tesselation, material0, material1}
{0, 1, 1}, {0, 1, 1}, {0, 1, 1},
{0, 1, 1}, {0, 1, 1}, {0, 1, 1},
{0, 1, 1}, {0, 1, 1}, {0, 1, 1}
};
size_t size = info.getWidth() * info.getHeight();
NxReal heightScale = info.getExtents().getSize().y / 65536.0f;

NxHeightFieldSample* samples = new NxHeightFieldSample[size];
NxHeightFieldSample* currentSample = samples;

for (NxU32 row = 0; row < info.getWidth(); ++row)
{
for (NxU32 col = 0; col < info.getHeight(); ++col)
{
NxU32 matrixOffset = (row % matrixSize) * matrixSize + (col % matrixSize);

// Height from terrain information
float worldHeight = info.getHeightAt(row * info.getScaling().x, col * info.getScaling().z);
currentSample->height = static_cast<NxI16>(worldHeight / (info.getExtents().getSize().y / 65536.0f));

// Material
currentSample->tessFlag = matrix[matrixOffset][0];
currentSample->materialIndex0 = matrix[matrixOffset][1];
currentSample->materialIndex1 = matrix[matrixOffset][2];

// Next sample
currentSample++;
}
}

// Create heightfield
NxHeightFieldDesc heightfieldDesc;
heightfieldDesc.nbRows = info.getWidth();
heightfieldDesc.nbColumns = info.getHeight();
heightfieldDesc.format = NX_HF_S16_TM;
heightfieldDesc.thickness = -256.0f * heightScale;
heightfieldDesc.convexEdgeThreshold = 0;
heightfieldDesc.samples = samples;
heightfieldDesc.sampleStride = sizeof(NxHeightFieldSample);
heightField = physicsSDK->createHeightField(heightfieldDesc);

// Delete samples
delete [] samples;

// Shape description
NxHeightFieldShapeDesc heightfieldShapeDesc;
heightfieldShapeDesc.heightField = heightField;
heightfieldShapeDesc.shapeFlags = NX_SF_FEATURE_INDICES;
if (enableDebugger)
heightfieldShapeDesc.shapeFlags |= NX_SF_VISUALIZATION;
heightfieldShapeDesc.heightScale = heightScale;
heightfieldShapeDesc.rowScale = info.getExtents().getSize().x / NxReal(info.getWidth() - 1);
heightfieldShapeDesc.columnScale = info.getExtents().getSize().z / NxReal(info.getHeight() - 1);
heightfieldShapeDesc.holeMaterial = 2;
heightfieldShapeDesc.materialIndexHighBits = 0;
heightfieldShapeDesc.meshFlags = NX_MESH_SMOOTH_SPHERE_COLLISIONS;

// Create actor
NxActorDesc actorDesc;
actorDesc.shapes.push_back(&heightfieldShapeDesc);
actorDesc.globalPose.t = NxVec3(0, 0, 0);
terrainActor = scene->createActor(actorDesc);
}


I'm now playing with the thickness parameter because the boxes I'm tossing penetrate a bit the terrain.
If you have some advise to give me, don't be afraid to share :)