Heightmap to mesh

noferat

20-12-2010 19:09:30

I'm in need of some help. How to generate mesh from heightmap ? Thanks.

Beauty

26-12-2010 12:28:45

Welcome to our Mogre community :D

If you want to add terrain, you can do this by scene managers, e.g. the Terrain Scene Manager (see tutorials).
Somewhere in the Ogre main forum I saw a code snippet (C++ Ogre) for creating a mesh from a height map. I suppose it was postet at least 2 years ago. (If you need this, I hope you can find it.)
Alternatively you could look to the Ogre source code. Somewhere is the Ogre own C++ code for the Terrain Scene Manager.

You also could write a sampler by the ray query class, which sends a vertical ray to the ground on different places of the map to get it's height. From the height values you could create a mesh.

Maybe it's also possible to use an external application to convert a height map to a 3D model.
Have a look to the applications Blender and L3DT. Maybe this is usable.

Sorry, I can't help you more.

Beauty

26-12-2010 16:31:59

Somewhere in the Ogre main forum I saw a code snippet (C++ Ogre) for creating a mesh from a height map.
I found it:
http://www.ogre3d.org/phpBB2addons/view ... 9&start=40

noferat

27-12-2010 19:26:40

I generated the mesh so:
private void CreateMeshGeom()
{
Bitmap image = (Bitmap)arr[0];
int width = (int)image.Width;
int height = (int)image.Height;
float xmin, zmin;
float xmax, zmax;
int xindex = 0;
int zindex = 0;

float heightMultiplier = 1f;

int sampleRate = 1;
int count = -1;
ManualObject obj = smgr.CreateManualObject("tmp_");

obj.Begin("", RenderOperation.OperationTypes.OT_TRIANGLE_LIST);
for (zindex = 0; zindex + sampleRate < height; zindex += sampleRate)
{
zmin = zindex;
zmax = zindex + sampleRate;

for (xindex = 0; xindex + sampleRate < width; xindex += sampleRate)
{
xmin = xindex;
xmax = xindex + sampleRate;

Color c = image.GetPixel((int)xmin, (int)zmin);
obj.Position(xmin, c.R * heightMultiplier, zmin);
obj.TextureCoord(xmin / (float)width, zmin / (float)height);

// bottom-right vertice
c = image.GetPixel((int)xmin, (int)zmax);
obj.Position(xmin, c.R * heightMultiplier, zmax);
obj.TextureCoord(xmin / (float)width, zmax / (float)height);

// top-right vertice
c = image.GetPixel((int)xmax, (int)zmax);
obj.Position(xmax, c.R * heightMultiplier, zmax);
obj.TextureCoord(xmax / (float)width, zmax / (float)height);


// top-left vertice
c = image.GetPixel((int)xmax, (int)zmin);
obj.Position(xmax, c.R * heightMultiplier, zmin);
obj.TextureCoord(xmax / (float)width, zmin / (float)height);
count += 4;
obj.Triangle((uint)count - 3, (uint)count - 2, (uint)count - 1);
obj.Triangle((uint)count - 1, (uint)count, (uint)count-3);
}
}
obj.End();
obj.ConvertToMesh("Rive_");
}


But when the camera up there artifacts:


My generated mesh - blue.
Its not z-fighting. Mogre simplifies the geometry of an increase in the height of the camera.
Changes near and far clipdistance, not what does not.
Where is my mistake ??
Thanks.

Beauty

30-12-2010 13:42:16

I don't know if Ogre simplifies Meshes for higher distances.
I just know that this happens for some scene managers (e.g. the terrain scene manager).

Just an idea:
Maybe the vertex order of some triangles is wrong.
In common cases triangle surfaces are only visible from one side. The top side is defined by the vertex order of the triangles.

Is your code a port of the C++ code snippet or did you create it by your own?

noferat

30-12-2010 18:44:57

Code taken from here: https://www.ogre3d.org/forums/viewtopic.php?f=2&t=32268
What order should have a mesh vertex?
I generated the mesh so, (0,1,2) - the first triangle, (2, 3, 0) - second triangle, (4, 5, 6) - third triangle, etc. by column:

mikael

31-12-2010 18:34:38

I hope ogre supports triangle strips, that is the one you should use, when creating heightmap -> polys.

http://en.wikipedia.org/wiki/Triangle_strip

noferat

31-12-2010 19:12:15

Thank you all. Problem solved.
Replaced in the configuration file TerrainManager -> MaxMipMapLevel=5 to MaxMipMapLevel=1, and it worked.

Beauty

01-01-2011 12:09:51

Nice to see, that it you found the solution :D

Triangle strip is more efficient (because less vertices) and supported by Ogre.
In your source code replace OT_TRIANGLE_LIST
by OT_TRIANGLE_STRIP.

Thanks for the wikipedia link.
I will add it to the wiki page of ManualObject and will add the image from wikipedia. ... done!

The mesh generation code is useful. It would be nice when you publish your final code.
Maybe as a static method?
Then I would add it to the wiki.

Do you know if it generates the equal 3D surface as the Terrain Scene Manager?

noferat

01-01-2011 12:35:00

