Eggoctree-How to loop

Hi, sorry, i’m sorta new here, but I saw that someone had made a oggoctree and I was trying to use it. My friend got it to work but we find that it only does the last object in our map. How can we get it to loop so it does all the objects in the scene? Also will this still let us call them by their name? Like “Cube 782”?

We was using the treeform scrip that was modified by lethe, 2 page.

Its purpose is to deal with level geometry only really, usually for collisions only (There are some cases where it can help with normal rendering, but the only common once are top-down/isometric viewing.), so typically you would only send it a single mesh. Saying that my todo list includes going through and fixing that issue, specifically by making you tag the geometry you want chopped up, but I haven’t the time right now, and its a long term goal anyway. It probably wouldn’t be that hard to modify the script however to get just that feature. I’ld first consider if you really need this though - you probably don’t, and doing it to a bunch of objects makes little sense as each object would still be at the root of the hierarchy. If you do need it I might be able to have a look next week, but I just don’t have the time this minute; you could always add it yourself. And no, you won’t be able to get the objects by their name - they are chopped up into many pieces.

I think a better modification would be to take all the geometry in the egg and flatten and and then occtree it and then add it to the existing geometry.

Good point treeform, and really much simpler - a one line fix as you just need to add a flatten strong into the script after loading the model. Really should of thought of that:-)

Ty for the replys. I’m not really the coder for our team, i’m just our model editor, our lead coder is a little busy with some other things. So i’m not sure where to put the “one line” code at, yes we are using it for collision, mostly the floors really, but having to load all the differnt parts would seem like a wast of space instead of just loading everything in one big scene really.

lethe, its not one line (there is no flatten strong because we are eading with egg structures) yet it can’t be that hard.

I converted that eggoctree script from using the egg interface to using geomvertexwriter/reader for my own purposes, I can post it if you want. (This would allow you to call flattenstrong and simply pass it to the script)

edit: here it is.

"""
							 _                 
							| |               
  ___  __ _  __ _  ___   ___| |_ _ __ ___  ___
 / _ \/ _` |/ _` |/ _ \ / __| __| '__/ _ \/ _ \
|  __/ (_| | (_| | (_) | (__| |_| | |  __/  __/
 \___|\__, |\__, |\___/ \___|\__|_|  \___|\___|
	   __/ | __/ | by treeform	   
	  |___/ |___/  modified by mindstormss                                                            
			 
This is a replacement of raytaller wonderful
Egg Octree script many people had problem using it
( i always guessed wrong about the size of cells )
and it generated many "empty" branches which this
one does not.  This one also uses geoms/primitives instead of egg data for real time usage
original see : ( https://discourse.panda3d.org/viewtopic.php?t=2502 )
This script like the original also released under the WTFPL license.
Usage: octreefy(node)
node -> node to be turned into an octree. Will create an octree for this node and a seperate octree for each child of this node
returns the octree as a node.  It will have all effects (parent/texture/color) as original node)
***at the moment it will not copy effects on child nodes of the original node.*** (like simply loading the smiley model 
the octreefy will not catch the texture...not a problem if using it for the only useful purpose-collision****
"""
__all__ = ['octreefy']
from pandac.PandaModules import *
   
def getCenter(vertexList):
	""" get a list of Polywraps and figure out their center """
	# Loop on the vertices determine the bounding box
	center = Point3(0)
	i = 0
	for vtx in vertexList:
		center += vtx.center
		i+=1
	if i:
		center /= i
	return center

def flatten(thing):
	""" get nested tuple structure like quadrents and flatten it """
	if type(thing) == tuple:
		for element in thing:
			for thing in flatten(element):
				yield thing
	else:
		yield thing

def splitIntoQuadrants(vertexList,center):
	"""
		+---+---+    +---+---+
		| 1 | 2 |    | 5 | 6 |
		+---+---+    +---+---+
		| 3 | 4 |    | 7 | 8 |
		+---+---+    +---+---+
		put all poly wraps into quadrents
	"""
	quadrants = ((([],[]),
				 ([],[])),
				 (([],[]),
				  ([],[])))
	for vtx in vertexList:
		vtxPos = vtx.center
		x =  vtxPos[0] > center[0]
		y =  vtxPos[1] > center[1]
		z =  vtxPos[2] > center[2]
		quadrants[x][y][z].append(vtx)
	quadrants = flatten(quadrants)
	return quadrants

class Polywrap:
	"""
		its a class that defines polygons center
		so that it does not have to be recomputed
	"""
	polygon = None
	center = None
   
	def __str__(self):
		""" some visualization to aid debugging """
		return str(self.polygon.getNumVertices())+":"+str(self.center)
   
