Keep faces together when modifying vertices?

I’m working on some code to modify vertices of existing objects. I was surprised to find that it makes the object explode (faces aren’t kept together), as if maya2egg makes individual copies of each vertex for every face which uses it. that’s going to be hugely useful for one of my projects, but for this one right now I’d like to be able to modify one vertex and have it be shared by all its connected faces.

Here’s the code:

import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.task import Task
from direct.showbase import DirectObject

class World(DirectObject.DirectObject):
  def __init__(self):
    self.outerObject=loader.loadModel("outerObject.egg")
    self.outerObject.reparentTo(render)
    self.innerObject=loader.loadModel("innerObject.egg")
    self.innerObject.reparentTo(render)

    light1=render.attachNewNode(PointLight('light1'))
    render.setLight(light1)
    light1.reparentTo(camera)

    self.setup()
    self.accept('a',self.modify,[.5])
    self.accept('s',self.modify,[-.5])  
  def setup(self):
    # get data from the thing we're manipulating
    
    np = self.outerObject.find("**/+GeomNode")
    geomNode=np.node()
    print geomNode.getNumGeoms()
    
    self.outerObjectGeom=geomNode.modifyGeom(0)
    self.vertexData = self.outerObjectGeom.modifyVertexData()
    print self.vertexData
    print self.vertexData.getFormat()
 
  def modify(self,amount):
    # get the vertices and normals of the outerObject and do stuff with them.
    vertex=GeomVertexRewriter(self.vertexData,'vertex')
    normal=GeomVertexRewriter(self.vertexData,'normal')
    
    while not vertex.isAtEnd():
      v=Vec3 (vertex.getData3f())
      n=Vec3 (normal.getData3f())
      
      v2=v + n * amount
      vertex.setData3f(v2[0],v2[1],v2[2]);
      
w=World()
run()

It will work ok as long as the normals are averaged beforehand, but it makes me wonder whether there is a way to make the internal structure share vertices to ensure a continuous mesh, or if they’re always separated like this.

The egg loader is free to either share vertices, or duplicate them, when it constructs the GeomVertexDatas for a given egg file. It makes its choice according to which it feels will be more optimal for a given model. So you can’t rely on this behavior universally.

If you want to insist that the vertices be shared, or unshared, you will have to construct the corresponding GeomVertexData yourself.

David

May be the easiest way is pre-grouping nearest vertices in tuple and work with this groups?

When it comes down to it, the geometry is made of polygons not vertices. For any two polygons to share the same vertex they need to have not only the same position but the same normal, UV, vertex color, etc.
In 3D modeling apps they are simply using a trick when you select a point on the mesh and move it, you are often moving two or more vertices as far as the graphics card is concerned.
I think the file format is done this way because it more closely mimics the actual data sent to the video card.

ah hah! thanks, that makes total sense. of course it needs independent vertices in the end because all attributes other than 3d position have to be independent.

sounds like @ninth’s suggestion is something like the trick that 3d modeling apps use so I’ll try that out.

So, that worked pretty well, so now I have a question about optimizing performance with the GeomVertexReader and GeomVertexWriter. How expensive is setRow()? Do you get much of an improvement by reading and writing everything in a batch vs randomly skipping around and modifying vertices?

It depends. Try it and see. :slight_smile:

David

hehe. well, actually, before that, here’s another question - is it possible to get the original polygons as they’re listed in the egg file, rather than the optimized mesh? or, alternately, is there a way to disable the mesher during load so, for example, you’d get polygons instead of triangle strips?

The internal geometry only stores triangles or triangle strips, not higher-order polygons, so no, not really. You can put:

egg-mesh 0

in your Config.prc file (and make sure that you clear your on-disk model cache), and then your egg files will come in with triangles instead of triangle strips, but still there won’t be a one-to-one correspondence with whatever you had in the original egg file.

Of course, you could always load the original egg file directly with the EggData interface, and walk through it and discover the original polygons you had there yourself. You could also modify the egg file to put each polygon within its own group, like this:

<Group> { <Model> { 1 } <Polygon> { ... } } }

and then when you load the egg file, each original polygon will be its own ModelNode which you can treat independently. Good luck with the performance, of course. :slight_smile:

David