forked from bartvdbraak/blender
Adding MDD import and export from patch 4969 with modifications, (import and export rvks, MDD is from lightwave AFAIK)
Added Mesh .key .removeAllKeys() and .insertKey() for MDD support (was using NMesh just for keys before) Since this is aparently an experemental feature in NMesh we may want to change this.
This commit is contained in:
parent
2d11fbe192
commit
ad51edd3bf
125
release/scripts/export_mdd.py
Normal file
125
release/scripts/export_mdd.py
Normal file
@ -0,0 +1,125 @@
|
||||
#!BPY
|
||||
|
||||
"""
|
||||
Name: 'Save Mesh RVKs as MDD'
|
||||
Blender: 242
|
||||
Group: 'Animation'
|
||||
Tooltip: 'baked vertex animation fromo selected model.'
|
||||
"""
|
||||
|
||||
__author__ = "Bill L.Nieuwendorp"
|
||||
__bpydoc__ = """\
|
||||
This script Exports Lightwaves MotionDesigner format.
|
||||
|
||||
The .mdd format has become quite a popular Pipeline format<br>
|
||||
for moving animations from package to package.
|
||||
"""
|
||||
# mdd export
|
||||
#
|
||||
#
|
||||
#
|
||||
# Warning if the vertex order or vertex count differs from frame to frame
|
||||
# The script will fail because the resulting file would be an invalid mdd file.
|
||||
#
|
||||
# mdd files should only be applied to the the origonating model with the origonal vert order
|
||||
#
|
||||
#Please send any fixes,updates,bugs to Slow67_at_Gmail.com
|
||||
#Bill Niewuendorp
|
||||
|
||||
import Blender
|
||||
from Blender import *
|
||||
import BPyMessages
|
||||
try:
|
||||
from struct import pack
|
||||
except:
|
||||
pack = None
|
||||
|
||||
def mdd_export(filepath, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
|
||||
|
||||
Window.EditMode(0)
|
||||
Blender.Window.WaitCursor(1)
|
||||
mesh_orig = ob.getData(mesh=1)
|
||||
|
||||
#Flip y and z matrix
|
||||
mat_flip= Mathutils.Matrix(\
|
||||
[1,0,0,0],\
|
||||
[0,0,1,0],\
|
||||
[0,-1,0,0],\
|
||||
[0,0,0,1],\
|
||||
)
|
||||
|
||||
me_tmp = Mesh.New() # container mesh
|
||||
|
||||
numverts = len(mesh_orig.verts)
|
||||
numframes = PREF_ENDFRAME-PREF_STARTFRAME+1
|
||||
PREF_FPS= float(PREF_FPS)
|
||||
f = open(filepath, 'wb') #no Errors yet:Safe to create file
|
||||
|
||||
# Write the header
|
||||
f.write(pack(">2i", numframes-1, numverts))
|
||||
|
||||
# Write the frame times (should we use the time IPO??)
|
||||
f.write( pack(">%df" % (numframes-1), *[frame/PREF_FPS for frame in xrange(numframes-1)]) ) # seconds
|
||||
|
||||
Blender.Set('curframe', PREF_STARTFRAME)
|
||||
for frame in xrange(numframes+1):
|
||||
Blender.Set('curframe', frame)
|
||||
# Blender.Window.RedrawAll() # not needed
|
||||
me_tmp.getFromObject(ob.name)
|
||||
|
||||
if len(me_tmp.verts) != numverts:
|
||||
Blender.Draw.PupMenu('Error%t|Number of verts has changed during animation|cannot export')
|
||||
Blender.Window.WaitCursor(0)
|
||||
f.close() # should we zero?
|
||||
return
|
||||
|
||||
me_tmp.transform(ob.matrixWorld * mat_flip)
|
||||
|
||||
# Write the vertex data
|
||||
f.write(pack(">%df" % (numverts*3), *[axis for v in me_tmp.verts for axis in v.co]))
|
||||
|
||||
me_tmp.verts= None
|
||||
f.close()
|
||||
|
||||
print'MDD Exported: %s frames:%d\n'% (filepath, numframes-1)
|
||||
Blender.Window.WaitCursor(0)
|
||||
|
||||
|
||||
def mdd_export_ui(filepath):
|
||||
# Dont overwrite
|
||||
if not BPyMessages.Warning_SaveOver(filepath):
|
||||
return
|
||||
|
||||
scn= Scene.GetCurrent()
|
||||
ob_act= scn.objects.active
|
||||
if not ob_act or ob_act.type != 'Mesh':
|
||||
BPyMessages.Error_NoMeshActive()
|
||||
|
||||
ctx = scn.getRenderingContext()
|
||||
orig_frame = Blender.Get('curframe')
|
||||
PREF_STARTFRAME= Blender.Draw.Create(ctx.startFrame())
|
||||
PREF_ENDFRAME= Blender.Draw.Create(ctx.endFrame())
|
||||
PREF_FPS= Blender.Draw.Create(ctx.fps)
|
||||
|
||||
block = [\
|
||||
("Start Frame: ", PREF_STARTFRAME, 1, 30000, "Start Bake from what frame?: Default 1"),\
|
||||
("End Frame: ", PREF_ENDFRAME, 1, 30000, "End Bake on what Frame?"),\
|
||||
("FPS: ", PREF_FPS, 1, 100, "Frames per second")\
|
||||
]
|
||||
|
||||
PREF_STARTFRAME, PREF_ENDFRAME=\
|
||||
min(PREF_STARTFRAME.val, PREF_ENDFRAME.val),\
|
||||
max(PREF_STARTFRAME.val, PREF_ENDFRAME.val)
|
||||
|
||||
if not Blender.Draw.PupBlock("Export MDD", block):
|
||||
return
|
||||
|
||||
print (filepath, ob_act, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS.val)
|
||||
mdd_export(filepath, ob_act, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS.val)
|
||||
Blender.Set('curframe', orig_frame)
|
||||
|
||||
if __name__=='__main__':
|
||||
if not pack:
|
||||
Draw.PupMenu('Error%t|This script requires a full python install')
|
||||
|
||||
Blender.Window.FileSelector(mdd_export_ui, 'EXPORT MDD', sys.makename(ext='.mdd'))
|
167
release/scripts/import_mdd.py
Normal file
167
release/scripts/import_mdd.py
Normal file
@ -0,0 +1,167 @@
|
||||
#!BPY
|
||||
|
||||
#"""
|
||||
#Name: 'Load MDD to Mesh RVKs'
|
||||
#Blender: 242
|
||||
#Group: 'Animation'
|
||||
#Tooltip: 'baked vertex animation to active mesh object.'
|
||||
#"""
|
||||
__author__ = "Bill L.Nieuwendorp"
|
||||
__bpydoc__ = """\
|
||||
This script Imports Lightwaves MotionDesigner format.
|
||||
|
||||
The .mdd format has become quite a popular Pipeline format<br>
|
||||
for moving animations from package to package.
|
||||
"""
|
||||
# mdd importer
|
||||
#
|
||||
# Warning if the vertex order or vertex count differs from the
|
||||
# origonal model the mdd was Baked out from their will be Strange
|
||||
# behavior
|
||||
#
|
||||
#
|
||||
#vertex animation to ShapeKeys with ipo and gives the frame a value of 1.0
|
||||
#A modifier to read mdd files would be Ideal but thats for another day :)
|
||||
#
|
||||
#Please send any fixes,updates,bugs to Slow67_at_Gmail.com
|
||||
#Bill Niewuendorp
|
||||
|
||||
try:
|
||||
import struct
|
||||
except:
|
||||
struct= None
|
||||
|
||||
import Blender
|
||||
from Blender import Mesh, Object, Scene
|
||||
import BPyMessages
|
||||
|
||||
def mdd_import(filepath, ob, PREF_IPONAME, PREF_START_FRAME, PREF_JUMP):
|
||||
|
||||
print '\n\nimporting mdd "%s"' % filepath
|
||||
|
||||
Blender.Window.DrawProgressBar (0.0, "Importing mdd ...")
|
||||
Blender.Window.EditMode(0)
|
||||
Blender.Window.WaitCursor(1)
|
||||
|
||||
file = open(filepath, 'rb')
|
||||
toUnpack = file.read(8)
|
||||
frames, points = struct.unpack(">2i",toUnpack)
|
||||
floatBytes = frames * 4
|
||||
furtherUnpack = file.read(floatBytes)
|
||||
floatBytes2 = points * 12
|
||||
floatBytes3 = 12 * points * frames
|
||||
restsize = points * 3
|
||||
pfsize = points * frames * 3
|
||||
restPoseUnpack = file.read(floatBytes2)
|
||||
PerFrameUnpack = file.read(floatBytes3)
|
||||
pattern = ">%df" % frames
|
||||
pattern2 = ">%df" % restsize
|
||||
pattern3 = ">%df" % pfsize
|
||||
time = struct.unpack(pattern, furtherUnpack)
|
||||
rest_pose = struct.unpack(pattern2, restPoseUnpack)
|
||||
PerFramexyz = struct.unpack(pattern3, PerFrameUnpack)
|
||||
|
||||
print '\tpoints:%d frames:%d' % (points,frames)
|
||||
|
||||
scn = Scene.GetCurrent()
|
||||
ctx = scn.getRenderingContext()
|
||||
#ctx.startFrame(PREF_START_FRAME)
|
||||
#ctx.endFrame(PREF_START_FRAME+frames)
|
||||
Blender.Set("curframe", PREF_START_FRAME)
|
||||
me = ob.getData(mesh=1)
|
||||
xyzs = PerFramexyz
|
||||
Point_list = []
|
||||
for i in xrange(len(xyzs)/3):
|
||||
xpos, zpos = i*3, (i*3)+3
|
||||
Point_list.append(xyzs[xpos:zpos])
|
||||
Frm_points = []
|
||||
Blender.Window.DrawProgressBar (0.2, "3 Importing mdd ...")
|
||||
for i in xrange(len(Point_list)):
|
||||
first, last = i*points, (i*points)+points
|
||||
Frm_points.append(Point_list[first:last])
|
||||
|
||||
|
||||
def UpdateMesh(me,fr):
|
||||
for vidx, v in enumerate(me.verts):
|
||||
v.co[:] = Frm_points[fr][vidx][0], Frm_points[fr][vidx][2], Frm_points[fr][vidx][1]
|
||||
me.update()
|
||||
|
||||
Blender.Window.DrawProgressBar (0.4, "4 Importing mdd ...")
|
||||
|
||||
|
||||
curfr = ctx.currentFrame()
|
||||
print'\twriting mdd data...'
|
||||
for i in xrange(frames):
|
||||
Blender.Set("curframe", i+PREF_START_FRAME)
|
||||
if len(me.verts) > 1 and (curfr >= PREF_START_FRAME) and (curfr <= PREF_START_FRAME+frames):
|
||||
UpdateMesh(me, i)
|
||||
ob.insertShapeKey()
|
||||
ob.makeDisplayList()
|
||||
Blender.Window.RedrawAll()
|
||||
|
||||
Blender.Window.DrawProgressBar (0.5, "5 Importing mdd ...")
|
||||
|
||||
key= me.key
|
||||
|
||||
# Add the key of its not there
|
||||
if not key:
|
||||
me.insertKey(1, 'relative')
|
||||
key= me.key
|
||||
|
||||
key.ipo = Blender.Ipo.New("Key", PREF_IPONAME)
|
||||
ipo = key.ipo
|
||||
block = key.getBlocks()
|
||||
all_keys = ipo.curveConsts
|
||||
|
||||
for i in xrange(PREF_JUMP, len(all_keys), PREF_JUMP):
|
||||
curve = ipo.getCurve(i)
|
||||
if curve == None:
|
||||
ipo.addCurve(all_keys[i])
|
||||
|
||||
Blender.Window.DrawProgressBar (0.8, "appending to ipos")
|
||||
for i in xrange(PREF_JUMP, len(all_keys), PREF_JUMP):# Key Reduction
|
||||
mkpoints = ipo.getCurve(i)
|
||||
mkpoints.append((1+PREF_START_FRAME+i-1,1))
|
||||
mkpoints.append((1+PREF_START_FRAME+i- PREF_JUMP -1,0))
|
||||
mkpoints.append((1+PREF_START_FRAME+i+ PREF_JUMP-1,0))
|
||||
mkpoints.setInterpolation('Linear')
|
||||
mkpoints.recalc()
|
||||
|
||||
print 'done'
|
||||
Blender.Window.WaitCursor(0)
|
||||
Blender.Window.DrawProgressBar (1.0, '')
|
||||
|
||||
|
||||
def mdd_import_ui(filepath):
|
||||
|
||||
if BPyMessages.Error_NoFile(filepath):
|
||||
return
|
||||
|
||||
scn= Scene.GetCurrent()
|
||||
ob_act= scn.objects.active
|
||||
|
||||
if ob_act == None or ob_act.type != 'Mesh':
|
||||
BPyMessages.Error_NoMeshActive()
|
||||
return
|
||||
|
||||
PREF_IPONAME = Blender.Draw.Create(filepath.split('/')[-1].split('\\')[-1].split('.')[0])
|
||||
PREF_START_FRAME = Blender.Draw.Create(1)
|
||||
PREF_JUMP = Blender.Draw.Create(1)
|
||||
|
||||
block = [\
|
||||
("Ipo Name: ", PREF_IPONAME, 0, 30, "Ipo name for the new shape key"),\
|
||||
("Start Frame: ", PREF_START_FRAME, 1, 3000, "Start frame for the animation"),\
|
||||
("Key Skip: ", PREF_JUMP, 1, 100, "KeyReduction, Skip every Nth Frame")\
|
||||
]
|
||||
|
||||
if not Blender.Draw.PupBlock("Import MDD", block):
|
||||
return
|
||||
orig_frame = Blender.Get('curframe')
|
||||
mdd_import(filepath, ob_act, PREF_IPONAME.val, PREF_START_FRAME.val, PREF_JUMP.val)
|
||||
Blender.Set('curframe', orig_frame)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not struct:
|
||||
Draw.PupMenu('Error%t|This script requires a full python install')
|
||||
|
||||
Blender.Window.FileSelector(mdd_import_ui, 'IMPORT MDD', '*.mdd')
|
@ -49,6 +49,7 @@
|
||||
|
||||
#include "BIF_editdeform.h"
|
||||
#include "BIF_editkey.h" /* insert_meshkey */
|
||||
#include "BIF_space.h" /* REMAKEIPO - insert_meshkey */
|
||||
#include "BIF_editview.h"
|
||||
#include "BIF_editmesh.h"
|
||||
#include "BIF_meshtools.h"
|
||||
@ -6324,6 +6325,54 @@ static PyObject *Mesh_getVertexInfluences( BPy_Mesh * self, PyObject * args )
|
||||
return influence_list;
|
||||
}
|
||||
|
||||
static PyObject *Mesh_removeAllKeys( BPy_Mesh * self )
|
||||
{
|
||||
Mesh *mesh = self->mesh;
|
||||
|
||||
if( !mesh || !mesh->key )
|
||||
Py_RETURN_FALSE;
|
||||
|
||||
mesh->key->id.us--;
|
||||
mesh->key = NULL;
|
||||
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *Mesh_insertKey( BPy_Mesh * self, PyObject * args )
|
||||
{
|
||||
Mesh *mesh = self->mesh;
|
||||
int fra = -1, oldfra = -1;
|
||||
char *type = NULL;
|
||||
short typenum;
|
||||
|
||||
if( !PyArg_ParseTuple( args, "|is", &fra, &type ) )
|
||||
return EXPP_ReturnPyObjError( PyExc_TypeError,
|
||||
"expected nothing or an int and optionally a string as arguments" );
|
||||
|
||||
if( !type || !strcmp( type, "relative" ) )
|
||||
typenum = 1;
|
||||
else if( !strcmp( type, "absolute" ) )
|
||||
typenum = 2;
|
||||
else
|
||||
return EXPP_ReturnPyObjError( PyExc_AttributeError,
|
||||
"if given, type should be 'relative' or 'absolute'" );
|
||||
|
||||
if( fra > 0 ) {
|
||||
fra = EXPP_ClampInt( fra, 1, MAXFRAME );
|
||||
oldfra = G.scene->r.cfra;
|
||||
G.scene->r.cfra = fra;
|
||||
}
|
||||
|
||||
insert_meshkey( mesh, typenum );
|
||||
allspace(REMAKEIPO, 0);
|
||||
|
||||
if( fra > 0 )
|
||||
G.scene->r.cfra = oldfra;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *Mesh_Tools( BPy_Mesh * self, int type, void **args )
|
||||
{
|
||||
Base *base;
|
||||
@ -6584,7 +6633,11 @@ static struct PyMethodDef BPy_Mesh_methods[] = {
|
||||
"Get names of vertex groups"},
|
||||
{"getVertexInfluences", (PyCFunction)Mesh_getVertexInfluences, METH_VARARGS,
|
||||
"Get list of the influences of bones for a given mesh vertex"},
|
||||
|
||||
/* Shape Keys */
|
||||
{"removeAllKeys", (PyCFunction)Mesh_removeAllKeys, METH_NOARGS,
|
||||
"Remove all the shape keys from a mesh"},
|
||||
{"insertKey", (PyCFunction)Mesh_insertKey, METH_VARARGS,
|
||||
"(frame = None, type = 'relative') - inserts a Mesh key at the given frame"},
|
||||
/* Mesh tools */
|
||||
{"smooth", (PyCFunction)Mesh_smooth, METH_NOARGS,
|
||||
"Flattens angle of selected faces (experimental)"},
|
||||
@ -7015,6 +7068,15 @@ static int Mesh_setMode( BPy_Mesh *self, PyObject *value )
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *Mesh_getKey( BPy_Mesh * self )
|
||||
{
|
||||
if( self->mesh->key )
|
||||
return Key_CreatePyObject(self->mesh->key);
|
||||
else
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *Mesh_getActiveFace( BPy_Mesh * self )
|
||||
{
|
||||
TFace *face;
|
||||
@ -7273,6 +7335,10 @@ static PyGetSetDef BPy_Mesh_getseters[] = {
|
||||
(getter)Mesh_getMode, (setter)Mesh_setMode,
|
||||
"The mesh's mode bitfield",
|
||||
NULL},
|
||||
{"key",
|
||||
(getter)Mesh_getKey, (setter)NULL,
|
||||
"The mesh's key",
|
||||
NULL},
|
||||
{"faceUV",
|
||||
(getter)Mesh_getFlag, (setter)Mesh_setFlag,
|
||||
"UV-mapped textured faces enabled",
|
||||
|
@ -961,6 +961,31 @@ class Mesh:
|
||||
and weight is a float value.
|
||||
"""
|
||||
|
||||
def removeAllKeys():
|
||||
"""
|
||||
Remove all mesh keys stored in this mesh.
|
||||
@rtype: bool
|
||||
@return: True if successful or False if the Mesh has no keys.
|
||||
"""
|
||||
|
||||
def insertKey(frame = None, type = 'relative'):
|
||||
"""
|
||||
Insert a mesh key at the given frame.
|
||||
@type frame: int
|
||||
@type type: string
|
||||
@param frame: The Scene frame where the mesh key should be inserted. If
|
||||
None or the arg is not given, the current frame is used.
|
||||
@param type: The mesh key type: 'relative' or 'absolute'. This is only
|
||||
relevant on meshes with no keys.
|
||||
@warn: This and L{removeAllKeys} were included in this release only to
|
||||
make accessing vertex keys possible, but may not be a proper solution
|
||||
and may be substituted by something better later. For example, it
|
||||
seems that 'frame' should be kept in the range [1, 100]
|
||||
(the curves can be manually tweaked in the Ipo Curve Editor window in
|
||||
Blender itself later).
|
||||
"""
|
||||
|
||||
|
||||
def smooth():
|
||||
"""
|
||||
Flattens angle of selected faces. Experimental mesh tool.
|
||||
|
Loading…
Reference in New Issue
Block a user