dae2egg GeomNodes Wont Convert to CollideNodes

How can I convert all GeomNodes to CollideNodes from an egg model that was converted by dae2egg?

Below was my attempt. Is this a fixable issue with the dae2egg converter? If so, I would like to know before I go writing my own (using pyCollada and pyxb for a quick turn around).

I drew a simple cylinder in sketchup and exported as .dae (attached). I then converted it using dae2egg (also attached) with the simple command: C:\Panda3D-1.8.0\bin\dae2egg cylinder.dae cylinder.egg

I converted all GeomNodes into CollideNodes as in the code provided here:
[url]GeomNode vs CollisionPolygon]

So, for the simple case of smiley.egg this works wonderfully, the CollideNodes perfectly resemble the location and shape of the GeomNodes. But, for my simple cylinder.egg this is not the case. Although the GeomNodes of the cylinder load and display correctly, the CollisionNodes do not.

from direct.showbase.ShowBase import ShowBase
from panda3d.core import CollisionTraverser
from panda3d.core import CollisionHandlerQueue,CollisionRay
from panda3d.core import CollisionNode
from panda3d.core import CollisionPolygon
from panda3d.core import NodePath
from panda3d.core import GeomVertexReader
from panda3d.core import BitMask32
from panda3d.core import PointLight
from panda3d.core import Point3


def geoms_to_collisions(incomingNode):
	parent = NodePath('cGeomConversionParent')
	for c in incomingNode.findAllMatches('**/+GeomNode'):
		geomNode = c.node()
		for i in range(geomNode.getNumGeoms()):
			geom = geomNode.getGeom(i)
			vdata = geom.getVertexData()
			cChild = CollisionNode(c.getName())
			for i in range(geom.getNumPrimitives()):
				prim = geom.getPrimitive(i)
				vertex = GeomVertexReader(vdata, 'vertex')
				prim = prim.decompose()
				for p in range(prim.getNumPrimitives()):
					s = prim.getPrimitiveStart(p)
					e = prim.getPrimitiveEnd(p)
					v = []
					for i in range(s, e):
						vi = prim.getVertex(i)
						vertex.setRow(vi)
						v.append(vertex.getData3f())

					colPoly = CollisionPolygon(*v)
					cChild.addSolid(colPoly)
	
			parent.attachNewNode (cChild)
	
	return parent

ShowBase()
base.cTrav = CollisionTraverser()

#this works:
model = loader.loadModel('smiley')
#this doesn't
#model = loader.loadModel('cylinder.egg')
#model.reparentTo(render)
model.setPos(0, 25, 0)
#model.setCollideMask(BitMask32.bit(0))

model_NP = geoms_to_collisions(model)
model_NP.set_pos(0,25,0)
model_NP.reparentTo(render) 

interior_test_ray = render.attachNewNode("interior_root")
inside_ray = CollisionRay()	 # Create the ray
inside_ray.setOrigin(0,0,0)	# Set its origin
inside_ray.setDirection(1,0,0) # And its direction
rayCol = CollisionNode('insideRay') # Create and name the node
rayCol.addSolid(inside_ray) # Add the ray
rayCol.setFromCollideMask(BitMask32.bit(0)) # Set its bitmasks
rayCol.setIntoCollideMask(BitMask32.all_off())
insideColNp = interior_test_ray.attachNewNode(rayCol)

cRayHandler = CollisionHandlerQueue()
base.cTrav.addCollider(insideColNp, cRayHandler)
base.cTrav.showCollisions(render)

insideColNp.show()

insideColNp.posInterval(5, Point3(5, 25, -2), startPos=Point3(-10, 25, 1), fluid=1).loop()

redPointLight = render.attachNewNode( PointLight( "PointLight" ) )
render.setLight( redPointLight )

run()

not_working_model.zip (5.04 KB)

The individual GeomNodes (and possibly its parents) can have a transformation applied, which I don’t see you applying to your CollisionNode. You should do cChild.setTransform(geomNode.getTransform(incomingNode)), or something of the sort.

That said, I would advise you to add a {Polyset keep descend} tag under the appropriate in the .egg file, this will cause the .egg loader to automatically create collision geometry for you, which is usually more efficient than doing it yourself. (“polyset” means to create a set of collision polygons, “keep” means to keep the original visible geometry around, and “descend” means to visit sub-groups.)

it appears dae2egg doesn’t have an option for automatically doing this to all groups (?) according to:
[url]SketchUp Observations:]

How might I automatically insert these tags programmatically? I see the api:
http://www.panda3d.org/apiref.php?page=EggGroup

Do I just do:

eggGroup.setTag('0', '<Collide> {Polyset keep descend}') 

for every group? Is there some nice example code for looping through all groups and adding such tags? Couldn’t find anything in the manual other than api.

I greatly appreciate it! :mrgreen:

You can’t use setTag, that only works for entries. (The line is not really a ‘tag’, strictly speaking, I just didn’t have a better name for it.) Tags are inherently meaningless pieces of metadata that you want to associate with your nodes, and are not specially interpreted by Panda.

You can add a simple Python script to your pipeline that uses loadEggFile to load an .egg file into an EggData object, gets the main EggGroup object, sets the collide flags, and writes it out again - you can simply run your models through this script after dae2egg (or it could even invoke dae2egg directly if you don’t like calling two commands).

egg files are simple text files, use any text editor with a find and replace option (even windows own Notepad has this function)
Search for replace with {Polyset keep descend}
If fou heve more then 50 models you can make a script for it, but the panda egg interface seems an overkill for that in my opinion - you can just parse the file line by line as if it was just plain text.

Ok, everything works - thank you rdb. And wezu, the panda interface was incredibly useful for this task! I appreciate your advice though.

for anyone else who stumbled upon this looking for a similar solution, the methods you want are:

egg_group.setCsType(EggGroup.CSTPolyset) 
egg_group.setCollideFlags(EggGroup.CFKeep+EggGroup.CFDescend )

Technically, it’s supposed to be EggGroup.CFKeep | EggGroup.CFDescend, just pointing that out in case you run into further trouble with that down the line.

Glad that you figured it out!