How to 'copy' a procedurally created node.

Making multiple references to a single NodePath from an external geometry model is simple … use loadModelCopy(…) instead of loadModel(…)

Now, given that this really useful method is available for loaded models, how could I do the same for procedurally created geometry nodes (That is … GeomNode instances that I create on the fly using GeomVertexFormat, GeomVertexData, GeomVertexWriter, and GeomTriangles)?

Can I do this?

I am trying to make a smoke trail (without ParticleEffects()) and I create a quad composed of two triangles using this function :


# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Function name : P3DCreateQuadXZ
#
# Description:
#
#	Create a unit quad lying on the XZ plane.
#
# Input(s):
#
#   twoSided - Set to True for two-sided, False otherwise
#
# Output(s):
#
#	A NodePath representing the grid
#
def P3DCreateQuadXZ(twoSided=False) :
	gvf = GeomVertexFormat.getV3n3c4t2 ()
	gvd = GeomVertexData('QuadVertices',gvf,Geom.UHStatic)
	gvwV = GeomVertexWriter(gvd, 'vertex')
	gvwT = GeomVertexWriter(gvd, 'texcoord')
	gvwC = GeomVertexWriter(gvd, 'color')
	gvwN = GeomVertexWriter(gvd, 'normal')

	gvwV.addData3f(-0.5, 0.0, -0.5)
	gvwN.addData3f(0, 0, 1)
	gvwC.addData4f(1, 1, 1, 1)
	gvwT.addData2f(0, 0)

	gvwV.addData3f(0.5, 0.0, -0.5)
	gvwN.addData3f(0, 0, 1)
	gvwC.addData4f(1, 1, 1, 1)
	gvwT.addData2f(0, 1)

	gvwV.addData3f(0.5, 0.0, 0.5)
	gvwN.addData3f(0, 0, 1)
	gvwC.addData4f(1, 1, 1, 1)
	gvwT.addData2f(1, 1)

	gvwV.addData3f(-0.5, 0.0, 0.5)
	gvwN.addData3f(0, 0, 1)
	gvwC.addData4f(1, 1, 1, 1)
	gvwT.addData2f(1, 0)

	geom = Geom(gvd)

	tris = GeomTriangles(Geom.UHStatic)

	tris.addVertex(0)
	tris.addVertex(1)
	tris.addVertex(2)
	tris.closePrimitive()

	tris.addVertex(0)
	tris.addVertex(2)
	tris.addVertex(3)
	tris.closePrimitive()

	if (twoSided) :

		tris.addVertex(2)
		tris.addVertex(1)
		tris.addVertex(0)
		tris.closePrimitive()

		tris.addVertex(3)
		tris.addVertex(2)
		tris.addVertex(0)
		tris.closePrimitive()

	geom.addPrimitive(tris)
	node = GeomNode('grid')
	node.addGeom(geom)
	return node

Once I define this I create a trail of particles, billboarded to face the viewer and spaced as required along the trail of a missile as follows :


	gRan = random.Random(5033)
	ranScale = 0.1
	self.mQuadNodes = []
	y = 0
	dy = .5
	tex = loader.loadTexture('Cloud.png')
	for i in range(100) :
		quad = P3DCreateQuadXZ(True)
		quadNode = render.attachNewNode(quad)
		x = ranScale*(gRan.random() - 0.5)
		z = ranScale*(gRan.random() - 0.5)
		quadNode.setPos(x, y, z)
		y += dy
		s = self.mMissile.getScaledThrust(i)
		quadNode.setScale(s,s,s)
		quadNode.reparentTo(render)
		quadNode.setBillboardPointEye()
		quadNode.setTexture(tex)
		quadNode.setTransparency(1)
		quadNode.setColor(1,1,1,0.8)
		quadNode.setLightOff()
		self.mQuadNodes.append(quadNode)

So, in the above code, I am essentially wanting to replace the creation call to :


quad = P3DCreateQuadXZCopy(True) 

You can use:


nodePath.copyTo(newParent)

to copy a node to a new parent. The original nodePath is unaffected; the return value of nodePath.copyTo() is the NodePath for the new copy.

If you don’t want to use the NodePath interface, but you have instead a node (such as a GeomNode), you can use the lower-level interface on PandaNode:


newNode = origNode.copySubgraph()

This is, incidentally, exactly what happens inside loader.loadModelCopy().

David

Awesome! Since I had a GeomNode I went ahead and used copySubgraph() and it works like a charm.

Thank you very much,
Paul