Snippets
Created by
John Martini
last modified
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | #!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'))
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | 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)
You can clone a snippet to your computer for local editing. Learn more.