Map created with Tiles

Hi guys, need your advice about what to do with big amount of tiles generation,
colony builder game, minimum what i need is 200x200 tiles (40,000) and desired amount is
400x400 (160,000), i tried do tile generation with CardMaker:

def DrawCard(self, map):
    # Create a texture for the mesh (using GPU for texture handling)
    tex = loader.loadTexture('sand_tile.png')
    tex.setMagfilter(Texture.FT_nearest)

    cm = CardMaker("plane")  # Quaternion plane
    cm.setFrame(0, 1, 0, 1)
    texture_cache = {}
    
    card_id_counter = 0
    
    # Create map planes after adding vertices (in bulk for better performance)
    for row_idx, row in enumerate(map):
        for col_idx, value in enumerate(row):
                if value == 0:

                    map_plane = render.attachNewNode(cm.generate())
                    map_plane.lookAt(0, 0, -1)
                    map_plane.setPos(col_idx, -(row_idx + 1), 0) # Zupdown
                    map_plane.setTexture(tex)

                    # Create a new card instance
                    card = Card(card_id_counter, col_idx, row_idx)
                    self.cards[card.card_id] = card  # Store card by its ID
                    
                    card_id_counter += 1
                    #print(self.cards.get(123))


                if value == 1:  # Obstacle or special tile
                    tile_image = self.get_tile(row_idx, col_idx, map)

                    # Check if the texture is already loaded (cache)
                    if tile_image not in texture_cache:
                        tex2 = self.load_texture(tile_image)
                        texture_cache[tile_image] = tex2
                    else:
                        tex2 = texture_cache[tile_image]

                    # Create the card and set texture
                    map_tile = render.attachNewNode(cm.generate())
                    map_tile.lookAt(0, 0, -1)
                    map_tile.setPos(col_idx, -(row_idx + 1), 0)
                    map_tile.setTexture(tex2)

but it take quite amount of time to generate 10+ seconds and with update
and in ingame edit it’s too much, i tried generate tiles with geom 4 points and cardmaker
the question is
Is there any way to mass generate tiles (with texturing), and get good loading speed and fps?
maybe someone do that before? also how to implement LOD and frustum when working with map generated with tiles.
I experimented with GeoMipTerrain and it gives very good results but can’t be textured and edited tile by tile.

I will say: That’s a lot of nodes to have in your scene, especially if you intend to have a significant proportion of them visible at a time…

So let me ask: how many tiles do you intend to have visible at a time? Do you want it to be possible for the player to see all of them at once? Or will the player only ever see a limited region–and if so, how large a region?

If the player will only ever see a small subset of those tiles, then perhaps you could generate only that many tiles (plus a few extra), and dynamically move and texture them so that they give the appearance of many tiles, without actually being many tiles.

If you really do want to generate the full 40 000 tiles, then I have three (untested!) ideas:

First, you could try generating a single tile, and then using scene-graph instancing to essentially “copy” it around the scene.

And second, perhaps you could create your tiles as a single, huge model–or maybe a small number of models, each being a “chunk” of tiles–complete with textures. Perhaps your editor might use separate tile-models, and then process them into “chunks” on exporting the map, or perhaps you might just model your map in a 3D modelling package like Blender.

And third and finally, perhaps you might be able to use some shader-magic here. Maybe a geometry shader to generate the tiles according to what’s visible, or something like that?

I’m not sure about LOD, but as long as you have your tiles (or “chunks”) as separate nodes, Panda should handle frustum-culling for you automatically, I believe.

The way to do culling with tiles is to structure your scene graph hierarchically, in the form of a “quadtree”. That is, each set of 4 tiles has a single parent node that groups together a 2x2 set, and each group of 4 2x2 sets is parented to another parent node, etc. This makes collision and culling very fast. However, you have to balance this with the node count. You cannot have 40 000 individual tiles in view, instancing or not. So you have to find a good balance between these. You could decide, say, to have each 8x8 set of tiles be generated together into a single Geom, and then applying a quadtree above that level.

As for texturing, you should consider using a big atlas texture holding all the textures together and have the UV coordinates on the different quads reference different parts of that big texture. Best suited for this is an array texture, though it requires a shader to index into it. You could have a special column on the GeomVertexData containing the index of the texture to use.

1 Like

The use of quadtrees in Panda3D is not possible to the full extent. Because this is an unmanageable situation. Again, you cannot get the state of any node without processor costs. For example, to find out which nodes are located within a radius of 200 meters, in order to implement a resource manager to generate shaders, and so on.

Panda3D makes a lot of functions, isolating them from the user, and without any common sense. It is almost impossible to implement a resource manager.

