[Solved] [Git] Ogre::Terrain + NxOgre Heightfield

Illidanz

16-08-2009 07:52:47

NOTE: See this wiki page for the solution: http://www.ogre3d.org/wiki/index.php/Bl ... eightfield

I am using this commit

Hello,
I'm trying to match the physx heightfield with the one that the new Ogre::Terrain creates

Following the hints in this thread I've been able to flip and rotate the heightfield successfully, but now I have problems to match the height, as you can see in this screenshot:



I've tried to play with the Pose, but if I use larger values to match the bottom part of the terrain, the top one is taller than what it should be

This is the relevant code:
NxOgre::ResourceSystem::getSingleton()->openArchive("media", "file:Assets\\Terrain");
NxOgre::HeightField* hf = NxOgre::HeightFieldManager::getSingleton()->load("media:terrain.xhf");

// These values are taken from Ogre::Terrain, maybe I should use something else for the height?
NxOgre::HeightFieldGeometry* hfg = new NxOgre::HeightFieldGeometry(hf, NxOgre::Real3(terrain->getWorldSize(), terrain->getMaxHeight(), terrain->getWorldSize()));
hfg->setLocalPose(NxOgre::Matrix44(NxOgre::Real3(0,0.5,0))); // <- tried to play with different values without luck
mScene->createSceneGeometry(hfg);


What parameters should i tweak to get a correct representation?

Thanks in advance

Illidanz

22-08-2009 17:38:00

Had some more time to play with this.

I can get the most correct representation using this code:
NxOgre::HeightFieldGeometry* hfg = new NxOgre::HeightFieldGeometry(hf, NxOgre::Real3(terrain->getWorldSize(), terrain->getMaxHeight() / 2.0, terrain->getWorldSize()));
hfg->setLocalPose(NxOgre::Matrix44(NxOgre::Real3(0, terrain->getMaxHeight() / 2.0, 0)));


However, it's still not perfect, and especially when the terrain is curved a lot (like hills or mountains) there's a difference up to 0.5 ogre units (meters, in my case)

There's a method to generate the .xhf manually using the data Ogre::Terrain gives me so that it matches better, or can I create it at runtime using the same data?

betajaen

22-08-2009 18:50:31

or can I create it at runtime using the same data?

Have a look at the manual height field class.

Illidanz

22-08-2009 22:39:00

or can I create it at runtime using the same data?

Have a look at the manual height field class.

Thanks, I've really missed that :D

There are still some imperfections, but it works a lot better than before! It's fast even for a 1000x1000 terrain and there's no need to use flour or flip/rotate the heightmap before.
If anyone has some fast-thoughts on a stupid error I've made, please post in this thread.

If anyone needs to do the same thing, here my code. Take it as it is, not sure if this is the best way and I've not tested it extensively
Moved to wiki

Thanks again betajaen :)

betajaen

22-08-2009 23:50:59

Glad to hear!

Spacegaier may come in here; Asking you if he can wiki that so others can use it. So how about we deny him the privilege and you put it in there for him? ;)

Illidanz

23-08-2009 07:19:55

Glad to hear!

Spacegaier may come in here; Asking you if he can wiki that so others can use it. So how about we deny him the privilege and you put it in there for him? ;)

I've put it under code snippets, as of now it's more a snippet than a complete tutorial spacegaier could make out of this.
Link here: http://www.ogre3d.org/wiki/index.php/Bl ... eightfield

Feel free to move it under a more appropriate category, edit it, or whatever

betajaen

23-08-2009 12:05:35

Excellent.

Also; since you have some minor inaccuracies, you may want to check if the tesselation of each sample is in the correct direction (I think Ogre switches the direction every other row). You can check by enabling the VisualDebugger in NxOgre and turning on the equivalent in Ogre and comparing the differences in the two wifeframe meshes.

Illidanz

23-08-2009 14:52:00

Excellent.

Also; since you have some minor inaccuracies, you may want to check if the tesselation of each sample is in the correct direction (I think Ogre switches the direction every other row). You can check by enabling the VisualDebugger in NxOgre and turning on the equivalent in Ogre and comparing the differences in the two wifeframe meshes.

