Texture Tiling - Possible?

Is it possible to tile textures using Panda3D?

Yes. See the large section in the manual about texturing.


panda3d.org/manual/index.php/T … Wrap_Modes

Depending on your situation you can also tile a texture in your 3d modeller. In Blender just scale the unwrapped faces to be bigger than that grid thingy in the UV Window

You can also change the scale of the uv in panda: panda3d.org/manual/index.php/T … Transforms (model should be unwrapped in the modeller)

Hmm. This doesn’t work in my situation.

Here’s what I have now:

It uses multi-texturing to load different terrain types and uses associated alpha files to determine where they should and should not be placed.

This is nice, but I want to get the individual textures (grass, rock, snow, water) to tile (thereby giving them a higher resolution) but remain constrained to their original alpha file.

When I do as Anon suggests, I get this:

Is there a way to make sure the alpha file does not also tile?

I’m using a shader and an “alpha” map for terrain placements, and I am able to scale the textures differently. However I am not sure if this will work with your setup.

you need 2 different UV-layers in blender. assign the alpha and normal texture to one each. you can scale them independently then.

Unfortunately, this is not possible. The terrain is a procedurally generated heightfield.

Do you use a custom shader for the terrain?
If you do you can just multiply the UV coordinates on the RGB, like this:

float4 p_color = tex2D(tex_0, l_texcoord0 * 4.0);
float4 p_alpha = tex2D(tex_0, l_texcoord0);
o_color = float4(p_color.rgb, p_alpha.a);

Just use a different TextureStage for each texture that you want to scale differently.


No shaders used. And, as far as I know, I am using different TextureStages.

Here’s some code. Maybe this’ll clear it up.

From Terrain.py:

    def setMultiTexture(self, alpha, texfile):
        self.it += 1
        tex = loader.loadTexture(texfile, alpha)
        ts = TextureStage('ts' + str(self.it))

        self.terrainRoot.setTexture(ts, tex)
        self.terrainRoot.setTexScale(ts, 1, 1);

From map.py:

        t = Terrain.Terrain()

It loads the alpha map in with the loader.loadTexture() call. Is there another way to do this?

*edit: fixed filename

When you do loader.loadTexture(colormap, alphamap), you are creating one texture with the colormap and alphamap inextricably combined. If you want to scale them independently, you will have to load them as two different textures instead.

For instance, something like:

colortex = loader.loadTexture(colormap)
alphatex = loader.loadTexture(alphamap)

Then you can apply these two different textures to two different TextureStages, and scale them independently.


    def setMultiTexture(self, alpha, texfile):
        self.it += 1
        colortex = loader.loadTexture(texfile)
        alphatex = loader.loadTexture(alpha)
        ts = TextureStage('ts' + str(self.it))
        ts_a = TextureStage('ts_a' + str(self.it))

        self.terrainRoot.setTexture(ts, colortex)
        self.terrainRoot.setTexture(ts_a, alphatex)
        self.terrainRoot.setTexScale(ts, 5, 5);

Heh. Um, what??

Wait, maybe I don’t understand what you’re trying to do. Why are you using MDecal on the alpha map? MDecal doesn’t make sense for an alpha-only map.

But if you had been using MDecal to apply the colormap/alphamap combination, my advice doesn’t work: you need it to remain a single texture, because MDecal is defined to use the alpha part of the texture to determine which part of the color is visible.

But are we talking about the island texture, or the water texture? I thought you were talking about repeating the water texture, which presumably isn’t decalled or alphaed or anything.


Basically I use alpha + color maps to apply this:

To only these areas of the heightmap:

The problem I run into is that I want to overlay them onto each other (rock, snow textures using MDecal), and I want to tile the colormaps so they aren’t so pixelated, while keeping the alpha maps the same. Maybe I should just take the loading speed hit and tile the textures beforehand…

You could also use CMInterpolate to use your alpha texture to select between the grass and the water textures.


Hmm, I haven’t an idea as to how to use that. And what about the Snow and Rock textures?

I tiled the textures up to 2048x2048 and tried this.
I get about 8-10 seconds of extra startup time.
There is marked improvement though.

This is what I’m shooting for in real-time, although I’m afraid it may take just as long to tile it in-game…

So, I’m just gonna guess that there’s no way possible to do this using my implementation?

If I understand what you are trying to do, it’s basically the same thing I’m trying to get working as well. A combination of tiled textures placed via alpha map with a full map texture blended on top. This seems to go a good job of adding detail while the blended full map texture blended on top blends in enough variation to somewhat hide the regular texture pattern.

The problem is I can only use 4 textures (3 if I create lights). If I use more it appears to drop back to a previous texture stage and I get:

**** End of process output ****
DirectStart: Starting the game.
Known pipe types:
(all display modules loaded.)
:gobj(error): created-shader: (20) : error C5102: output semantic attribute “TEXCOORD” has too big of a numeric index (8)
:gobj(error): Shader encountered an error.
:gobj(error): created-shader: (20) : error C5102: output semantic attribute “TEXCOORD” has too big of a numeric index (8)
:gobj(error): created-shader: (20) : error C5041: cannot locate suitable resource to bind parameter “l_eye_normal”

**** End of process output ****

I’ve tried a few different ways, all with texture stages, but I have yet to get past those errors. Here is one of the ways I have tried. It should give you an idea of one way to do it, and hopefully someone can explain if/how to get around those errors.

Calling script:

import direct.directbase.DirectStart
from pandac.PandaModules import Vec4
from pandac.PandaModules import TextureStage
from pandac.PandaModules import GeoMipTerrain
from pandac.PandaModules import AmbientLight

from MyTerrainClass import myTerrainClass
#from myLightClass import myLightClass


myterrain = myTerrainClass()
myterrain.buildterrain("learningHeight.png", "myterrain")
#taskMgr.add(myterrain.myupdateTerrainTask, "update")

#add textures - start with textures that will be blended with full map
#myterrain.addalphatex("learningSandAlpha.png", "sandtexture.jpg", 64, "stage-sand")
myterrain.addalphatex("learningGrass1Alpha.png", "grass.jpg", 64, "stage-grass1")
#myterrain.addalphatex("learningGrass2Alpha.png", "grass.png", 64, "stage-grass2")
#myterrain.addalphatex("learningGrass3Alpha.png", "grass_ground2.jpg", 64, "stage-grass3")
myterrain.addalphatex("learningRock1Alpha.png", "rock.jpg", 64, "stage-rock1")
#myterrain.addalphatex("learningRock2Alpha.png", "rock_02.jpg", 64, "stage-rock2")
#myterrain.addalphatex("learningRock3Alpha.png", "rock3.jpg", 64, "stage-rock3")
#myterrain.addalphatex("learningSnowAlpha.png", "snow2.jpg", 64, "stage-snow")

#add full map texture - will be blended with existing textures
myterrain.addterraintex("learningFullmapTex.png", "stage-fulllowrezmap")

#add mapped textures on top of existing textures
#myterrain.addalphatex("alpha4.png", "road.jpg", 128, "stage-road")
#myterrain.addalphatex("alpha5.png", "wood.jpg", 64, "stage-wood")



from pandac.PandaModules import GeoMipTerrain
from pandac.PandaModules import TextureStage

class myTerrainClass:

	def __init__(self):
            self.tssort = 0
        def buildterrain(self, heightmap, tername):
            # Set up the GeoMipTerrain
            self.terrain = GeoMipTerrain(tername)

            # Set terrain properties
            # Generate it.
            # Store the root NodePath for convenience
            root = self.terrain.getRoot()
        def addterraintex(self, tex, stage):
            self.tssort += 1
            root = self.terrain.getRoot()
            # Step 4: full map texture is blended with everything
            ts = TextureStage(stage)
            ts.setCombineRgb(TextureStage.CMModulate, TextureStage.CSPrevious, TextureStage.COSrcColor,
                                                        TextureStage.CSTexture, TextureStage.COSrcColor)
            root.setTexture(ts, loader.loadTexture(tex))

	def addalphatex(self, alphamap, tex, scale, stage):
            self.tssort += 1
            root = self.terrain.getRoot()
            #apply the texture to the entire terrain
            ts = TextureStage(stage)
            root.setTexture(ts, loader.loadTexture(tex))
            root.setTexScale(ts, scale, scale)
            self.tssort += 1

            #Use an alpha map set texture to either previous texture or last saved texture
            ts = TextureStage(stage + "alpha")
            root.setTexture(ts, loader.loadTexture(alphamap))
            ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSPrevious, TextureStage.COSrcColor,
                                                        TextureStage.CSLastSavedResult, TextureStage.COSrcColor,
                                                        TextureStage.CSTexture, TextureStage.COSrcColor)

	# Add a task to keep updating the terrain
	def myupdateTerrainTask(self, task):
	  return task.cont

Setting “basic-shaders-only #f” in Config.prc doesn’t have any effect.