Modifying vertices at runtime

I’ve been searching all over for a solution to modify the vertices of a geom but i’m out of luck.
What i’m trying to accomplish is to remove certain triangles after they have been added to a primitive, and my first approach would be to just set the vertex coordinates to (0,0,0) for all the sides of the triangle to make it not visible since I’m looking for speed rather than a good structured table of vertices (The geom may contain serveral hundred thousand vertices). If anyone has a better solution I would really appriciate an example of this.

So to the code:

Declaring the geom:

def createGeom(self):
	format = GeomVertexFormat.getV3n3cpt2()
	gvd = GeomVertexData('materialGvd', format, Geom.UHDynamic)
	geom = Geom(gvd)
	gvdPrim = GeomTriangles(Geom.UHDynamic)
	gvdVertex = GeomVertexWriter(gvd, 'vertex')
	gvdNormal = GeomVertexWriter(gvd, 'normal')
	gvdTexcoord = GeomVertexWriter(gvd, 'texcoord')
	gvdColor = GeomVertexWriter(gvd, 'color')
	gvdTex = loader.loadTexture('textures/2_.png')
	gvdTex.setMagfilter(Texture.FTLinearMipmapLinear)
	gvdTex.setMinfilter(Texture.FTLinearMipmapLinear)
	geoms = {'geom':geom,
				  'prim':gvdPrim,
				  'vertex':gvdVertex,
				  'normal':gvdNormal,
				  'texcoord':gvdTexcoord,
				  'color':gvdColor,
				  'index':0,
				  'gvd':gvd,
				  'texture':gvdTex}
				  
	geomNode = GeomNode('material')
	geoms['geom'].addPrimitive(geoms['prim'])
	geomNode.addGeom(geoms['geom'])
	
	chunkNode = render.attachNewNode(geomNode)
	chunkNode.setPos(Vec3(0,0,0))
	chunkNode.setTwoSided(False)
	chunkNode.setCollideMask(BitMask32.allOff())
	
	return chunkNode,geomNode,geoms,gvd

With this code I then add a bunch of vertices:

def writeMaterial(self,geoms,displacement,faces,color):
	for v in faces:
		# format of v: "Vec3(20,0,20)" and so forth
		displacement = self.createMesh(geoms,displacement,v,color)
	return displacement
	
def createMesh(self,geoms,displacement,v,color):
	geoms['vertex'].addData3f(v)
	geoms['color'].addData4f(color)

	geoms['prim'].addVertex(displacement)
	displacement += 1
	return displacement

The displacement of the first and last vertex is stored so it can later be accessed and modified with this code:

#mD is an array with this format: "[0,35]", where 0 is the first vertex and 35 is the last vertex that I want to modify.
geom = geomNode.modifyGeom(0)
vdata = geom.modifyVertexData()
prim = geom.modifyPrimitive(0)
vertexWriter = GeomVertexWriter(vdata, 'vertex')
vertexReader = GeomVertexReader(vdata, 'vertex')
row = 0
mdCounter = mD[0]
while not vertexReader.isAtEnd():
	vr = vertexReader.getData3f()
	if row == mdCounter and row <= mD[1]:
		vr = Vec3(0,0,0)
		mdCounter += 1
		print "Deleteed row ",row
	vertexWriter.setData3f(vr)
	row += 1

(Sorry for not posting a better view of the code but it’s spread over several files so it’s hard to make a good overview of it)

Unfortunatly i can’t seem to get this to work correctly. Do I need to apply the changes to the primitive/geom somehow? When I add vertices the changes (new triangles) appear instantly.

You need a GeomVertexRewriter instead of a GeomVertexWriter if you want to change data. I would also suggest that you call setNumRows() to set the number of vertices you’re going to have before calling addData3f to avoid the performance penalty from having Panda constantly resize the table.

Instead of trying to modify the vertices themselves, though, I’d suggest changing the indices associated with the GeomTriangles instead. Triangles are built out of sets of 3 indices that reference an index in the table of vertices. Since there are typically fewer indices than vertices, it is far more efficient to change the indices than the vertices.

Thank you for the quick reply!
I’ve changed the GeomVertexWriter to GeomVertexRewriter but the changes still doesn’t apply. I’ve printed out the vertices changed and they have indeed been modified to (0,0,0). When I apply the changes to one specific triangle however (I have several boxes drawn in the scene), the coordinates of one of the corners of the triangle changes to (0,0,0), even though all of the corners have been changed to (0,0,0). maybe there’s something else wrong with the code as well?

I’ve seem to have found the solution (although I haven’t been able to pinpoint any specific error in the code that caused this not to work).
I wrote a small program to test this and it worked like a charm with the GeomVertexRewriter! Thank you for your help rdb!

Here is the program for anyone looking for a similar solution. This can of course be easily modified to just change coordinates for specific triangles/vertices at runtime instead of “hiding” them.
Press “Delete” to remove the front side of the box:

import direct.directbase.DirectStart
from pandac.PandaModules import *
from random import random
from direct.showbase.DirectObject import DirectObject