Thanks betajaen, I haven't noticed before, now it's fixed. Updated code can be found in the wiki.

I've also fixed a problem with the size of the terrain that was causing the heightfield to be smaller than what it should be, rendering it very inaccurate when you were far from the origin
This is the offending line, with the fix highlighted

NxOgre::HeightFieldGeometry* hfg = new NxOgre::HeightFieldGeometry(hf, NxOgre::Real3(terrain->getWorldSize() + (terrain->getWorldSize() / terrain->getSize()), terrain->getMaxHeight() / 2.0, terrain->getWorldSize() + (terrain->getWorldSize() / terrain->getSize())));

I've come up with this just through trial and error and tests, but I'm confident that it will work with every terrain size/world size

End of the story: now it's REALLY perfect :) Here's a screenshot (not the best angle maybe, but whatever)



Thanks again for your support betajaen, and for the awesome nxogre of course! :D

betajaen

23-08-2009 16:48:18

Excellent work! I'm glad you have it pixel perfect now.

And thanks for wiking it.

spacegaier

23-08-2009 19:34:25

Cool, that this works now. This will definetly find its way in the Terrain / Heightfield tutorial. So far this was the only big show stopper for it (the non-alignment). That being fixed, I could immediately start writing, but I still have some other things upfront (raycasting tutorial and betajaen's special tutorial <- not forgotten, only on hold right now...)

Illidanz

25-08-2009 10:13:18

As someone pointed out this via PM, I'll post the answer here too so everyone knows:
in the screenshot it seems that on the left side the tesselation is wrong, but if you look closely you'll see that every "ogre square" (the brown ones), is made of 4 "physx squares" (the red ones), this is because the terrain on the left is LODed, but when you go near it, and you see the highest level of detail, everything is pixel-perfect and with the right tesselation

Also, the code doesn't support terrains in non-zero position, or multiple terrains, this will be worked out in the next days when I have a bit of time and I'll edit the code in the wiki

spacegaier

25-08-2009 10:33:29

Great! Really appreciating all the effort you are putting into this. Am really keen on seeing these new features in action.

Illidanz

31-08-2009 07:08:04

Here's me again-

Had a very little time these days so sorry for the delay :)

I've moved the code into another page of the wiki, as it was starting to clutter the snippet page, that I feel should contain very little snippets instead of big chunks of code, so this is the new link: http://www.ogre3d.org/wiki/index.php/Bl ... eightfield
Updated the code, that is a little bit polished, and it now supports terrain in every kind of position.

For the name of the NxOgre heightfield, it now uses the material name of the terrain, that I assume is unique for every terrain, so there should be no problem with using multiple terrains.

If someone has problem with this, please post in this thread and I'll look into it.

XpLoDWilD

23-12-2009 12:03:28

Tried recently, it works quite well... Unless you edit it downwards.

If I make a terrain with some hills, everything works well. But if I make some lakes (ie. push terrain downwards), the physics geometry isn't quite right, like it's not scaled in the Y axis properly. I'm using BloodyMess, with the code from wiki, and latest Ogre SVN. Maybe sinbad changed something in the Terrain component ?
I can't use the VisualDebugger, as it freeze my app when rendering.

Illidanz

24-12-2009 07:42:39

Tried recently, it works quite well... Unless you edit it downwards.

If I make a terrain with some hills, everything works well. But if I make some lakes (ie. push terrain downwards), the physics geometry isn't quite right, like it's not scaled in the Y axis properly. I'm using BloodyMess, with the code from wiki, and latest Ogre SVN. Maybe sinbad changed something in the Terrain component ?
I can't use the VisualDebugger, as it freeze my app when rendering.

Unfortunately I cannot work with NxOgre these days.

Can you however post the heightmap and the code you use to generate the Ogre terrain so I can reproduce the bug?

Also, a screenshot with the visual debugger would really help, just enable it via an hotkey or whatever if it freezes the app so bad.

