Finding TerrainQuad of the players position

hi,



fairly new to JME3, but have done a fair amount of searching,

i can’t seem to find a method for finding a terrain quad based on x and z values.



Scenario:

server generates terrain, client starts up and sends a message to server to request terrain given x and z values, server returns a specific terrainquad’s heightmap and immediate neighbours, so client sees terrain.



what i’ve tried so far is trying to send entire heightmap, but this is a very large value, one way is to split it up sequentially and stream that, but this requires a lot of uploading especially if the terrain grows.



i hope i made it clear,

thanks in advance.

A raytest downwards from the player or x/y position.

i dont see how that would work, terrainquad doesnt provide any vector3f resulting methods and a physicsRayTestResult would either return a physicsCollisionObject not the terrainQuad involved or the vector of the normal at which it hit, which would be useful if there was a method for knowing which range of x,z a terrainQuad was assigned to

if it helps, im generating terrain by following the HelloTerrain wiki exmaple of:



terrain = new TerrainQuad(“my terrain”,33, 513, heightmap.getHeightMap());



*heightmap generated by image

If you dont see how this would work then you should maybe read up on jME3. Seems like you didn’t even do the basic tutorials… So I’ll write it down, just for you.



[java]

Ray ray = new Ray(…);

CollisionResults results = terrain.collideWith(ray);

(normally you’d loop over results:)

CollisionResult result = results.getCollision(0);

Geometry terrainQuad = result.getGeometry();[/java]



If you use physics, you can do the same (this example does no checks on the returned collision results, you should ofc check if the Spatial is in fact a geometry):

[java]

List<PhysicsRayTestResult> list = physicsSpace.rayTest(…);

Geometry terrainQuad = (Geometry)list.get(0).getCollisionObject().getUserObject();

[/java]

ah i do apologize, i was looking at the wrong class for ray testing, i also started looking at mapspinner i think that would also work nicely.

thanks.

mapspinner is for jME2

I’m using a similar approach with the TerrainGrid class I’m currently implementing. I don’t think raytesting is the fastest approach for this.



You simply know where the character is (x,z). the server should use a mechanism, so that this x,z coordinate pairs can be assigned to one and only one TerrainQuad heightmaps. A simple procedure I’m using is to divide both coordinates with the size of the quad (eg. 512), and use the integer part:



[java]

public Vector3f getCell(Vector3f location) {

final Vector3f v = location.clone().divideLocal(this.getLocalScale().mult(this.quadSize)).add(0.5f, 0, 0.5f);

return new Vector3f(FastMath.floor(v.x), 0, FastMath.floor(v.z));

}

[/java]



I add 0.5 to both so that the origo becomes the center of a quad, not the corner of four quads. But it’s just how I prefer… :slight_smile:



Then I store the heightmaps as:



terrain_cellX_cellZ.png



This way I get a unique ID for all quads.

Thanks anthyon that is a nice approach, i was thinking of splitting the heightmap in GIMP and loading them up, sending heightmap images is easier especially with the cap on size of serializable objects.

so does TerrainGrid apply above TerrainQuad or instead of it ?

TerrainGrid is an extension of the TerrainQuad class, so it can be used anywhere in place of your current terrain, without any modifications. It uses the LOD update control to automatically update the quads visible. A short code to use it:



[java]

this.terrain = new TerrainGrid("terrain", 65, 1025, new ImageBasedHeightMapGrid("Textures/Terrain/splat/terrain", "png",

this.assetManager));



this.terrain.setMaterial(this.mat_terrain);

this.terrain.setLocalTranslation(0, 0, 0);

this.terrain.setLocalScale(2f, 1f, 2f);

this.rootNode.attachChild(this.terrain);



List<Camera> cameras = new ArrayList<Camera>();

cameras.add(this.getCamera());

TerrainLodControl control = new TerrainLodControl(this.terrain, cameras);

this.terrain.addControl(control);

[/java]



Note: LODControl uses a list of cameras, but TerrainGrid uses only the first of them. The classes are already in the svn version. :slight_smile:

ah yes sorry i meant extended, wierdly height doesnt register at all, is this intended ? i think its because im not using assetmanager properly, for some reason it throws asset not found exception on my terrain squares even though i supplied it a absolute path (png format).

