GeomVertexReader reading "color" returns only black?

I’m using GeomVertexReaders in order to examine the vertices of a model. To this end, I have three such readers: one for vertex-positions (attached to the “vertex” column), one for vertex-normals (attached to the “normal” column), and one for vertex-colours (attached to the “color” column).

I haven’t yet tested the reader that examines normals, but the one that examines positions seems to work as expected.

The one that examines colours, however, doesn’t. Specifically, I seem to only get black (i.e. (0, 0, 0, 1)) when I call “getData4()” on it.

I’ve examined the model, and it does appear to have vertex-colours. (Indeed, those colours show up on the original, visible model as shown in the scene, I believe.)

I’ve also checked that the vertex-data does have a “color” column, and it seems that it does.

This–somewhat abbreviated–is what I’m doing:

            for geom in node.modifyGeoms():
                newGeom = geom.decompose()
                newGeom.makeNonindexed(False)
                vData = newGeom.getVertexData()
                rowCount = vData.getNumRows()

                reader = GeomVertexReader(vData, "vertex")

                if dataCallback is not None:
                    polys = []
                    readerColours = GeomVertexReader(vData, "color")
                    readerNormals = GeomVertexReader(vData, "normal")

                for i in range(0, rowCount, 3):
                    # ... vertex-position stuff here ...

                    if dataCallback is not None:
                        if vData.hasColumn("normal"):
                            normal1 = readerNormals.getData3()
                            normal2 = readerNormals.getData3()
                            normal3 = readerNormals.getData3()
                        else:
                            normal1 = normal2 = normal3 = Vec3(0, 0, 1)

                        if vData.hasColumn("color"):
                            colour1 = readerColours.getData4()
                            colour2 = readerColours.getData4()
                            colour3 = readerColours.getData4()
                        else:
                            # Note here that the fourth component of this
                            # is zero, while the fourth component that I'm
                            # getting in my results is one. Further, I think
                            # that I've checked that the code is in fact
                            # getting into the if-statement above.
                            colour1 = colour2 = colour3 = Vec4(0, 0, 0, 0)

If all vertices have the same colours, the egg loader will optimise the model by converting the vertex colours into a ColorAttrib.

So, check that the Geom state doesn’t have a ColorAttrib applied to it.

They shouldn’t have the same colours in this case, however. (And don’t in the original geometry as rendered in the 3D scene.)

Well, I don’t know what to tell you, other than “it probably doesn’t have vertex colors”. It looks like you’re doing everything right. It’s possible that the egg loader split things up by material such that each individual Geom ended up having the same colors and received a ColorAttrib.

Otherwise, please .writeBamFile() the node in question and send it to me.

Note that you can use print() to print out the format and/or the vdata and see what’s actually in there.

I presume that this would be set on the GeomNode from which the Geom is drawn? (I don’t see such state in the Geom class itself.) If so, then it doesn’t seem that such an attrib is being set.

And indeed, the colours vary across the vertices of the triangles in many cases in this model, so even if it were being split into individual triangles I wouldn’t expect those triangles to have the same colour at every vertex…

Fair enough!

To be specific, I’ve written out the NodePath that is the origin for the geoms that I’m examining–I’m not yet sure of how to write out at the geom level. If you want me to do so, however, please say and I’ll give it a shot!

Note also in the code that I gave above that I’m processing this NodePath by iterating over its Geoms (as acquired via a call to “modifyGeoms” on its node), and for each, creating a copy via “decompose”. I then work on that copy.

Here, then, is the resultant bam-file:
vertexColourTest0.bam (3.1 KB)

Well, it does indeed have vertex colours, and continues to after calling decompose() and make_nonindexed(False). Is the following not consistent with what you’re seeing?