XpLoDWilD

24-12-2009 09:28:50

Here's the heightmap:
http://filebeam.com/232324302ee730cb734ccf4eba921701

To load it, just do terrain->load("Ilots_1.adt");

I tried again visualdebugger, it takes about 5-10s to render a frame, and then crash with a null pointer exception. I really can't use it, sorry :/ (without terrain, it works btw).

Illidanz

24-12-2009 09:51:10

Here's the heightmap:
http://filebeam.com/232324302ee730cb734ccf4eba921701

To load it, just do terrain->load("Ilots_1.adt");

I tried again visualdebugger, it takes about 5-10s to render a frame, and then crash with a null pointer exception. I really can't use it, sorry :/ (without terrain, it works btw).

Thanks, I'll look into that asap (after the holidays I hope)

XpLoDWilD

03-01-2010 09:54:19

I've played around with it a little bit, tried different values or maths operations, but still no luck, I really have problems when making lakes (editing downwards), like if the Y scale wasn't good. Did you have some time Illidanz to look into it?

Cryogenik28

03-01-2010 23:53:17

What about using .raw or .png file types with the BloodyMess Ogre::Terrain heightfield code, instead of using .adt files? How would I properly load a raw file to create the manualheightfield after creating the terrain pointer and using the load funtion? I was originally using an xhf file and using the NxOgre load process and I am having the same problem of matching up the Ogre terrain with the NxOgre physX terrain -- original process:

mSceneMgr->setWorldGeometry("terrain.cfg");
NxOgre::ResourceSystem::getSingleton()->openArchive("Nx", "file:Levels\\LV1-HOME\\Terrains");
NxOgre::HeightField* hf= NxOgre::HeightFieldManager::getSingleton()->load("Nx:level1.xhf");
NxOgre::HeightFieldGeometry* hfg = new NxOgre::HeightFieldGeometry(hf,NxOgre::Real3(3000,700,3000));
hfg->setLocalPose(NxOgre::Matrix44(NxOgre::Real3(0,500,0)));//should be 350 but seems to be too low
mScene->createSceneGeometry(hfg);

---------------------------
With the new code I tried loading that .adt file using the terrain->load and at least I don't get a serializer error that I was with the raw, so I assume setting up some type of data stream process to get it loaded, but I am having trouble and wanted some direction on using either raw or png file type properly. Thanks.

Illidanz

04-01-2010 13:30:17

@XpLoDWilD: I just returned from the holidays, I'll try to look into it in the next weeks, but no promise: I'm onto another project now so the old one that uses Physx/NxOgre is on standby.

@Cryogenik28: What do you mean by using .raw or .png files? The whole point of this code is to use the data that Ogre::Terrain provides to create an exact matching heightfield.
If you really want to use the image file to create the ManualHeightfield, you can look in Ogre::Image to load the heightfield and parse the data. There's a little example here, although it's made for old versions of the code it should put you on the right track.

Cryogenik28

04-01-2010 16:58:56

Illidanz -- Thanks. That's mainly what I was looking for. I was about to go to using a mesh to make things work better, but found this new code! Thanks for your time in coding that manual heightfield and for answering my questions.

Cryogenik28

04-01-2010 20:38:42



@Cryogenik28: What do you mean by using .raw or .png files? The whole point of this code is to use the data that Ogre::Terrain provides to create an exact matching heightfield.
If you really want to use the image file to create the ManualHeightfield, you can look in Ogre::Image to load the heightfield and parse the data. There's a little example here, although it's made for old versions of the code it should put you on the right track.


Ok, I see your point, even though I guess I could load a raw. But what I am doing is setting my terrain.cfg using mSceneMgr->setWorldGeometry("terrain.cfg"); --- then I create a new terrain pointer for the Ogre:Terrain using the mSceneMgr:

Ogre:Terrain terrain = new Ogre::Terrain(mSceneMgr);

and then should I do a terrain->load(); ? with or without a filename like an .adt file?? or just utilize the Terrain manual heightfield code after creating the pointer without a load? either way I get zero for my values of size within the code, so I get nothing. I can load a file like the .adt file provided and my terrain.cfg terrain loads.

