I’m trying to modify a Terrain in realtime. I (mostly) succeed, but sometimes the heightmap go crazy with huge spikes and narrow holes. I suspect that this is because of cumulative rounding errors.
Here is a small example of what I’m talking about:
You are testing if the difference between the current height and the desired height is more or less than the digAmount and weather you should dig up or dig down. But you do not account if that difference in height is less than the dig amount for that frame. If the dig amount for that frame is larger than the difference between the two heights then you want to set the height to be the desired height, not add digAmount. There will always be some offset where it goes back and forth unless you check for that.
It could be because you have scaled the terrain and are not updating the points in the inbetween locations of the terrain. So if the terrain is 64x64 in size and is then scaled by 2, the world size of the terrain will be 128x128. You will need to make sure you update the size of the terrain at world coordinates: 0, 2, 4, 6… It looks like there might be some intermediate points you aren’t raising.
Picture you are in a level editor and in wireframe view. You use a terrain raise/lower tool at a vertex of the terrain, that vertex raises. The ones next to it do not until you move the tool near to them. This is how raising the terrain works so you need to be in world coordinates (appropriate to the scale of the terrain) and cover all the places that you want to raise/lower.
As @sploreg said, expecially with scaled terrain, I must raise/lower all the vertex. Is there a way to get all the xy coordinates of the vertexes of a TerrainQuad?
The setHeight()/adjustHeight() can possibly do its job on a slightly different position from where the getHeight() is calculated; therefore I’m raising or lowering terrain that is already on desired position. By comparison:
int x = Math.round((xz.get(i).x / getWorldScale().x) + halfSize);
int z = Math.round((xz.get(i).y / getWorldScale().z) + halfSize);
If you’re getting spikes, you have to make sure the value you passed to setHeight() or adjustHeight() is scaled back to a value between 0f and 1f (e.g.: 0.3f) also if you’re using adjustHeight() make sure it does not make it so that it exceeds >1f or <0f. Think of it like a percentage and always account for your terrain scale. If getWorldHeight() == 128f for instance and getWorldScale() == 4f for instance, then: 0.3f == 30% of height (128f) times scale (4f) so setHeight(0.3f) == 153.6f
Maybe you just forgot the scale factor.
EDIT: And just to be clear adjustHeight() needs a delta, not a final value. So it will ADD the passed value to the current terrain triangle height. So if you’re calling adjustHeight(0.3f) on a terrain triangle that is already 0.25f then the final triangle height will be 0.25f + 0.3f = 0.55f and if you’re calling it again later on it will be 0.55f + whatever value, so it always adds up, that’s why you may be better to stick with setHeight() to start with, because it’s simpler.
Aha! I think I’ve found it! I’ve to do further testing, but it appears that there’s a bug when:
you create a scene that contains a Terrain
you do sceneModel.setLocalScale(something)
The Terrain (which is a child of the scene) is scaled, but somehow internally it thinks that is still unscaled. This produces weird result on my plugin, and also the bulletAppState is affected (in particular, the native bullet shows that the mesh don’t match what you see).
My current solution is: DO NOT apply scaling on the Scene, only on the Terrain. But this makes the Scene editor less useful until a fix is found.