Snippets

John Martini pc2 Exporters

Created by John Martini last modified
#!BPY

"""
Name: 'Point Cache 2 (.pc2)...'
Blender: 243
Group: 'Export'
Tooltip: 'Export animated object to Point Cache 2 format'
"""

__author__ = "Matt Ebb"
__url__ = ['mke3.net', 'blenderartists.org']
__version__ = "1.0"

__bpydoc__ = """\
This script exports to The Point Cache 2 file format.

Usage:

Choosing "Point Cache 2 (.pc2)" in the File->Export menu will export the active object to
an animated point sequence.

The Point Cache format just contains vertex positions, so to bring your animated mesh into 
another application, such as 3DS Max, you will also need to export the mesh itself in another 
format such as OBJ.

For use in Max, import the OBJ into Max with the standard File->Import, then add a Point Cache modifier,
click 'Load', and open the point cache file.

All objects that can be represented as a mesh (mesh, curve, metaball, surface, text)
will be exported as mesh data.
"""


# --------------------------------------------------------------------------
# PC2 Export v1.0 by Matt Ebb
# Thanks to Rangi Sutton for PC2 Python code snippets
# and Campbell Barton who's OBJ exporter was used as reference for much
# of this script
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------

import Blender, struct
from Blender import *
from Blender.Scene import Render
import BPyMesh
import BPyObject
import BPyMessages

def export_pc2(filename, ob, scn, \
EXPORT_WORLDSPACE, EXPORT_ROTX90, EXPORT_STARTFRAME, \
EXPORT_ENDFRAME, EXPORT_SAMPLERATE):

	temp_mesh_name = '~tmp-mesh'
	# Get the container mesh to copy the mesh's vertex positions to
	containerMesh = meshName = tempMesh = None
	for meshName in Blender.NMesh.GetNames():
		if meshName.startswith(temp_mesh_name):
			tempMesh = Mesh.Get(meshName)
			if not tempMesh.users:
				containerMesh = tempMesh
	if not containerMesh:
		containerMesh = Mesh.New(temp_mesh_name)
	
	if EXPORT_ROTX90:
		mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x')
		
	del meshName
	del tempMesh
	
	me= BPyMesh.getMeshFromObject(ob, containerMesh, True, False, scn)

	numPoints = len(me.verts)
	startFrame = float(EXPORT_STARTFRAME)
	numSamples = float(EXPORT_ENDFRAME - EXPORT_STARTFRAME)
	sampleRate = float(EXPORT_SAMPLERATE)
	
	# .pc2 files have a header defined as such:

	# char    cacheSignature[12];   // Will be 'POINTCACHE2' followed by a trailing null character.
	# int     fileVersion;          // Currently 1
	# int     numPoints;            // Number of points per sample
	# float   startFrame;           // Corresponds to the UI value of the same name.
	# float   sampleRate;           // Corresponds to the UI value of the same name.
	# int     numSamples;           // Defines how many samples are stored in the fi

	# Create the header
	headerFormat='<12ciiffi'
	headerStr = struct.pack(headerFormat, 'P','O','I','N','T','C','A','C','H','E','2','\0', 1, numPoints, startFrame, sampleRate, numSamples)

	file = open(filename, "wb")
	file.write(headerStr)

	for frame in range(startFrame, startFrame+numSamples, sampleRate):
	
		Blender.Set('curframe', frame)
		me= BPyMesh.getMeshFromObject(ob, containerMesh, True, False, scn)
		
		if EXPORT_WORLDSPACE:
			me.transform(ob.matrixWorld)
		
		if EXPORT_ROTX90:
			me.transform(mat_xrot90)
	
		for v in me.verts:
			thisVertex = struct.pack('<fff', float(v.co[0]), float(v.co[1]), float(v.co[2]))
			file.write(thisVertex)
		
			
	file.flush()
	file.close()

