Adapting code in switching from on GeomVertexFormat to another

I’m currently using some code drawn from this post, and indeed, it works quite well.

However, that code only extracts vertex-position data from the source-mesh, and I find myself wanting more. So, to that end, I’m trying to adapt the code to work with a vertex-format that includes such data. Specifically, where the code given there uses a “V3” format, I’m attempting to use a “tV3n3c4” format. (These acquired via their associated “get”-calls in GeomVertexFormat.)

And this is where I’m getting stuck: I don’t seem to be figuring out quite what to change in order for the data in the memory-view line up properly with the vertices in this new format.

To quote a bit of code from the post linked-to above, with credit to Epihaius for it, here is more-or-less the original form of what I have:

for geom in model_node.modify_geoms():

        geom.decompose_in_place()
        vertex_data = geom.modify_vertex_data()
        vertex_data.format = GeomVertexFormat.get_v3()
        view = memoryview(vertex_data.arrays[0]).cast("B").cast("f")
        index_list = geom.primitives[0].get_vertex_list()
        index_count = len(index_list)

        for indices in (index_list[i:i+3] for i in range(0, index_count, 3)):
            points = [Point3(*view[index*3:index*3+3]) for index in indices]
            coll_poly = CollisionPolygon(*points)
            collision_node.add_solid(coll_poly)

I’m then modifying the “getV3” count to look more or less like this:

vertex_data.format = GeomVertexFormat.get_v3n3c4()

Now, naturally this results in the vertex-data in the memory-view no longer lining up as shown in the code above.

So, my thought is to change the line that creates the “points” list to look like this:

points = [Point3(*view[index*3:index*3+3]) for index in indices]

Since there are no longer three floats per vertex-entry, but ten (three position, three normal, and four colour), I would expect to have to multiply my indices by ten instead of three, producing something like this:

points = [Point3(*view[index*10:index*10+3]) for index in indices]

However, this doesn’t seem to work–I end up with malformed geometry.

(And I’ve tried a few other alternatives to that line, also to little avail.)

I’m not seeing where I’m going wrong right now, so I appeal to the forum for help: does anyone see how to modify the code to work with this altered vertex-format?

Consider that the data in a column may be aligned to the size of a (16-byte) SSE2 register so that CPU vertex animation can be performed more efficiently. In that case, there are 4 empty bytes between the position and the normal columns (ie. as though there were a fourth float).

The GeomVertexFormat class has accessors to determine the offset and alignment of each column, you could use this to inspect the format in question.

Ah, tricky, I see.

Thank you–I intend to give that a shot and report back!

Also, c4 is stored as 4 bytes, not 4 floats, so the whole column takes up the same size as a single float.

You can of course compose your own GeomVertexFormat so that there are no surprises. :slight_smile:

Hmm… Would that interfere with examining geometry-data loaded from a model? (Which is what this is being used for.)

(I’m not all that familiar with this side of Panda, I’m afraid! ^^; )

Okay, I’m trying a hopefully-simpler approach, using GeomVertexReader and its higher-level methods.

For now, I’m just trying to replicate the original, base functionality: reading sets of three vertices corresponding to the triangles that make up the given mesh. Thus far, however, it’s not working–and I’m not sure of why.

Here is my current version–can someone see where I’m going wrong, by any chance?

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

                from panda3d.core import GeomVertexReader

                reader = GeomVertexReader(vData, "vertex")

                for i in range(0, rowCount, 3):
                    reader.setRow(i)
                    vert1 = reader.getData3()
                    reader.setRow(i + 1)
                    vert2 = reader.getData3()
                    reader.setRow(i + 2)
                    vert3 = reader.getData3()
                    poly = CollisionPolygon(vert1, vert2, vert3)
                    if not isSolid:
                        poly.setTangible(False)
                    collisionNode.addSolid(poly)

I don’t think you need to explicitly control the position of the reading row. Because the getData3() method does this automatically by advancing to the next line.

Hmm… Simply removing the calls to “setRow” doesn’t seem to help, however: I’m still getting mangled geometry.

It’s entirely possible that you’re correct in what you say–indeed, I had thought that it was so, before spotting some explicit calls to “setRow” in some other code. However, if so, then there’s presumably something else wrong there… :/

decompose() doesn’t guarantee that the data is non-indexed, as you seem to be expecting. Call .makeNonindexed(False) as well. Otherwise, you will have to go through the primitives and read out the indices for the individual triangles, which tell you which rows in the vertex table correspond to each triangle.

Hmm, okay, I see.

And indeed, that does seem to make it work! So thank you! (Both of you!)

I take it that the original approach–which didn’t use GeomVertexReader, but instead used a “memoryview”–worked because it was expecting vertices to be laid out one after the next, rather than indexed?

[edit]
I can, I believe, only mark one post as the “solution”, so let it be known that both rdb and serega, above, contributed to the solution to my problem. :slight_smile: