Hey guys,

I have a 3D texture for the terrain I am trying to render, and i want to use a certain layer of the texture (ie, grass, rock, ice) depending on the slope of the terrain (or normal). Flat areas should use grass.

I think TexGenAttrib.MWorldNormal would do it for me, but i need to only set the W texture space, and not set U and V. In other words, I want to copy just use the Z component of the normal to the W texture coordinate.

Any way to accomplish this?


I think there are two choices available to you: you could write a custom shader to generate your texture coordinates (requires learning Cg, and a card that supports shaders). Or you could write Python code to generate them using the GeomVertexWriter class (works anywhere).

But you can’t use TexGenAttrib.MWorldNormal to generate just one component of an existing texture coordinate, and leave the other two the same.


ah i didnt think of using a shader to do that! Should be pretty east I would think.


Well this is turning out harder than i thought. Im using the code below to manually change the texture coordinates of an imported model:

geomObj = self.terrain.getNode(0).getChild(0).getChild(0).getGeom(0)
vdata = geomObj.getVertexData()
rw = GeomVertexRewriter(vdata, “texcoord”)
while not rw.isAtEnd() :
tex = rw.getData3f()

Now if I change the U or V coord, then it works as expected. But nothing happens when I change the W (or Z) coord.

Anyone have ideas why this wouldnt work?

Are you sure you have a 3-D texture? An ordinary 2-D texture ignores the W coordinate.


I am using self.tex2 = loader.load3DTexture(MYDIR + ‘models/s_#.png’) for the texture.

One more thing I noticed. I am using 3ds max to export models into egg files. And when examining the texcoords from these egg files, there is no Z (or W) coordinate information. I know I am generating 3D coords from 3ds max, but it looks like the information isnt saved in the egg file.

Thanks for the help

Ah, so your geometry doesn’t have space to store the W component, and it is getting dropped on the floor.

I guess the real problem is that the 3DSMax converter is not converting the 3-D texture coordinates (this doesn’t surprise me). So one answer is, of course, to fix the converter–the source code is right there for you. :slight_smile:

The next answer is to hack the egg file produced by the converter by hand, and change lines like this:
{ 0.25 0.5 }
To this:
{ 0.25 0.5 0 }

The third answer is to load the unhacked egg file, then get a pointer to the GeomVertexData like you are doing now; then create a new GeomVertexData that has the same format, with a 3-d texture coordinate instead; and copy the vertices from the original to the new GeomVertexData. Then you can store this new GeomVertexData back into the node, and you can manipulate it as you are doing now.


I thought I was doing your third answer, by adding the Z component to the TexCoord vertexData:

tex = rw.getData3f()

Is there something else that im not doin?

That doesn’t add a third component to the data. That only sets the third component, if it happens to be there. If the texcoord only has two components, though, it will quietly ignore the third component.

In order to actually add a third component, you will need to create a new GeomVertexFormat, whose ‘texcoord’ column is a 3-component value. Since there are no default formats with a 3-component texture coordinate, you’ll have to build it up by hand, with code like this:

format = GeomVertexArrayFormat()
format.addColumn(InternalName.make('vertex'), 3, Geom.NTFloat32, Geom.CPoint)
format.addColumn(InternalName.make('normal'), 3, Geom.NTFloat32, Geom.CVector)
format.addColumn(InternalName.make('color'), 4, Geom.NTUint8, Geom.CColor)
format.addColumn(InternalName.make('texcoord'), 3, Geom.NTFloat32, Geom.CTexture)
format = GeomVertexFormat.registerFormat(format)

Then you can use this format to create a new GeomVertexData:

data = GeomVertexData('data', format, Geom.UHStatic)

And then you can copy geom data from the old GeomVertexData to your new one, using a GeomVertexReader/GeomVertexWriter combination.


Oh, incidentally, this code is asking for a crash:

tex = rw.getData3f()

The reason is that the value returned by getData3f() is a const value. You’re not supposed to be able to modify it directly, as you are doing in the line “tex.setZ(.5)”. Unfortunately, Python doesn’t have a concept of a const structure, so it lets you modify it anyway, even though you might be modifying static memory or writing off the end of an array somewhere.

The correct, safe way to do this is the following:

tex = VBase3(rw.getData3f())

This will make a copy of the data first, which you can then safely modify. The reason that GeomVertexReader doesn’t return a copy by default is that it is a low-level class that must be optimized for speed. In C++, it is safe, because C++ does support the idea of a const structure.