I generate mesh of grayscale heightmap, based on: http://www.ogre3d.org/tikiwiki/Generati ... e=Cookbook
My code:
void GenMesh()
{
/// Create the mesh via the MeshManager
MeshPtr msh = MeshManager.Singleton.CreateManual("Rive_", "General");
float max = 0;
/// Create one submesh
SubMesh sub = msh.CreateSubMesh();
////////////Image in ArrayList, its grayscale heightmap
Bitmap image = (Bitmap)arr[0];
////////////////////
int nVertices = image.Width*image.Height;
int vbufCount = 3*2*nVertices;
//////generate triangles order
ArrayList arra = new ArrayList();
int jf = 0;
int ibufCount = nVertices;
for (int j = 0; j < image.Height-1; j++)
for (int i = 0; i < image.Width; i++)
{
if (i - 1 >= 0)
{
arra.Add(jf - 1);
arra.Add(jf);
arra.Add(image.Width + jf);

}
if (i + 1 <= image.Width)
{
arra.Add(jf);
arra.Add(image.Width + 1 + jf);
arra.Add(image.Width + jf);
}
jf++;
}
int iVerticles=arra.Count;
uint[] face = new uint[arra.Count];
for (int i = 0; i < iVerticles; i++) face[i] = (uint)(int)arra[i];

///////////
float []vertices = new float[vbufCount];
int temp=0;
for(int i=0;i<image.Width;i++)
for(int j=0;j<image.Height;j++)
{
Vector3 vc=new Vector3(i,image.GetPixel(i,j).R,j);//R - height mesh, as grayscale, for example (255,255,255)- r,g,b - equal
Vector3 nc=vc.NormalisedCopy;
vertices[temp]=vc.x;
vertices[temp+1]=vc.y;
vertices[temp+2]=vc.z;
vertices[temp+3]=nc.x;
vertices[temp+4]=nc.y;
vertices[temp+5]=nc.z;
if (max < vc.y) max = vc.y;
temp+=6;
}
/////Vertex color
uint[] color = new uint[nVertices];
for (int i = 0; i < nVertices; i++) color[i] = 43534346;

/// Create vertex data structure for 8 vertices shared between submeshes
msh.sharedVertexData = new VertexData();
msh.sharedVertexData.vertexCount = (uint)nVertices;

/// Create declaration (memory format) of vertex data
VertexDeclaration decl = msh.sharedVertexData.vertexDeclaration;
uint offset = 0;
// 1st buffer
decl.AddElement(0, offset, VertexElementType.VET_FLOAT3,VertexElementSemantic.VES_POSITION);
offset += VertexElement.GetTypeSize(VertexElementType.VET_FLOAT3);
decl.AddElement(0, offset,VertexElementType.VET_FLOAT3,VertexElementSemantic.VES_NORMAL);
offset += VertexElement.GetTypeSize(VertexElementType.VET_FLOAT3);
/// Allocate vertex buffer of the requested number of vertices (vertexCount)
/// and bytes per vertex (offset)
HardwareVertexBufferSharedPtr vbuf =
HardwareBufferManager.Singleton.CreateVertexBuffer(
offset, msh.sharedVertexData.vertexCount, HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY);
/// Upload the vertex data to the card
unsafe
{
fixed(void* vert=vertices) vbuf.WriteData(0, vbuf.SizeInBytes, vert, true);
}

/// Set vertex buffer binding so buffer 0 is bound to our vertex buffer
VertexBufferBinding bind = msh.sharedVertexData.vertexBufferBinding;
bind.SetBinding(0, vbuf);

// 2nd buffer
offset = 0;
decl.AddElement(1, offset, VertexElementType.VET_COLOUR, VertexElementSemantic.VES_DIFFUSE);
offset += VertexElement.GetTypeSize(VertexElementType.VET_COLOUR);
///// Allocate vertex buffer of the requested number of vertices (vertexCount)
///// and bytes per vertex (offset)
vbuf = HardwareBufferManager.Singleton.CreateVertexBuffer(
offset, msh.sharedVertexData.vertexCount, HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY);
///// Upload the vertex data to the card
unsafe
{
fixed (void* vert = color) vbuf.WriteData(0, vbuf.SizeInBytes, vert, true);
}

///// Set vertex buffer binding so buffer 1 is bound to our colour buffer
bind.SetBinding(1, vbuf);

/// Allocate index buffer of the requested number of vertices (ibufCount)
HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager.Singleton.
CreateIndexBuffer(
HardwareIndexBuffer.IndexType.IT_32BIT,
(uint)iVerticles,
HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY);

///// Upload the index data to the card
unsafe
{
fixed (void* vert = face) ibuf.WriteData(0, ibuf.SizeInBytes, vert, true);
}

/// Set parameters of the submesh
sub.useSharedVertices = true;
sub.indexData.indexBuffer = ibuf;
sub.indexData.indexCount = (uint)iVerticles;
sub.indexData.indexStart = 0;

/// Set bounding information (for culling)
msh._setBounds(new AxisAlignedBox(0,0,0,image.Width,max,image.Height));

/// Notify -Mesh object that it has been loaded
msh.Load();
}

Beauty

01-01-2011 13:22:03

Thanks, I created a wiki page and added it :D
http://www.ogre3d.org/tikiwiki/Heightma ... h+by+MOGRE

mikael

01-01-2011 18:51:36

Well this is offtopic but why there are methods that have _ prefix, like _setBounds ? What is the reason using this _ ?

Beauty

02-01-2011 11:39:48

Some Ogre methods starts with an underscore _.
As I read the aim of this methods is to get public access to internal methods.
In normal cases they shouldn't be used. (Maybe I'm wrong, but I think this was the reason.)

Maybe the aim has changed now, because sometimes you are forced to use such methods.
For example the method SceneNode.getWorldPosition() was removed. Now you have to use ._getDerivedPosition() instead.