I am procedurally creating a mesh from a height map, creating one vertex of the mesh per pixel in the height map.
The X and Y values of the resultant vertices are predictable - they are pixel indices into the height map, they are an evenly distributed sequence going from 0 to heightMapLength and heightMapWidth respectively. So I can translate the X and Y values of my vertices by -0.5heightMapLength and -0.5heightMapWidth respectively and my mesh will be positioned around its origin on the x and y axes.
This should mean that scaling and rotating and functions like lookAt work nicely as far as the X and Y axes are concerned.
The Z coordinates are different, they come from the greyscale values in the height map. I know that they are all values between 0 and 1, but the lowest and highest values may be anywhere between 0 and 1, and the values are not evenly distributed between 0 and 1. If I put these values directly in my mesh, the mesh will be hovering above its origin, rotating it will not work as I want, and scaling it will actually move my mesh up, lookAt is broken too.
But it is not so simple to translate my mesh to be about its origin on the z-axis. I tried finding both the lowest point and the highest point in the mesh and computing a value half way between the two, then moving every vertex in the mesh down by that value. That ought to mean that the mesh was in some sense centered around its origin on the z-axis and scaling, rotation etc. are fixed. But it doesn’t seem to work. I think I may be suffering from one or two pixels in the height map being orders of magnitude lower in value than all the others, and messing up my calculations.
Is there any good way to do this? The problem as I see it is that I have an unevenly distributed sequence of Z values all between 0 and 1 but not necessarily touching 0 or 1, and I need to translate these values so that they will in some sense be ‘centered’ around the z-origin so that scaling, rotating etc. the mesh will work.
I guess the problem is that you need to define what the origin of your mesh should be, so that you clearly define what it means to scale, etc., the mesh. This really depends on your application.
For instance, if you are defining this mesh to be ground terrain, it might be perfectly reasonable to define the origin at Z=0 of your mesh. You can say this is sea level. Scaling the mesh will indeed make it taller–you are making the mountains bigger, so this is the correct response.
Or, maybe you want the origin to be at Z=0.5. This allows you to define mountains and valleys. Scaling the mesh about this origin will make the mountains bigger and the valleys deeper.
On the other hand, if you are just using this procedural code to build an object that you hold in your hand, maybe you want the origin to be at the visual middle of the piece, so that scaling it seems to scale it around its apparent center. This might be the average of the highest and lowest Z value, as you have already described; or it might be the even average of all the Z values. Or maybe it’s the median. Or maybe it’s a user-defined point that’s different for each mesh. Really, it’s just a question of what looks right.
My trouble is that I’m not talking about any one particular mesh, I’m talking about meshes produced from arbitrary height maps. So there is no general sensible point (like z = 0.5) at which mountains begin and move upwards and valleys begin and move downwards. Basically I want the same code to be able to scale up any terrain to any size, and position the camera in some sensible way so that the terrain (or some of it, if it’s really big) is in view.
But I take your point that there is no general way to center my mesh at the origin on the z-axis. I was thinking about this last night, and it’s not even what I would want to do.
I’m optimistic that I can find some way of doing it, like placing the camera 100 units above one corner of the mesh and orienting it to look at the other corner, something like that, so it won’t matter if the mesh has moved due to scaling.
I would say you should define the sea level point in all of your meshes. Pick an arbitrary point, and declare it to be sea level. Then you must say to anyone who wants to paint a height map for you, “50% gray means sea level. Anything darker than that is a valley; anything brighter than that is a mountain.”
If you don’t want to do this for some reason, then you will have to have some way for the artist to communicate what the intended sea level for a particular mesh is. I don’t think you can determine it by examining the map.