Runtime recoloring of models

I’m trying to figure out a way to recolor models (via their vertex colors) at runtime. I just can’t figure out why Panda keeps complaining about the vertex data I am trying to read and write to. Here is my model-coloring code:

def colorModel(model, pcolor, scolor):
    geomNodeCollection = model.findAllMatches('**/+GeomNode')
    for nodePath in geomNodeCollection.asList():
        geomNode = nodePath.node()
        for i in range(geomNode.getNumGeoms()):
            geom = geomNode.modifyGeom(i)
            vdata = geom.getVertexData()
            
            print type(vdata)
            print vdata
            
            # color using GeomVertexRewriter
            vcolor = GeomVertexRewriter(vdata, 'color')
            if(vcolor is None):
                print "Error: model has no color data available"
                return

            while not vcolor.isAtEnd():
                v = vcolor.getData3f()
                print "colorvector : ", type(v)
                # we will mark vertex colors in the modeller based on how we
                # want them to be colored
                # magenta is primary
                if(v == [1.0, 0.0, 1.0, 1.0]):
                    newv = pcolor
                #cyan is secondary
                elif(v == [0.0, 1.0, 1.0, 1.0]):
                    newv = scolor
                
                # leave other colors as they are
                if(newv is not None):
                    vcolor.setData3f(newv[0], newv[1], newv[2], 1.0)

I constructed most of this function (everything but the stuff at the end) by pasting together the functions in this page of the Panda manual http://www.panda3d.org/manual/index.php/Reading_existing_geometry_data into one big function.

The problem is, when I try to declare my GeomVertexRewriter, I get a TypeError. I am following the manual to the line, and it TypeError complaint lists this as a possible constructor:

GeomVertexRewriter(non-const GeomVertexData vertex_data, const InternalName name)

Which looks a whole hell of a lot like what I’m giving it. As you can see, I’m printing vdata’s type just to make sure it’s a GeomVertexData. I am also printing the contents of vdata, and I can see that there is a ‘color’ column included:

<type 'libpanda.GeomVertexData'>
color_runner
  28 rows.
  Array 0 (00FF09B0, [ vertex(3f) normal(3f) color(4b) ]):
    row 0:
      vertex -0.33 -0.396584 0
      normal 0 -0.295494 0.955345
      color 0 1 1 1
more vertices.....

Could someone please point out where I’m messing up?

If you are curious, I am trying to combine this with flat shading and low-poly models without textures to create a retro-looking aesthetic, from the days where we were beyond wireframes but didn’t have gourad shading yet. The runtime coloring is intended to, as you might expect, provide team coloring for the models.

instead of messing with vertex colors i suggest you either try node.setColor() which colors the entire node. or you simply use small textures with plain colors in them and just swap the textures.
both are usualy faster than working through the entire vertexdata of the model using pyhon-code. and both cause less trobule.
as for your current approach. sry no idea.

Actually, I figured out the problem. Along with re-doing the actual color-writing code, I should have written this:

vdata = geom.modifyVertexData()

Instead of this:

vdata = geom.getVertexData()

But thanks for the advice. I’m going to try and figure out a way of doing the recoloring only once for a given model for a given team, which is what I’d be doing anyways if I were using the texturing strategy. I think I’ll end up making my own loadModel wrapper which will figure out if there is a teamcolored model or not already loaded, and just load that instead, but otherwise load and color a new model. If I end up limiting the sorts of models a team can have, I will probably just go ahead and load+color the models at load time. This isn’t very memory-efficient, but I figure it’s not too bad, because like I said, all the models are going to be low-poly, and I’m either not loading textures or I’m loading very small and simple textures.

Note also that if you use the higher-level interface like setColor(), Panda is free to use additional optimizations. For instance, in most cases setColor() doesn’t require duplicating the vertices at all–instead, Panda just plays games with the lighting subsystem to change the apparent color of a model.

David

Sorry to dig up an old thread, but I actually don’t want the effects of setColor(), at least at the model level. My vertex coloring actually isn’t working out properly… here are screenshots to illustrate.

This is how I colored them in the modeller:

This is what happens when I recolor them in-game:

Hopefully this also illustrates more what I’m aiming for. I think I might just go to the texturing route, as it’s simpler. I’m concentrating more on physics and gameplay and such for now, though.

Sorry, it’s not obvious to me from these pictures what you expect the color to do, or what is the particular problem you’re having with setColor().

There are two common problems people experience with setColor():

  • It completely replaces any vertex color already assigned from the modeling package. If you’d rather modulate the existing color, rather than replacing it, use setColorScale() instead.

  • It might color parts of the model you don’t expect it to. If you want setColor() only to color certain parts of a model, you have to make sure those parts are set aside as their own nodes, and then you can get a handle to those nodes. The manual explains how to do this.

But, yeah, there’s no requirement to use setColor() or setColorScale(). If you’re happy with directly modifying the vertices, go right ahead with that approach.

David