Poser Export to Egg

Hi,

I have written a script for Poser to export characters to egg files for use with panda3d. I have only tested it with Poser Pro, Panda 1.6.2 on windows.

This is really a proof of concept, but it works remarkably well.
It current only exports the mesh, vertex normals and the joint
heirarchy, so use per pixel lighting.
I have plans to export full morphs and animations when i get more time.

i hope somebody finds it useful

PIC: http://www.zgeek.com/forum/picture.php?albumid=175&pictureid=1432

############################################################
#
# poser2egg.py - Egg File Exporter for Poser Pro
#
# Version 0.1 - Current only exports vertex positions
# and normals. joints are exported, but there are still some
# issues. It currently doesnt export UV coords, textures,
# materials, morphs, weights or animation data, but i have
# plans for all of those.
#
# Run this script inside the Poser in the PoserPython
# interpreter. You should also have Panda3d installed
# on the system. I have only tested it on windows vista
# with Panda3D 1.6.2
#
############################################################
import poser
import os, sys

############################################################
# General Functions
############################################################

def IndentString(string, level):
   # indent size is 2 chars
   return string.rjust(len(string) + (level * 2))

def FixName(name):
   # currently only removes spaces
   return name.replace(" ","")
   
def RemoveIkChains():
   ikStatusList = []
   for i in range(0, currentFigure.NumIkChains()):
      ikStatusList.append(currentFigure.IkStatus(i))
      currentFigure.SetIkStatus(i, 0) # Turn off
   return ikStatusList

def RestoreIkChains(ikStatusList):
   for i in range(0, currentFigure.NumIkChains()):
      currentFigure.SetIkStatus(i, ikStatusList[i])
      
def VecSubtract(v1, v2):
   return (v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2])
   
def GetMatrix(t):
   return ((1, 0, 0, 0), 
           (0, 1, 0, 0),
           (0, 0, 1, 0),
           (t[0], t[1], t[2], 1))
           
def GetActorIndex(actor):
   for i, a in enumerate(uniActorList):
      if a.InternalName() == actor.InternalName():
         return i
   return None
           
############################################################
# Egg Writing Functions
############################################################

def WriteComment(name, comment, level):
   r = []
   r.append(IndentString('<Comment> %(name)s {\n', level))
   for ln in comment.splitlines():
      r.append(IndentString('"%s"' % (ln), level + 1))
   r.append(IndentString('}\n', level))
   output.write(string.join(r))
   
def WriteTransform(matrix, level):
   output.write(IndentString('<Transform> {\n', level))
   output.write(IndentString('<Matrix4> {\n', level + 1))
   for row in matrix:
      s = " ".join([str(f) for f in row])
      output.write(IndentString(s, level + 2))
      output.write('\n')
   output.write(IndentString('}\n', level + 1))
   output.write(IndentString('}\n', level))

def WriteJoint(actor, parentEndPointIndex, level):
   if not actor.IsBodyPart(): return 
   actorName = FixName(actor.Name())
   print IndentString('processing %s' % (actorName), level)
   output.write(IndentString('<Joint> ', level))
   output.write(actorName)
   output.write(' {\n')
   origin = actor.Origin()
   endPoint = actor.EndPoint()
   parentOrigin = actor.Parent().Origin()
   parentEndPoint = actor.Parent().EndPoint()
   if actor.Name() == currentFigure.ParentActor().Name():
      WriteTransform(ID_MATRIX, level + 1)
   elif not parentEndPointIndex:
      WriteTransform(GetMatrix(origin), level + 1)
   else:
      WriteTransform(GetMatrix(VecSubtract(origin, parentOrigin)), level + 1)
   originIndex = -1
   endPointIndex = -1
   if actor.Geometry():
      # First create some geometry
      # to represent bones and joints
      boneVertexList.append(origin)
      originIndex = len(boneVertexList) - 1
      boneVertexList.append(endPoint)
      endPointIndex = len(boneVertexList) - 1
      # Main bone
      output.write(IndentString('<Line> bones {\n', level + 1))
      output.write(IndentString('// %s main bone\n' % (actorName), level + 2))
      output.write(IndentString('<Scalar> thick { 3 }\n', level + 2))
      output.write(IndentString('<VertexRef> { %d %d <Ref> { bones } }\n'%(originIndex, endPointIndex), level + 2))
      output.write(IndentString('}\n', level + 1))
      # Now we need 'connector' bones for the children.
      for child in actor.Children():
         childName = FixName(child.Name())
         boneVertexList.append(child.Origin())
         childEndPointIndex = len(boneVertexList) - 1
         output.write(IndentString('<Line> bones {\n', level + 1))
         output.write(IndentString('// %s connector bone to %s\n' % (actorName, childName), level + 2))
         output.write(IndentString('<Scalar> thick { 1 }\n', level + 2))
         output.write(IndentString('<VertexRef> { %d %d <Ref> { bones } }\n'%(endPointIndex, childEndPointIndex), level + 2))
         output.write(IndentString('}\n', level + 1))
      output.write(IndentString('<PointLight> joints {\n', level + 1))
      output.write(IndentString('// %s joint\n' % (actorName), level + 2))
      output.write(IndentString('<Scalar> thick { 5 }\n', level + 2))
      output.write(IndentString('<VertexRef> { %d <Ref> { bones } }\n' % (originIndex), level + 2))
      output.write(IndentString('}\n', level + 1))
      # Now add the mesh geometry...
      actorIndex = GetActorIndex(actor)
      geometry = actor.Geometry()
      for i in geometry.Sets():
         j = uniActorVertexInfoList[actorIndex][i]
         output.write(IndentString('<VertexRef> {\n', level + 1))
         output.write(IndentString('%d\n' %(j), level + 2))
         output.write(IndentString('<Ref> { mesh }\n', level + 2))
         output.write(IndentString('}\n', level + 1))
   if originIndex != -1:  parentEndPointIndex = endPointIndex
   for child in actor.Children(): WriteJoint(child, parentEndPointIndex, level + 1)
   output.write(IndentString('} // End Joint: ', level))
   output.write(actorName)
   output.write('\n')
      