def write_ui(filename):
	
	if not filename.lower().endswith('.pc2'):
		filename += '.pc2'
	
	if not BPyMessages.Warning_SaveOver(filename):
		return
	
	scn = Scene.GetCurrent()
	ren = scn.getRenderingContext()
	ob = scn.objects.active
	
	if not ob: ob = scn.objects.context[0]
	if not ob: return
	
	EXPORT_WORLDSPACE = Draw.Create(0)
	EXPORT_ROTX90 = Draw.Create(0)
	EXPORT_STARTFRAME = Draw.Create(ren.sFrame)
	EXPORT_ENDFRAME = Draw.Create(ren.eFrame)
	EXPORT_SAMPLERATE = Draw.Create(1)
	
	# Get USER Options
	pup_block = [\
	('World Space', EXPORT_WORLDSPACE, 'Use this if you have moving object (centers), rather than just a deforming object.'),\
	('Rotate X90', EXPORT_ROTX90 , 'Rotate on export so Blenders Z axis up is translated into Y axis up'),\
	('Start: ', EXPORT_STARTFRAME, -300000, 300000, 'Start frame of animation to export'),\
	('End: ', EXPORT_ENDFRAME, -300000, 300000, 'End frame of animation to export'),\
	('Sample Rate: ', EXPORT_SAMPLERATE, 1, 10000, 'How frequently to sample (or skip) the frames. Only integers are supported'),\
	]
	
	if not Draw.PupBlock('Export...', pup_block):
		return
		
	Window.EditMode(0)
	Window.WaitCursor(1)
	
	EXPORT_WORLDSPACE = EXPORT_WORLDSPACE.val
	EXPORT_ROTX90 = EXPORT_ROTX90.val
	EXPORT_STARTFRAME = EXPORT_STARTFRAME.val
	EXPORT_ENDFRAME = EXPORT_ENDFRAME.val
	EXPORT_SAMPLERATE = EXPORT_SAMPLERATE.val
	
	export_pc2(filename, ob, scn, EXPORT_WORLDSPACE, EXPORT_ROTX90, EXPORT_STARTFRAME, EXPORT_ENDFRAME, EXPORT_SAMPLERATE)

	Window.WaitCursor(0)
	
if __name__ == '__main__':
	Window.FileSelector(write_ui, 'Export Point Cache 2', sys.makename(ext='.pc2'))
import maya.cmds as cmds
import struct
import time
import tempfile
import shutil
import os
import math

"""
def getfileLimit():
    count = 0
    try:
        fileDict = {}
        for a in range(900):
            fileDict[a] = open('C:/debug/rrrr'+str(a)+'.txt', "wb")
            count+=1

    except:
         return count

"""
def chunks(l, n):
    if n < 1:
        n = 1
    return [l[i:i + n] for i in range(0, len(l), n)]
	
def frange(x, y, jump,):
    ar =[]
    while x < y:
        ar.append(x)
        x += jump
    return ar


def getShapeVertCount(shapeList):
    count = 0
    for s in shapeList:
      #  print 'before p-eval' ,s 
        count += len(cmds.ls(s+'.vtx[*]',fl=True))  ###cmds.polyEvaluate(s,v=True)
      #  print 'after p-eval',s
    return count
    
def writePC2File(filename, shape, world=True, zUp=False, startF=0, endF=100, samplesPerFrame=1):
    if type(shape) != list: #-- this way shape can be a single shape or a list of shapes..
        shape = [shape]
    
    print "PC2start caching shape ",shape
    ''' 
    bench mark notes
    startF=1000 endF=1201 sampleRate=1.0 pnts=322174 shape=veh_zetros_1:mesh_M_strapsShape time 7.5833 minutes..
    startF=1000 endF=1201 sampleRate=1.0 pnts=75574 shape=veh_zetros_1:mesh_M_strapHooksShape time 1.75 minutes
    startF=1000 endF=1201 sampleRate=1.0 pnts=89726 shape=veh_zetros_1:mesh_L_strapRingsShape time 2.10 minutes
    '''
    st = time.time()
    if samplesPerFrame == 0:samplesPerFrame = 1
    sampleRate = 1.0/(samplesPerFrame)
    numPoints = getShapeVertCount(shape) #cmds.polyEvaluate(shape,v=True)#len(me.verts)
    totalFrames = endF - startF
    timeRange = frange(startF, startF+totalFrames+sampleRate, sampleRate)
    numSamples = len(timeRange)
    
    headerFormat='<12ciiffi'
    headerStr = struct.pack(headerFormat, 'P','O','I','N','T','C','A','C','H','E','2','\0', 1, numPoints, startF, sampleRate, numSamples)
    tmpFpn = tempfile.gettempdir() + "\\tempMayaPC2.pc2"
    
    file = open(tmpFpn, "wb")
    file.write(headerStr)
    #---loop through time..
    sampleFrames = [] #--generate sample frames...
    vertDumpFormat = '<'
    for i in range(numPoints):vertDumpFormat += 'f'
    print "startF=%s endF=%s sampleRate=%s pnts=%s shape=%s " % (startF, startF+numSamples, sampleRate,numPoints,shape)
    
    cmds.refresh(su=True)
    for i in timeRange:
        cmds.currentTime(i)
        #--method 1
        
        for s in shape:
            mesh = cmds.xform(s+'.vtx[*]', q=True, ws=True, t=True)
            for m in mesh:
                f = struct.pack('<f', m)
                file.write(f)

    
    cmds.refresh(su=False)
    #--copy it over to the network location...
    print "moving file ",file.name," to ",filename
    if os.path.exists(filename):os.remove(filename)
    cST = time.time()
    shutil.copy2(file.name, filename)
    if not (os.path.exists(filename)):
       print 'pc2 error:Warning failed to make pc2 files for ',shape
       return False
    cET = time.time()
    print "total time to copy file to source dest was ",(cET-cST)," seconds.."
    
    file.flush()
    file.close()
    print filename," was sucessfully written out"
    
    en = time.time()
    print "total time to write cache was ", (en-st)," seconds"
    return True