The approach im working on right now is trying to stitch nodes together based on the name of the image (i.e. terrain_x_z) increments every 64 pixels in .setLocalTranslation()

the reason im trying to do it this way is because at client startup ill perform checksum on the client side terrain segments and if some dont match then update, and while the client is running and say player digs a hole the client will save that in the terrain images (and update server).



edit(heres the problem with my approach):

http://i51.tinypic.com/16lmp6w.jpg

Hey, I’m trying to create the exact same thing… :slight_smile: That’s why I needed to create the TerrainGrid class. The imageBasedHeightMapGrid class will create a plain 0 terrain if it fails to load the heightmap because I got weird results when throwing an exception instead. Also I wanted to know where my terrain ended.



I’m assuming you already create 65 pixel terrainQuads and would like to offset them by 64 as it must be done :slight_smile: so only two things come to my mind about the borders you see:


  1. in real you offset by quad size that is 65
  2. I got such vertical lines that can be seen in the center of your image, when the borders (the right in your case) were not filled with height data



    At least these were my findings with the same problems.



    As for the grid. I need the same setting as you, a server that creates new heightmaps on demand and keeps track of changes to them. I also need the terrain to be extendable “infinitely” in both directions. I was just about preparing some “ServerBasedHeightMapGrid” class, but I’m not too good at server programming yet. :confused:

with the way nodes work, well from what i understand how they work, isn’t the terrain split into 4 each time untill its at a terrain patch level, so would starting at the center be neccessary ?

Sorry, I don’t understand the question… :confused:

i was wandering if there was any specific order for loading terrain, ive been looking at TerrainGrid but im not 100% on how it stitches the quads together

Ohh I see… :slight_smile:



TerrainGrid works the following way:


  1. Initialize the grid with a class that can provide heightmap of a specific cell
  2. The initial location (currentCell attribute) is set to null, as no location info is known
  3. Any time an updateLOD request is done to the terrain (let’s say in every update of the LODControl) the first location of the first camera is checked against the currentCell, if it crossed a cell boundary (any distance and direction), and updateChildrens is called with the new cell.

    3.a. LOD update is called first when the control is created



    The grid stores four quads as a TerrainQuad. All the extra it does, is replacing any quad that is too far away from the camera with new ones approaching, by simply detaching unneeded children and attaching the new ones, and renumbering the quads.



    An example:



    the grid contains 4 quads as it is explained in the terrain tutorial, except that all 4 quads are from different heightmaps (terrain_0_0, terrain_0_1, terrain_1_0, terrain_1_1 in order). 12 neighbouring quads are also cached (from [-1,-1] to [2,2]). When you move north the following happens:
  • the camera cell becomes [0, -1]
  • the bottom two quads (2 and 4) are detached
  • the top two quads (1, 3) are moved to the bottom, setting their quadrant member to 2 and 4 respectively, and resetting their localtranslation
  • new two top quads are added from the cache
  • the whole terraingrid’s localtranslation is changed so that the moved top quads take the same place in space



    the new children of the terrainGrid became: terrain_0_-1, terrain_0_0, terrain_1_-1, terrain_1_0



    the cache is updated in a background thread to contain the new neighbours



    That’s the theory I came up with, the practice is different in replacing all four quads from the cache without any check, as it seemed to be faster (no cell change checks should be made)



    If a RigidBodyControl instance is found on the grid, it’s data is also updated so physics work quite simple.



    I know I have to do more comment on my code, and write a few words about it in the wiki as soon as I’ll have more spare time. :slight_smile:

that explained it very well thank you, i was bothering myself on the low level specs too much im good with stuff from scratch. i was looking at procedural terrain thread, did you write a test/example java for TerrainGrid ive just checked out svn ill search there ?

yes, there is a test at jme3test.terrain.TerrainGridTest. It uses a FractalHeightMapGrid class that provides endless data for the test, so you can get as far as you want. Physics are broken sometimes (known bug, still working on it) and you might see that two terrain patches does not fit well, but if you wait the LOD update will smooth them together in less then a few seconds. (known bug as well).

The second parameter for the FractalHeightMapGrid is the disk cache path for the heightmap images. If set to null, no cache is used, if set to an existing path, the generated heightmaps will be cached there, and used when a request is made by the update.



For example it can generate an endless terrain procedurally, but the cached heightmaps can be modified later, and it will be used instead of regenerating it.