class SpawnMaterial(DirectObject):
	def __init__(self):
		# Keeps track of displacement for each square
		self.displacementStartEnd = []
		# Define the geom and associated data
		nodePath,geomNode,geoms = self.createGeom()
		# Look at geomNode
		base.cam.setPos(Vec3(-10,-10,10))
		base.cam.lookAt(Point3(2.5,2.5,2.5))
		# Displacement for the vertex table starts at 0
		displacement = 0
		# Get faces for the squares to draw with a dimension of 5x5x5
		faces = self.getFaces(5,5,5)
		# Write vertices
		displacement = self.writeMaterial(geoms,displacement,faces)
		# Press "Delete" to remove front square (displacement-index 1)
		self.accept("delete", self.modify, [1,geomNode])

	def modify(self,index,geomNode):
		geom = geomNode.modifyGeom(0)
		vdata = geom.modifyVertexData()
		prim = geom.modifyPrimitive(0)
		# Define new GeomVertexRewriter for modifying the existing geom
		vertexWriter = GeomVertexRewriter(vdata, 'vertex')		
		# Displacement-start for vertex to modify
		displacementStart = self.displacementStartEnd[index][0]
		# Displacement-end for vertex to modify
		displacementEnd = self.displacementStartEnd[index][1]
		# Run through all vertices for affected square
		for i in range(displacementStart,displacementEnd+1):
			# Change only the vertices between displacement start and end by calling setRow() to change current row in vertex table
			vertexWriter.setRow(i)
			# Change vertex
			vertexWriter.setData3f(0,0,0)

	def createGeom(self):
		format = GeomVertexFormat.getV3n3cpt2()
		gvd = GeomVertexData('materialGvd', format, Geom.UHDynamic)
		geom = Geom(gvd)
		gvdPrim = GeomTriangles(Geom.UHDynamic)
		gvdVertex = GeomVertexRewriter(gvd, 'vertex')
		gvdNormal = GeomVertexRewriter(gvd, 'normal')
		gvdTexcoord = GeomVertexRewriter(gvd, 'texcoord')
		gvdColor = GeomVertexRewriter(gvd, 'color')
		geoms = {'geom':geom,
					  'prim':gvdPrim,
					  'vertex':gvdVertex,
					  'normal':gvdNormal,
					  'texcoord':gvdTexcoord,
					  'color':gvdColor,
					  'index':0,
					  'gvd':gvd}
					  
		geomNode = GeomNode('material')
		geoms['geom'].addPrimitive(geoms['prim'])
		geomNode.addGeom(geoms['geom'])
		
		nodePath = render.attachNewNode(geomNode)
		nodePath.setTwoSided(False)
		nodePath.setCollideMask(BitMask32.allOff())
		
		return nodePath,geomNode,geoms
		
	def writeMaterial(self,geoms,displacement,faces):
		# Run through each set of square coordinates
		for f in faces:
			# Save start of displacement for this square
			displacementStart = displacement
			# Run through each vertex for the square
			for v in f:
				# Generate random color for vertex
				color = self.genColor()
				# Add vertex
				displacement = self.createMesh(geoms,displacement,v,color)
			# Save end of displacement for this square (-1 for not overlapping with new set of vertices)
			displacementEnd = displacement-1
			# Add displacement start and end to array for later use
			self.displacementStartEnd.append([displacementStart,displacementEnd])
		return displacement
		
	def createMesh(self,geoms,displacement,v,color):
		# Add vertex
		geoms['vertex'].addData3f(v)
		# Add color to vertex
		geoms['color'].addData4f(color)
		geoms['prim'].addVertex(displacement)
		displacement += 1
		return displacement
		
	def getFaces(self,x,y,z):
		dimensions = []
		#name = "top"
		a1 = Vec3(0,y,z)
		b1 = Vec3(0,0,z)
		c1 = Vec3(x,0,z)
		a2 = Vec3(0,y,z)
		b2 = Vec3(x,0,z)
		c2 = Vec3(x,y,z)
		dimensions.append((a1,b1,c1,a2,b2,c2))
		#name = "front"
		a1 = Vec3(0,0,0)
		b1 = Vec3(x,0,0)
		c1 = Vec3(x,0,z)
		a2 = Vec3(0,0,z)
		b2 = Vec3(0,0,0)
		c2 = Vec3(x,0,z)
		dimensions.append((a1,b1,c1,a2,b2,c2))
		#name = "back"
		b1 = Vec3(0,y,0)
		a1 = Vec3(x,y,0)
		c1 = Vec3(x,y,z)
		b2 = Vec3(0,y,z)
		a2 = Vec3(0,y,0)
		c2 = Vec3(x,y,z)
		dimensions.append((a1,b1,c1,a2,b2,c2))
		#name = "left"
		a1 = Vec3(0,0,0)
		b1 = Vec3(0,0,z)
		c1 = Vec3(0,y,0)
		a2 = Vec3(0,0,z)
		b2 = Vec3(0,y,z)
		c2 = Vec3(0,y,0)
		dimensions.append((a1,b1,c1,a2,b2,c2))
		#name = "right"
		a1 = Vec3(x,0,z)
		b1 = Vec3(x,0,0)
		c1 = Vec3(x,y,0)
		a2 = Vec3(x,y,z)
		b2 = Vec3(x,0,z)
		c2 = Vec3(x,y,0)
		dimensions.append((a1,b1,c1,a2,b2,c2))
		#name = "bottom"
		a1 = Vec3(0,0,0)
		b1 = Vec3(0,y,0)
		c1 = Vec3(x,0,0)
		a2 = Vec3(0,y,0)
		b2 = Vec3(x,y,0)
		c2 = Vec3(x,0,0)
		dimensions.append((a1,b1,c1,a2,b2,c2))
		return dimensions
		
	def genColor(self):
		return Vec4(random(), random(), random(), 1)
		
SpawnMaterial()
run()