def genPolyWraps(vdata,prim):
	""" generate a list of polywraps from a group of polygons """
	vertex = GeomVertexReader(vdata, 'vertex')
	for p in range(prim.getNumPrimitives()):
		s = prim.getPrimitiveStart(p)
		e = prim.getPrimitiveEnd(p)
		center = Vec3(0)
		num = 0
		for i in range(s, e):
			vertex.setRow(prim.getVertex(i))
			center+=vertex.getData3f()
			i+=1
		if i: center/=i
		pw = Polywrap()
		pw.polygon = p
		pw.center = center
		yield pw
		 
def buildOctree(vdata,state,prim,maxNumber,verbose):
	""" build an octree from a primitive and vertex data """
	polywraps = [i for i in genPolyWraps(vdata,prim)]
	if verbose: print len(polywraps),"triangles"
	center = getCenter(polywraps)
	quadrants = splitIntoQuadrants(polywraps,center)
	node = NodePath(PandaNode('octree-root'))
	for n in recr(quadrants,vdata,state,prim,maxNumber,verbose):
		n.reparentTo(node)
	return node

def recr(quadrants,vdata,state,prim,maxNumber,verbose,indent=0):
	"""
		visit each quadrent and create octree there
	"""
	vertex = GeomVertexReader(vdata,'vertex')
	qs = [i for i in quadrants]
	if verbose: print "    "*indent,"8 quadrents have ",[len(i) for i in qs]," triangles"
	for quadrent in qs:
		if len(quadrent) == 0:
			if verbose: print "    "*indent," no triangles at this quadrent"
			continue
		elif len(quadrent) <= maxNumber:
			center = getCenter(quadrent)
			if verbose: print "    "*indent," triangle center", center, len(quadrent)
			p = GeomTriangles(Geom.UHStatic)
			for pw in quadrent:
				s = prim.getPrimitiveStart(pw.polygon)
				e = prim.getPrimitiveEnd(pw.polygon)
				l = []
				for i in range(s,e):
					l.append(prim.getVertex(i))
				p.addVertices(*l)
				p.closePrimitive()
			geom = Geom(vdata)
			geom.clearPrimitives()
			geom.addPrimitive(p)
			geomnode = GeomNode('gnode')
			geomnode.addGeom(geom)
			geomnode.setGeomState(0,state)
			node = NodePath('leaf-%i'%indent)
			node.attachNewNode(geomnode)
			yield node
		else:
			node = NodePath('branch-%i'%indent)
			center = getCenter(quadrent)
			for n in recr(splitIntoQuadrants(quadrent,center),vdata,state,prim,maxNumber,verbose,indent+1):
				n.reparentTo(node)
			yield node
			
def octreefy(node,maxNumber=3,verbose=False):
	"""
		octreefy this node and it's children
		using the buildOctree functions
	"""

	finishedNode = node.copyTo(render)
	finishedNode.detachNode()
	
	for node in finishedNode.findAllMatches('**/+GeomNode'):
		geomNode = node.node()
		for i in range(geomNode.getNumGeoms()):
			geom = geomNode.modifyGeom(i)
			geom.decomposeInPlace()
			vdata = geom.modifyVertexData()
			state = geomNode.getGeomState(i)
			for i in range(geom.getNumPrimitives()):
				n = buildOctree(vdata,state,geom.getPrimitive(i),maxNumber,verbose)
				n.reparentTo(node)
			geom.clearPrimitives()
	return finishedNode

Yes that be most helpful, i’m just not that code savy to do such a sorta thing sadly.

put it above…

Oky I did this, but it doesnt seem to make anything… maybe I did something wrong?

import direct.directbase.DirectStart 
from eggoctree import *
from direct.showbase.DirectObject import DirectObject
class Octree(DirectObject):
  def __init__(self):
    node = loader.loadModel("map")
    node.flattenStrong()
    octreefy(node)
Octree()
run()

it returns the octreefyd node.

so something like

self.octreeNode = octreefy(node)

then whenever you want to test for a colision do something like this

self.visibleNode.detachNode()
self.octreeNode.reparentTo(render)
do collision checking
self.octreeNode.detachNode()
self.visibleNode.reparentTo(render)

Ty for being so helpful! Ok I got it to show now, but i’m a little lost on where you got self.visibleNode? Also when I did collision checking it didnt seem to show anything with base.cTrav.showCollisions(render)

Edit… ok my friend (our lead programer) told me that the collision tag wasnt there. He wasnt sure where to put the collision tag either…

addObjectType(‘barrier’)?

mindstormss, good work!

There is one major problem though. The geoms you create are slow at collisions. This is what you should be using video.google.com/videoplay?docid … 0926&hl=en

