Procedural City Generator

Hi guys !



Here is a little blog that I wrote to present my Procedural city generaiton project with JME3. I’m very sad to say that JME seems not to be adapted to that project because I need meshes optimisation and don’t have the tools to get some perfs.



But I don’t know JME3 very well, so I would like to share this blog with you, get your opinions and maybe find some solutions to continue with JME.



Hope you’ll like it.



http://wearehumansandbox.blogspot.fr/

1 Like

Did you try the GeometryBatchFactory?

there is an optimize(node) method that merge objects with the same material. (be sure to use last nighlty)



In some screens there is 13k objects, this is too much, however there is only 9 textures and 4 shaders, so it seems you have few materials. So the batch factory will give you a huge perf increase.

look at this post for a similar issue and explanations http://hub.jmonkeyengine.org/groups/graphics/forum/topic/slow-fps-when-looking-at-a-bunch-of-boxs-1/



That’s seems to be a very nice project, it definitely can be done with jME3, don’t hesitate to post questions on this forum.

Yeah you should either

→ Use the GeometryBatchFactory on a house basis directly after generating (Easier to modify houses as only the house mesh needs to be regenerated)

or

→ Generate the whole City and then use the GeometryBatchFactory(probably more speed if city has not enormous amounts of polygons)

Looking at mythruna, which runs nicely at 60fps on my laptop I think the culprit is not jME3 in this case, no :slight_smile:

1 Like

Thanks for your help guys, I tried out the optimizer and it works well. The fps increase dramaticaly but I was wondering about the memory usage. My app create all the city map at each start (no save on the hard drive) and I would like to makes objects lighter.



when I create a city headless (no rendering with JME, just model) the app takes about 300 mo of memory and compute about 600 000 polygons. When I compute the rendering (updated during the generation), it grows to 1go and begin to swap on the harddrive with only 60 000 polygons to manage.



I generate and optimse model house by house, so I thought that the geometries done this way would be light in memory, or partially stored on the graphic card, but I don’t understand very well these things.



Do you know what I’m doing wrong or what I need to do to free memory?



Thanks for your interest !

You can limit the heap size that the application will use via the -Xms and -Xmx VM commands, that way your memory usage won’t grow as much.

1 Like

Also, check that you are not instancing objects in the update loop. Use temp objects as often as you can.

1 Like

Ok thanks for all your advises, i works much better now. I let you see by yourself on picture.



I have one more question, about materials. I’ve made a materialManager class that instantiate a new material with only one color or texture path param. The number of materials grows anormally.



This causes two problems :

  • When using Batch Factory, it can’t find two materials equals even if they have strictly similiar attributes. This could be changed but I think it won’t, because creating redundant materials may not be a “best practice”
  • When rendering a large number of geometries in this way, the new materials take a lot of place in memory.



    I have two questions :
  • The materials are merge somewhere but I don’t know why. I say that because while rendering house by house, in the hud, we can see material quantity growing and decreasing to a normal value. What is the mecanism?
  • What is the best practice to get a material of a single color or texture, without having to declare it initApp? I have a shape grammar that is interpreted outside the app, and the shapes could have any color or any texture path written in txt file. So I need to create new materials at any time.



    thanks for your precious help so far.



    http://4.bp.blogspot.com/-wpjtys3yMtM/Tawg3e1wWKI/AAAAAAAAACs/FR8vaZMuSZs/s1600/generator42.jpg

Hi there !



I’ve found my self a solution to my problem. I’ve coded a mathod that map requested material and return materials that have already been map. Piece of code here. See ya :slight_smile:



[java]public Material getLightingTexture(String texturePath) {

// We first check if the requested texture exist in the material map

if(texturesMap.containsKey(texturePath))

return texturesMap.get(texturePath);



// At this point, we know that the texture doesn’t exist.

// We must create a new material, add it to the map and return it.

Material res = new Material(assetManager, “Common/MatDefs/Light/Lighting.j3md”);

Texture t = assetManager.loadTexture(texturePath);

res.setTexture(“DiffuseMap”, t);

res.setFloat(“Shininess”, 128f); // [0,128]



texturesMap.put(texturePath, res);



return res;

}[/java]