class PC2(object):
    def __init__(self,filename = None,shape =None,startF =None,endF =None,numSamples =None,samplesPerFrame =None):
        self.filename = filename
        self.shape = shape
        self.startF = startF
        self.numSamples = numSamples
        self.samplesPerFrame = samplesPerFrame
        self.sampleRate = 1.0/self.samplesPerFrame
       # print 'set', shape, 'variables'
        self.numPoints = getShapeVertCount([shape]) #cmds.polyEvaluate(shape,v=True)#len(me.verts)
      #  print 'set', shape, 'num points'
        totalFrames = endF - startF
        timeRange = frange(startF, startF+totalFrames+self.sampleRate, self.sampleRate)
        numSamples = len(timeRange)
        
        headerFormat= '<12ciiffi'
        headerStr = struct.pack(headerFormat, 'P','O','I','N','T','C','A','C','H','E','2','\0', 1, self.numPoints, self.startF, self.sampleRate, self.numSamples)
     #   print  shape, 'struct packed'
        self.tmpFpn = tempfile.gettempdir() + "\\"+self.shape+"_tempMayaPC2.pc2"   
    #    print  shape, 'temp dire decided'		
        self.fileObject = open(self.tmpFpn, "wb")
     #   print  shape, 'file object opened'		
        self.fileObject.write(headerStr)
      #  print  shape, 'header written'	
        #---loop through time..

    
def writePC2FilesSingleScrub(masterfilenameList, mastershapeList, world=True, zUp=False, startF=0, endF=100, samplesPerFrame=1):
    if type(mastershapeList) != list: #-- this way shape can be a single shape or a list of shapes..
        mastershapeList = [mastershapeList]
        masterfilenameList = [masterfilenameList]
		
		
	############ seperating list into sets of 300 toa void hitting os ulimit @@@@@@@@@@	
    brokenshapeList = chunks(mastershapeList,300)
    brokenfilenameList = chunks(masterfilenameList,300)
	
    print "Breaking geo list into",len(brokenshapeList),"timeline scrubs"

    st = time.time()	
    print "clock started"
    for listNum in range(len(brokenshapeList)):
		################### settign current sub list ##################
        shapeList = brokenshapeList[listNum]
        filenameList = brokenfilenameList[listNum]
		
        print "PC2start caching shapes ",shapeList


        if samplesPerFrame == 0:samplesPerFrame = 1
        totalFrames = endF - startF
        sampleRate = 1.0/(samplesPerFrame)
        timeRange = frange(startF, startF+totalFrames+sampleRate, sampleRate)
        print "timerange set "
		
        PC2Dict = {}

        for num in range(len(shapeList)):
           # print 'adding pc2' , shapeList[num], num
            PC2Dict[shapeList[num]] = PC2(filename = filenameList[num],shape =shapeList[num],startF =startF,endF=endF,numSamples = len(timeRange),samplesPerFrame =samplesPerFrame )

        print 'dict created'
        cmds.refresh(su=True)
        print 'refreshed'
        for i in timeRange:
          #  print 'setting time'
            cmds.currentTime(i)
            #--method 1
           # print 'time set'
            for s in shapeList:
               # print 'recording', s
                mesh = cmds.xform(s+'.vtx[*]', q=True, ws=True, t=True)
                for m in mesh:
                    f = struct.pack('<f', m)
                    PC2Dict[s].fileObject.write(f)

        cmds.refresh(su=False)
        #--copy it over to the network location...
        cST = time.time()
        for shape in shapeList:
		
            PC2Dict[shape].fileObject.flush()
            PC2Dict[shape].fileObject.close()
            print PC2Dict[shape].filename," was sucessfully written out"
			
            print "moving file ",PC2Dict[shape].fileObject.name," to ",PC2Dict[shape].filename
            if os.path.exists(PC2Dict[shape].filename):os.remove(PC2Dict[shape].filename)
			
            shutil.copy2(PC2Dict[shape].fileObject.name, PC2Dict[shape].filename)
            if not (os.path.exists(PC2Dict[shape].filename)):
                 print 'pc2 error:Warning failed to make pc2 files for ',shape
                 return False

        cET = time.time()
        print "total time to copy all file to source dest was ",(cET-cST)," seconds.."

    en = time.time()
    print "total time to write cache was ", (en-st)," seconds"
    return True

if __name__ == '__main__':    
    #example    
    out = r"C:\Users\carlos.anguianao\Desktop\testMaya\test2.pc2"
    shp = cmds.listRelatives(shapes=True)
    writePC2File(out,shp[0],startF=1000,endF=1005)

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.