also it looks like you are buding octree out of every geom. It should be build one octree out of the whole thing.

oh, didn’t know about the special collision polygons, I’ll look into it!
I did this a while ago, so it may take some time for the changes to come, but they will eventually come. In the meantime I have been using this and it gave enough of a speed increase for me not to worry about it :slight_smile:–but I agree that these optimizations should be made.

edit: here is the modified version. It includes all geoms into one octree and it uses collisionpolygons.

"""
							 _                 
							| |               
  ___  __ _  __ _  ___   ___| |_ _ __ ___  ___
 / _ \/ _` |/ _` |/ _ \ / __| __| '__/ _ \/ _ \
|  __/ (_| | (_| | (_) | (__| |_| | |  __/  __/
 \___|\__, |\__, |\___/ \___|\__|_|  \___|\___|
	   __/ | __/ | by treeform	   
	  |___/ |___/  modified by mindstormss                                                            
			 
This is a replacement of raytaller wonderful
Egg Octree script many people had problem using it
( i always guessed wrong about the size of cells )
and it generated many "empty" branches which this
one does not.  This one also uses geoms/primitives instead of egg data for real time usage
original see : ( https://discourse.panda3d.org/viewtopic.php?t=2502 )
This script like the original also released under the WTFPL license.
Usage: octreefy(node)
node -> node to be turned into an octree. Will create an octree for this node and a seperate octree for each child of this node
returns the octree as a node.  It will have all effects (parent/texture/color) as original node)
***at the moment it will not copy effects on child nodes of the original node.*** (like simply loading the smiley model 
the octreefy will not catch the texture...not a problem if using it for the only useful purpose-collision****
"""
__all__ = ['octreefy']
from pandac.PandaModules import *
   
def getCenter(vertexList):
	""" get a list of Polywraps and figure out their center """
	# Loop on the vertices determine the bounding box
	center = Point3(0)
	i = 0
	for vtx in vertexList:
		center += vtx.center
		i+=1
	if i:
		center /= i
	return center

def flatten(thing):
	""" get nested tuple structure like quadrents and flatten it """
	if type(thing) == tuple:
		for element in thing:
			for thing in flatten(element):
				yield thing
	else:
		yield thing

def splitIntoQuadrants(vertexList,center):
	"""
		+---+---+    +---+---+
		| 1 | 2 |    | 5 | 6 |
		+---+---+    +---+---+
		| 3 | 4 |    | 7 | 8 |
		+---+---+    +---+---+
		put all poly wraps into quadrents
	"""
	quadrants = ((([],[]),
				 ([],[])),
				 (([],[]),
				  ([],[])))
	for vtx in vertexList:
		vtxPos = vtx.center
		x =  vtxPos[0] > center[0]
		y =  vtxPos[1] > center[1]
		z =  vtxPos[2] > center[2]
		quadrants[x][y][z].append(vtx)
	quadrants = flatten(quadrants)
	return quadrants

class Polywrap:
	"""
		its a class that defines polygons center
		so that it does not have to be recomputed
	"""
	polygon = None
	center = None
   
	def __str__(self):
		""" some visualization to aid debugging """
		return str(self.polygon.getNumVertices())+":"+str(self.center)
   
def genPolyWraps(vdata,prim):
	""" generate a list of polywraps from a group of polygons """
	vertex = GeomVertexReader(vdata, 'vertex')
	for p in range(prim.getNumPrimitives()):
		s = prim.getPrimitiveStart(p)
		e = prim.getPrimitiveEnd(p)
		center = Vec3(0)
		num = 0
		for i in range(s, e):
			vertex.setRow(prim.getVertex(i))
			center+=vertex.getData3f()
			i+=1
		if i: center/=i
		pw = Polywrap()
		pw.polygon = p
		pw.center = center
		yield pw
		 
def buildOctree(vdata,prim,maxNumber,verbose):
	""" build an octree from a primitive and vertex data """
	polywraps = [i for i in genPolyWraps(vdata,prim)]
	if verbose: print len(polywraps),"triangles"
	center = getCenter(polywraps)
	quadrants = splitIntoQuadrants(polywraps,center)
	node = NodePath(PandaNode('octree-root'))
	for n in recr(quadrants,vdata,prim,maxNumber,verbose):
		n.reparentTo(node)
	return node