>>> cols = GeomVertexReader(vdata, "color")
>>> while not cols.is_at_end():
...     print(cols.get_data4())
...
LVecBase4f(0, 0, 0, 1)
LVecBase4f(0, 0, 0, 1)
LVecBase4f(0.109804, 0, 0, 1)
LVecBase4f(0.109804, 0, 0, 1)
LVecBase4f(0, 0, 0, 1)
LVecBase4f(0, 0, 0, 1)
LVecBase4f(0.109804, 0, 0, 1)
LVecBase4f(0, 0, 0, 1)
LVecBase4f(0.109804, 0, 0, 1)
LVecBase4f(0.109804, 0, 0, 1)
LVecBase4f(0, 0, 0, 1)
LVecBase4f(0, 0, 0, 1)
LVecBase4f(0.109804, 0, 0, 1)
LVecBase4f(0, 0, 0, 1)
LVecBase4f(0.164706, 0, 0, 1)
LVecBase4f(0.164706, 0, 0, 1)
LVecBase4f(0, 0, 0, 1)
LVecBase4f(0, 0, 0, 1)
LVecBase4f(0.164706, 0, 0, 1)
LVecBase4f(0, 0, 0, 1)
LVecBase4f(0.309804, 0, 0, 1)
LVecBase4f(0.309804, 0, 0, 1)
LVecBase4f(0, 0, 0, 1)
LVecBase4f(0.0745098, 0, 0, 1)
LVecBase4f(0.309804, 0, 0, 1)
LVecBase4f(0.0745098, 0, 0, 1)
LVecBase4f(0.309804, 0, 0, 1)
LVecBase4f(0.309804, 0, 0, 1)
LVecBase4f(0.0745098, 0, 0, 1)
LVecBase4f(0.0745098, 0, 0, 1)
LVecBase4f(0.309804, 0, 0, 1)
LVecBase4f(0.0745098, 0, 0, 1)
LVecBase4f(0.654902, 0, 0, 1)
LVecBase4f(0.654902, 0, 0, 1)
LVecBase4f(0.0745098, 0, 0, 1)
LVecBase4f(0.164706, 0, 0, 1)
LVecBase4f(0.654902, 0, 0, 1)
LVecBase4f(0.164706, 0, 0, 1)
LVecBase4f(0.74902, 0, 0, 1)
LVecBase4f(0.74902, 0, 0, 1)
LVecBase4f(0.164706, 0, 0, 1)
LVecBase4f(0.313726, 0, 0, 1)
LVecBase4f(0.74902, 0, 0, 1)
LVecBase4f(0.313726, 0, 0, 1)
LVecBase4f(0.74902, 0, 0, 1)
LVecBase4f(0.74902, 0, 0, 1)
LVecBase4f(0.313726, 0, 0, 1)
LVecBase4f(0.313726, 0, 0, 1)
LVecBase4f(0.74902, 0, 0, 1)
LVecBase4f(0.313726, 0, 0, 1)
LVecBase4f(0.831373, 0, 0, 1)
LVecBase4f(0.831373, 0, 0, 1)
LVecBase4f(0.313726, 0, 0, 1)
LVecBase4f(0.494118, 0, 0, 1)
LVecBase4f(0.831373, 0, 0, 1)
LVecBase4f(0.494118, 0, 0, 1)
LVecBase4f(1, 0, 0, 1)
LVecBase4f(1, 0, 0, 1)
LVecBase4f(0.494118, 0, 0, 1)
LVecBase4f(0.576471, 0, 0, 1)
LVecBase4f(1, 0, 0, 1)
LVecBase4f(0.576471, 0, 0, 1)
LVecBase4f(1, 0, 0, 1)
LVecBase4f(1, 0, 0, 1)
LVecBase4f(0.576471, 0, 0, 1)
LVecBase4f(0.576471, 0, 0, 1)
LVecBase4f(1, 0, 0, 1)
LVecBase4f(0.576471, 0, 0, 1)
LVecBase4f(1, 0, 0, 1)
LVecBase4f(1, 0, 0, 1)
LVecBase4f(0.576471, 0, 0, 1)
LVecBase4f(0.576471, 0, 0, 1)
LVecBase4f(1, 0, 0, 1)
LVecBase4f(0.576471, 0, 0, 1)
LVecBase4f(1, 0, 0, 1)
LVecBase4f(1, 0, 0, 1)
LVecBase4f(0.576471, 0, 0, 1)
LVecBase4f(0.576471, 0, 0, 1)
LVecBase4f(1, 0, 0, 1)
LVecBase4f(0.576471, 0, 0, 1)
LVecBase4f(0.784314, 0, 0, 1)
LVecBase4f(0.784314, 0, 0, 1)
LVecBase4f(0.576471, 0, 0, 1)
LVecBase4f(0.54902, 0, 0, 1)
LVecBase4f(0.784314, 0, 0, 1)
LVecBase4f(0.54902, 0, 0, 1)
LVecBase4f(0, 0, 0, 1)
LVecBase4f(0, 0, 0, 1)
LVecBase4f(0.54902, 0, 0, 1)
LVecBase4f(0, 0, 0, 1)

Huh, trying it again I am seeing colours now!

In which case, it would seem that the issue is arising elsewhere, in my own code somewhere.

It’s strange–I very much thought that I’d tested the code given above and found no colours! (Unless Panda was using an old cached version of the model for some reason–I did shut down the IDE earlier, and re-opened it for this round of testing.)

In any case, my apologies, then–it seems that I was mistaken as to the source of my problem! ^^;

Thank you for your help!

[edit]
Ah, I found the problem, I do believe!

I was storing the Vec3s and Vec4s that I was reading from my vertex-data–and it would seem that at least some of it was being cleaned up, and zeroed in the process. (Or perhaps being reused in some way, to the same effect.)

I’m now storing copy-constructed versions of those Vec3s and Vec4s–and do seem to be getting the expected data! :slight_smile:

1 Like

Ah, yeah, well caught, there are a bunch of places in the Panda API where a reference to a vector object is returned rather than a copy, and this can be a little counter-intuitive from the Python point of view.

1 Like

Minor addendum, especially for any others who may stumble over this:

As it turns out, it seems that, when you’re not using the data directly after reading, it’s called for to perform the above-mentioned copy-construction immediately on reading the relevant data: it would appear that the vectors involved aren’t just cleaned up or re-used at some point, they’re cleaned up or re-used with each new read.

I’m guessing that each read just re-uses the same vector, meaning that if you read in three vertices worth of data in a row and aren’t copy-constructing the results there and then, you end up with all of your data reflecting the last-read vertex. Or so it would seem!

(Which makes sense, in retrospect.)

To explain by example:

The following seems to result in all three variables holding the same value

vert1 = reader.getData4()
vert2 = reader.getData4()
vert3 = reader.getData4()

The following, however, seems to allow the three variables to hold different values:

vert1 = Vec4(reader.getData4())
vert2 = Vec4(reader.getData4())
vert3 = Vec4(reader.getData4())