def WriteBoneVertexPool():
   output.write('  <VertexPool> bones {\n')
   output.write('    // This is vertex data to represent\n')
   output.write('    // the rig only. It is seperate from\n')
   output.write('    // the mesh data.\n')
   for i, v in enumerate(boneVertexList):
      output.write('    <Vertex> ' + str(i) + ' {\n')
      output.write('      ' + ' '.join([str(j) for j in v]) + '\n')
      #output.write('      <RGBA> { 0 1 0.5 1 }\n')
      output.write('    }\n')
   output.write('  } // End VertexPool: bones\n')
   
def WriteMeshVertexPool():
   print 'Writing vertices ...'
   output.write('  <VertexPool> mesh {\n')
   output.write('    // This is vertex data to represent\n')
   output.write('    // the model mesh.\n')
   percentComplete = 0
   for i in range(0, numVertices):
      p = int((i / float(numVertices)) * 100)
      if not p == percentComplete:
         print '*',
         if p % 10 == 0: print p, '%'
         percentComplete = p
      v = vertices[i]
      n = normals[i]
      output.write('    <Vertex> %d { %f %f %f <Normal> { %f %f %f } }\n' % \
         (i, vertices[i].X(), vertices[i].Y(), vertices[i].Z(), 
             normals[i].X(),normals[i].Y(), normals[i].Z()))
   print '* 100 %'
   output.write('  } // End VertexPool: mesh\n')
   
def WritePolygons():
   print 'Writing Polygons ...'
   percentComplete = 0
   for i in range(0, numPolygons):
      p = int((i / float(numVertices)) * 100)
      if not p == percentComplete:
         print '*',
         if p % 10 == 0: print p, '%'
         percentComplete = p
      polygon = polygons[i]
      start = polygon.Start()
      refs = ' '.join([str(j) for j in sets[start : start + polygon.NumVertices()]])
      output.write('  <Polygon> mesh { <RGBA> { %d %d %d %d } <VertexRef> { %s <Ref> { mesh } } }\n' % \
         (1.0, 1.0, 1.0, 1.0, refs))
   print '* 100 %'
      
def WriteFigureGroup():
   """"""
   output.write('<Group> ')
   output.write(figureName)
   output.write(' {\n')
   output.write('  <Dart> { 1 }\n')
   WriteJoint(currentFigure.ParentActor(), None, 1)
   WriteBoneVertexPool()
   WriteMeshVertexPool()
   poser.Scene().ProcessSomeEvents()
   WritePolygons()
   poser.Scene().ProcessSomeEvents()
   output.write('} // End Group: ')
   output.write(figureName)
   output.write('\n')
   
############################################################
#
# Poser2Egg Script
#
############################################################
             
import os
poser.DialogSimple.MessageBox('Poser 2 Egg\n\nVersion 0.1')
currentFigure = poser.Scene().CurrentFigure()
assert currentFigure, 'No currently selected figure!'
figureName = FixName(currentFigure.Name())
abort = False
getSaveFile = poser.DialogFileChooser(2, 0, "Save Egg File" , figureName, '', '*.egg' )
getSaveFile.Show()
fileName = getSaveFile.Path()
if os.path.exists(fileName): 
   if not poser.DialogSimple.YesNo("Overwrite " + fileName + "?"):
      abort = True
if not abort:
   ikStatusList = RemoveIkChains()
   print 'Exporting character:', figureName, 'to', fileName
   try:
      output = open(fileName, 'w')
      boneVertexList = []
      uniGeometry, uniActorList, uniActorVertexInfoList = currentFigure.UnimeshInfo()
      vertices = uniGeometry.Vertices()
      numVertices = uniGeometry.NumVertices()
      normals = uniGeometry.Normals()
      numNormals = uniGeometry.NumNormals()
      polygons = uniGeometry.Polygons()
      numPolygons = uniGeometry.NumPolygons()
      sets = uniGeometry.Sets()
      output.write("<CoordinateSystem> { Y-Up-Right }\n")
      WriteComment(None, 'poser2egg - ' + figureName, 0)
      WriteFigureGroup()
   except IOError, (errno, strerror):
       print 'failed to open file', fileName, 'for writing'
       print "I/O error(%s): %s" % (errno, strerror)
   else:
      print 'finished writing data'
      output.close()
      print 'processing egg file with panda binaries...'
      os.chdir(OUTPUT_PATH)
      cmdln = \
         'echo Optimizing egg character ... && ' + \
         'egg-optchar "'+fileName+'" -inplace -keepall -TS 12 && ' + \
         'echo ""&& ' + \
         'echo Converting to bam file ... && ' + \
         'egg2bam "'+fileName+'" -o "'+fileName+'.bam" && ' + \
         'echo Opening pview ... && ' + \
         'start pview "'+fileName+'.bam" -c -l'
      if os.system(cmdln) == 1:
         print "Error while processing egg file!"
   RestoreIkChains(ikStatusList)
   print "Done."
      
      

[/code]

Thanks a lot, this will be very useful to me:D Do you think you will post the animation and morph part of the script soon?

didn’t work for Poser 7; ID_MATRIX undefined. Put the following line in middle:

ID_MATRIX = GetMatrix( [0, 0, 0] )