[Solved][Git] ManualHeightField question

Druha

14-10-2009 07:14:12

I am experimenting with runtime heightfield generation and choose ManualHeightField as a tool to get it working.
But, as expected, I've met a problem, again...

After hours of trying to figure out how does it work, I noticed that generated geometry scaled a bit wrong (look at screenshot)
[attachment=0]Esertia-2009-10-13-23-59-04-14.jpg[/attachment]
The edge of geometry (marked as red line) seems to be moving depending on number of rows/collumns that I pass to ManualHeightField::begin()
When it is a big number, the edge moves to its desired position (thick grey line on screenshot), but never reaches it. The distance between edge's position and a place it should be seems to be as between the two nearest vertexes along a world axis (they are also marked on screenshot)
When the number is small, size of geometry become smaller, so edge moves there where red arrow points.
There is also small white dots on the image - those are the cubes placed by the generator function.

And this is the code generated such stuff:

void MapManager::heightFromShape(const unsigned int numQueries, const Vector3& bounds){
RaySceneQuery* rq = GameRoot::getSingleton().getSceneMgr()->createRayQuery(Ray(Vector3(0,0,0),Vector3::NEGATIVE_UNIT_Y));

NxOgre::ManualHeightField* mhf = new NxOgre::ManualHeightField();
mhf->begin(numQueries,numQueries);

const Real normMin = 0.0f;
const Real normMax = 32767.0f;
short sample;

static int counter = 0;

unsigned int x,z;
for(x = 0;x<numQueries;++x){
for(z = 0;z<numQueries;++z){
Ray r = Ray(Vector3(x*(bounds.x-1)/(numQueries-1), bounds.y+1, z*(bounds.z-1)/(numQueries-1)), Vector3::NEGATIVE_UNIT_Y);
rq->setRay(r);
RaySceneQueryResult res = rq->execute();
RaySceneQueryResult::iterator it = res.begin();
while(it!=res.end()){
if(it->worldFragment){
// code based on Wiki Tutorial about Ogre::Terrain and NxOgre
sample = (short)(((it->worldFragment->singleIntersection.y)/(bounds.y)) * (normMax - normMin) + normMin);
mhf->sample(sample);

// add a cube to actually see, where is this point located
SceneNode* sn = GameRoot::getSingleton().getSceneMgr()->getRootSceneNode()->createChildSceneNode(it->worldFragment->singleIntersection);
Entity* ent = GameRoot::getSingleton().getSceneMgr()->createEntity(StringConverter::toString(counter)+"fds","cube.mesh");
sn->attachObject(ent);
sn->setScale(0.02,0.02,0.02);
++counter;
}
++it;
}
}
}
NxOgre::HeightFieldGeometry* hfg = new NxOgre::HeightFieldGeometry(mhf->end(("hf_"+StringConverter::toString(counter)).c_str()),bounds);
if(mMapGeom)
GameRoot::getSingleton().getScene()->destroySceneGeometry(mMapGeom);
mMapGeom = GameRoot::getSingleton().getScene()->createSceneGeometry(hfg);

GameRoot::getSingleton().getSceneMgr()->destroyQuery(rq);
}

At higher resolutions of heightfield I can see, that it copies shape of original terrain almost perfectly, but that scaling... May be I am doing something wrong when creating ManualHeightField class instance?

And, yeah, a link to commit, here it is http://github.com/betajaen/nxogre/commi ... 50b4a4afb3

Druha

19-10-2009 09:41:19

Any suggestions how to fix it?
Or all I have to do is to pass adjusted terrain bounds to HeightFieldGeometry constructor?

betajaen

19-10-2009 10:14:48

Actually, before you start taking your code apart looking for a bug, it may be my fault -- I found a bug with the VisualDebugger, my mistake; currently it's only rendering half of the lines that should be on the screen.

In OGRE3DRenderSystem.cpp

This is the BloodyMess version;

void OGRE3DRenderable::drawVisualDebugger(NxOgre::VisualDebuggerMeshData* data)
{
_resize(data->getNbLines(), 0);

// Write the vertices.
mVertexBuffer->writeData(0, 3 * data->getNbLines() * sizeof(float), data->getLines() );

mVertexColourBuffer->writeData(0, data->getNbLines() * sizeof(unsigned int), data->getColours() );

mBox.setInfinite();

}


This is the correct Detritus version.

void OGRE3DRenderable::drawVisualDebugger(NxOgre::VisualDebuggerMeshData* data)
{
_resize(data->getNbLines() * 2, 0);

// Write the vertices.
mVertexBuffer->writeData(0, 3 * data->getNbLines() * 2 * sizeof(float), data->getLines() );

mVertexColourBuffer->writeData(0, data->getNbLines() * 2 * sizeof(unsigned int), data->getColours() );

mBox.setInfinite();

}


If you want to copy and paste the code over to see if solves your problem go ahead (I may make an official commit in a few days). I can't make no promises, but it's worth having a proper point of reference rather than an incorrect one.

Druha

19-10-2009 15:55:02

Thanks for fix of visual debugger, but nope, it didn't fix the problem.
I've looked into NxOgre code and probably found a place which may contain error.
In NxOgreHeightFieldGeometry.cpp:

HeightFieldGeometry::HeightFieldGeometry(HeightField* heightfield, const Vec3& size, HeightFieldGeometryBlueprint* blueprint)
: Shape(blueprint), mHeightField(0), mHeightFieldShape(0)
{
blueprint->mHeightField = heightfield;

blueprint->mSize.x = size.x / Real(blueprint->mHeightField->getHeightField()->getNbRows()-1); <-- Here must be `getNbRows()-1`
blueprint->mSize.y = size.y / 32768.0f;
blueprint->mSize.z = size.z / Real(blueprint->mHeightField->getHeightField()->getNbColumns()-1); <-- Here must be `getNbColumns()-1`

blueprint->mTerrainCentering = Enums::TerrainCentering_LocalPose;
blueprint->mSmoothSphereCollisions;
blueprint->mHoleMaterial = 65535;
blueprint->mHighBits = 0;
}

Why did I change it to be getNbRows()-1 ? Cause it returns number of Vertices rows, not Faces (number of faces is 1 less then vertices). Later in create method this values used to calculate heightfield scale, that's why it "fails".
These changes solved the problem :wink:

betajaen

19-10-2009 15:59:15

Alright.

Thanks for coming up with a fix, I'll put it into BloodyMess/Detritus.