[bug] Terrain realtime modification goes weird

Hi,
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:

http://pastebin.com/B6EuPnFE

The terrain should morph to a nice ramp, but at the last minute becomes full of spikes.

I there a way to avoid that? Unfortunately, I can’t directly set the HeightMap, because the API shields such usage… :frowning:

Thanks!

You do not want to adjust the heightmap but the terrain itself. The original heightmap just builds a terrain.
Terrain.setHeight()/adjustHeight()/getHeight()
http://hub.jmonkeyengine.org/javadoc/com/jme3/terrain/Terrain.html

1 Like

Thank you @Sploreg! However, I believe that I’m using the API correctly but get wrong results (maybe because of cumulative rounding errors).

Could you please take a look at my example:

http://pastebin.com/B6EuPnFE

The terrain should morph to a nice ramp, but at the last minute becomes full of spikes.

This code doesn’t seem quite right:
[java]
if ((hLocal - height) > digAmount) {
heights.add(-digAmount);
} else if ((hLocal - height) < -digAmount) {
heights.add(digAmount);
} else {
heights.add(0f);
} [/java]

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.

1 Like

Thanks @Sploreg for taking a look to the code. I did as you suggested:

[java]
if ((hLocal - height) > digAmount) {
heights.add(-digAmount);
} else if ((hLocal - height) < -digAmount) {
heights.add(digAmount);
} else {
heights.add(height-hLocal);
}
[/java]

This is the self-contained code:

http://pastebin.com/3q35WDJm

But the original problem got much worse because of this.

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.

1 Like

There is a JME sample test about this. Use this to guide your code.

Still haven’t managed to make it work right. :frowning:

I think there are 2 fundamental issues:

  1. 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?

  2. 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:

[java]
TerrainQuad.setHeight()

int x = Math.round((xz.get(i).x / getWorldScale().x) + halfSize);
int z = Math.round((xz.get(i).y / getWorldScale().z) + halfSize);

public float getHeight(Vector2f xz) {
    // offset
    float x = (float)(((xz.x - getWorldTranslation().x) / getWorldScale().x) + (float)(totalSize-1) / 2f);
    float z = (float)(((xz.y - getWorldTranslation().z) / getWorldScale().z) + (float)(totalSize-1) / 2f);

[/java]

  1. terrain vertices are 1x1 units apart. Take the translation and the scale and work out where the vertices are. If the terrain is scaled 2,1,2 then raise the points every 2 units in both X and Z.

  2. if you raise the terrain in the same spot twice it will doubly raise. Sort out 1) and there will be no problem with raising in the same place multiple times.

1 Like

A-W-E-S-O-M-E @Sploreg!!!
It works =D =D =D

I feel the urge to dance like a monkey 8)

Many thanks!

Cool. Glad it is working now =)
Keep us updated on your progress, I’m always interested in these projects.

Unfortunately, I’ve discovered that it doesn’t always work (I still get some spikes).

I’d like to run my code against a modified TerrainQuad. How can I do that from jMonkey?

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.

Unfortunately the problem is a bit tricky to explain and reproduce on a small case; but I’ll post all the relevant information.

Aha! I think I’ve found it! I’ve to do further testing, but it appears that there’s a bug when:

  1. you create a scene that contains a Terrain
  2. 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.