How would I create an .adt file of my terrain for that matter? I seem to be missing something between creating my terrain pointer and using the code. I would rather see if I can just use the code without having to load a raw or png file first, and my terrain.cfg is loading my raw heightmap. Thanks again for any help.

Illidanz

04-01-2010 20:42:53



@Cryogenik28: What do you mean by using .raw or .png files? The whole point of this code is to use the data that Ogre::Terrain provides to create an exact matching heightfield.
If you really want to use the image file to create the ManualHeightfield, you can look in Ogre::Image to load the heightfield and parse the data. There's a little example here, although it's made for old versions of the code it should put you on the right track.


Ok, I see your point, even though I guess I could load a raw. But what I am doing is setting my terrain.cfg using mSceneMgr->setWorldGeometry("terrain.cfg"); --- then I create a new terrain pointer for the Ogre:Terrain using the mSceneMgr:

Ogre:Terrain terrain = new Ogre::Terrain(mSceneMgr);

and then should I do a terrain->load(); ? with or without a filename like an .adt file?? or just utilize the Terrain manual heightfield code after creating the pointer without a load? either way I get zero for my values of size within the code, so I get nothing. I can load a file like the .adt file provided and my terrain.cfg terrain loads.

How would I create an .adt file of my terrain for that matter? I seem to be missing something between creating my terrain pointer and using the code. I would rather see if I can just use the code without having to load a raw or png file first, and my terrain.cfg is loading my raw heightmap. Thanks again for any help.

Nope.

You can't create the "old" terrain with setWorldGeometry and the "new" Ogre::Terrain together, they're two totally different things.

You should get rid of the setWorldGeometry, and concentrate on Ogre::Terrain. See the Sample_Terrain that comes with Ogre for more informations, it's a bit hard to grasp at the beginning but it's much better than the older one. If you're in trouble with that, post in the Ogre's Help forum, they'll help you out much better than me.

Then, when you have your Ogre::Terrain successfully rendered on the screen, you can use my code to create the PhysX heightfield. And if you have problems with that, post here :)

Cryogenik28

04-01-2010 20:54:00

Cool -- Thanks again for all your help, I should be able to get things going now.

XpLoDWilD

05-01-2010 19:25:19

Btw, "adt" is just a dummy extension, it's an Ogre::Terrain that has been saved with terrain->save(); . I could have put anything as an extension :)

Cryogenik28

05-01-2010 19:39:38

Yeah -- I noticed that after looking at the new 1.7 Terrain code in the sample_terrain, that it can be saved as "dat" and you just used "adt". Nonetheless I was doing things the old way and mixing things up until I looked at the new Terrain stuff. Thanks for pointing that out though.

Cryogenik28

06-01-2010 16:29:04

I thought I would mention I got the new v1.7 Terrain stuff working with this NxOgre Heightfield code and it works like a charm. I followed what everyone pointed out, and I am loading my heightfield using my png for the terrain. I tested with some cube meshes and everything doesn't fall through the Terrain, like it should!!! and it is fairly speedy, as I get good FPS on my 513x513 terrain. So thanks Illidanz for pointing me in the right direction on the new stuff, I am finally off of the old way of doing things!! :)

XpLoDWilD

16-01-2010 11:24:39

Well, I still haven't found a solution to my problem. Illidanz, did you have some time to look into it?

archangel92

16-01-2010 15:22:14

How can i use it with PhysX SDK, not NxOgre?

Illidanz

16-01-2010 17:45:42

Well, I still haven't found a solution to my problem. Illidanz, did you have some time to look into it?
Just to let anyone else know: I'm looking into the issue with XpLoDWilD in private. If we come up with a solution, we'll post it here.

How can i use it with PhysX SDK, not NxOgre?
I honestly don't know, I've never used PhysX without NxOgre.

As NxOgre is opensource, you can read the sources of the components that I use so you can see what's being done under the hood.

archangel92

17-01-2010 09:47:44

