Yes, I’ve seen that case. I have a .bam terrain with 97792 vertices, 97410 tris. The result of bam2egg is even corrupted. The .egg only has half of the vertices. That terrain was built by triangles strips and flattened, without vertex normals.
Though for the other 307583 vertices, 203090 tris model, built NOT by triangles strips, with normals, it’s just fine.
How did you create your model ?
[UPDATE] :
to allow me to exclude some parts of the model in the octree process, I used my SceneGraphBrowser :
discourse.panda3d.org/viewtopic.php?t=3474
from pandac.PandaModules import *
import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject
from direct.gui.OnscreenText import OnscreenText
from direct.interval.IntervalGlobal import *
from direct.gui.DirectGui import DirectLabel
from direct.showbase import PythonUtil as PU
from direct.task import Task
from random import random
import sys, math
from SceneGraphBrowser import *
def createSceneGraphBrowser():
# create SceneGraphBrowser and point it on the model
global SGB
SGB = SceneGraphBrowser(
parent=None, # where to attach SceneGraphBrowser frame
root=sourceNodePath, # display children under this root node
command=nodeSelected, # user defined method, executed when a node get selected,
# with the selected node passed to it
contextMenu=nodeRightClicked,
# selectTag and noSelectTag are used to filter the selectable nodes.
# The unselectable nodes will be grayed.
# You should use only selectTag or noSelectTag at a time. Don't use both at the same time.
#selectTag=['select'], # only nodes which have the tag(s) are selectable. You could use multiple tags.
noSelectTag=['noSelect','dontSelectMe'], # only nodes which DO NOT have the tag(s) are selectable. You could use multiple tags.
# nodes which have exclusionTag wouldn't be displayed at all
exclusionTag=['internal component'],
frameSize=(1,1.6),
font=None, titleScale=.05, itemScale=.035, itemTextScale=1.2, itemTextZ=0,
rolloverColor=(1,.8,.2,1),
collapseAll=0, # initial tree state
suppressMouseWheel=1, # 1 : blocks mouse wheel events from being sent to all other objects.
# You can scroll the window by putting mouse cursor
# inside the scrollable window.
# 0 : does not block mouse wheel events from being sent to all other objects.
# You can scroll the window by holding down the modifier key
# (defined below) while scrolling your wheel.
modifier='control' # shift/control/alt
)
selected = None
selectedIval = None
excludedText = None
excludedIval = None
def renderFrame():
base.graphicsEngine.renderFrame()
base.graphicsEngine.renderFrame()
def nodeSelected(np): # don't forget to receive the selected node (np)
global selected,selectedIval,excludedText,excludedIval
if selected!=None:
selected.hideBounds()
selectedIval.finish()
selected.clearRenderMode()
if excludedIval!=None:
if excludedIval.isPlaying():
excludedIval.finish()
if np.isStashed():
excludedText = DirectLabel(text='THIS NODE IS EXCLUDED\nright-click it again to include it back',
scale=.06, pad=(.5,.5), frameColor=(1,1,1,.5),
text_fg=(0,0,0,1),sortOrder=2000)
excludedIval = Sequence(
excludedText.colorScaleInterval(5,Vec4(1,1,1,0),blendType='easeIn'),
Func(excludedText.destroy)
)
excludedIval.start()
return
selected=np
np.showTightBounds()
selectedIval = Sequence(
Func(np.setRenderModeWireframe,1),
np.colorScaleInterval(.3,Vec4(1,0,0,1)),
np.colorScaleInterval(.3,Vec4(1,1,1,1)),
Func(np.setRenderModeFilled,1),
np.colorScaleInterval(.3,Vec4(1,0,0,1)),
np.colorScaleInterval(.3,Vec4(1,1,1,1)),
Wait(.5)
)
selectedIval.loop()
print np.getName(),'SELECTED'
def nodeRightClicked(np): # don't forget to receive the selected node (np)
if result!=None:
return
if np.isStashed():
np.unstash()
else:
np.stash()
updateGrids(updateSpacing=0)
class EggOctree(object):
def build(self, sourceNodePath, destNode, cellSize, collide=False):
sourceNode=sourceNodePath.copyTo( sourceNodePath.getParent() )
sourceNode.flattenStrong()
print 'storing vertices & triangles.....'
geomList=sourceNode.findAllMatches('**/+GeomNode').asList()
if not geomList:
return
vpool=EggVertexPool('octV_0')
collNumVtx=0
collnumface=0
# list for the vertices
collVertices=[]
collUniqueVtxIdx=[]
# list for the vertices
collNormals=[]
# list for the vertices index
collFaces=[]
# append all vertex data into a complete list
for collGeom in geomList:
for gIdx in range(collGeom.node().getNumGeoms()):
currentGeom=collGeom.node().getGeom(gIdx)
collVtxData=currentGeom.getVertexData()
numVtx=collVtxData.getNumRows()
#=========================================================
# create vertex reader
collVtxReader=GeomVertexReader(collVtxData)
# begin reading at vertex 0
collVtxReader.setRow(0)
# get the vertex position column
column=-1
columnName=''
while ( columnName!='vertex' ):
column+=1
collVtxReader.setColumn(column)
columnName=str(collVtxReader.getColumn().getName())
#=========================================================
# create vertex normal reader
collNormalReader=GeomVertexReader(collVtxData)
# begin reading at vertex 0
collNormalReader.setRow(0)
# get the vertex normal column
hasNormals=1
column=-1
columnName=''
while ( columnName!='normal' ):
column+=1
collNormalReader.setColumn(column)
if collNormalReader.getColumn()==None:
hasNormals=0
break
else:
columnName=str(collNormalReader.getColumn().getName())
for i in range(numVtx):
# respect each geomNode's transform which may be exist
vtx=sourceNode.getRelativePoint(collGeom,collVtxReader.getData3f())
collVertices.append(vtx)
eVtx=EggVertex()
eVtx.setPos(Point3D(vtx[0],vtx[1],vtx[2]))
if hasNormals:
normal=sourceNode.getRelativeVector(collGeom,collNormalReader.getData3f())
eVtx.setNormal(Vec3D(normal[0],normal[1],normal[2]))
collUniqueVtxIdx.append( vpool.createUniqueVertex(eVtx).getIndex() )
for prim in range(currentGeom.getNumPrimitives()):
# store the vertices index for each triangle
collFaceData=currentGeom.getPrimitive(prim).decompose()
# get the triangle counts
numface=collFaceData.getNumFaces()
for i in range(0,numface*3,3):
# refer to the vertex data length list created earlier
vtxIdx1=collNumVtx+collFaceData.getVertex(i)
vtxIdx2=collNumVtx+collFaceData.getVertex(i+1)
vtxIdx3=collNumVtx+collFaceData.getVertex(i+2)
vtxIdx=(collUniqueVtxIdx[vtxIdx1],collUniqueVtxIdx[vtxIdx2],collUniqueVtxIdx[vtxIdx3])
collFaces.append(vtxIdx)
collnumface+=numface
# add the current collected vertices count
collNumVtx+=numVtx
collNormals=None
print 'NUM UNIQUE VTX :',vpool.getHighestIndex()+1
# ############################################################
# ################ DEBUG !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# ED=EggData()
# ED.addChild(vpool)
# for idx in range(collnumface):
# # Get the triangle center
# poly=EggPolygon()
# for i in range(3) :
# poly.addVertex(vpool.getVertex(collFaces[idx][i]))
# ED.addChild(poly)
# ED.writeEgg(Filename(output_file+'_debug.egg'))
# return
# ################ DEBUG !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# ############################################################
# model's bounding box
minB,maxB=sourceNode.getTightBounds()
minBB = Vec3D(minB[0]+0.001, minB[1]+0.001, minB[2]+0.001)
maxBB = Vec3D(maxB[0]+0.001, maxB[1]+0.001, maxB[2]+0.001)
sourceNode.removeNode()
cellXsize=cellSize[0]
cellYsize=cellSize[1]
cellZsize=cellSize[2]
# Number of leaves x,y,z
bboxSize = maxBB - minBB
self.ncx = math.ceil(bboxSize.getX() / cellXsize)
self.ncy = math.ceil(bboxSize.getY() / cellYsize)
self.ncz = math.ceil(bboxSize.getZ() / cellZsize)
# Depth of the tree x,y,z
self.depthX = math.ceil(math.log(self.ncx) / math.log(2))
self.depthY = math.ceil(math.log(self.ncy) / math.log(2))
self.depthZ = math.ceil(math.log(self.ncz) / math.log(2))
self.depth = max(self.depthX, self.depthY, self.depthZ)
collVertices=None
print self.ncz, self.ncy, self.ncx
print 'initializing cells...'
self.cells = [[[
{'-':
Point3D( minBB.getX() + x * cellXsize,
minBB.getY() + y * cellYsize,
minBB.getZ() + z * cellZsize),
'+':
Point3D( minBB.getX() + (x+1) * cellXsize,
minBB.getY() + (y+1) * cellYsize,
minBB.getZ() + (z+1) * cellZsize),
'g':EggGroup('L_%d_%d_%d' % (x,y,z))}
for z in range(self.ncz)]
for y in range(self.ncy)]
for x in range(self.ncx)]
print 'Cell grid is %dx%dx%d' % (len(self.cells), len(self.cells[0]), len(self.cells[0][0]))
if collide :
for x in range(self.ncx) :
for y in range(self.ncy) :
for z in range(self.ncz) :
self.cells[x][y][z]['g'].addObjectType('barrier')
print 'filling cells...'
# Iterate on the triangles
for idx in range(collnumface):
# Get the triangle center
polyCenter = Point3D(0,0,0)
poly=EggPolygon()
trie=collFaces[idx]
for i in range(3) :
vtx=vpool.getVertex( trie[i] )
polyCenter +=vtx.getPos3()
poly.addVertex(vtx)
polyCenter /= 3.0
# Add the triangle to the corresponding cell group
cx = int(math.floor((polyCenter[0]-minBB[0]) / cellXsize))
cy = int(math.floor((polyCenter[1]-minBB[1]) / cellYsize))
cz = int(math.floor((polyCenter[2]-minBB[2]) / cellZsize))
# doing this would yield uniform normals for all 3 vertices
# so, preserve normals from the vertex data instead
# (already done above after creating EggVertex)
# if not hasNormals:
# poly.recomputePolygonNormal()
self.cells[cx][cy][cz]['g'].addChild(poly)
# Add the vertex data
destNode.addChild(vpool)
print 'Started........'
self.nleaves = self.recur(destNode, 0, 0,0,0)
print self.nleaves, 'leaves added'
def recur(self, node, depth, x, y, z) :
if depth < self.depth :
nnode = EggGroup('')
delt = int(math.pow(2, self.depth - depth - 1))
nchilds = 0
nchilds += self.recur(nnode, depth+1, x, y, z)
nchilds += self.recur(nnode, depth+1, x + delt, y, z)
nchilds += self.recur(nnode, depth+1, x, y + delt, z)
nchilds += self.recur(nnode, depth+1, x + delt, y + delt, z)
nchilds += self.recur(nnode, depth+1, x, y, z + delt)
nchilds += self.recur(nnode, depth+1, x + delt, y, z + delt)
nchilds += self.recur(nnode, depth+1, x, y + delt, z + delt)
nchilds += self.recur(nnode, depth+1, x + delt, y + delt, z + delt)
if nchilds > 0 :
node.addChild(nnode)
return nchilds
else :
# We are in a leaf
if x < self.ncx and y < self.ncy and z < self.ncz :
node.addChild(self.cells[x][y][z]['g'])
return 1
else:
return 0
eoct=EggOctree()
distX=4.
distY=4.
distZ=4.
result=None
inc=.1
adjusted=-1
grid=render.attachNewNode('grid')
grid.setLightOff(1)
LSgrid=LineSegs()
LSgrid.setThickness(1)
base.setBackgroundColor(.3,.7,1,1)
base.camLens.setNearFar(.1,100000)
loadingText=OnscreenText(text='LOADING.....',scale=.12,fg=(1,0,0,1),shadow=(0,0,0,1))
renderFrame()
loadingText.destroy()
offOnText=['OFF','ON']
offOnFG=[(1,0,0,1),(0,0,1,1)]
walkerTextParent=aspect2d.attachNewNode('')
walkerTextParent.setZ(-1.2)
walkerText = OnscreenText( parent=walkerTextParent,
text='WALKING ON SCENEGRAPH HIERARCHY',pos=(0,.075),scale=.05,mayChange=1)
stepOnText = OnscreenText( parent=walkerTextParent,
text='sdf',pos=(0,.02),scale=.05,mayChange=1)
gridPropsTextParent=aspect2d.attachNewNode('')
gridPropsTextParent.setZ(-1)
incText = OnscreenText( parent=gridPropsTextParent,
text='increment : %.3f'%inc,pos=(0,.02),scale=.05,mayChange=1)
XYZtext=[]
XYZtext.append( OnscreenText( parent=gridPropsTextParent,
text='X : %.3f'%distX,pos=(-.5,.075),scale=.05,mayChange=1) )
XYZtext.append( OnscreenText( parent=gridPropsTextParent,
text='Y : %.3f'%distY,pos=( 0,.075),scale=.05,mayChange=1) )
XYZtext.append( OnscreenText( parent=gridPropsTextParent,
text='Z : %.3f'%distZ,pos=( .5,.075),scale=.05,mayChange=1) )
def setupLights():
ambientLight = AmbientLight( 'ambientLight' )
ambientLight.setColor( Vec4(0.3, 0.3, 0.3, 1) )
directionalLight = DirectionalLight( 'directionalLight1' )
directionalLight.setDirection( Vec3( 1, 2,-1 ) )
directionalLight.setColor( Vec4( .7, .7, .7, 1 ) )
render.setLight(render.attachNewNode( ambientLight ))
render.setLight(render.attachNewNode( directionalLight ))
def updateGrids(g=(1,1,1),inc=0,updateSpacing=1):
global distX,distY,distZ
TB1,TB2=sourceNodePath.getTightBounds()
TB=TB2-TB1
threshold=.1
if updateSpacing:
if g[0] and TB[0]>threshold:
distX=PU.clampScalar(threshold,TB[0],distX+inc)
XYZtext[0]['text']='X : %.3f'%distX
if g[1] and TB[1]>threshold:
distY=PU.clampScalar(threshold,TB[1],distY+inc)
XYZtext[1]['text']='Y : %.3f'%distY
if g[2] and TB[2]>threshold:
distZ=PU.clampScalar(threshold,TB[2],distZ+inc)
XYZtext[2]['text']='Z : %.3f'%distZ
# remove all grids ###############################################
for g in grid.findAllMatches('**/+GeomNode').asList():
g.removeNode()
# gridX ###############################################
LSgrid.reset()
LSgrid.setColor(1,1,0)
for z in range(int(1+TB[2]/distZ)):
for x in range(int(1+TB[0]/distX)):
LSgrid.moveTo(x*distX,0,z*distZ)
LSgrid.drawTo(x*distX,TB[1],z*distZ)
LSgrid.moveTo(TB[0],0,z*distZ)
LSgrid.drawTo(TB[0],TB[1],z*distZ)
for x in range(int(1+TB[0]/distX)):
LSgrid.moveTo(x*distX,0,TB[2])
LSgrid.drawTo(x*distX,TB[1],TB[2])
LSgrid.moveTo(TB[0],0,TB[2])
LSgrid.drawTo(TB[0],TB[1],TB[2])
grid.attachNewNode(LSgrid.create()).setPos(TB1)
# gridY ###############################################
LSgrid.reset()
LSgrid.setColor(1,0,0)
for z in range(int(1+TB[2]/distZ)):
for y in range(int(1+TB[1]/distY)):
LSgrid.moveTo(0,y*distY,z*distZ)
LSgrid.drawTo(TB[0],y*distY,z*distZ)
LSgrid.moveTo(0,TB[1],z*distZ)
LSgrid.drawTo(TB[0],TB[1],z*distZ)
for y in range(int(1+TB[1]/distY)):
LSgrid.moveTo(0,y*distY,TB[2])
LSgrid.drawTo(TB[0],y*distY,TB[2])
LSgrid.moveTo(0,TB[1],TB[2])
LSgrid.drawTo(TB[0],TB[1],TB[2])
grid.attachNewNode(LSgrid.create()).setPos(TB1)
# gridZ ###############################################
LSgrid.reset()
LSgrid.setColor(0,0,1)
for x in range(int(1+TB[0]/distX)):
for y in range(int(1+TB[1]/distY)):
LSgrid.moveTo(x*distX,y*distY,0)
LSgrid.drawTo(x*distX,y*distY,TB[2])
LSgrid.moveTo(x*distX,TB[1],0)
LSgrid.drawTo(x*distX,TB[1],TB[2])
for y in range(int(1+TB[1]/distY)):
LSgrid.moveTo(TB[0],y*distY,0)
LSgrid.drawTo(TB[0],y*distY,TB[2])
LSgrid.moveTo(TB[0],TB[1],0)
LSgrid.drawTo(TB[0],TB[1],TB[2])
grid.attachNewNode(LSgrid.create()).setPos(TB1)
def adjustX():
global adjusted
adjusted=0
updateXYZtextScale()
def adjustY():
global adjusted
adjusted=1
updateXYZtextScale()
def adjustZ():
global adjusted
adjusted=2
updateXYZtextScale()
def updateXYZtextScale():
for t in XYZtext:
t['scale']=.05
t['fg']=(0,0,0,1)
XYZtext[adjusted]['scale']=.07
XYZtext[adjusted]['fg']=(0,0,1,1)
def adjustGrid(dir):
if adjusted==-1:
print "CHOOSE X, Y, or Z"
return
adjustedGrid=[0,0,0]
adjustedGrid[adjusted]=1
if grid.isHidden():
grid.show()
updateGrids(adjustedGrid,dir*inc)
def adjustInc(Iinc):
global inc
inc=PU.clampScalar(.05,100,inc+Iinc)
incText['text']='increment : %.3f'%inc
def toggleCollision():
global collide
collide=not collide
collText['text']='COLLISION : '+offOnText[collide]
collText['fg']=offOnFG[collide]
def toggleGridVis():
if grid.isHidden():
grid.show()
else:
grid.hide()
def toggleHierarchyWalk(status=None):
global result,isWalkingOnHierarchy,selected
if status==None:
isWalkingOnHierarchy=not isWalkingOnHierarchy
else:
isWalkingOnHierarchy=status
if isWalkingOnHierarchy:
setMode(MODE_hierarchyWalk)
if selected==None:
if result==None:
SGB.command(sourceNodePath)
stepOnText['text']=sourceNodePath.getName()
else:
SGB.command(result)
stepOnText['text']=result.getName()
gridPropsTextParent.posInterval(.25,Point3(0,0,-1.2),blendType='easeIn').start()
walkerTextParent.posInterval(.25,Point3(0,0,-1),blendType='easeIn').start()
text=helpWalker+helpAllModes
if result==None:
text+=helpInclusion
helpText['text']=text
else:
setMode(MODE_gridAdjustment)
gridPropsTextParent.posInterval(.25,Point3(0,0,-1),blendType='easeIn').start()
walkerTextParent.posInterval(.25,Point3(0,0,-1.2),blendType='easeIn').start()
text=helpGrid+helpAllModes
if result==None:
text+=helpInclusion
helpText['text']=text
def getChildIndex(np):
children=np.getParent().getChildrenAsList()
for c in children:
if c==np:
return children.index(np)
def gotoParent():
if selected!=sourceNodePath and selected!=result:
parent=selected.getParent()
SGB.selectNode(parent)
numChildren=parent.getParent().getNumChildren()
selfIdx=getChildIndex(selected)
if parent!=sourceNodePath and parent!=result:
stepOnText['text']='child #%s of %s (num children : %s)'%(selfIdx+1,numChildren,parent.getNumChildren())
def gotoChild():
numChildren=selected.getNumChildren()
if numChildren:
SGB.selectNode(selected.getChild(0))
stepOnText['text']='child #%s of %s (num children : %s)'%(1,numChildren,selected.getNumChildren())
def gotoNextSibling():
if selected==sourceNodePath or selected==result:
return
parent=selected.getParent()
siblingIdx=getChildIndex(selected)+1
if siblingIdx<parent.getNumChildren():
SGB.selectNode(parent.getChild(siblingIdx))
stepOnText['text']='child #%s of %s (num children : %s)'%(siblingIdx+1,parent.getNumChildren(),selected.getNumChildren())
def gotoPrevSibling():
if selected==sourceNodePath or selected==result:
return
parent=selected.getParent()
siblingIdx=getChildIndex(selected)-1
if siblingIdx>-1:
SGB.selectNode(parent.getChild(siblingIdx))
stepOnText['text']='child #%s of %s (num children : %s)'%(siblingIdx+1,parent.getNumChildren(),selected.getNumChildren())
def setMode(mode):
base.buttonThrowers[0].node().setPrefix(mode+':-> ')
def acceptKey(event,method,extraArgs=[]):
for mode in MODES:
DO.accept('%s:-> %s'%(mode,event),method,extraArgs)
def zoomNode(toNode=0):
if toNode:
if selected==None:
return
else:
np=selected
else:
np=sourceNodePath
if np.getBounds().isEmpty():
return
center=np.getBounds().getCenter()
radius=np.getBounds().getRadius()
camPivot.setPos(center)
camPivot.setHpr(camera,0,0,0)
camera.setPos(0,-radius*5,0)
camera.lookAt(0,0,0)
mat4=Mat4(camera.getMat())
mat4.invertInPlace()
base.mouseInterfaceNode.setMat(mat4)
def reviveModel():
global result,selected
if result==None:
return
if selected!=None:
selected.hideBounds()
selectedIval.finish()
selected.clearRenderMode()
selected=None
loader.unloadModel(result)
result.removeNode()
result=None
# revive the model
sourceNodePath.unstash()
# put a notification text
waitText = DirectLabel(text='updating SceneGraphBrowser.....',
scale=.045,text_fg=(0,0,0,1), frameColor=(1,1,1,.8), pad=(.5,.5),
sortOrder=2000)
renderFrame()
waitText.destroy()
# restore stashed nodes, so it will be found by the SGBrowser
stashedNPs=sourceNodePath.findAllMatches('**/@@*')
stashedNPs.unstash()
# display the model's scenegraph
SGB.setRoot(sourceNodePath)
# stash them back
stashedNPs.stash()
stashedNPs.clear()
toggleHierarchyWalk(0)
print 'REVIVED !!!'
def splitModel():
global result,selected
waitText = DirectLabel(text='please wait.....',
scale=.1, frameColor=(1,1,1,.7), pad=(1,.2), text_fg=(0,0,0,1),
sortOrder=2000)
renderFrame()
waitText.destroy()
ed = EggData()
ed.setCoordinateSystem(0) # set it to Z-Up
eoct.build(sourceNodePath, ed, Vec3D(distX, distY, distZ), collide=collide)
print 'writing EGG...',
if collide:
ed.writeEgg(Filename(output_file+'_coll.egg'))
else:
ed.writeEgg(Filename(output_file+'.egg'))
print 'done'
if selected!=None:
selected.hideBounds()
selectedIval.finish()
selected.clearRenderMode()
selected=None
sourceNodePath.stash()
if result!=None:
loader.unloadModel(result)
result.removeNode()
result = NodePath( loadEggData(ed) )
result.setName(output_file)
result.reparentTo(render)
if collide:
result.writeBamFile(output_file+'_coll.bam')
result.setTransparency(0,10)
for g in result.findAllMatches('**/+CollisionNode').asList():
g.show()
else:
result.writeBamFile(output_file+'_White.bam')
for g in result.findAllMatches('**/+GeomNode').asList():
g.setColor(random(),random(),random(),1)
result.writeBamFile(output_file+'_Colored.bam')
waitText = DirectLabel(text='updating SceneGraphBrowser.....',
scale=.045,text_fg=(0,0,0,1), frameColor=(1,1,1,.8), pad=(.5,.5),
sortOrder=2000)
renderFrame()
waitText.destroy()
SGB.setRoot(result)
# result.ls()
doneText = DirectLabel(text='DONE',
scale=.1, frameColor=(1,1,1,.7), pad=(1,.2),text_fg=(0,0,0,1),
sortOrder=2000)
Sequence(
doneText.colorScaleInterval(3,Vec4(1,1,1,.2)),
Func(doneText.destroy)
).start()
print '###########################################'
print '###########################################'
result.analyze()
print '###########################################'
print '###########################################'
toggleHierarchyWalk(0)
ed = None
DO=DirectObject()
MODE_hierarchyWalk='[walking around]'
MODE_gridAdjustment='[adjusting grid]'
isWalkingOnHierarchy=0
MODES=[MODE_gridAdjustment]
acceptKey('x',adjustX)
acceptKey('y',adjustY)
acceptKey('z',adjustZ)
acceptKey('arrow_right',adjustInc,[.05])
acceptKey('arrow_right-repeat',adjustInc,[.05])
acceptKey('arrow_left',adjustInc,[-.05])
acceptKey('arrow_left-repeat',adjustInc,[-.05])
acceptKey('arrow_up',adjustGrid,[1])
acceptKey('arrow_up-repeat',adjustGrid,[1])
acceptKey('arrow_down',adjustGrid,[-1])
acceptKey('arrow_down-repeat',adjustGrid,[-1])
MODES=[MODE_hierarchyWalk]
acceptKey('arrow_right',gotoNextSibling)
acceptKey('arrow_left',gotoPrevSibling)
acceptKey('arrow_up',gotoParent)
acceptKey('arrow_down',gotoChild)
MODES=[MODE_gridAdjustment,MODE_hierarchyWalk]
acceptKey('escape',sys.exit)
acceptKey('enter',splitModel)
acceptKey('r',reviveModel)
acceptKey('c',toggleCollision)
acceptKey('w',base.toggleWireframe)
acceptKey('g',toggleGridVis)
acceptKey('h',toggleHierarchyWalk)
acceptKey('s',base.screenshot)
acceptKey('a',zoomNode,[0])
acceptKey('f',zoomNode,[1])
helpGrid='''[ X/Y/Z ] : select X/Y/Z axis
[ arrow up/down ] : adjust cell size along selected axis
[ arrow left/right ] : adjust cell size increment
'''
helpWalker='''[ arrow up/down ] : go up to parent or down to children
[ arrow left/right ] : go to previous/next sibling
'''
helpAllModes='''[ ENTER ] : SPLIT NOW !!
[ R ] : revive model
[ C ] : toggle collision
[ W ] : toggle wireframe
[ G ] : toggle grid visibility
[ H ] : toggle grid adjustment / hierarchy walker
[ SPACE ] : toggle SceneGraphBrowser
[ A ] : zoom extent
[ F ] : zoom selected node'''
helpInclusion='''
RIGHT CLICK node in SceneGraphBrowser :
toggle inclusion in octree process'''
helpText = OnscreenText(text=helpGrid+helpAllModes+helpInclusion,
scale=.045,align=TextNode.ALeft,fg=(0,0,0,1),mayChange=1)
NodePath(helpText).setPos(render2d,-.995,0,.95)
setupLights()
##########################################################
## THE INPUT FILE CAN BE ANY OF THE SUPPORTED FORMATS ##
##########################################################
input_file='teapot.egg'# <----- YOUR FILE
# input_file='panda.egg'# <----- YOUR FILE
# input_file='RalphWorld.egg'# <----- YOUR FILE
output_file=input_file[:input_file.rfind('.')]+'-split'
#=========================================================
collide=0
##########################################################
##########################################################
collText=OnscreenText(text='COLLISION : '+offOnText[collide],
scale=.05,pos=(0,-.86),fg=offOnFG[collide],shadow=(0,0,0,1), mayChange=1)
sourceNodePath=loader.loadModel(input_file)
sourceNodePath.reparentTo(render)
sourceNodePath.analyze()
camPivot=render.attachNewNode('camPivot')
camera.reparentTo(camPivot)
camera.setPos(1,-1.2,1)
camera.lookAt(0,0,0)
zoomNode(0)
updateGrids()
waitText = DirectLabel(text='creating SceneGraphBrowser.....',
scale=.045,text_fg=(0,0,0,1), frameColor=(1,1,1,.9), pad=(.5,.5),
sortOrder=2000)
renderFrame()
waitText.destroy()
createSceneGraphBrowser()
acceptKey('space',SGB.toggleVisibility)
setMode(MODE_gridAdjustment)
run()
and don’t call me sir, I’m not bearded yet.