Change Terrain "on the fly"

Hey folks,



Due to requests from the MW3D camp, a new Terrain feature has been added that makes it possible for you to edit a Terrain's data and view the new terrain in your scene without recreating the Terrain object.



For a quick demo, add the following to TestTerrainPage (make sure you update everything from cvs first):


  int x, y = 0;
  protected void simpleUpdate() {
     
      for (;x<=256;x++)
          page.addHeightMapValue(x,y,(int)(FastMath.nextRandomFloat() * 20) - 10);
      page.updateFromHeightMap();
      x = 0;
      y++;
      if (y > 256)
          y = 0;
  }



Basically that goes through the demo's TerrainPage and randomly adds/substracts about 10 points from the heightmap at each point along row y. 

So, the point is that you can manipulate a TerrainBlock's heightmap data and call updateFromHeightMap() to regenerate verts and normals on that block.  That's great all by itself, but it's annoying to calculate the correct 1d position in the heightmap array from a 2d point.  So I've also added convienent set/add and mult methods to do that calculation for you (if you want).

Even more annoying would be to try to figure out given a TerrainPage which block holds the coordinate you want to alter and properly alter that.  Especially with vertex doubling on the borders.  To solve that, you can call those aforementioned methods directly on the TerrainPage and it will go to the proper sub block.

If you need any help with this, or find bugs, pipe up as always!

Thanks for this renanse.

We will try it out in MonkeyWorld3D and keep you up to date on what is

going on!

Again, thanks for this.

Thanks renanse for the fast reponse, this would really rock.

Awesome



Have been trying this in conjunction with the FaultFractalHeightMap and the ProceduralTextureGenerator.



Have managed to recreate the ProceduralTextureGenerator to show correct terrain per altitude



Had to subclass my own FaultFractalHeightMap, so i could regenerate with an int [] heightmap, also had to coordinate the update to the page as well as the height map - but hey - it works



Fantastic work…

One quick observation, the heightmap is an int[] with each page making its own copy.

Would there be any benefit in this being an object essentially wrapping an int [], that way you only need to update heightmap in one place. The procedural generator would also have the reference to the same int []  through the wrapping object

actually, TerrainPages do not have a copy of the heightmap at all and TerrainBlock has a copy only of its individual heightmap, so extra data is not being stored.

As a small word of advice: when you post code put it between [ code ] [ /code ] tags, so it doesn't turn text into smileys. You can still edit your post of course.

Small observation



In TerrainPage, the else's highlighted in red could be added



public void setHeightMapValue(int x, int y, int newVal) {

        int quad = findQuadrant(x,y);

        int split = (size + 1) >> 1;

        for (int i = children.size(); --i >= 0; ) {

            Spatial spat = (Spatial)children.get(i);

            String name = spat.getName();

            int col = x;

            int row = y;

            if (name.endsWith("1") && (quad & 1) != 0) {

                ; // vals are correct

            }

            else if (name.endsWith("2") && (quad & 2) != 0) {

                row = y-split+1;

            }

            else if (name.endsWith("3") && (quad & 4) != 0) {

                col = x-split+1;

            }

            else if (name.endsWith("4") && (quad & 8) != 0) {

                col = x-split+1;

                row = y-split+1;

            }

           

            if ((spat.getType() & Spatial.TERRAIN_PAGE) != 0) {

                ((TerrainPage)spat).setHeightMapValue(col, row, newVal);

            } else if ((spat.getType() & Spatial.TERRAIN_BLOCK) != 0) {

                ((TerrainBlock)spat).setHeightMapValue(col, row, newVal);                   

            }

        }

}

Thanks, copy paste artifact. :slight_smile:

Hi



Small buglet in the latest change. It seems that all children are passed into the method and tested on

Thanks.  I've got that in locally and I'm looking into int comparisons.  Stay tuned.

I was able to remove all of the name comparisons as well as a bunch of Iterator creation spots.  It's looking a lot cleaner and should run faster as well.  During testing I noted that updating the terrain does not reinit the bounds.  Make sure you do that after doing all the updates required for a given frame to prevent camera culling issues.  The methods themselves do not do that automatically because it would generate a ton of extra work when you really just want to update the bounds once after all manipulations are done.

Nice - the culling is probably another issue i have with something else ( im such a newbie - lol ).



Ok - im kinda thinking that the parent of the terrain page, on construction could be informed of the page/block depths. If the parent knew this, then it would know how to directly call the block height change methods bypassing the nesting via an algoryrythm. It may also introduce the possibility of using the same heightmap array from the original heightmap. - but all the buffer updating melarky is way out my depth as is so i may be waffling utter nonsense.

Nesting is important to a lot of things, such as culling and the whole quadtree implementation.  The filtering down of heightmap changes is pretty fast, uses no extra memory, etc. so I think we're good where we are.

Hi there guys.

I have a computation problem. I know it is easy but for some reason

I can't get my head arround it.

I want to change the height of the terrain at a certain position (x, y) on the terrain.

I which to have an even decrease in the height as it goes outwards to the radius maximum.

If anyone can help me or someone who successfully done this, please?, this is for MW3D.

Also, it should update from the old height of that point in an even movement!



:smiley:

Hi their, renanse, well this method was working realy nice, until the latest update, here is what we got in update.







I have also went and tested the TestTerrainPage, and its the same result, we are using terrian pages, and i think the method works for the terrian block but not for the terrain pages.



Thanks in advance.

I've seen this done with a "brush"… basically a square pattern that you can apply to the heightfield.  The pattern would just be an array of ints with values where the value means how much affect the brush has on the terrain at that point (0 meaning no effect)  Then basically when the brush is applied to the terrain at a given point, you walk through the brush values and add them to the corresponding points on the terrain (for a lowering effect such as right mouse button or shift click you could simply subtract instead of add).  It would also be pretty easy to turn these brush arrays into simple images allowing a user to choose their brush type before working on the terrain.



Anyhow, my two cents there.

May not be relevant to JME, but the brush has to also affect neighbouring terrain pages, otherwise you end up with something like the image where page edges don't match.



Torque's terrain editor does a great job of this, with multiple brush styles and sizes.

Have got the fix for it - its a small glitch on TP and TB,



And, btw - what renanse has done has made it like lightening, its fantastic



Where, how do i post the fix ( that bug tracking thing requires serious tolerance )

if it's really small, post it here.  otherwise email it to me.