ok, i'm trying this

XpLoDWilD

23-01-2010 11:24:02

I played around with the code, and finally manage to make it working !
Here's the working code, if you have edited your terrain downwards (creating lakes, etc) :


while (iter.hasMoreElements())
{
Ogre::Terrain* terrain = iter.getNext()->instance;

if (!terrain)
continue;

// Create the manual heightfield
NxOgre::ManualHeightField *mhf = OGRE_NEW_T(NxOgre::ManualHeightField, Ogre::MEMCATEGORY_GENERAL)();
mhf->begin(terrain->getSize(), terrain->getSize());
// Get data from Ogre::Terrain
float *terrainData = terrain->getHeightData();
unsigned short mapSize = terrain->getSize();
Ogre::Real min = terrain->getMinHeight();
Ogre::Real max = terrain->getMaxHeight();
Ogre::Real normMin = -32767.0f;
Ogre::Real normMax = 32767.0f;
// Sample the data to the manual heightfield
for(int x = 0; x < mapSize; ++x)
{
NxOgre::Enums::HeightFieldTesselation tess = NxOgre::Enums::HeightFieldTesselation_NW_SE;
for(int z = mapSize-1; z >= 0; --z)
{
Ogre::Real height = terrainData[(mapSize * z) + x];
short sample = (short)(((height - min) / (max - min)) * (normMax - normMin) + normMin);
mhf->sample(sample, 0, 0, tess);
if(tess == NxOgre::Enums::HeightFieldTesselation_NE_SW)
tess = NxOgre::Enums::HeightFieldTesselation_NW_SE;
else
tess = NxOgre::Enums::HeightFieldTesselation_NE_SW;
}
}
// Create the actual heightfield
NxOgre::HeightField *hf = mhf->end(terrain->getMaterialName().c_str());
Ogre::Real hf_size = terrain->getWorldSize() + (terrain->getWorldSize() / terrain->getSize());
Ogre::Real hf_height = (terrain->getMaxHeight() - terrain->getMinHeight())/2.0f; // / 2.0f;
NxOgre::HeightFieldGeometry* hfg = new NxOgre::HeightFieldGeometry(hf, NxOgre::Real3(hf_size, hf_height, hf_size));
Ogre::Real hf_pose_x = terrain->getPosition().x - (terrain->getWorldSize() / 2.0f);
Ogre::Real hf_pose_y = terrain->getPosition().y + ((terrain->getMaxHeight() + terrain->getMinHeight()) / 2.0f);// + (terrain->getMaxHeight() / 2.0f);
Ogre::Real hf_pose_z = terrain->getPosition().z - (terrain->getWorldSize() / 2.0f);
hfg->setLocalPose(NxOgre::Matrix44(NxOgre::Real3(hf_pose_x, hf_pose_y, hf_pose_z)));
m_Scene->createSceneGeometry(hfg);
// Free memory
OGRE_DELETE_T(mhf, ManualHeightField, Ogre::MEMCATEGORY_GENERAL);

}


I haven't tested it much, but now my character doesn't hover over terrain when going in holes :)
The code is pretty much the same, I just edited hf_height and hf_pose_y calculations

Illidanz

23-01-2010 12:21:44

Thanks for your help.

I've done a couple of tests with my terrain and everything seems fine, so I've updated the code in the wiki: http://www.ogre3d.org/wiki/index.php/Bl ... eightfield

The code is now in the useful form of a function, and it works with both 1.6 (Detritus) and 1.5 (Mess/Git).

betajaen

23-01-2010 14:17:46

Excellent!

If I meet you guys in a pub, I'll buy a round.

[Edit]

If you like, I can put it into Detritus's OGRE3DRenderSystem.

Illidanz

23-01-2010 15:13:02

If you like, I can put it into Detritus's OGRE3DRenderSystem.
It would be great, maybe use a #if OGRE_VERSION_MAJOR >= 1 && OGRE_VERSION_MINOR >= 7 for ppl that are still using Ogre 1.6

betajaen

23-01-2010 17:05:45

That is what I was thinking.