same as in Rimworld, from 50-100 tiles to whole map when camera is far above,
colonist will “know” every tile on map as part of Ecs

The thing is that all that initial tiles is more like fillers based on biom, all other stuff will be animated (png seq) like stones, plants, poe and other, plus those tiles need to be ready to be edited by environment, player, so i cant just FlatStrong them (beside it take way to much time)

Same as before, i need them to be editable at anytime, beside in Ecs all including npc, walls and floor tiles is Entitiy, so i really don’t know how to join flatstrong them that way

That good idea, make class for them and address to one of them individually

What benefits of this? use it like picture bank, will it speed up tile creation? for now i have small png files for every type of tiles, but as part of Ecs every tile might change own texture

For now i archived this results during loading
FillMap Time: 0.00s
MakeFromMap Time: 0.56s
DrawCard Time: 0.76s
NavGraph Time: 2.29s
BulletWorld Time: 0.09s
amd 45-50fps in-game on my potato pc, but this is for empty map with two npc and building placeholder.
And i can give it go with loading time (providing it will not grow with more content)
but really need to find a way to boost fps, FlatStrog helps but it slow loading by 30-40s
Medium and Light strong don’t affect it at all.Maybe should try rbc

Sadly it is, as for finding other tile i still not implement any collisions
for now i use distance <1 between npc and poe, still have no idea how to do interaction between
npc and walls, tiles, my first idea was bullet ghost but i think this will take too much resources
if i draw ghost shape over every tile,
Is there other way to do light cost interaction?

Oof, that may well be tough.

I didn’t suggest that you FlattenStrong them.

In short, instancing would allow you to have a single node for the geometry, and set individual states–e.g. individual textures or texture-offsets on the instances.

“Chunking” may still work here: it may just call for re-generating your “chunks” when tiles within them are changed.

(This is essentially what rdb was suggesting with the mention of 8x8 sets of tiles being generated as a single Geom, I believe.)

Mainly because Panda handles a lot of that sort of stuff internally, at least given a well-structured scene, I believe.

I think i may done that with
map_plane.reparent_to(group_np)
inside tile set loop
if that what you mean,

I am still looking into it, i have clone craft examples for chunking but for now i have no idea how to implement this.

No, that would just change the singular parent that the node has; in short, at the end, you’d still have just one tile.

For more information on scene-graph instancing, see the manual page on the topic:
https://docs.panda3d.org/1.10/python/programming/scene-graph/instancing

That said, note that rdb has opined that it may not be useful in your case.

It’s not something that I’ve worked with myself, so I don’t have a lot to add here.

I might think to either use Panda’s “Rigid Body Combiner” (see this manual page), or dynamic geometry generation.

Unfortunately, you’ve missed my point again. You can structure the level as much as you want, but you won’t get feedback on the state of the objects. For example, you don’t know which tiles need to be prepared for the game process, load physics, generate shaders, and so on, because panda does the culling inside itself and doesn’t inform you about it in any way.

If you recommend using a quadtree, then it should be implemented self-sufficiently, there should be methods for interacting with the state of the quadtree, add an object, delete it, get a list of leaves and objects in it, and so on, at the moment this is not implemented in panda.

I used this approach, it gave me the opportunity to manage my resources, but Panda3D repeats all the work internally. It turns out to be a double job…

1 Like

Can you provide small example on Panda3d?

Also question can i use GeoMipTerrain as one small tile and fill with it whole 200x200 map?

I had a simple demo code somewhere. GeoMipTerrain itself is slow. You can use Geom for all your needs.

I actually use geom, as they perform faster than cards, both in drawing and loading.

So that you can have multiple tiles with different textures as part of the same node.

No idea what you’re talking about. Panda implements a BVH tree, and quadtrees are a special case of a BVH tree. Panda generates shaders for nodes that are in view, or you can traverse it yourself easily to get the nodes in a certain area, which takes very little processing time in the case of BVH/quadtree.

1 Like

I do not think that at the moment it is possible to implement a flexible resource manager, one only use the BVH tree built into Panda3D, not there is no feedback with this system.

The point is that, for most purposes at least, one doesn’t need this: it’s all handled by Panda.

Why? If Panda provides a sufficient implementation, why should one re-invent that?

This is the first time I’ve heard that Panda3D generates mesh bullet for collisions, I’ll keep silent about computational shaders, apparently I haven’t fully read the manual.

Something like this. You create an array of coordinates for each tile, and change the geom state at the request of the game logic. However, this is explained in detail in the video.

test_tiles.zip (2.2 KB)