def recr2(quadrants,vdata,prim,maxNumber,verbose,indent=0):
	"""
		visit each quadrent and create octree there
	"""
	vertex = GeomVertexReader(vdata,'vertex')
	qs = [i for i in quadrants]
	if verbose: print "    "*indent,"8 quadrents have ",[len(i) for i in qs]," triangles"
	for quadrent in qs:
		if len(quadrent) == 0:
			if verbose: print "    "*indent," no triangles at this quadrent"
			continue
		elif len(quadrent) <= maxNumber:
			center = getCenter(quadrent)
			if verbose: print "    "*indent," triangle center", center, len(quadrent)
			p = GeomTriangles(Geom.UHStatic)
			for pw in quadrent:
				s = prim.getPrimitiveStart(pw.polygon)
				e = prim.getPrimitiveEnd(pw.polygon)
				l = []
				for i in range(s,e):
					l.append(prim.getVertex(i))
				p.addVertices(*l)
				p.closePrimitive()
			geom = Geom(vdata)
			geom.clearPrimitives()
			geom.addPrimitive(p)
			geomnode = GeomNode('gnode')
			geomnode.addGeom(geom)
			node = NodePath('leaf-%i'%indent)
			node.attachNewNode(geomnode)
			yield node
		else:
			node = NodePath('branch-%i'%indent)
			center = getCenter(quadrent)
			for n in recr(splitIntoQuadrants(quadrent,center),vdata,prim,maxNumber,verbose,indent+1):
				n.reparentTo(node)
			yield node

def recr(quadrants,vdata,prim,maxNumber,verbose,indent=0):
	"""
		visit each quadrent and create octree there
	"""
	vertex = GeomVertexReader(vdata,'vertex')
	qs = [i for i in quadrants]
	if verbose: print "    "*indent,"8 quadrents have ",[len(i) for i in qs]," triangles"
	for quadrent in qs:
		if len(quadrent) == 0:
			if verbose: print "    "*indent," no triangles at this quadrent"
			continue
		elif len(quadrent) <= maxNumber:
			center = getCenter(quadrent)
			if verbose: print "    "*indent," triangle center", center, len(quadrent)
			p = GeomTriangles(Geom.UHStatic)
			collNode = CollisionNode('leaf-%i'%indent)
			
			for pw in quadrent:
				s = prim.getPrimitiveStart(pw.polygon)
				e = prim.getPrimitiveEnd(pw.polygon)
				l = []
				for i in range(s,e):
					l.append(prim.getVertex(i))
				for i in range(0,len(l),3):
					v = []
					for i2 in range(3):
						vertex.setRow(l[i+i2])
						v.append(vertex.getData3f())
					p = CollisionPolygon(*v)
					collNode.addSolid(p)
			
			node = NodePath('leaf-%i'%indent)
			node.attachNewNode(collNode)
			yield node
		else:
			node = NodePath('branch-%i'%indent)
			center = getCenter(quadrent)
			for n in recr(splitIntoQuadrants(quadrent,center),vdata,prim,maxNumber,verbose,indent+1):
				n.reparentTo(node)
			yield node
	
def combine(node):
	'''combines all of the geoms into one. a preprocessing step'''
	newVdata = GeomVertexData('name', GeomVertexFormat.getV3(), Geom.UHStatic)
	vertexWriter = GeomVertexWriter(newVdata, 'vertex')
	newPrim = GeomTriangles(Geom.UHStatic)
	startingPos = 0
	pos = 0
	
	for node in node.findAllMatches('**/+GeomNode'):
		geomNode = node.node()
		for i in range(geomNode.getNumGeoms()):
			geom = geomNode.getGeom(i).decompose()
			vdata = geom.getVertexData()
			vertexReader = GeomVertexReader(vdata,'vertex')
			while not vertexReader.isAtEnd():
				v = vertexReader.getData3f()
				vertexWriter.addData3f(v[0],v[1],v[2])
				pos+=1
			for i in range(geom.getNumPrimitives()):
				prim = geom.getPrimitive(i)
				for i2 in range(prim.getNumPrimitives()):
					s = prim.getPrimitiveStart(i2)
					e = prim.getPrimitiveEnd(i2)
					count = 0
					for i in range(s, e):
						newPrim.addVertex(prim.getVertex(i)+startingPos)
						count+=1
						if count==3:
							count = 0
							newPrim.closePrimitive()
			startingPos=pos
	return [newVdata,newPrim]
			
def octreefy(node,maxNumber=3,verbose=False):
	"""
		octreefy this node and it's children
		using the buildOctree functions
	"""
	vdata,prim = combine(node)	#combine all of the geoms into one vertex/triangle list
	#print vdata
	#print prim
	return buildOctree(vdata,prim,maxNumber,verbose)	#build the octree

in this version, simply use
collisionNode = octreefy(visualNode)
collisionNode.setCollideMask(…)

and to collide
visualNode.detachNode()
collisionNode.reparentTo(render)
do collision check
collisinNode.detachNode()
visualNode.reparentTo(render)

visualNode is the rendered version of your octree.