Nice, I guess we should implement a Material.equals() method

I added an issue into the issue tracker for this

1 Like

Hi !



Here is a video of my project. Hope you like it !



http://www.youtube.com/watch?v=ZYYKrfNfbtA&feature=share

3 Likes

Cool, looking good!

UaU !!! very nice !

wow… congrats, that looks really nice :slight_smile:



I read that paper you mentioned earlier, but could not get an idea how to start. Do you think this algorithm can be used to build an entire country with roadmap and cities / villages, given an elevationmap and some demographic details?

very nice !!

Very cool.

2000 objects is still a lot, does batching even more help? Or is the issue due to the triangle count at that point?

Hi everybody and thanks for your messages.



@Momoko yeah, 2000 objects is still too much, but i’m not optimizing the street elements (sidewalks, street lanes and crossings). Each building count as one object, but each street element too. I have a large work to do with optimization but i’m still thinking about it because I need to implement a system of LOD, and need to know where to go before merging more objects.



@Anthyon I’m certain that the L-System could generate a no limit world with any level of detail you need, because it’s generated on the fly. Like in the project Infinity (where you fly over 200 billions unique planet, from galaxy to grass), the world is made when you reach a zone, and destructed when you leave to save memory. The seed system guarantee that the same generation is done if you come back later. It’s not very hard to implement, when you got the good generation engine.



For the map, I’m implementing the density map with interpolated populated zones. This is quite easy to do and control the road and building generation in a very realistic way. For the elevation map, it is not very hard too but the quadtree must be altered by the shapes of the roads/city and this is some hard work. For exemple, you can’t work with the jMonkey terrain tools and have to create your own data structure.



I could share some code, if you need.



See ya everybody and thanks again for your comments !

Hey,



It’s been a while, and I was busy with another part of my project, but now I’m turning back to this topic again…



So what I’m thinking of is to create a complete kingdom map for a fantasy setting. I have some statistics already available, and I have the terrain part giving me the heightmap. I would like to create a network of roads / paths between the settlements, and generate the cities, town and villages themselves. As far as I could understand from the doc you used, the algorithm first finds the territories with the highest population densities (in a bigger scene these are the main cities and towns), and then casts rays from one such territory to it’s neighbourhoods, and does this for every territory. These will give the highways, and when they’re done it calculates the secondary and tertiary roads.



I could see from your examples that it can work pretty well in practice, but I have a strange requirement. I can generate the whole kingdom in small pieces at once. The terrain generator can get me any part independent of another, and it will always fit into the whole when it’s neighbours are loaded as well. So is there a way to generate the roadmap that is contained in such a part, without generating the whole at once?

The road generation is selfsensitive because the roads connects on each other. so it is quite difficult to generate a single part with limited borders, and estimate that the neighbor parts won’t came back.



Plus, the road generation needs starts point to begin the generation, and for the same interconnection issue, all these initial roads must be started to get the final road map.



these issues requires some constraints in the roadmap to be solved, like generating a whole continent at once, or delimit some ie geographic limitations, like sides of a montain/river, etc.



But you have another solution wich is not exlained in the doc you read, but that I have implemented. It is to set different level of road generation. In my last exemple, I generate highways, that target density peaks, and turn around density area. Then, inside the populated area, major roads are drawn from the highways. Then I get some quarters between major roads, and I can generate my minor roads to get blocks.



In your exemple, one solution is to draw main axis on the whole landscape (like a country). Then you find graph loops in your “highway map”, the so-called “regions”. You assign a seed to each region but you launch the drawing of the road map of one single region only when required. In the same way, when this new level of road is drawn you obtain new graph loops, ie so-called “quarters” and launch road generation in one quarter only when needed, etc.



This way, you can define any level of generation you need. All you have to do is find a good balance between quantity of content stored in memory at one time, and time needed to generate one content. If you’re game have a walking caracter, you can generate very little parts to save memory, because he moves slowly. if you make a flight simulation, you should generate larger parts.



hope it helps.

I forgot to say that no, I don’t know any way to generate a single part of the road map without generating the big canvas (because of the selfsensitive issue). This method only allow to generate the whole map in a very light level of detail.