Mapping textures

I made a terrain of many small tiles with individual textures each. Of course its very slow if i dont call flattenStrong (130 fps instead of 3).

How can I get this texture-effect without the need to call 30sec-flatten?
Is there evan a way to get it faster than with flattening?
(yes i know geomip is made for such terrains but i dont get that texturing there)

if you dont need to regenerate it on every game start, you could use writeBamFile to cache it on disk. othervise split it into chunks or generate the terrain by writing the whole terrain into a model at once (using the vertexwriters).

bam-ing it is a good idea and ill do that if there is no other way, thx.
is there a way to get that texturing with geomipterrain or heightfieldtesselator without making one huge texture which makes panda exit?

Yes there is.
You’ll need to have two or more UV sets. One set covers the whole terrain and the other is repeated many times (tileing). The first set is a mask it, where it’s white texture #1 will be visible where it’s black texture #2 will show, gray colors will be a blend of #1 and #2.
This is called multitexturing.

Look up the forum for YARR if I’m not wrong it used this for geomitmapterrain.

the problem with multitexturing is that i cant put more than 4 different textures on the terrain (without using shaders making it slow).

Propably the only way to boost performance and to keep this tiling is to combine all tiles with the same texture to one geomnode.

What do you mean, using shaders making it slow? Modern GPUs translate everything to shaders anyway, so you shouldn’t be seeing a performance impact if you use a shader.

i meant that it propably will get slow when i use 50 layers - thats about the number of different tile-textures i need.
even though it could be fast enough - there should be a less brute-force way than excessive multitexturing.

im not totally happy with the current aproach: flattenStrong-bam-ing the whole terrain makes visibility-checks which could improve performance useless. i think ill have to subdivide the terrain eg in 8x8-parts for flattening so vis-check could help.

Are you sure you’ll need 50 layers on each and every tile?

You can have for example grass, rock, moss, dirt on some tiles, sand, pebbles, leaves, mud on some other and so on. You can have a colour variation layer or bake that into vertex colour.

i thought if i use geomip then i have to texture the whole terrain with one multitexture. this way ther would be layers for eg:
red flowers, yellow flowers, …, mixed fowers, wet grass, dry grass, sand-rocks, granite, mud, street, fallen leaves,…

ok 50 was too many and maybe 10 are enough…

With GeoMipTerrain, you can texture each tile individually.

How? (Obviously to stupid to find out myself…)

Try ls() on the terrain root.

i think i got it.

here i my code for those having the same problem:

class Tileset(object):
    def __init__(self, templateString):
		self.ts = templateString #some %-string like "tilesetname/tile-%02i.png" for warzone-tiles
        self.loaded = dict() #already loaded textures
    def getTex(self, num):
        try:
            return self.loaded[num]
        except KeyError:
            tex = Texture()
            tex.load(self.ts % num)
            tex.setWrapU(Texture.WMClamp)
            tex.setWrapV(Texture.WMClamp)
            tex.setMinfilter(Texture.FTLinearMipmapLinear)
            tex.compressRamImage()
            self.loaded[num] = tex
            return tex

class Terrain(NodePath):
    def __init__(self, heightmap, tileset, tilemap, hscale=32, blocksize=8):
        self.tilemap = tilemap #which tile-type (in this version only texture) to put where
        self.tileset = tileset #currently ony a wrapper for texture management and loading
        self.terrain = GeoMipTerrain("")
        self.terrain.setHeightfield(heightmap) #heightmap is obvious...
        self.terrain.setBruteforce(True) #this is just a first implementation - should work without this as well. but beware when updating...
        self.terrain.setBlockSize(blocksize) #attention: one texture per block
        self.xTiles = heightmap.getReadXSize() / blocksize #tilemap has to be at least this large
        self.yTiles = heightmap.getReadYSize() / blocksize
        NodePath.__init__(self, self.terrain.getRoot())
        self.setSz(hscale)
        self.terrain.generate()
        for x in xrange(self.xTiles):
            for y in xrange(self.yTiles):
                self.texTile(x, y)

    def texTile(self, x, y): #puts a texture on the tile
        v = self.tilemap.getGrayVal(x, self.yTiles - y - 1)
        tile = self.getTile(x, y)
        tile.setTexture(self.tileset.get(v))
        tile.setTexPos(TextureStage.getDefault(), -x, -y, 0)
        tile.setTexScale(TextureStage.getDefault(), self.xTiles, self.yTiles)



    def getTile(self, mx, my): #the geomip's function only returns immutable tiles
        return self.find("gmm%ix%i" % (mx, my))

    def getTileAt(self, x, y):
        return self.find("gmm%ix%i" % tuple(self.terrain.getBlockFromPos(x, y)))
		
#example
terrain=Terrain(PNMImage("heightfield.png"),Tileset("tilesetname/tile-%02i.png"),PNMImage("tiles.png"))

edit: added comments (i hope they make it understandeable)