The orange -> HEAD merge reverted some scripts to older versions. This only
affected the ones that already existed before the orange branch.
Minor issue, easy to fix.

All in all, kudos to kaito, Hos and others for all the hard work in
bringing (coding, merging) all these changes to the main branch.
This commit is contained in:
2006-01-29 19:17:53 +00:00
parent 282fbcc763
commit 4b01aa7aa5
37 changed files with 4234 additions and 2835 deletions

View File

@@ -54,49 +54,55 @@ directly manipulate or export its data.
#
# ***** END GPL LICENCE BLOCK *****
import Blender
Blender.Window.EditMode(0)
NAME_LENGTH = 19
PREFIX = "_def"
PREFIX_LENGTH = len(PREFIX)
ob_list = Blender.Object.GetSelected()
for ob in ob_list:
ob.sel = 0
used_names = [ob.name for ob in Blender.Object.Get()]
used_names.extend(Blender.NMesh.GetNames())
deformedList = []
for ob in ob_list:
if ob.getType() == "Mesh":
name = ob.getName()
new_name = name + "_deformed"
new_name = "%s_def" % name[:NAME_LENGTH-PREFIX_LENGTH]
num = 0
new_mesh = Blender.NMesh.GetRawFromObject(name)
mesh = Blender.NMesh.GetRaw(new_name)
while mesh:
while new_name in used_names:
new_name = "%s_def.%.3i" % (name[:NAME_LENGTH-(PREFIX_LENGTH+PREFIX_LENGTH)], num)
num += 1
new_name = name + "_deformed." + "%03i" % num
mesh = Blender.NMesh.GetRaw(new_name)
used_names.append(new_name)
new_ob = Blender.NMesh.PutRaw(new_mesh, new_name)
new_ob.setMatrix(ob.getMatrix())
try:
new_ob = Blender.Object.Get(new_name)
while 1:
num += 1
new_name = name + "_deformed." + "%03i" % num
new_ob = Blender.Object.Get(new_name)
except:
pass
new_ob.setName(new_name)
deformedList.append(new_ob)
# Vert groups.
ob_mesh = ob.getData()
new_ob_mesh = new_ob.getData()
# If SubSurf is off on the original, copy the vertex weight
if not ob_mesh.getMode() & Blender.NMesh.Modes['SUBSURF']:
for vgroupname in ob_mesh.getVertGroupNames():
for vgroupname in ob_mesh.getVertGroupNames():
new_ob_mesh.addVertGroup(vgroupname)
if len(ob_mesh.verts) == len(new_ob_mesh.verts):
vlist = ob_mesh.getVertsFromGroup(vgroupname, True)
new_ob_mesh.addVertGroup(vgroupname)
for vpair in vlist:
new_ob_mesh.assignVertsToGroup(vgroupname, [vpair[0]], vpair[1], 'add')
# If it's on, just add the vertex groups
else:
for vgroupname in ob_mesh.getVertGroupNames():
new_ob_mesh.addVertGroup(vgroupname)
try:
for vpair in vlist:
new_ob_mesh.assignVertsToGroup(vgroupname, [vpair[0]], vpair[1], 'add')
except:
pass
new_ob_mesh.update()
Blender.Window.EditMode(1)
for ob in deformedList:
ob.sel = 1
deformedList[0].sel = 1 # Keep the same object active.

View File

@@ -2,7 +2,7 @@
""" Registration info for Blender menus: <- these words are ignored
Name: 'Axis Orientation Copy'
Blender: 233
Blender: 239
Group: 'Object'
Tip: 'Copy the axis orientation of the active object to all selected mesh objects'
"""
@@ -10,7 +10,7 @@ Tip: 'Copy the axis orientation of the active object to all selected mesh object
__author__ = "A Vanpoucke (xand)"
__url__ = ("blender", "elysiun",
"French Blender support forum, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
__version__ = "1.1 11/05/04"
__version__ = "2 17/12/05"
__bpydoc__ = """\
This script copies the axis orientation -- X, Y and Z rotations -- of the
@@ -75,7 +75,7 @@ from Blender.Mathutils import *
def applyTransform(mesh,mat):
for v in mesh.verts:
vec = VecMultMat(v.co,mat)
vec = v.co*mat
v.co[0], v.co[1], v.co[2] = vec[0], vec[1], vec[2]
@@ -87,13 +87,13 @@ lenob=len(oblist)
error = 0
for o in oblist[1:]:
if o.getType() != "Mesh":
Draw.PupMenu("ERROR%t|Selected objects must be meshes")
Draw.PupMenu("Error: selected objects must be meshes")
error = 1
if not error:
if lenob<2:
Draw.PupMenu("ERROR%t|You must select at least 2 objects")
else :
Draw.PupMenu("Error: you must select at least 2 objects")
else :
source=oblist[0]
nsource=source.name
texte="Copy axis orientation from: " + nsource + " ?%t|OK"
@@ -102,9 +102,9 @@ if not error:
for cible in oblist[1:]:
if source.rot!=cible.rot:
rotcible=cible.mat.toEuler().toMatrix()
rotsource=source.mat.toEuler().toMatrix()
rotsourcet = CopyMat(rotsource)
rotcible=cible.mat.rotationPart().toEuler().toMatrix()
rotsource=source.mat.rotationPart().toEuler().toMatrix()
rotsourcet = Matrix(rotsource)
rotsourcet.invert()
mat=rotcible*rotsourcet
ncible=cible.name

View File

@@ -1,17 +1,16 @@
#!BPY
""" Registration info for Blender menus:
Name: 'DirectX8(.x)...'
Blender: 239
Name: 'DirectX(.x)...'
Blender: 240
Group: 'Export'
Submenu: 'Export all the scene' export
Submenu: 'Export selected obj' exportsel
Tip: 'Export to DirectX8 text file format format.'
Tip: 'Export to DirectX text file format format.'
"""
__author__ = "Arben (Ben) Omari"
__url__ = ("blender", "elysiun", "Author's site, http://www.omariben.too.it")
__version__ = "1.0"
__version__ = "2.0"
__bpydoc__ = """\
This script exports a Blender mesh with armature to DirectX 8's text file
@@ -21,8 +20,8 @@ Notes:<br>
Check author's site or the elYsiun forum for a new beta version of the
DX exporter.
"""
# DirectX8Exporter.py version 1.0
# Copyright (C) 2003 Arben OMARI -- omariarben@everyday.com
# DirectXExporter.py version 2.0
# Copyright (C) 2006 Arben OMARI -- omariarben@everyday.com
#
# 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
@@ -42,10 +41,17 @@ DX exporter.
import Blender
from Blender import Types, Object, NMesh, Material,Armature
from Blender.Mathutils import *
import math
global new_bon,mat_flip,index_list
global mat_flip,index_list,space,bone_list,mat_dict
bone_list =[]
index_list = []
new_bon = {}
mat_dict = {}
space = 0
ANIM = 1
NORMAL = 1
TEXCOORDS = 1
TEXTURE = 1
mat_flip = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1])
@@ -64,6 +70,7 @@ class xExport:
#Select Scene objects
#***********************************************
def SelectObjs(self):
global chld_obj
print "exporting..."
self.writeHeader()
for obj in Object.Get():
@@ -154,115 +161,117 @@ class xExport:
#Export Root Bone
#***********************************************
def writeRootBone(self,am_ob,child_obj):
global new_bon,mat_flip
space = 0
arm = am_ob.getData()
Blender.Set('curframe',1)
mat_ob = mat_flip * am_ob.matrixWorld
self.writeArmFrames(mat_ob, "RootFrame", 0)
root_bon = arm.getBones()
mat_r = self.writeCombineMatrix(root_bon[0])
name_r = root_bon[0].getName()
new_bon[name_r] = len(root_bon[0].getChildren())
self.writeArmFrames(mat_r, name_r, 1)
self.writeListOfChildrens(root_bon[0],2,arm)
self.file.write("}\n")
self.exportMeshArm(arm,am_ob,child_obj)
#***********************************************
#Export Children Bones
#***********************************************
def writeListOfChildrens(self,bon,space,arm):
global new_bon
bon_c = bon.getChildren()
Blender.Set('curframe',1)
for n in range(len(bon_c)):
name_h = bon_c[n].getName()
chi_h = bon_c[n].getChildren()
new_bon[name_h] = len(chi_h)
if bon_c == [] :
self.CloseBrackets(bon, new_bon, space, arm.getBones()[0])
for nch in range(len(bon_c)):
mat = self.writeCombineMatrix(bon_c[nch])
name_ch = bon_c[nch].getName()
self.writeArmFrames(mat, name_ch,space)
self.findChildrens(bon_c[nch],space,arm)
global mat_flip,space,root_bon,mat_ob
arms = am_ob.getData()
self.writeArmFrames(mat_flip, "RootFrame")
for bon in arms.bones.values():
if bon.hasParent():
pass
else:
root_bon = bon
space += 1
mat_rb = self.writeCombineMatrix(root_bon)
mat_r = mat_rb #* am_ob.matrixLocal
name_r = root_bon.name
name_f = name_r.replace(".","")
self.writeArmFrames(mat_r, name_f)
bon_c = self.findChildrens(root_bon)
self.writeChildren(bon_c)
self.file.write(" }\n")
self.exportMeshArm(arms,am_ob,child_obj)
#***********************************************
#Create Children structure
#***********************************************
def CloseBrackets(self, bon, new_bon, space, root_bon):
def writeBon(self,bon):
global space
mat_r = self.writeCombineMatrix(bon)
name_r = bon.name
name_f = name_r.replace(".","")
self.writeArmFrames(mat_r, name_f)
def findChildrens(self,bon):
bon_c = bon.children
return bon_c
def writeChildren(self,bon_c):
global space,bone_list
space += 1
if bon_c:
for bo in bon_c:
if bo.name not in bone_list:
self.writeBon(bo)
bone_list.append(bo.name)
bo_c = bo.children
self.writeChildren(bo_c)
self.closeBrackets()
def closeBrackets(self):
global space
space = space-1
tab = " "
self.file.write("%s" % (tab * (space -1)))
self.file.write("%s" % (tab * space))
self.file.write("}\n")
while bon.hasParent():
if new_bon[bon.getName()] == 0:
pare = bon.getParent()
name_p = pare.getName()
if new_bon[name_p] > 0:
new_bon[name_p] = new_bon[name_p] - 1
if new_bon[name_p] == 0 and pare != root_bon:
self.file.write("%s" % (tab * (space-2)))
self.file.write("}\n")
space = space - 1
bon = pare
else:
break
#***********************************************
#Create Children structure
#***********************************************
def findChildrens(self,bon_c,space,arm):
bon_cc = bon_c
space += 1
self.writeListOfChildrens(bon_cc,space,arm)
#***********************************************
#Offset Matrix
#***********************************************
def writeMatrixOffset(self,bon):
Blender.Set('curframe',1)
mat_b = bon.getRestMatrix()
mat_b.invert()
global chld_obj
Blender.Set('curframe', 1)
pose = chld_obj.getPose()
pos_b = pose.bones[bon.name]
mat_b = pos_b.poseMatrix
mat_b.invert()
return mat_b
#***********************************************
#Combine Matrix
#***********************************************
def writeCombineMatrix(self,bon):
Blender.Set('curframe',1)
mat_b = bon.getRestMatrix()
global chld_obj
Blender.Set('curframe', 1)
pose = chld_obj.getPose()
pos_b = pose.bones[bon.name]
mat_b = pos_b.poseMatrix
if bon.hasParent():
pare = bon.getParent()
mat_p = pare.getRestMatrix()
else :
pare = bon.parent
pos_p = pose.bones[pare.name]
mat_p = pos_p.poseMatrix
else:
mat_p = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1])
mat_p.invert()
mat_rb = mat_b * mat_p
return mat_rb
mat_f = mat_b * mat_p
return mat_f
#***********************************************
#Combine Matrix
#***********************************************
def writeCombineAnimMatrix(self,bon):
mat_b = bon.getRestMatrix()
def writeAnimCombineMatrix(self,bon,fre):
global chld_obj
Blender.Set('curframe', fre)
pose = chld_obj.getPose()
pos_b = pose.bones[bon.name]
mat_b = pos_b.poseMatrix
if bon.hasParent():
pare = bon.getParent()
mat_p = pare.getRestMatrix()
else :
pare = bon.parent
pos_p = pose.bones[pare.name]
mat_p = pos_p.poseMatrix
else:
mat_p = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1])
mat_p.invert()
mat_rb = mat_b * mat_p
return mat_rb
mat_f = mat_b * mat_p
return mat_f
#*********************************************************************************************************************************************
@@ -271,16 +280,23 @@ class xExport:
#***********************************************
def writeSkinWeights(self, arm, mesh):
global index_list
v_dict = {}
Blender.Set('curframe',1)
self.file.write(" XSkinMeshHeader {\n")
max_infl = 0
for bo in arm.getBones() :
name = bo.getName()
#this part supply the missing getVertexInfluences(index)
for v in index_list:
v_dict[v] = []
for bo in arm.bones.values() :
name = bo.name
try :
vertx_list = mesh.getVertsFromGroup(name,1)
for vn in vertx_list:
v_dict[vn[0]].append(name)
#---------------------------------------------------
for inde in vertx_list :
vert_infl = mesh.getVertexInfluences(inde[0])
vert_infl = v_dict[inde[0]]
ln_infl = len(vert_infl)
if ln_infl > max_infl :
max_infl = ln_infl
@@ -288,20 +304,21 @@ class xExport:
except:
pass
self.file.write(" %s; \n" % (max_infl))
self.file.write(" %s; \n" % (max_infl * 3))
self.file.write(" %s; \n" % (len(arm.getBones())))
self.file.write(" %d; \n" % (max_infl))
self.file.write(" %d; \n" % (max_infl * 3))
self.file.write(" %d; \n" % (len(arm.bones.values())))
self.file.write(" }\n")
for bo in arm.getBones() :
for bo in arm.bones.values() :
bo_list = []
weight_list = []
name = bo.getName()
name = bo.name
f_name = name.replace(".","")
try :
vert_list = mesh.getVertsFromGroup(name,1)
le = 0
for indx in vert_list:
ver_infl = mesh.getVertexInfluences(indx[0])
ver_infl = v_dict[indx[0]]
len_infl = float(len(ver_infl))
infl = 1 / len_infl
i = -1
@@ -314,28 +331,27 @@ class xExport:
self.file.write(" SkinWeights {\n")
self.file.write(' "%s"; \n' % (name))
self.file.write(' %s; \n' % (le))
self.file.write(' "%s"; \n' % (f_name))
self.file.write(' %d; \n' % (le))
count = 0
for ind in bo_list :
count += 1
if count == len(bo_list):
self.file.write(" %s; \n" % (ind))
self.file.write(" %d; \n" % (ind))
else :
self.file.write(" %s, \n" % (ind))
self.file.write(" %d, \n" % (ind))
cou = 0
for wegh in weight_list :
cou += 1
if cou == len(weight_list):
self.file.write(" %s; \n" % (round(wegh,6)))
self.file.write(" %f; \n" % (round(wegh,6)))
else :
self.file.write(" %s, \n" % (round(wegh,6)))
self.file.write(" %f, \n" % (round(wegh,6)))
matx = self.writeMatrixOffset(bo)
self.writeOffsFrames(matx, name, 1)
self.writeOffsFrames(matx, name)
except :
pass
self.file.write(" }\n")
@@ -344,7 +360,8 @@ class xExport:
#***********************************************
# Write Matrices
#***********************************************
def writeArmFrames(self, matx, name, space):
def writeArmFrames(self, matx, name):
global space
tab = " "
self.file.write("%s" % (tab * space))
self.file.write("Frame ")
@@ -352,16 +369,16 @@ class xExport:
self.file.write("%s" % (tab * space))
self.file.write(" FrameTransformMatrix {\n")
self.file.write("%s" % (tab * space))
self.file.write(" %s,%s,%s,%s,\n" %
self.file.write(" %f,%f,%f,%f,\n" %
(round(matx[0][0],4),round(matx[0][1],4),round(matx[0][2],4),round(matx[0][3],4)))
self.file.write("%s" % (tab * space))
self.file.write(" %s,%s,%s,%s,\n" %
self.file.write(" %f,%f,%f,%f,\n" %
(round(matx[1][0],4),round(matx[1][1],4),round(matx[1][2],4),round(matx[1][3],4)))
self.file.write("%s" % (tab * space))
self.file.write(" %s,%s,%s,%s,\n" %
self.file.write(" %f,%f,%f,%f,\n" %
(round(matx[2][0],4),round(matx[2][1],4),round(matx[2][2],4),round(matx[2][3],4)))
self.file.write("%s" % (tab * space))
self.file.write(" %s,%s,%s,%s;;\n" %
self.file.write(" %f,%f,%f,%f;;\n" %
(round(matx[3][0],4),round(matx[3][1],4),round(matx[3][2],4),round(matx[3][3],6)))
self.file.write("%s" % (tab * space))
self.file.write(" }\n")
@@ -369,19 +386,20 @@ class xExport:
#***********************************************
# Write Matrices
#***********************************************
def writeOffsFrames(self, matx, name, space):
def writeOffsFrames(self, matx, name):
space = 1
tab = " "
self.file.write("%s" % (tab * space))
self.file.write(" %s,%s,%s,%s,\n" %
self.file.write(" %f,%f,%f,%f,\n" %
(round(matx[0][0],4),round(matx[0][1],4),round(matx[0][2],4),round(matx[0][3],4)))
self.file.write("%s" % (tab * space))
self.file.write(" %s,%s,%s,%s,\n" %
self.file.write(" %f,%f,%f,%f,\n" %
(round(matx[1][0],4),round(matx[1][1],4),round(matx[1][2],4),round(matx[1][3],4)))
self.file.write("%s" % (tab * space))
self.file.write(" %s,%s,%s,%s,\n" %
self.file.write(" %f,%f,%f,%f,\n" %
(round(matx[2][0],4),round(matx[2][1],4),round(matx[2][2],4),round(matx[2][3],4)))
self.file.write("%s" % (tab * space))
self.file.write(" %s,%s,%s,%s;;\n" %
self.file.write(" %f,%f,%f,%f;;\n" %
(round(matx[3][0],4),round(matx[3][1],4),round(matx[3][2],4),round(matx[3][3],6)))
self.file.write("%s" % (tab * space))
self.file.write(" }\n")
@@ -445,7 +463,8 @@ template SkinWeights {\n\
mat_ob.invert()
mat = mat_arm * mat_ob
mat.invert()
self.writeArmFrames(mat, name.name, 1)
name_f = name.name.replace(".","")
self.writeArmFrames(mat, name_f)
mesh = NMesh.GetRawFromObject(name.name)
self.file.write("Mesh {\n")
numface=len(mesh.faces)
@@ -461,8 +480,8 @@ template SkinWeights {\n\
for n in range(len(face.v)):
index_list.append(face.v[n].index)
vec_vert = Vector([face.v[n].co[0], face.v[n].co[1], face.v[n].co[2], 1])
f_vec_vert = VecMultMat(vec_vert, mat)
self.file.write("%s; %s; %s;" % (f_vec_vert[0], f_vec_vert[1], f_vec_vert[2]))
f_vec_vert = vec_vert * mat
self.file.write("%f; %f; %f;" % (round(f_vec_vert[0],4), round(f_vec_vert[1],4), round(f_vec_vert[2],4)))
if counter == numface :
if n == len(face.v)-1 :
self.file.write(";\n")
@@ -505,7 +524,8 @@ template SkinWeights {\n\
global index_list
#ROTATION
mat_ob = mat_flip * name.matrixWorld
self.writeArmFrames(mat_ob, name.name, 0)
name_f = name.name.replace(".","")
self.writeArmFrames(mat_ob, name_f)
self.file.write("Mesh {\n")
numface=len(mesh.faces)
@@ -589,10 +609,9 @@ template SkinWeights {\n\
##MATERIAL NAME
for mat in Material.Get():
self.file.write(" Material")
for a in range(0,len(mat.name)):
if mat.name[a] == ".":
print "WARNING:the material " + mat.name + " contains '.' within.Many viewers may refuse to read the exported file"
self.file.write(" %s "% (mat.name))
name_m = mat.name
name_f = name_m.replace(".","")
self.file.write(" %s "% (name_f))
self.file.write("{\n")
self.file.write(" %s; %s; %s;" % (mat.R, mat.G, mat.B))
self.file.write("%s;;\n" % (mat.alpha))
@@ -609,7 +628,7 @@ template SkinWeights {\n\
self.file.write(" 1.0;\n")
self.file.write(" 1.0; 1.0; 1.0;;\n")
self.file.write(" 0.0; 0.0; 0.0;;\n")
self.file.write(" TextureFilename {\n")
self.file.write(" TextureFilename {")
self.file.write(' "%s" ;'% (mat))
self.file.write(" }\n")
self.file.write(" }\n")
@@ -711,47 +730,45 @@ template SkinWeights {\n\
#***********************************************
#WRITE ANIMATION KEYS
#***********************************************
def writeAnimation(self,arm_ob):
global mat_dict
arm = arm_ob.getData()
act_list = arm_ob.getAction()
ip = act_list.getAllChannelIpos()
for bon in arm.getBones() :
for bon in arm.bones.values() :
point_list = []
name = bon.name
name_f = name.replace(".", "")
try :
ip_bon_channel = ip[bon.name]
ip_bon_name = ip_bon_channel.getName()
ip_bon = Blender.Ipo.Get(ip_bon_name)
poi = ip_bon.getCurves()
for po in poi[3].getPoints():
a = po.getPoints()
point_list.append(int(a[0]))
point_list.pop(0)
#point_list.pop(0)
self.file.write(" Animation { \n")
self.file.write(" {%s}\n" %(bon.getName()))
self.file.write(" {%s}\n" %(name_f))
self.file.write(" AnimationKey { \n")
self.file.write(" 4;\n")
self.file.write(" %s; \n" % (len(point_list)+1))
self.file.write(" %s;" % (1))
self.file.write("16;")
mat = self.writeCombineMatrix(bon)
self.writeFrames(mat)
self.file.write(",\n")
self.file.write(" %s; \n" % (len(point_list)))
for fr in point_list:
mat = self.writeAnimCombineMatrix(bon,fr)
self.file.write(" %s;" % (fr))
self.file.write("16;")
Blender.Set('curframe',fr)
mat_new = self.writeCombineAnimMatrix(bon)
self.writeFrames(mat_new)
self.writeFrames(mat)
if fr == point_list[len(point_list)-1]:
self.file.write(";\n")
@@ -864,8 +881,8 @@ arg = __script__['arg']
if arg == 'exportsel':
fname = Blender.sys.makename(ext = ".x")
Blender.Window.FileSelector(my_callback_sel, "Export DirectX8", fname)
Blender.Window.FileSelector(my_callback_sel, "Export DirectX", fname)
else:
fname = Blender.sys.makename(ext = ".x")
Blender.Window.FileSelector(my_callback, "Export DirectX8", fname)
Blender.Window.FileSelector(my_callback, "Export DirectX", fname)

View File

@@ -202,7 +202,8 @@ def transform_verts(verts, m):
vecs = []
for v in verts:
vec = Mathutils.Vector([v[0],v[1],v[2], 1])
vecs.append(Mathutils.VecMultMat(vec, m))
#vecs.append(Mathutils.VecMultMat(vec, m))
vecs.append(vec*m)
return vecs
# ---

View File

@@ -10,7 +10,7 @@ Tip: 'Import an AC3D (.ac) file.'
__author__ = "Willian P. Germano"
__url__ = ("blender", "elysiun", "AC3D's homepage, http://www.ac3d.org",
"PLib 3d gaming lib, http://plib.sf.net")
__version__ = "2.36 2005-04-14"
__version__ = "2.36a 2005-12-04"
__bpydoc__ = """\
This script imports AC3D models into Blender.
@@ -43,9 +43,9 @@ users can configure (see config options above).
# $Id$
#
# --------------------------------------------------------------------------
# AC3DImport version 2.36 Apr 14, 2005
# AC3DImport version 2.36a Dec 04, 2005
# Program versions: Blender 2.36+ and AC3Db files (means version 0xb)
# changed: updated to use the Scripts Config Editor facilities
# changed: fixed a bug: error on 1 vertex "closed" polylines
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
@@ -366,7 +366,7 @@ class AC3DImport:
faces.append(cut)
face = face[1:]
if flaglow == 1:
if flaglow == 1 and faces:
face = [faces[-1][-1], faces[0][0]]
faces.append(face)
@@ -498,7 +498,9 @@ class AC3DImport:
for vi in range(len(f)):
bface.v.append(mesh.verts[f[vi][0]])
bface.uv.append((f[vi][1][0], f[vi][1][1]))
mesh.faces.append(bface)
#mesh.faces.append(bface)
# quick hack, will switch from NMesh to Mesh later:
if len(bface.v) > 1: mesh.addFace(bface)
mesh.mode = 0
object = Blender.NMesh.PutRaw(mesh)

View File

@@ -2,21 +2,21 @@
""" Registration info for Blender menus
Name: 'Bevel Center'
Blender: 236
Blender: 240
Group: 'Mesh'
Tip: 'Bevel selected vertices'
Tip: 'Bevel selected faces, edges, and vertices'
"""
__author__ = "Loic Berthe"
__author__ = "Loic BERTHE"
__url__ = ("blender", "elysiun")
__version__ = "1.0"
__version__ = "2.0"
__bpydoc__ = """\
This script implements vertex bevelling in Blender.
This script implements vertex and edges bevelling in Blender.
Usage:
Select the mesh you want to work on, enter Edit Mode and select the vertices
Select the mesh you want to work on, enter Edit Mode and select the edges
to bevel. Then run this script from the 3d View's Mesh->Scripts menu.
You can control the thickness of the bevel with the slider -- redefine the
@@ -24,358 +24,295 @@ end points for bigger or smaller ranges. The thickness can be changed even
after applying the bevel, as many times as needed.
For an extra smoothing after or instead of direct bevel, set the level of
recursiveness and use the "Recursive" button.
recursiveness and use the "Recursive" button.
This "Recursive" Button, won't work in face select mode, unless you choose
"faces" in the select mode menu.
Notes:<br>
You can undo and redo your steps just like with normal mesh operations in
You can undo and redo your steps just like with normal mesh operations in
Blender.
"""
# $Id$
#
######################################################################
# Bevel Center v1 for Blender
#
# This script lets you bevel the selected vertices and control the
# Bevel Center v2.0 for Blender
# This script lets you bevel the selected vertices or edges and control the
# thickness of the bevel
#
# (c) 2004 Lo<EFBFBD>c Berthe (loic.berthe@lilotux.net)
# (c) 2004-2006 Loïc Berthe (loic+blender@lilotux.net)
# released under Blender Artistic License
#
######################################################################
import Blender
from Blender import NMesh, Window
from Blender import NMesh, Window, Scene
from Blender.Draw import *
from Blender.Mathutils import *
from Blender.BGL import *
from math import pi, sin, sqrt
######################################################################
# Functions to handle the global structures of the script NV, NE and NC
# which contain informations about the vertices, faces and corners to be
# created
# Functions to handle the global structures of the script NF, NE and NC
# which contain informations about faces and corners to be created
class Dir:
def __init__(self, co):
self.co = co
global E_selected
E_selected = NMesh.EdgeFlags['SELECT']
def add_to_NV(old,co,new):
dir = Dir(co)
#
if old in NV.keys():
NV[old][dir] = new
else:
NV[old] = {dir:new}
def is_in_NV(old,co):
if old in NV.keys():
for dir in NV[old]:
if dir.co == co : return NV[old][dir]
#
return False
def add_to_NE(old, new):
ind1 = old[0].index
ind2 = old[1].index
if ind1 > ind2:
new.reverse()
ind1,ind2 = ind2,ind1
id = str(ind1)+"_"+str(ind2)
if id in NE.keys():
[NE[id].append(v) for v in new]
else:
NE[id] = new
def add_to_NC(old,edge):
if old in NC.keys():
NC[old].append(edge)
else:
NC[old] = [edge]
######################################################################
# Geometric functions
def norm(vec):
n = sqrt(vec[0]**2+vec[1]**2+vec[2]**2)
return [vec[0]/n,vec[1]/n,vec[2]/n]
def parall_coord(old, dir):
co = old.co
vec = [0.0,0.0,0.0]
nco = [0.0,0.0,0.0]
#
if len(dir) == 1:
for i in range(3): vec[i] = dir[0].co[i] - co[i]
vec = norm(vec)
#
elif len(dir) == 2:
vec1 = [0.0,0.0,0.0]
vec2 = [0.0,0.0,0.0]
for i in range(3):
vec1[i] = dir[0].co[i] - co[i]
vec2[i] = dir[1].co[i] - co[i]
vec1 = norm(vec1)
vec2 = norm(vec2)
for i in range(3) : vec[i] = vec1[i]+vec2[i]
#
for i in range(3): nco[i] = co[i] + dist.val*vec[i]
return (nco,vec)
def get_vert(old, dir):
""" Look in NV if a vertice corresponding to the vertex old and the
direction dir already exists, and create one otherwise"""
(nco, vec) = parall_coord(old, dir)
v = is_in_NV(old,vec)
if v: return v
#
v = NMesh.Vert(nco[0],nco[1],nco[2])
v.sel = 1
def make_sel_vert(*co):
vi= NMesh.Vert(*co)
v.sel = 1
me.verts.append(v)
add_to_NV(old,vec,v)
return v
######################################################################
# Functions to create the differents faces
def make_sel_face(verts):
f = NMesh.Face(verts)
f.sel = 1
me.addFace(f)
def add_to_NV(old,dir,new):
if old in NV.keys(): NV[old][dir] = new
else: NV[old] = {dir:new}
def get_v(old, *neighbors):
# compute the direction of the new vert
if len(neighbors) == 1 : dir = (neighbors[0].co - old.co).normalize()
else : dir = (neighbors[0].co - old.co).normalize() + (neighbors[1].co-old.co).normalize()
# look in NV if this vert already exists
key = tuple(dir)
if old in NV and key in NV[old] : return NV[old][key]
def make_NF():
""" Analyse the mesh, sort the faces containing selected vertices and
create a liste NF : NF = [[flag, vertlist, old_face]]. Flag describes the
topology of the face."""
#
for f in me.faces:
V = f.v
v_sel = [x.sel for x in V]
nb_sel = sum(v_sel)
if nb_sel == 0 :
pass
else:
nb_v = len(V)
#
if nb_v == 4:
#
if nb_sel == 4:
NF.append([1,V,f])
#
elif nb_sel == 3:
if v_sel == [0,1,1,1]: V = [V[1],V[2],V[3],V[0]]
elif v_sel == [1,0,1,1]: V = [V[2],V[3],V[0],V[1]]
elif v_sel == [1,1,0,1]: V = [V[3],V[0],V[1],V[2]]
NF.append([2,V,f])
#
elif nb_sel == 2:
if v_sel == [1,0,1,0] or v_sel == [0,1,0,1]:
if v_sel == [0,1,0,1]: V = [V[1],V[2],V[3],V[0]]
NF.append([5,[V[0],V[1],V[3]],f])
NF.append([5,[V[2],V[1],V[3]]])
else:
if v_sel == [0,1,1,0]: V = [V[1],V[2],V[3],V[0]]
elif v_sel == [0,0,1,1]: V = [V[2],V[3],V[0],V[1]]
elif v_sel == [1,0,0,1]: V = [V[3],V[0],V[1],V[2]]
NF.append([3,V,f])
#
else:
if v_sel == [0,1,0,0]: V = [V[1],V[2],V[3],V[0]]
elif v_sel == [0,0,1,0]: V = [V[2],V[3],V[0],V[1]]
elif v_sel == [0,0,0,1]: V = [V[3],V[0],V[1],V[2]]
NF.append([4,V,f])
#
elif nb_v == 3:
#
if nb_sel == 3:
NF.append([6,V,f])
#
elif nb_sel == 2:
if v_sel == [0,1,1]: V = [V[1],V[2],V[0]]
elif v_sel == [1,0,1]: V = [V[2],V[0],V[1]]
NF.append([7,V,f])
#
else:
if v_sel == [0,1,0]: V = [V[1],V[2],V[0]]
elif v_sel == [0,0,1]: V = [V[2],V[0],V[1]]
NF.append([5,V,f])
# else, create it
new = old.co + dist.val*dir
v = make_sel_vert(new.x,new.y,new.z)
add_to_NV(old,key,v)
return v
def make_faces():
""" Make the new faces according to NF """
#
for N in NF:
cas = N[0]
V = N[1]
#
if cas < 6:
new_v = [0,0,0,0]
if cas == 1: # v_sel = [1,1,1,1]
for i in range(-1,3):
new_v[i] = get_vert(V[i],[V[i-1],V[i+1]])
new_f = NMesh.Face(new_v)
me.faces.append(new_f)
for i in range(-1,3):
add_to_NE([V[i],V[i+1]],[new_v[i],new_v[i+1]])
#
elif cas == 2: # v_sel = [1,1,1,0]
new_v[0] = get_vert(V[0],[V[3]])
new_v[1] = get_vert(V[1],[V[0],V[2]])
new_v[2] = get_vert(V[2],[V[3]])
new_v[3] = V[3]
#
new_f = NMesh.Face(new_v)
me.faces.append(new_f)
#
add_to_NE([V[0],V[1]],[new_v[0],new_v[1]])
add_to_NE([V[1],V[2]],[new_v[1],new_v[2]])
#
elif cas == 3: # v_sel = [1,1,0,0]
new_v[0] = get_vert(V[0],[V[3]])
new_v[1] = get_vert(V[1],[V[2]])
new_v[2] = V[2]
new_v[3] = V[3]
#
new_f = NMesh.Face(new_v)
me.faces.append(new_f)
#
add_to_NE([V[0],V[1]],[new_v[0],new_v[1]])
#
elif cas == 4: # v_sel = [1,0,0,0]
new_v[0] = get_vert(V[0],[V[3]])
new_v[1] = get_vert(V[0],[V[1]])
new_v[2] = V[1]
new_v[3] = V[3]
#
new_f = NMesh.Face(new_v)
me.faces.append(new_f)
#
add_to_NC(V[0], new_v[0:2])
#
new_v[0] = V[1]
new_v[1] = V[2]
new_v[2] = V[3]
#
new_f = NMesh.Face(new_v[:3])
me.faces.append(new_f)
#
else: # v_sel = [1,0,0]
new_v[0] = get_vert(V[0],[V[2]])
new_v[1] = get_vert(V[0],[V[1]])
new_v[2] = V[1]
new_v[3] = V[2]
#
new_f = NMesh.Face(new_v)
me.faces.append(new_f)
#
add_to_NC(V[0], new_v[0:2])
#
else:
new_v = [0,0,0]
#
if cas == 6: # v_sel = [1,1,1]
for i in range(-1,2):
new_v[i] = get_vert(V[i],[V[i-1],V[i+1]])
new_f = NMesh.Face(new_v)
me.faces.append(new_f)
for i in range(-1,2):
add_to_NE([V[i],V[i+1]],[new_v[i],new_v[i+1]])
#
elif cas == 7: # v_sel = [1,1,0]
new_v[0] = get_vert(V[0],[V[2]])
new_v[1] = get_vert(V[1],[V[2]])
new_v[2] = V[2]
#
new_f = NMesh.Face(new_v)
me.faces.append(new_f)
add_to_NE([V[0],V[1]],[new_v[0],new_v[1]])
""" Analyse the mesh, make the faces corresponding to selected faces and
fill the structures NE and NC """
# make the differents flags consistent
for e in me.edges:
if e.flag & E_selected :
e.v1.sel = 1
e.v2.sel = 1
NF =[] # NF : New faces
for f in me.faces:
V = f.v
nV = len(V)
enumV = range(nV)
E = [me.findEdge(V[i],V[(i+1) % nV]) for i in enumV]
Esel = [x.flag & E_selected for x in E]
# look for selected vertices and creates a list containing the new vertices
newV = V[:]
changes = False
for (i,v) in enumerate(V):
if v.sel :
changes = True
if Esel[i-1] == 0 and Esel[i] == 1 : newV[i] = get_v(v,V[i-1])
elif Esel[i-1] == 1 and Esel[i] == 0 : newV[i] = get_v(v,V[(i+1) % nV])
elif Esel[i-1] == 1 and Esel[i] == 1 : newV[i] = get_v(v,V[i-1],V[(i+1) % nV])
else : newV[i] = [get_v(v,V[i-1]),get_v(v,V[(i+1) % nV])]
if changes:
# determine and store the face to be created
lenV = [len(x) for x in newV]
if 2 not in lenV :
new_f = NMesh.Face(newV)
if sum(Esel) == nV : new_f.sel = 1
NF.append(new_f)
else :
nb2 = lenV.count(2)
if nV == 4 : # f is a quad
if nb2 == 1 :
ind2 = lenV.index(2)
NF.append(NMesh.Face([newV[ind2-1],newV[ind2][0],newV[ind2][1],newV[ind2-3]]))
NF.append(NMesh.Face([newV[ind2-1],newV[ind2-2],newV[ind2-3]]))
elif nb2 == 2 :
# We must know if the tuples are neighbours
ind2 = ''.join([str(x) for x in lenV+lenV[:1]]).find('22')
if ind2 != -1 : # They are
NF.append(NMesh.Face([newV[ind2][0],newV[ind2][1],newV[ind2-3][0],newV[ind2-3][1]]))
NF.append(NMesh.Face([newV[ind2][0],newV[ind2-1],newV[ind2-2],newV[ind2-3][1]]))
else: # They aren't
ind2 = lenV.index(2)
NF.append(NMesh.Face([newV[ind2][0],newV[ind2][1],newV[ind2-2][0],newV[ind2-2][1]]))
NF.append(NMesh.Face([newV[ind2][1],newV[ind2-3],newV[ind2-2][0]]))
NF.append(NMesh.Face([newV[ind2][0],newV[ind2-1],newV[ind2-2][1]]))
elif nb2 == 3 :
ind2 = lenV.index(3)
NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2],newV[ind2-3][0]]))
NF.append(NMesh.Face([newV[ind2-1][0],newV[ind2-1][1],newV[ind2-3][0],newV[ind2-3][1]]))
NF.append(NMesh.Face([newV[ind2-3][1],newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0]]))
else:
if (newV[0][1].co-newV[3][0].co).length + (newV[1][0].co-newV[2][1].co).length \
< (newV[0][0].co-newV[1][1].co).length + (newV[2][0].co-newV[3][1].co).length :
ind2 = 0
else :
ind2 = 1
NF.append(NMesh.Face([newV[ind2-1][0],newV[ind2-1][1],newV[ind2][0],newV[ind2][1]]))
NF.append(NMesh.Face([newV[ind2][1],newV[ind2-3][0],newV[ind2-2][1],newV[ind2-1][0]]))
NF.append(NMesh.Face([newV[ind2-3][0],newV[ind2-3][1],newV[ind2-2][0],newV[ind2-2][1]]))
else : # f is a tri
if nb2 == 1:
ind2 = lenV.index(2)
NF.append(NMesh.Face([newV[ind2-2],newV[ind2-1],newV[ind2][0],newV[ind2][1]]))
elif nb2 == 2:
ind2 = lenV.index(3)
NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2],newV[ind2-2][0]]))
NF.append(NMesh.Face([newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0],newV[ind2-1][1]]))
else:
ind2 = min(((newV[i][1].co-newV[i-1][0].co).length, i) for i in enumV)[1]
NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2][0],newV[ind2][1],newV[ind2-2][0]]))
NF.append(NMesh.Face([newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0],newV[ind2-1][1]]))
# Preparing the corners
for i in enumV:
if lenV[i] == 2 : NC.setdefault(V[i],[]).append(newV[i])
old_faces.append(f)
# Preparing the Edges
for i in enumV:
if Esel[i]:
verts = [newV[i],newV[(i+1) % nV]]
if V[i].index > V[(i+1) % nV].index : verts.reverse()
NE.setdefault(E[i],[]).append(verts)
# Create the faces
for f in NF: me.addFace(f)
def make_edges():
""" Make the faces corresponding to selected edges """
#
for l in NE.values():
if len(l) == 4:
f = NMesh.Face([l[0],l[1],l[3],l[2]])
me.faces.append(f)
for old,new in NE.iteritems() :
if len(new) == 1 : # This edge was on a border
oldv = [old.v1, old.v2]
if old.v1.index < old.v2.index : oldv.reverse()
make_sel_face(oldv+new[0])
me.findEdge(*oldv).flag |= E_selected
me.findEdge(*new[0]).flag |= E_selected
for v in oldv : NV_ext.add(v)
else:
make_sel_face(new[0] + new[1][::-1])
me.findEdge(*new[0]).flag |= E_selected
me.findEdge(*new[1]).flag |= E_selected
def make_corners():
""" Make the faces corresponding to selected corners """
#
""" Make the faces corresponding to corners """
for v in NV.keys():
V = NV[v].values()
nb_v = len(V)
#
if nb_v < 3:
pass
#
elif nb_v == 3:
new_f = NMesh.Face(V)
me.faces.append(new_f)
#
nV = len(V)
if nV == 1: pass
elif nV == 2 :
if v in NV_ext:
make_sel_face(V+[v])
me.findEdge(*V).flag |= E_selected
else:
# We need to know which are the edges around the corner.
# First, we look for the quads surrounding the corner.
q = [NE[id] for id in NE.keys() if str(v.index) in id.split('_')]
#
# We will put the associated edges in the list eed
is_in_v = lambda x:x in V
eed = [filter(is_in_v, l) for l in q]
#
# We will add the edges coming from faces where only one vertice is selected.
# They are stocked in NC.
if v in NC.keys():
eed = eed+NC[v]
b = eed.pop()
# b will contain the sorted list of vertices
#
while eed:
for l in eed:
if l[0] == b[-1]:
b.append(l[1])
eed.remove(l)
break
elif l[1] == b[-1]:
b.append(l[0])
eed.remove(l)
break
# Now we can create the faces
if nb_v == 4:
new_f = NMesh.Face(b[:4])
me.faces.append(new_f)
#
else:
co = [0.0, 0.0,0.0]
vec = [0.0, 0.0,0.0]
for x in V:
co[0] += x[0]
co[1] += x[1]
co[2] += x[2]
#
for dir in NV[v]:
vec[0] += dir.co[0]
vec[1] += dir.co[1]
vec[2] += dir.co[2]
#
co = [x/nb_v for x in co]
vec = [x/nb_v for x in vec]
center = NMesh.Vert(co[0],co[1],co[2])
center.sel = 1
me.verts.append(center)
add_to_NV(v,vec,center)
#
for k in range(nb_v):
new_f = NMesh.Face([center, b[k], b[k+1]])
me.faces.append(new_f)
#
if nV == 3 and v not in NV_ext : make_sel_face(V)
else :
# We need to know which are the edges around the corner.
# First, we look for the quads surrounding the corner.
eed = []
for old, new in NE.iteritems():
if v in (old.v1,old.v2) :
if v.index == min(old.v1.index,old.v2.index) : ind = 0
else : ind = 1
if len(new) == 1: eed.append([v,new[0][ind]])
else : eed.append([new[0][ind],new[1][ind]])
# We will add the edges coming from faces where only one vertice is selected.
# They are stored in NC.
if v in NC: eed = eed+NC[v]
# Now we have to sort these vertices
hc = {}
for (a,b) in eed :
hc.setdefault(a,[]).append(b)
hc.setdefault(b,[]).append(a)
for x0,edges in hc.iteritems():
if len(edges) == 1 : break
b = [x0] # b will contain the sorted list of vertices
for i in range(len(hc)-1):
for x in hc[x0] :
if x not in b : break
b.append(x)
x0 = x
b.append(b[0])
# Now we can create the faces
if len(b) == 5: make_sel_face(b[:4])
else:
New_V = Vector(0.0, 0.0,0.0)
New_d = [0.0, 0.0,0.0]
for x in hc.keys(): New_V += x.co
for dir in NV[v] :
for i in xrange(3): New_d[i] += dir[i]
New_V *= 1./len(hc)
for i in range(3) : New_d[i] /= nV
center = make_sel_vert(New_V.x,New_V.y,New_V.z)
add_to_NV(v,tuple(New_d),center)
for k in range(len(b)-1): make_sel_face([center, b[k], b[k+1]])
if 2 < nV and v in NC :
for edge in NC[v] : me.findEdge(*edge).flag |= E_selected
def clear_old():
""" Erase old faces and vertices """
for F in NF:
if len(F) == 3:
me.faces.remove(F[2])
#
for f in old_faces: me.removeFace(f)
for v in NV.keys():
me.verts.remove(v)
if v not in NV_ext : me.verts.remove(v)
for e in me.edges:
if e.flag & E_selected :
e.v1.sel = 1
e.v2.sel = 1
######################################################################
# Interface
#
global dist
NV = {}
dist = Create(0.2)
left = Create(0.0)
right = Create(1.0)
@@ -393,83 +330,79 @@ def draw():
global EVENT_NOEVENT, EVENT_BEVEL, EVENT_UPDATE, EVENT_RECURS, EVENT_EXIT
glClear(GL_COLOR_BUFFER_BIT)
Button("Bevel",EVENT_BEVEL,10,100,300,25)
left=Number('', EVENT_NOEVENT,10,70,50, 20,left.val,0,right.val,'Set the minimum of the slider')
right = Number("",EVENT_NOEVENT,260,70,50,20,right.val,left.val,200,"Set the maximum of the slider")
dist=Slider("Thickness ",EVENT_UPDATE,65,70,190,20,dist.val,left.val,right.val,0,"Thickness of the bevel, can be changed even after bevelling")
glRasterPos2d(10,40)
Button("Bevel",EVENT_BEVEL,10,100,280,25)
left=Number('', EVENT_NOEVENT,10,70,45, 20,left.val,0,right.val,'Set the minimum of the slider')
right = Number("",EVENT_NOEVENT,245,70,45,20,right.val,left.val,200,"Set the maximum of the slider")
dist=Slider("Thickness ",EVENT_UPDATE,60,70,180,20,dist.val,left.val,right.val,0, \
"Thickness of the bevel, can be changed even after bevelling")
glRasterPos2d(8,40)
Text('To finish, you can use recursive bevel to smooth it')
num=Number('', EVENT_NOEVENT,10,10,50, 16,num.val,1,100,'Recursion level')
Button("Recursive",EVENT_RECURS,65,10,100,16)
Button("Exit",EVENT_EXIT,230,10,80,20)
num=Number('', EVENT_NOEVENT,10,10,40, 16,num.val,1,100,'Recursion level')
Button("Recursive",EVENT_RECURS,55,10,100,16)
Button("Exit",EVENT_EXIT,210,10,80,20)
def event(evt, val):
if ((evt == QKEY or evt == ESCKEY) and not val):
Exit()
if ((evt == QKEY or evt == ESCKEY) and not val): Exit()
def bevent(evt):
if evt == EVENT_EXIT :
Exit()
#
elif evt == EVENT_BEVEL:
bevel()
#
elif evt == EVENT_UPDATE:
try:
bevel_update()
except NameError:
pass
#
elif evt == EVENT_RECURS:
recursive()
if evt == EVENT_EXIT : Exit()
elif evt == EVENT_BEVEL : bevel()
elif evt == EVENT_UPDATE :
try: bevel_update()
except NameError : pass
elif evt == EVENT_RECURS : recursive()
Register(draw, event, bevent)
######################################################################
def bevel():
""" The main function, which creates the bevel """
global me,NF,NV,NE,NC, old_dist
#
is_editmode = Window.EditMode()
if is_editmode: Window.EditMode(0)
objects = Blender.Object.GetSelected()
bev_obj = objects[0]
if bev_obj.getType() != "Mesh":
PupMenu("ERROR: active object must be a mesh")
global me,NV,NV_ext,NE,NC, old_faces,old_dist
scn = Scene.GetCurrent()
ob = scn.getActiveObject()
if ob == None or ob.getType() != 'Mesh':
Draw.PupMenu('ERROR%t|Select a mesh object.')
return
me = NMesh.GetRaw(bev_obj.getData(name_only = True))
#
NF = []
Window.WaitCursor(1) # Change the Cursor
is_editmode = Window.EditMode()
if is_editmode: Window.EditMode(0)
me = ob.getData()
NV = {}
NV_ext = set()
NE = {}
NC = {}
#
make_NF()
old_faces = []
make_faces()
make_edges()
make_corners()
clear_old()
#
old_dist = dist.val
#
me.update(1)
if is_editmode: Window.EditMode(1)
Window.WaitCursor(0)
Blender.Redraw()
def bevel_update():
""" Use NV to update the bevel """
global dist, old_dist, NV
if not NV: return
global dist, old_dist
is_editmode = Window.EditMode()
if is_editmode: Window.EditMode(0)
fac = dist.val - old_dist
old_dist = dist.val
#
for old_v in NV.keys():
for dir in NV[old_v].keys():
for i in range(3):
NV[old_v][dir].co[i] += fac*dir.co[i]
#
NV[old_v][dir].co[i] += fac*dir[i]
me.update(1)
if is_editmode: Window.EditMode(1)
Blender.Redraw()
@@ -477,24 +410,23 @@ def bevel_update():
def recursive():
""" Make a recursive bevel... still experimental """
global dist
#
from math import pi, sin
if num.val > 1:
a = pi/4
ang = []
for k in range(num.val):
ang.append(a)
a = (pi+2*a)/4
#
l = [2*(1-sin(x))/sin(2*x) for x in ang]
R = dist.val/sum(l)
l = [x*R for x in l]
#
dist.val = l[0]
bevel_update()
#
for x in l[1:]:
dist.val = x
bevel()
# vim:set ts=4 sw=4:

View File

@@ -5,12 +5,28 @@
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | September 28, 2002 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Common Functions & Global Variables For All IO Modules |
# +---------------------------------------------------------+
# ***** 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
import sys
@@ -35,7 +51,16 @@ def append_faces(mesh, faces, facesuv, uvcoords):
for i in range(len(faces)):
if not i%100 and show_progress: Blender.Window.DrawProgressBar(float(i)/len(faces), "Generating Faces")
numfaceverts=len(faces[i])
if numfaceverts <= 4: # This face is a triangle or quad
if numfaceverts == 2: #This is not a face is an edge
if mesh.edges == None: #first run
mesh.addEdgeData()
#rev_face = revert(cur_face)
i1 = faces[i][0]
i2 = faces[i][1]
ee = mesh.addEdge(mesh.verts[i1],mesh.verts[i2])
ee.flag |= Blender.NMesh.EdgeFlags.EDGEDRAW
ee.flag |= Blender.NMesh.EdgeFlags.EDGERENDER
elif numfaceverts in [3,4]: # This face is a triangle or quad
face = Blender.NMesh.Face()
for j in range(numfaceverts):
index = faces[i][j]

File diff suppressed because it is too large Load Diff

View File

@@ -1,40 +1,60 @@
#!BPY
"""
Name: 'BVH Empties to Armature'
Blender: 237
Name: 'Empties to Armature'
Blender: 241
Group: 'Animation'
Tooltip: 'Create Armature from Empties created by BVH importer'
Tooltip: 'Create Armature from a parented-empties chain'
"""
__author__ = " Jean-Baptiste PERIN (jb_perin(at)yahoo.fr)"
__author__ = " Jean-Baptiste PERIN (jb_perin(at)yahoo.fr) with valuable help from Vincent BILLET "
__url__ = ("blender", "elysiun",
"BVH 2 ARMATURE, http://www.zoo-logique.org/3D.Blender/index.php3?zoo=dld&rep=zip ",
"BVH 2 ARMATURE, http://perso.wanadoo.fr/jb.perin/",
"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
__version__ = "2.2"
__version__ = "2.42"
__bpydoc__ = """ BVH2ARM.py v2.2
__bpydoc__ = """ BVH2ARM.py
Script for generating armature on BVH empties.
This script generates an armature and make bones
follow empties created by Blender BVH import script.
This script generates an armature upon an empty-made parented chain,
and make the armature follow the empties
Usage:<br>
- Import a bvh in Blender (File->Import->BVH);<br>
- Launch this script (Alt-P);<br>
- Rotate some empties to match your model and insert Rot key for them. <br>
- Select the root empty of the hierarchical chain.<br>
- Launch this script ;<br>
- Set up variables:<br>
"hipbonename": the name of the main bone;<br>
"hipbonename": the name of the main bone (automatically set to the selected empty).<br>
"startframe": the first frame of your anim;<br>
"endframe": the last frame of your anim;<br>
"decimation": the frequency (in number of frame) to which the armature is updated;<br>
"scale" to size the created armature.<br>
- Press "Create Armature".
"decimation": the frequency (in number of frame) to which the armature's pos is updated;<br>
- Press "Create Armature".
Notes: <br>
- The start frame configuration is used as the rest pose for the armature.<br>
- If the armature already exists when script is launched, the current armature is re-used.
"""
#----------------------------------------------
# (c) Jean-Baptiste PERIN june 2005, released under Blender Artistic Licence
# for the Blender 2.34-2.36 Python Scripts Bundle.
#----------------------------------------------
# --------------------------------------------------------------------------
# BVH2ARM.py
# --------------------------------------------------------------------------
# ***** 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 *****
# --------------------------------------------------------------------------
@@ -50,6 +70,9 @@ dicEmptyChild={}
dicBoneRestInvEmpRest={}
dicEmpRestInvBoneRest={}
restFrame = 1
bonerest={}
emprest={}
emp2bone={}
########################################################################
#
@@ -111,8 +134,8 @@ def getEmpty(name):
p = o
return p
def getChild(emp, emp_list):
return dicEmptyChild[emp.getName()]
##def getChild(emp, emp_list):
## return dicEmptyChild[emp.getName()]
#########
@@ -206,32 +229,6 @@ def GetOrCreateCurve(ipo, curvename):
#
########################################################################
def computeRootQuat2(empty, bone):
M1=dicBoneRestInvEmpRest[bone.getName()].rotationPart()
M2=dicEmpRestInvBoneRest[bone.getName()].rotationPart()
emprot = empty.getMatrix('worldspace').rotationPart()
emprot.transpose()
mat = M1*emprot*M2
mat.transpose()
return (mat.toQuat())
#emprest = dicEmptiesRestMatrix[empty.getName()].rotationPart()
#invemprest= dicEmptiesRestMatrix[empty.getName()].rotationPart()
##invemprest= emprest
##invemprest.invert()
##invemprest= dicEmptiesInvRestMatrix[empty.getName()].rotationPart()
#emprot = empty.getMatrix('worldspace').rotationPart()
#bonerest = dicBoneRestMatrix[bone.getName()].rotationPart()
#invbonerest = dicBoneRestMatrix[bone.getName()].rotationPart()
#invbonerest.invert()
#T2=emprot*invemprest
#T2.transpose()
#mat = bonerest*invemprest*T2*emprest*invbonerest
#mat.transpose()
#return (mat.toQuat())
#########
@@ -239,27 +236,6 @@ def computeRootQuat2(empty, bone):
# in :
# out :
#########
def computeRootPos(empty, bone):
vec = computeScaledPos(empty.getMatrix('worldspace').translationPart()) - dicBoneRestMatrix[bone.getName()].translationPart()
mat = dicBoneRestMatrix[bone.getName()].rotationPart()
vec2 = Mathutils.MatMultVec (mat, vec)
return vec2
def computeRelativePos(empty,bone):
vec = computeScaledPos(empty.getMatrix('worldspace').translationPart()) - dicBoneRestMatrix[bone.getName()].translationPart()
rootempty = getEmpty(hipbonename)
vec3 = computeScaledPos(rootempty.getMatrix('worldspace').translationPart())
mat = dicBoneRestMatrix[bone.getName()].rotationPart()
vec2 = Mathutils.MatMultVec (mat, vec-vec3)
return vec2
#########
# Cette fonction
# in :
# out :
#########
def computeScaledPos(vec):
global scalef
vec2 = Mathutils.Vector([vec[0]*scalef, vec[1]*scalef, vec[2]*scalef])
@@ -277,31 +253,28 @@ def computeScaledPos(vec):
# out :
#########
def createBone (armature, empty, bone, empties):
global bonerest, emprest
children = getChildren(empty, empties)
for ch in children:
if len(children) != 0:
for ch in children:
if len(children) >= 2:
bonename = empty.getName()[1:len(empty.getName())]+'_'+ch.getName()[1:len(ch.getName())]
else :
bonename = empty.getName()[1:len(empty.getName())]
b=Blender.Armature.Bone.New(bonename)
b.setHead(computeScaledPos(empty.getMatrix('worldspace').translationPart()))
b.setTail(computeScaledPos(ch.getMatrix('worldspace').translationPart()))
#b.setParent(bone)
matrice = empty.getMatrix('worldspace')
invmatrice = empty.getMatrix('worldspace')
invmatrice.invert()
invmatricet=empty.getMatrix('worldspace')
invmatricet.invert()
invmatricet.transpose()
dicEmptiesRestMatrix[empty.getName()] = matrice
dicEmptiesInvRestMatrix[empty.getName()] = invmatrice
armature.addBone(b)
invbonerest=b.getRestMatrix()
invbonerest.invert()
dicBoneRestMatrix[b.getName()] = b.getRestMatrix()
dicBoneRestInvEmpRest[b.getName()]=b.getRestMatrix()*invmatrice*invmatricet
dicEmpRestInvBoneRest[b.getName()]=matrice*invbonerest
dicBone[b.getName()]=b
print "creating Bone %s"%(bonename)
b=Blender.Armature.Editbone()
b.head = (computeScaledPos(empty.getMatrix('worldspace').translationPart()))
b.tail = (computeScaledPos(ch.getMatrix('worldspace').translationPart()))
b.parent = bone
# armature.makeEditable() should already be editable????
armature.bones[bonename] = b
#print b.matrix
bonerest[bonename]=Blender.Mathutils.Matrix(b.matrix).resize4x4()
emprest[empty.getName()]=Blender.Mathutils.Matrix(empty.getMatrix('localspace')).resize4x4()
#M = Blender.Mathutils.Matrix(emprest[empty.getName()])
#emp2bone[bonename] = Blender.Mathutils.Matrix(M.invert().rotationPart()*bonerest[bonename].rotationPart()).resize4x4()
#print emp2bone[bonename].rotationPart().toEuler()
dicBone[b.name]=b
createBone(armature, ch, b, empties)
#########
@@ -310,13 +283,12 @@ def createBone (armature, empty, bone, empties):
# out :
#########
def f_createBone (armData, empty, bone, empties):
bones = armData.getBones()
bones = armData.bones.values()
def getBone(bonename):
bone = None
for b in bones:
#print b.getName()
if b.getName() == bonename:
if b.name == bonename:
bone = b
return bone
@@ -328,56 +300,41 @@ def f_createBone (armData, empty, bone, empties):
bonename = empty.getName()[1:len(empty.getName())]
#b=Blender.Armature.Bone.New(bonename)
b=getBone(bonename)
#b.setHead(empty.getMatrix('worldspace').translationPart())
#b.setTail(ch.getMatrix('worldspace').translationPart())
#b.setParent(bone)
matrice = empty.getMatrix('worldspace')
invmatrice = empty.getMatrix('worldspace')
invmatrice.invert()
invmatricet=empty.getMatrix('worldspace')
invmatricet.invert()
invmatricet.transpose()
dicEmptiesRestMatrix[empty.getName()] = matrice
dicEmptiesInvRestMatrix[empty.getName()] = invmatrice
#armature.addBone(b)
invbonerest=b.getRestMatrix()
invbonerest.invert()
dicBoneRestMatrix[b.getName()] = b.getRestMatrix()
dicBoneRestInvEmpRest[b.getName()]=b.getRestMatrix()*invmatrice*invmatricet
dicEmpRestInvBoneRest[b.getName()]=matrice*invbonerest
dicBone[b.getName()]=b
b.head = (computeScaledPos(empty.getMatrix('worldspace').translationPart()))
b.tail = (computeScaledPos(ch.getMatrix('worldspace').translationPart()))
b.parent = bone
bonerest[bonename]=Blender.Mathutils.Matrix(b.matrix).resize4x4()
emprest[empty.getName()]=Blender.Mathutils.Matrix(empty.getMatrix('localspace')).resize4x4()
dicBone[b.name]=b
#print "Ajout de ", b.getName()," au dictionnaire"
f_createBone(armData, ch, b, empties)
#########
# Cette fonction fabrique une arma
# in :
# out :
#########
def createArmature (rootEmpty, empties):
armData=Blender.Armature.New('monArmature')
def createArmature (armObj, rootEmpty, empties):
global bonerest, emprest
armData=Blender.Armature.Armature('monArmature')
children = getChildren(rootEmpty, empties)
armObj.link(armData)
armData.makeEditable()
for ch in children:
b=Blender.Armature.Bone.New(rootEmpty.getName()[1:len(rootEmpty.getName())] + ch.getName()[1:len(ch.getName())])
b.setHead(computeScaledPos(rootEmpty.getMatrix('worldspace').translationPart()))
b.setTail(computeScaledPos(ch.getMatrix('worldspace').translationPart()))
armData.addBone(b)
matrice = ch.getMatrix('worldspace')
invmatrice = ch.getMatrix('worldspace')
invmatrice.invert()
invmatricet=ch.getMatrix('worldspace')
invmatricet.invert()
invmatricet.transpose()
dicEmptiesRestMatrix[rootEmpty.getName()] = matrice
dicEmptiesInvRestMatrix[rootEmpty.getName()] = invmatrice
invbonerest=b.getRestMatrix()
invbonerest.invert()
dicBoneRestMatrix[b.getName()] = b.getRestMatrix()
dicBoneRestInvEmpRest[b.getName()]=b.getRestMatrix()*invmatrice*invmatricet
dicEmpRestInvBoneRest[b.getName()]=matrice*invbonerest
dicBone[b.getName()]=b
b=Blender.Armature.Editbone()
bonename = rootEmpty.getName()[1:len(rootEmpty.getName())] + ch.getName()[1:len(ch.getName())]
print "creating Bone %s"%(bonename)
#print b, dir([b])
b.head=(computeScaledPos(rootEmpty.getMatrix('worldspace').translationPart()))
b.tail=(computeScaledPos(ch.getMatrix('worldspace').translationPart()))
bonerest[bonename]=Blender.Mathutils.Matrix(b.matrix).resize4x4()
emprest[rootEmpty.getName()]=Blender.Mathutils.Matrix(rootEmpty.getMatrix('localspace')).resize4x4()
armData.bones[bonename] = b
dicBone[b.name]=b
createBone(armData, ch, b, empties)
armData.update()
return armData
@@ -388,37 +345,27 @@ def createArmature (rootEmpty, empties):
# out :
#########
def f_createArmature (rootEmpty, empties, armData):
bones = armData.getBones()
armData.makeEditable()
bones = armData.bones.values()
def getBone(bonename):
bone = None
for b in bones:
#print b.getName()
if b.getName() == bonename:
if b.name == bonename:
bone = b
return bone
children = getChildren(rootEmpty, empties)
for ch in children:
b=getBone(rootEmpty.getName()[1:len(rootEmpty.getName())] + ch.getName()[1:len(ch.getName())])
matrice = ch.getMatrix('worldspace')
invmatrice = ch.getMatrix('worldspace')
invmatrice.invert()
invmatricet=ch.getMatrix('worldspace')
invmatricet.invert()
invmatricet.transpose()
dicEmptiesRestMatrix[rootEmpty.getName()] = matrice
dicEmptiesInvRestMatrix[rootEmpty.getName()] = invmatrice
invbonerest=b.getRestMatrix()
invbonerest.invert()
dicBoneRestMatrix[b.getName()] = b.getRestMatrix()
dicBoneRestInvEmpRest[b.getName()]=b.getRestMatrix()*invmatrice*invmatricet
dicEmpRestInvBoneRest[b.getName()]=matrice*invbonerest
dicBone[b.getName()]=b
dicBone[b.name]=b
#print "Ajout de ", b.getName()," au dictionnaire"
bonerest[b.name]=Blender.Mathutils.Matrix(b.matrix).resize4x4()
emprest[rootEmpty.getName()]=Blender.Mathutils.Matrix(rootEmpty.getMatrix('localspace')).resize4x4()
f_createBone(armData, ch, b, empties)
armData.update()
#########
@@ -426,20 +373,34 @@ def f_createArmature (rootEmpty, empties, armData):
# in :
# out :
#########
def moveBones(armature, empty, empties):
def moveBones(larmature, empty, empties):
#print "move bones"
global bonerest, emprest
children = dicEmptyChild[empty.getName()]
thepose = larmature.getPose()
for ch in children:
if len(children) >= 2:
bonename = empty.getName()[1:len(empty.getName())]+'_'+ch.getName()[1:len(ch.getName())]
else :
bonename = empty.getName()[1:len(empty.getName())]
bone = dicBone[bonename]
#bone.setLoc(computeRootPos(empty,bone))
bone.setLoc(computeRelativePos(empty,bone))
bone.setQuat(computeRootQuat2(empty,bone))
chch = dicEmptyChild[ch.getName()]
thebone = thepose.bones[bonename]
trMatrix = empty.getMatrix('localspace')
bonerestmat = Blender.Mathutils.Matrix(bonerest[bonename])
invbonerestmat = Blender.Mathutils.Matrix(bonerest[bonename])
invbonerestmat.invert()
trMatrix[3][0] = 0.0
trMatrix[3][1] = 0.0
trMatrix[3][2] = 0.0
invemprestmat = Blender.Mathutils.Matrix(emprest[empty.getName()].rotationPart()).resize4x4()
invemprestmat.invert()
emprestmat = Blender.Mathutils.Matrix(emprest[empty.getName()].rotationPart()).resize4x4()
thebone.localMatrix = bonerestmat* invemprestmat *trMatrix * invbonerestmat
thepose.update()
thebone.insertKey(larmature, Blender.Get('curframe'), [Blender.Object.Pose.ROT, Blender.Object.Pose.LOC])
thepose.update()
chch = dicEmptyChild[ch.getName()]
if len(chch) >= 1:
moveBones(armature, ch, empties)
moveBones(larmature, ch, empties)
#########
@@ -447,26 +408,20 @@ def moveBones(armature, empty, empties):
# in :
# out :
#########
def moveArmature (armature, empties):
def moveArmature (larmature, empties):
global bonerest, emprest
#print "move armature"
thepose = larmature.getPose()
#armature.makeEditable()
root = Blender.Object.Get(hipbonename)
children = dicEmptyChild[hipbonename]
for ch in children:
b=dicBone[hipbonename[1:len(hipbonename)] + ch.getName()[1:len(ch.getName())]]
#b.setLoc(computeRootPos(root, b))
b.setLoc([0.0, 0.0, 0.0])
b.setQuat(computeRootQuat2(root, b))
moveBones(armature, ch, empties)
moveBones(larmature, ch, empties)
#armature.update()
def eraseIPO (objectname):
object = Blender.Object.Get(objectname)
lIpo = object.getIpo()
if lIpo != None:
nbCurves = lIpo.getNcurves()
for i in range(nbCurves):
nbBezPoints = lIpo.getNBezPoints(i)
for j in range(nbBezPoints):
lIpo.delBezPoint(i)
########################################################################
@@ -512,7 +467,7 @@ def Main():
lesEmpties = getEmpties()
#print dicEmptyChild
print "creating armature"
#armData = createArmature(em0, lesEmpties)
objects = Blender.Object.Get()
if 'OBArmature' in map(names,objects):
@@ -523,15 +478,16 @@ def Main():
#print armData.getBones()
f_createArmature(em0, lesEmpties, armData)
else:
armData= createArmature(em0, lesEmpties)
armObj=Blender.Object.New('Armature', 'OBArmature')
armObj.link(armData)
armData= createArmature(armObj, em0, lesEmpties)
#armObj.link(armData)
scn = Blender.Scene.getCurrent()
scn.link (armObj)
print 'OBArmature'+' was created'
#return myobj
print emprest
armData.drawType = Blender.Armature.STICK
##-----------
## Creation de l'ipo de l'armature
##-----------
@@ -540,7 +496,11 @@ def Main():
curvX = GetOrCreateCurve(lipo, 'LocX')
curvY = GetOrCreateCurve(lipo, 'LocY')
curvZ = GetOrCreateCurve(lipo, 'LocZ')
curvrX = GetOrCreateCurve(lipo, 'RotX')
curvrY = GetOrCreateCurve(lipo, 'RotY')
curvrZ = GetOrCreateCurve(lipo, 'RotZ')
print "animating armature"
#armData.drawAxes(1)
#armData.drawNames(1)
@@ -549,13 +509,16 @@ def Main():
Blender.Redraw()
action = Blender.Armature.NLA.NewAction()
action.setActive(armObj)
##-----------
## Enregistrement de la position de l'armature
##-----------
bones = armData.getBones()
for bo in bones:
bo.setPose([Blender.Armature.Bone.ROT, Blender.Armature.Bone.LOC])
bones = armData.bones.values()
curvX.addBezier((Blender.Get("curframe"), getEmpty(hipbonename).getMatrix('worldspace').translationPart()[0]*scalef))
curvY.addBezier((Blender.Get("curframe"), getEmpty(hipbonename).getMatrix('worldspace').translationPart()[1]*scalef))
@@ -566,6 +529,12 @@ def Main():
curvY.setExtrapolation('Constant')
curvZ.setInterpolation('Linear')
curvZ.setExtrapolation('Constant')
curvrX.setInterpolation('Linear')
curvrX.setExtrapolation('Constant')
curvrY.setInterpolation('Linear')
curvrY.setExtrapolation('Constant')
curvrZ.setInterpolation('Linear')
curvrZ.setExtrapolation('Constant')
Blender.Redraw()
@@ -576,18 +545,19 @@ def Main():
## Positionnement des os
##-----------
moveArmature(armData, lesEmpties)
moveArmature(armObj, lesEmpties)
##-----------
## Enregistrement de la position de l'armature
##-----------
for bo in bones:
bo.setPose([Blender.Armature.Bone.ROT, Blender.Armature.Bone.LOC])
curvX.addBezier((Blender.Get("curframe"), (getEmpty(hipbonename).getMatrix('worldspace').translationPart()[0])*scalef))
curvY.addBezier((Blender.Get("curframe"), (getEmpty(hipbonename).getMatrix('worldspace').translationPart()[1])*scalef))
curvZ.addBezier((Blender.Get("curframe"), (getEmpty(hipbonename).getMatrix('worldspace').translationPart()[2])*scalef))
curvrX.addBezier((Blender.Get("curframe"), (getEmpty(hipbonename).getMatrix('worldspace').rotationPart().toEuler()[0])*scalef/10))
curvrY.addBezier((Blender.Get("curframe"), (getEmpty(hipbonename).getMatrix('worldspace').rotationPart().toEuler()[1])*scalef/10))
curvrZ.addBezier((Blender.Get("curframe"), (getEmpty(hipbonename).getMatrix('worldspace').rotationPart().toEuler()[2])*scalef/10))
##-----------
## Passage a la frame suivante
@@ -596,6 +566,12 @@ def Main():
print num_frame
Blender.Set("curframe", num_frame)
curvX.Recalc()
curvY.Recalc()
curvZ.Recalc()
curvrX.Recalc()
curvrY.Recalc()
curvrZ.Recalc()
Blender.Set("curframe",startframe)
Blender.Redraw()
@@ -627,26 +603,35 @@ def button_event(evt):
global endframe, startframe, insertionframe, hipbonename, framedecimation , scalef
if evt==1:
startframe = SFrame2.val
insertionframe = IFrame.val
insertionframe = 100 #IFrame.val
endframe = EFrame.val
hipbonename = HBName.val
framedecimation = FrameDecimation.val
scalef= eval(str(ScaleF.val))
scalef= 1.0 #eval(str(ScaleF.val))
#print "scalef = ", scalef
if startframe>=endframe:
Msg = 'Start frame must be lower than End frame'
error_txt = "Error|Start frame must be lower than End frame"
Blender.Draw.PupMenu(error_txt)
else:
ob = getEmpty(hipbonename)
if (ob!=None):
if ob.getParent()!=None:
Msg = 'Empty '+hipbonename+ ' is not a root bone.'
error_txt = "Error|Empty %s is not a root bone"%hipbonename
Blender.Draw.PupMenu(error_txt)
else:
if (0.0 > scalef):
Msg = 'Scale factor must be greater than 0'
error_txt = "Error|Scale factor must be greater than 0"
Blender.Draw.PupMenu(error_txt)
else:
#Blender.Draw.Exit()
Main()
#Main()
else:
error_txt = "Error|Empty %s not found"%hipbonename
Blender.Draw.PupMenu(error_txt)
Msg = 'Empty '+ hipbonename+ ' not found'
#Blender.Draw.Redraw(1)
@@ -655,6 +640,9 @@ def button_event(evt):
ob = getEmpty(hipbonename)
if (ob!=None):
if ob.getParent()!=None:
error_txt = "Error|Empty %s is not a root bone"%hipbonename
Blender.Draw.PupMenu(error_txt)
Msg = 'Empty '+hipbonename+ ' is not a root bone.'
else:
#Blender.Draw.Exit()
@@ -671,15 +659,17 @@ def GUI():
Blender.BGL.glClear(Blender.BGL.GL_COLOR_BUFFER_BIT)
Blender.BGL.glColor3f(1,1,1)
Blender.BGL.glRasterPos2i(20,200)
Blender.Draw.Text ("BVH 2 ARMATURE v2.2 by Jean-Baptiste PERIN", 'normal')
HBName = Blender.Draw.String("HipBoneName: ", 0, 20, 175, 250, 20, '_Hips', 100)
selobj = Blender.Object.GetSelected()
if len(selobj) == 1 and type (selobj[0]) == Blender.Types.ObjectType:
hipname = selobj[0].getName()
else:
hipname = '_Hips'
Blender.Draw.Text ("BVH 2 ARMATURE v%s by %s"%(__version__, __author__), 'normal')
HBName = Blender.Draw.String("HipBoneName: ", 0, 20, 175, 250, 20, hipname, 100)
SFrame2 = Blender.Draw.Number("Startframe: ", 0, 20, 150, 250, 20, 1, 1,3000,"Start frame of anim")
EFrame = Blender.Draw.Number("Endframe: ", 0, 20, 125, 250, 20, Blender.Get("endframe"), 1,3000,"Last frame of anim")
#IFrame = Blender.Draw.Number("Insertionframe: ", 0, 20, 100, 250, 20, Blender.Get("staframe"), 1,3000,"")
FrameDecimation = Blender.Draw.Number("FrameDecimation: ", 0, 20, 75, 250, 20,5, 1,10,'number of frame to skip between two action keys')
ScaleF = Blender.Draw.Number("Scale: ", 0, 20, 50, 250, 20, 1.0, 0.0, 10.0, 'Scale Factor')
FrameDecimation = Blender.Draw.Number("FrameDecimation: ", 0, 20, 75, 250, 20,1, 1,10,'number of frame to skip between two action keys')
Blender.Draw.Toggle("Create Armature", 1, 20, 10, 100, 20, 0, "Create Armature")
#Blender.Draw.Toggle("Remove Empties", 2, 200, 10, 100, 20, 0, "Remove Empties")
Blender.BGL.glRasterPos2i(20,40)
Blender.Draw.Text (Msg, 'normal')

View File

@@ -9,7 +9,7 @@ Tip: 'Export a (.bvh) motion capture file'
__author__ = "Campbell Barton"
__url__ = ("blender", "elysiun")
__version__ = "1.0 03/30/04"
__version__ = "1.1 12/16/05"
__bpydoc__ = """\
This script exports animation data to BVH motion capture file format.
@@ -30,12 +30,11 @@ Notes:<br>
# BVH Export script 1.0 by Campbell Barton #
# Copyright MetaVR 30/03/2004, #
# if you have any questions about this script #
# email me ideasman@linuxmail.org #
# #
# email me cbarton@metavr.com #
#===============================================#
# --------------------------------------------------------------------------
# BVH Export v0.9 by Campbell Barton (AKA Ideasman)
# BVH Export v1.1 by Campbell Barton (AKA Ideasman)
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
@@ -46,12 +45,12 @@ Notes:<br>
#
# 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
# 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.
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
@@ -59,348 +58,328 @@ Notes:<br>
import Blender
from Blender import Scene, Object
import math
time = Blender.sys.time
from math import *
# Get the current scene.
scn = Scene.GetCurrent()
context = scn.getRenderingContext()
frameRate = 0.3333 # 0.04 = 25fps
scale = 1
frameRate = 1.0/context.framesPerSec() # 0.04 = 25fps
scale = 1.0
indent = ' ' # 2 space indent per object
indent = '\t' # 2 space indent per object
prefixDelimiter = '_'
# Vars used in eular rotation funtcion
RAD_TO_DEG = 180.0/3.14159265359
DEG_TO_RAD = math.pi/180.0
#====================================================#
# Search for children of this object and return them #
#====================================================#
def getChildren(parent):
children = [] # We'll assume none.
for child in Object.Get():
if child.getParent() == Object.Get(parent):
children.append( child.getName() )
return children
children = [] # We'll assume none.
for child in Object.Get():
if child.parent == parent:
children.append( child )
return children
#====================================================#
# MESSY BUT WORKS: Make a string that shows the #
# hierarchy as a list and then eval it #
# MESSY BUT WORKS: Make a string that shows the #
# hierarchy as a list and then eval it #
#====================================================#
def getHierarchy(root, hierarchy):
hierarchy = hierarchy + '["' + root + '",'
for child in getChildren(root):
hierarchy = getHierarchy(child, hierarchy)
hierarchy += '],'
return hierarchy
hierarchy = '%s["%s",' % (hierarchy, root.name)
for child in getChildren(root):
hierarchy = getHierarchy(child, hierarchy)
hierarchy = '%s],' % hierarchy
return hierarchy
#====================================================#
# Strips the prefix off the name before writing #
# Strips the prefix off the name before writing #
#====================================================#
def stripName(name): # name is a string
# WARNING!!! Special case for a custom RIG for output
# for MetaVR's HPX compatable RIG.
print 'stripname', name[0:10]
if name[0:10] == 'Transform(':
name = name[10:]
while name[-1] != ')':
name = name[0:-1]
print name
name = name[:-1]
return name[1+name.find(prefixDelimiter): ]
#====================================================#
# Return a 6 deciaml point floating point value #
# as a string that dosent have any python chars #
#====================================================#
def saneFloat(float):
#return '%(float)b' % vars() # 6 fp as house.hqx
return str('%f' % float) + ' '
# WARNING!!! Special case for a custom RIG for output
# for MetaVR's HPX compatable RIG.
# print 'stripname', name[0:10]
if name.lower().startswith('transform('):
name = name[10:].split(prefixDelimiter)[0]
return name.split('_')[0]
#====================================================#
# Recieves an object name, gets all the data for that#
# node from blender and returns it for formatting #
# and writing to a file. #
#====================================================#
def getNodeData(nodeName):
Object.Get(nodeName)
# Get real location
offset = Object.Get(nodeName).getLocation()
offset = (offset[0]*scale, offset[1]*scale, offset[2]*scale,)
#=========================#
# Test for X/Y/Z IPO's #
#=========================#
obipo = Object.Get(nodeName).getIpo()
# IF we dont have an IPO then dont check the curves.
# This was added to catch end nodes that never have an IPO, only an offset.
if obipo == None:
xloc=yloc=zloc=xrot=yrot=zrot = 0
else: # Do have an IPO, checkout which curves are in use.
# Assume the rot's/loc's exist until proven they dont
xloc=yloc=zloc=xrot=yrot=zrot = 1
if obipo.getCurve('LocX') == None:
xloc = 0
if obipo.getCurve('LocY') == None:
yloc = 0
if obipo.getCurve('LocZ') == None:
zloc = 0
# Now for the rotations, Because of the conversion of rotation coords
# if there is one rotation er need to store all 3
if obipo.getCurve('RotX') == None and \
obipo.getCurve('RotY') == None and \
obipo.getCurve('RotZ') == None:
xrot=yrot=zrot = 0
# DUMMY channels xloc, yloc, zloc, xrot, yrot, zrot
# [<bool>, <bool>, <bool>, <bool>, <bool>, <bool>]
channels = [xloc, yloc, zloc, xrot, yrot, zrot]
return offset, channels
def getNodeData(nodeOb):
ob = nodeOb
obipo = ob.getIpo()
# Get real location
offset = [o*scale for o in ob.getLocation()]
#=========================#
# Test for X/Y/Z IPO's #
#=========================#
# IF we dont have an IPO then dont check the curves.
# This was added to catch end nodes that never have an IPO, only an offset.
# DUMMY channels xloc, yloc, zloc, xrot, yrot, zrot
# [<bool>, <bool>, <bool>, <bool>, <bool>, <bool>]
channels = [0,0,0,0,0,0] # xloc,yloc,zloc,xrot,yrot,zrot
if obipo != None: # Do have an IPO, checkout which curves are in use.
# Assume the rot's/loc's dont exist until they proven they do.
if obipo.getCurve('LocX') != None:
channels[0] = 1
if obipo.getCurve('LocY') != None:
channels[1] = 1
if obipo.getCurve('LocZ') != None:
channels[2] = 1
# Now for the rotations, Because of the conversion of rotation coords
# if there is one rotation er need to store all 3
if obipo.getCurve('RotX') != None or \
obipo.getCurve('RotY') != None or \
obipo.getCurve('RotZ') != None:
channels[3] = channels[4] = channels[5] = 1
#print ob, channels
return offset, channels
#====================================================#
# Return the BVH hierarchy to a file from a list #
# Writes the BVH hierarchy to a file #
# hierarchy: is a list of the empty hierarcht #
# bvhHierarchy: a string, in the bvh format to write #
# level: how many levels we are down the tree, #
# ...used for indenting #
# Also gathers channelList , so we know the order to #
# write the motiondata in #
# write the motiondata in #
#====================================================#
def hierarchy2bvh(hierarchy, bvhHierarchy, level, channelList, nodeObjectList):
nodeName = hierarchy[0]
# Add object to nodeObjectList
nodeObjectList.append(Object.Get(nodeName))
#============#
# JOINT NAME #
#============#
bvhHierarchy += level * indent
if level == 0:
# Add object to nodeObjectList
nodeObjectList.append(Object.Get(nodeName))
bvhHierarchy+= 'ROOT '
bvhHierarchy += stripName(nodeName) + '\n'
# If this is the last object in the list then we
# dont bother withwriting its real name, use "End Site" instead
elif len(hierarchy) == 1:
bvhHierarchy+= 'End Site\n'
# Ok This is a normal joint
else:
# Add object to nodeObjectList
nodeObjectList.append(Object.Get(nodeName))
bvhHierarchy+= 'JOINT '
bvhHierarchy += stripName(nodeName) + '\n'
#================#
# END JOINT NAME #
#================#
def hierarchy2bvh(file, hierarchy, level, channelList, nodeObjectList):
nodeName = hierarchy[0]
ob = Object.Get(nodeName)
'''
obipo = ob.getIpo()
if obipo != None:
obcurves = obipo.getCurves()
else:
obcurves = None
'''
#============#
# JOINT NAME #
#============#
file.write(level * indent)
if level == 0:
# Add object to nodeObjectList
#nodeObjectList.append( (ob, obipo, obcurves) )
nodeObjectList.append( ob )
file.write( 'ROOT %s\n' % stripName(nodeName) )
# If this is the last object in the list then we
# dont bother withwriting its real name, use "End Site" instead
elif len(hierarchy) == 1:
file.write( 'End Site\n' )
# Ok This is a normal joint
else:
# Add object to nodeObjectList
#nodeObjectList.append((ob, obipo, obcurves))
nodeObjectList.append( ob )
file.write( 'JOINT %s\n' % stripName(nodeName) )
#================#
# END JOINT NAME #
#================#
# Indent again, this line is just for the brackets
file.write( '%s{\n' % (level * indent) )
# Indent again, this line is just for the brackets
bvhHierarchy += level * indent + '{' + '\n'
# Indent
level += 1
#================================================#
# Data for writing to a file offset and channels #
#================================================#
offset, channels = getNodeData(ob)
#============#
# Offset #
#============#
file.write( '%sOFFSET %.6f %.6f %.6f\n' %\
(level*indent, scale*offset[0], scale*offset[1], scale*offset[2]) )
#============#
# Channels #
#============#
if len(hierarchy) != 1:
# Channels, remember who is where so when we write motiondata
file.write('%sCHANNELS %i ' % (level*indent, len([c for c in channels if c ==1]) ))
if channels[0]:
file.write('Xposition ')
channelList.append([len(nodeObjectList)-1, 0])
if channels[1]:
file.write('Yposition ')
channelList.append([len(nodeObjectList)-1, 1])
if channels[2]:
file.write('Zposition ')
channelList.append([len(nodeObjectList)-1, 2])
if channels[5]:
file.write('Zrotation ')
channelList.append([len(nodeObjectList)-1, 5])
if channels[3]:
file.write('Xrotation ')
channelList.append([len(nodeObjectList)-1, 3])
if channels[4]:
file.write('Yrotation ')
channelList.append([len(nodeObjectList)-1, 4])
file.write('\n')
# Indent
level += 1
#================================================#
# Data for writing to a file offset and channels #
#================================================#
offset, channels = getNodeData(nodeName)
#============#
# Offset #
#============#
bvhHierarchy += level * indent + 'OFFSET ' + saneFloat(scale * offset[0]) + ' ' + saneFloat(scale * offset[1]) + ' ' + saneFloat(scale * offset[2]) + '\n'
#============#
# Channels #
#============#
if len(hierarchy) != 1:
# Channels, remember who is where so when we write motiondata
bvhHierarchy += level * indent + 'CHANNELS '
# Count the channels
chCount = 0
for chn in channels:
chCount += chn
bvhHierarchy += str(chCount) + ' '
if channels[0]:
bvhHierarchy += 'Xposition '
channelList.append([len(nodeObjectList)-1, 0])
if channels[1]:
bvhHierarchy += 'Yposition '
channelList.append([len(nodeObjectList)-1, 1])
if channels[2]:
bvhHierarchy += 'Zposition '
channelList.append([len(nodeObjectList)-1, 2])
if channels[5]:
bvhHierarchy += 'Zrotation '
channelList.append([len(nodeObjectList)-1, 5])
if channels[3]:
bvhHierarchy += 'Xrotation '
channelList.append([len(nodeObjectList)-1, 3])
if channels[4]:
bvhHierarchy += 'Yrotation '
channelList.append([len(nodeObjectList)-1, 4])
bvhHierarchy += '\n'
# Loop through children if any and run this function (recursively)
for hierarchyIdx in range(len(hierarchy)-1):
bvhHierarchy, level, channelList, nodeObjectList = hierarchy2bvh(hierarchy[hierarchyIdx+1], bvhHierarchy, level, channelList, nodeObjectList)
# Unindent
level -= 1
bvhHierarchy += level * indent + '}' + '\n'
return bvhHierarchy, level, channelList, nodeObjectList
# Loop through children if any and run this function (recursively)
for hierarchyIdx in range(len(hierarchy)-1):
level = hierarchy2bvh(file, hierarchy[hierarchyIdx+1], level, channelList, nodeObjectList)
# Unindent
level -= 1
file.write('%s}\n' % (level * indent))
return level
# added by Ben Batt 30/3/2004 to make the exported rotations correct
def ZYXToZXY(x, y, z):
'''
Converts a set of Euler rotations (x, y, z) (which are intended to be
applied in z, y, x order) into a set which are intended to be applied in
z, x, y order (the order expected by .bvh files)
'''
A,B = cos(x),sin(x)
C,D = cos(y),sin(y)
E,F = cos(z),sin(z)
'''
Converts a set of Euler rotations (x, y, z) (which are intended to be
applied in z, y, x order, into a set which are intended to be applied in
z, x, y order (the order expected by .bvh files)
'''
A,B = cos(x),sin(x)
C,D = cos(y),sin(y)
E,F = cos(z),sin(z)
x = asin(-B*C)
y = atan2(D, A*C)
z = atan2(-B*D*E + A*F, B*D*F + A*E)
x = asin(-B*C)
y = atan2(D, A*C)
z = atan2(-B*D*E + A*F, B*D*F + A*E)
# this seems to be necessary - not sure why (right/left-handed coordinates?)
x = -x
return x*RAD_TO_DEG, y*RAD_TO_DEG, z*RAD_TO_DEG
# this seems to be necessary - not sure why (right/left-handed coordinates?)
# x = -x # x is negative, see below.
return -x*RAD_TO_DEG, y*RAD_TO_DEG, z*RAD_TO_DEG
def getIpoLocation(object, frame):
x = y = z = 0
obipo = object.getIpo()
for i in range(object.getIpo().getNcurves()):
if obipo.getCurves()[i].getName() =='LocX':
x = object.getIpo().EvaluateCurveOn(i,frame)
elif obipo.getCurves()[i].getName() =='LocY':
y = object.getIpo().EvaluateCurveOn(i,frame)
elif obipo.getCurves()[i].getName() =='LocZ':
z = object.getIpo().EvaluateCurveOn(i,frame)
return x, y, z
''' # UNUSED, JUST GET OBJECT LOC/ROT
def getIpoLocation(object, obipo, curves, frame):
x = y = z = rx = ry = rz =0
if obipo:
for i in range(obipo.getNcurves()):
if curves[i].getName() =='LocX':
x = obipo.EvaluateCurveOn(i,frame)
elif curves[i].getName() =='LocY':
y = obipo.EvaluateCurveOn(i,frame)
elif curves[i].getName() =='LocZ':
z = obipo.EvaluateCurveOn(i,frame)
elif curves[i].getName() =='RotX':
rx = obipo.EvaluateCurveOn(i,frame)
elif curves[i].getName() =='RotY':
ry = obipo.EvaluateCurveOn(i,frame)
elif curves[i].getName() =='RotZ':
rz = obipo.EvaluateCurveOn(i,frame)
return x, y, z, rx*10*DEG_TO_RAD, ry*10*DEG_TO_RAD, rz*10*DEG_TO_RAD
'''
#====================================================#
# Return the BVH motion for the spesified frame #
# hierarchy: is a list of the empty hierarcht #
# bvhHierarchy: a string, in the bvh format to write #
# level: how many levels we are down the tree, #
# ...used for indenting #
#====================================================#
def motion2bvh(frame, chennelList, nodeObjectList):
motionData = '' # We'll append the frames to the string.
for chIdx in chennelList:
ob = nodeObjectList[chIdx[0]]
chType = chIdx[1]
# Get object rotation
x, y, z = ob.getEuler()
# Convert the rotation from ZYX order to ZXY order
x, y, z = ZYXToZXY(x, y, z)
# Using regular Locations stuffs upIPO locations stuffs up
# Get IPO locations instead
xloc, yloc, zloc = getIpoLocation(ob, frame)
# WARNING non standard Location
xloc, zloc, yloc = -xloc, yloc, zloc
if chType == 0:
motionData += saneFloat(scale * (xloc))
if chType == 1:
motionData += saneFloat(scale * (yloc))
if chType == 2:
motionData += saneFloat(scale * (zloc))
if chType == 3:
motionData += saneFloat(x)
if chType == 4:
motionData += saneFloat(y)
if chType == 5:
motionData += saneFloat(z)
motionData += ' '
motionData += '\n'
return motionData
def motion2bvh(file, frame, chennelList, nodeObjectList):
for chIdx in chennelList:
#ob, obipo, obcurves = nodeObjectList[chIdx[0]]
ob = nodeObjectList[chIdx[0]]
chType = chIdx[1]
# Get object rotation
x, y, z = ob.getEuler()
# Convert the rotation from ZYX order to ZXY order
x, y, z = ZYXToZXY(x, y, z)
# Location
xloc, yloc, zloc = ob.matrixLocal[3][:3]
# Using regular Locations stuffs upIPO locations stuffs up
# Get IPO locations instead
#xloc, yloc, zloc, x, y, z = getIpoLocation(ob, obipo, obcurves, frame)
# Convert the rotation from ZYX order to ZXY order
#x, y, z = ZYXToZXY(x, y, z)
# WARNING non standard Location
# xloc, zloc, yloc = -xloc, yloc, zloc
if chType == 0:
file.write('%.6f ' % (scale * xloc))
if chType == 1:
file.write('%.6f ' % (scale * yloc))
if chType == 2:
file.write('%.6f ' % (scale * zloc))
if chType == 3:
file.write('%.6f ' % x)
if chType == 4:
file.write('%.6f ' % y)
if chType == 5:
file.write('%.6f ' % z)
file.write('\n')
def saveBVH(filename):
if filename.find('.bvh', -4) <= 0: filename += '.bvh' # for safety
# Here we store a serialized list of blender objects as they appier
# in the hierarchy, this is refred to when writing motiondata
nodeObjectList = []
# In this list we store a 2 values for each node
# 1) An index pointing to a blender object
# in objectList
# 2) The type if channel x/y/z rot:x/y/z - Use 0-5 to indicate this
chennelList = []
print ''
print 'BVH 1.0 by Campbell Barton (Ideasman) - ideasman@linuxmail.org'
# Get the active object and recursively traverse its kids to build
# the BVH hierarchy, then eval the string to make a hierarchy list.
hierarchy = eval(getHierarchy(Object.GetSelected()[0].getName(),''))[0] # somhow this returns a tuple with one list in it.
# Put all data in the file we have selected file.
file = open(filename, "w")
file.write('HIERARCHY\n') # all bvh files have this on the first line
# Write the whole hirarchy to a list
bvhHierarchy, level, chennelList, nodeObjectList = hierarchy2bvh(hierarchy, '', 0, chennelList, nodeObjectList)
file.write( bvhHierarchy ) # Rwite the var fileBlock to the output.
bvhHierarchy = None # Save a tit bit of memory
#====================================================#
# MOTION: Loop through the frames ande write out #
# the motion data for each #
#====================================================#
# Do some basic motion file header stuff
file.write('MOTION\n')
file.write( 'Frames: ' + str(1 + context.endFrame() - context.startFrame()) + '\n' )
file.write( 'Frame Time: ' + saneFloat(frameRate) + '\n' )
#print 'WARNING- exact frames might be stuffed up- inclusive whatever, do some tests later on.'
frames = range(context.startFrame(), context.endFrame()+1)
print 'exporting ' + str(len(frames)) + ' of motion...'
for frame in frames:
context.currentFrame(frame)
scn.update(1) # Update locations so we can write the new locations
#Blender.Window.RedrawAll() # causes crash
file.write( motion2bvh(frame, chennelList, nodeObjectList) )
file.write('\n') # newline
file.close()
print 'done'
t = time()
if not filename.lower().endswith('.bvh'):
filename += '.bvh' # for safety
# Here we store a serialized list of blender objects as they appier
# in the hierarchy, this is refred to when writing motiondata
nodeObjectList = []
# In this list we store a 2 values for each node
# 1) An index pointing to a blender object
# in objectList
# 2) The type if channel x/y/z rot:x/y/z - Use 0-5 to indicate this
chennelList = []
print '\nBVH 1.1 by Campbell Barton (Ideasman) - cbarton@metavr.com'
# Get the active object and recursively traverse its kids to build
# the BVH hierarchy, then eval the string to make a hierarchy list.
hierarchy = eval(getHierarchy(scn.getActiveObject(),''))[0] # somhow this returns a tuple with one list in it.
# Put all data in the file we have selected file.
file = open(filename, "w")
file.write('HIERARCHY\n') # all bvh files have this on the first line
# Write the whole hirarchy to a list
level = 0 # Indenting level, start with no indent
level = hierarchy2bvh(file, hierarchy, level, chennelList, nodeObjectList)
#====================================================#
# MOTION: Loop through the frames ande write out #
# the motion data for each #
#====================================================#
# Do some basic motion file header stuff
file.write( 'MOTION\n' )
file.write( 'Frames: %i\n' % ( 1 + context.endFrame() - context.startFrame() ) )
file.write( 'Frame Time: %.6f\n' % frameRate )
frames = range(context.startFrame()+1, context.endFrame()+1)
print 'exporting %i of motion...' % len(frames)
for frame in frames:
context.currentFrame(frame)
scn.update(1) # Update locations so we can write the new locations. This is the SLOW part.
# Blender.Window.RedrawAll() # Debugging.
motion2bvh(file, frame, chennelList, nodeObjectList) # Write the motion to a file.
file.write('\n') # newline
file.close()
print '...Done in %.4f seconds.' % (time()-t)
Blender.Window.FileSelector(saveBVH, 'Export BVH')

View File

@@ -2,14 +2,14 @@
"""
Name: 'Motion Capture (.bvh)...'
Blender: 236
Blender: 239
Group: 'Import'
Tip: 'Import a (.bvh) motion capture file'
"""
__author__ = "Campbell Barton"
__url__ = ("blender", "elysiun", "http://jmsoler.free.fr/util/blenderfile/py/bvh_import.py")
__version__ = "1.0.2 04/12/28"
__url__ = ("blender", "elysiun")
__version__ = "1.0.4 05/12/04"
__bpydoc__ = """\
This script imports BVH motion capture data to Blender.
@@ -21,32 +21,52 @@ Missing:<br>
Known issues:<br>
Notes:<br>
Jean-Michel Soler improved importer to support Poser 3.01 files;<br>
Jean-Baptiste Perin wrote a script to create an armature out of the
Jean-Michel Soler improved importer to support Poser 3.01 files;<br>
Jean-Baptiste Perin wrote a script to create an armature out of the
Empties created by this importer, it's in the Scripts window -> Scripts -> Animation menu.
"""
# $Id$
#
#===============================================#
# BVH Import script 1.05 patched by Campbell #
# Modified to use Mathutils for matrix math, #
# Fixed possible joint naming bug, #
# Imports BVH's with bad EOF gracefully #
# Fixed duplicate joint names, make them unique #
# Use \r as well as \n for newlines #
# Added suppot for nodes with 0 motion channels #
# Rotation IPOs never cross more then 180d #
# fixes sub frame tweening and time scaling #
# 5x overall speedup. #
# 06/12/2005, #
#===============================================#
#===============================================#
# BVH Import script 1.04 patched by jms #
# Small modif for blender 2.40 #
# 04/12/2005, #
#===============================================#
#===============================================#
# BVH Import script 1.03 patched by Campbell #
# Small optimizations and scale input #
# 01/01/2005, #
# 01/01/2005, #
#===============================================#
#===============================================#
# BVH Import script 1.02 patched by Jm Soler #
# to the Poser 3.01 bvh file #
# 28/12/2004, #
# to the Poser 3.01 bvh file #
# 28/12/2004, #
#===============================================#
#===============================================#
# BVH Import script 1.0 by Campbell Barton #
# 25/03/2004, euler rotation code taken from #
# Reevan Mckay's BVH import script v1.1 #
# if you have any questions about this script #
# email me ideasman@linuxmail.org #
# if you have any questions about this scrip. #
# email me cbarton@metavr.com #
#===============================================#
#===============================================#
@@ -57,7 +77,7 @@ Empties created by this importer, it's in the Scripts window -> Scripts -> Anima
#===============================================#
# --------------------------------------------------------------------------
# BVH Import v0.9 by Campbell Barton (AKA Ideasman)
# BVH Import v1.05 by Campbell Barton (AKA Ideasman)
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
@@ -68,457 +88,410 @@ Empties created by this importer, it's in the Scripts window -> Scripts -> Anima
#
# 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
# 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.
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
import string
import math
import Blender
from Blender import Window, Object, Scene, Ipo, Draw
from Blender.Scene import Render
# # PSYCO IS CRASHING ON MY SYSTEM
# # Attempt to load psyco, speed things up
# try:
# print 'using psyco to speed up BVH importing'
# import psyco
# psyco.full()
#
# except:
# print 'psyco is not present on this system'
# Default scale
scale = 0.01
# Update as we load?
debug = 0
# Get the current scene.
scn = Scene.GetCurrent()
context = scn.getRenderingContext()
# Here we store the Ipo curves in the order they load.
channelCurves = []
# Object list
# We need this so we can loop through the objects and edit there IPO's
# Chenging there rotation to EULER rotation
objectList = []
def getScale():
return Draw.PupFloatInput('BVH Scale: ', 0.01, 0.001, 10.0, 0.1, 3)
def MAT(m):
if len(m) == 3:
return Blender.Mathutils.Matrix(m[0], m[1], m[2])
elif len(m) == 4:
return Blender.Mathutils.Matrix(m[0], m[1], m[2], m[3])
# Attempt to load psyco, speed things up
try:
import psyco
psyco.full()
print 'using psyco to speed up BVH importing'
except:
#print 'psyco is not present on this system'
pass
#===============================================#
# eulerRotation: converts X, Y, Z rotation #
# to eular Rotation. This entire function #
# is copied from Reevan Mckay's BVH script #
#===============================================#
# Vars used in eular rotation funtcion
DEG_TO_RAD = math.pi/180.0
RAD_TO_DEG = 180.0/math.pi
PI=3.14159
def main():
global scale
scale = None
# Update as we load?
debug = 0
def getScale():
return Draw.PupFloatInput('BVH Scale: ', 0.01, 0.001, 10.0, 0.1, 3)
#===============================================#
# MAIN FUNCTION - All things are done from here #
#===============================================#
def loadBVH(filename):
global scale
print '\nBVH Importer 1.05 by Campbell Barton (Ideasman) - cbarton@metavr.com'
objectCurveMapping = {}
objectNameMapping = {}
objectMotiondataMapping = {}
# Here we store the Ipo curves in the order they load.
channelCurves = []
# Object list
# We need this so we can loop through the objects and edit there IPO's
# Chenging there rotation to EULER rotation
objectList = []
if scale == None:
tempscale = getScale()
if tempscale:
scale = tempscale
else:
scale = 0.01
Window.WaitCursor(1)
# Unique names, dont reuse any of these names.
uniqueObNames = [ob.name for ob in Object.Get()]
# FUNCTIONS ====================================#
def getUniqueObName(name):
i = 0
newname = name[:min(len(name), 12)] # Concatinate to 12 chars
while newname in uniqueObNames:
newname = name + str(i)
i+=1
return newname
# Change the order rotation is applied.
RotationMatrix = Blender.Mathutils.RotationMatrix
MATRIX_IDENTITY_3x3 = Blender.Mathutils.Matrix([1.0,0.0,0.0],[0.0,1.0,0.0],[0.0,0.0,1.0])
def eulerRotate(x,y,z):
x,y,z = x%360,y%360,z%360 # Clamp all values between 0 and 360, values outside this raise an error.
xmat = RotationMatrix(x,3,'x')
ymat = RotationMatrix(y,3,'y')
zmat = RotationMatrix(z,3,'z')
# Standard BVH multiplication order, apply the rotation in the order Z,X,Y
return (ymat*(xmat * (zmat * MATRIX_IDENTITY_3x3))).toEuler()
def eulerRotate(x,y,z):
#=================================
def RVMatMult3 (mat1,mat2):
#=================================
mat3=[[0.0,0.0,0.0],[0.0,0.0,0.0],[0.0,0.0,0.0]]
for i in range(3):
for k in range(3):
for j in range(3):
mat3[i][k]=mat3[i][k]+mat1[i][j]*mat2[j][k]
return mat3
#=================================
def RVAxisAngleToMat3 (rot4):
# Takes a direction vector and
# a rotation (in rads) and
# returns the rotation matrix.
# Graphics Gems I p. 466:
#=================================
mat3=[[0.0,0.0,0.0],[0.0,0.0,0.0],[0.0,0.0,0.0]]
if math.fabs(rot4[3])>0.01:
s=math.sin(rot4[3])
c=math.cos(rot4[3])
t=1.0-math.cos(rot4[3])
else:
s=rot4[3]
c=1.0
t=0.0
currentFrame = 1 # Set the initial frame to import all data to.
#===============================================#
# makeJoint: Here we use the node data #
# from the BVA file to create an empty #
#===============================================#
BVH2BLEND_TX_NAME = {'Xposition':'LocX','Yposition':'LocY','Zposition':'LocZ','Xrotation':'RotX','Yrotation':'RotY','Zrotation':'RotZ'}
def makeJoint(name, parent, offset, channels):
ob = Object.New('Empty', name) # New object, ob is shorter and nicer to use.
objectNameMapping[name] = ob
scn.link(ob) # place the object in the current scene
ob.sel = 1
# Make me a child of another empty.
# Vale of None will make the empty a root node (no parent)
if parent[-1]: # != None
obParent = objectNameMapping[parent[-1]] # We use this a bit so refrence it here.
obParent.makeParent([ob], 1, 0) #ojbs, noninverse, 1 = not fast.
# Offset Empty from BVH's initial joint location.
ob.setLocation(offset[0]*scale, offset[1]*scale, offset[2]*scale)
# Add Ipo's for necessary channels
newIpo = Ipo.New('Object', name)
ob.setIpo(newIpo)
obname = ob.name
for channelType in channels:
channelType = BVH2BLEND_TX_NAME[channelType]
curve = newIpo.addCurve(channelType)
curve.setInterpolation('Linear')
objectCurveMapping[(obname, channelType)] = curve
# Add to object list
objectList.append(ob)
# Redraw if debugging
if debug: Blender.Redraw()
#===============================================#
# makeEnd: Here we make an end node #
# This is needed when adding the last bone #
#===============================================#
def makeEnd(parent, offset):
new_name = parent[-1] + '_end'
ob = Object.New('Empty', new_name) # New object, ob is shorter and nicer to use.
objectNameMapping[new_name] = ob
scn.link(ob)
ob.sel = 1
# Dont check for a parent, an end node MUST have a parent
obParent = objectNameMapping[parent[-1]] # We use this a bit so refrence it here.
obParent.makeParent([ob], 1, 0) #ojbs, noninverse, 1 = not fast.
# Offset Empty
ob.setLocation(offset[0]*scale, offset[1]*scale, offset[2]*scale)
# Redraw if debugging
if debug: Blender.Redraw()
# END FUNCTION DEFINITIONS ====================================#
time1 = Blender.sys.time()
# Get the current scene.
scn = Scene.GetCurrent()
#context = scn.getRenderingContext()
# DeSelect All
for ob in scn.getChildren():
ob.sel = 0
# File loading stuff
# Open the file for importing
file = open(filename, 'r')
# Seperate into a list of lists, each line a list of words.
lines = file.readlines()
# Non standard carrage returns?
if len(lines) == 1:
lines = lines[0].split('\r')
# Split by whitespace.
lines =[ll for ll in [ [w for w in l.split() if w != '\n' ] for l in lines] if ll]
# End file loading code
# Create Hirachy as empties
if lines[0][0] == 'HIERARCHY':
print 'Importing the BVH Hierarchy for:', filename
else:
return 'ERROR: This is not a BVH file'
# A liniar list of ancestors to keep track of a single objects heratage
# at any one time, this is appended and removed, dosent store tree- just a liniar list.
# ZERO is a place holder that means we are a root node. (no parents)
parent = [None]
#channelList, sync with objectList: [[channelType1, channelType2...], [channelType1, channelType2...)]
channelList = []
channelIndex = -1
lineIdx = 0 # An index for the file.
while lineIdx < len(lines) -1:
#...
if lines[lineIdx][0] == 'ROOT' or lines[lineIdx][0] == 'JOINT':
# Join spaces into 1 word with underscores joining it.
if len(lines[lineIdx]) > 2:
lines[lineIdx][1] = '_'.join(lines[lineIdx][1:])
lines[lineIdx] = lines[lineIdx][:2]
# MAY NEED TO SUPPORT MULTIPLE ROOT's HERE!!!, Still unsure weather multiple roots are possible.??
# Make sure the names are unique- Object names will match joint names exactly and both will be unique.
name = getUniqueObName(lines[lineIdx][1])
uniqueObNames.append(name)
print '%snode: %s, parent: %s' % (len(parent) * ' ', name, parent[-1])
lineIdx += 2 # Incriment to the next line (Offset)
offset = ( float(lines[lineIdx][1]), float(lines[lineIdx][2]), float(lines[lineIdx][3]) )
lineIdx += 1 # Incriment to the next line (Channels)
# newChannel[Xposition, Yposition, Zposition, Xrotation, Yrotation, Zrotation]
# newChannel references indecies to the motiondata,
# if not assigned then -1 refers to the last value that will be added on loading at a value of zero, this is appended
# We'll add a zero value onto the end of the MotionDATA so this is always refers to a value.
newChannel = [-1, -1, -1, -1, -1, -1]
for channel in lines[lineIdx][2:]:
channelIndex += 1 # So the index points to the right channel
if channel == 'Xposition':
newChannel[0] = channelIndex
elif channel == 'Yposition':
newChannel[1] = channelIndex
elif channel == 'Zposition':
newChannel[2] = channelIndex
elif channel == 'Xrotation':
newChannel[3] = channelIndex
elif channel == 'Yrotation':
newChannel[4] = channelIndex
elif channel == 'Zrotation':
newChannel[5] = channelIndex
channelList.append(newChannel)
channels = lines[lineIdx][2:]
# Call funtion that uses the gatrhered data to make an empty.
makeJoint(name, parent, offset, channels)
# If we have another child then we can call ourselves a parent, else
parent.append(name)
# Account for an end node
if lines[lineIdx][0] == 'End' and lines[lineIdx][1] == 'Site': # There is somtimes a name after 'End Site' but we will ignore it.
lineIdx += 2 # Incriment to the next line (Offset)
offset = ( float(lines[lineIdx][1]), float(lines[lineIdx][2]), float(lines[lineIdx][3]) )
makeEnd(parent, offset)
# Just so we can remove the Parents in a uniform way- End end never has kids
# so this is a placeholder
parent.append(None)
if len(lines[lineIdx]) == 1 and lines[lineIdx][0] == '}': # == ['}']
parent.pop() # Remove the last item
#=============================================#
# BVH Structure loaded, Now import motion #
#=============================================#
if len(lines[lineIdx]) == 1 and lines[lineIdx][0] == 'MOTION':
print '\nImporting motion data'
lineIdx += 3 # Set the cursor to the first frame
#=============================================#
# Add a ZERO keyframe, this keeps the rig #
# so when we export we know where all the #
# joints start from #
#=============================================#
for obIdx, ob in enumerate(objectList):
obname = ob.name
if channelList[obIdx][0] != -1:
objectCurveMapping[obname, 'LocX'].addBezier((currentFrame,0))
objectMotiondataMapping[obname, 'LocX'] = []
if channelList[obIdx][1] != -1:
objectCurveMapping[obname, 'LocY'].addBezier((currentFrame,0))
objectMotiondataMapping[obname, 'LocY'] = []
if channelList[obIdx][2] != -1:
objectCurveMapping[obname, 'LocZ'].addBezier((currentFrame,0))
objectMotiondataMapping[obname, 'LocZ'] = []
if\
channelList[obIdx][3] != -1 or\
channelList[obIdx][4] != -1 or\
channelList[obIdx][5] != -1:
objectMotiondataMapping[obname, 'RotX'] = []
objectMotiondataMapping[obname, 'RotY'] = []
objectMotiondataMapping[obname, 'RotZ'] = []
#=============================================#
# Loop through frames, each line a frame #
#=============================================#
MOTION_DATA_LINE_LEN = len(lines[lineIdx])
while lineIdx < len(lines):
line = lines[lineIdx]
if MOTION_DATA_LINE_LEN != len(line):
print 'ERROR: Incomplete motion data on line %i, finishing import.' % lineIdx
break
# Exit loop if we are past the motiondata.
# Some BVH's have extra tags like 'CONSTRAINTS and MOTIONTAGS'
# I dont know what they do and I dont care, they'll be ignored here.
if len(line) < len(objectList):
print '...ending on unknown tags'
break
currentFrame += 1 # Incriment to next frame
#=============================================#
# Import motion data and assign it to an IPO #
#=============================================#
line.append(0.0) # Use this as a dummy var for objects that dont have a loc/rotate channel.
if debug: Blender.Redraw()
for obIdx, ob in enumerate(objectList):
obname = ob.name
obChannel = channelList[obIdx]
if channelList[obIdx][0] != -1:
objectMotiondataMapping[obname, 'LocX'].append((currentFrame, scale * float( line[obChannel[0]] )))
if channelList[obIdx][1] != -1:
objectMotiondataMapping[obname, 'LocY'].append((currentFrame, scale * float( line[obChannel[1]] )))
x=rot4[0]; y=rot4[1]; z=rot4[2]
mat3[0][0]=t*x*x+c
mat3[0][1]=t*x*y+s*z
mat3[0][2]=t*x*z-s*y
mat3[1][0]=t*x*y-s*z
mat3[1][1]=t*y*y+c
mat3[1][2]=t*y*z+s*x
mat3[2][0]=t*x*z+s*y
mat3[2][1]=t*y*z-s*x
mat3[2][2]=t*z*z+c
return mat3
eul = [x,y,z]
for jj in range(3):
while eul[jj] < 0:
eul[jj] = eul[jj] + 360.0
while eul[jj] >= 360.0:
eul[jj] = eul[jj] - 360.0
eul[0] = eul[0]*DEG_TO_RAD
eul[1] = eul[1]*DEG_TO_RAD
eul[2] = eul[2]*DEG_TO_RAD
xmat=RVAxisAngleToMat3([1,0,0,eul[0]])
ymat=RVAxisAngleToMat3([0,1,0,eul[1]])
zmat=RVAxisAngleToMat3([0,0,1,eul[2]])
mat=[[1.0,0.0,0.0],[0.0,1.0,0.0],[0.0,0.0,1.0]]
# Standard BVH multiplication order
mat=RVMatMult3 (zmat,mat)
mat=RVMatMult3 (xmat,mat)
mat=RVMatMult3 (ymat,mat)
'''
# Screwy Animation Master BVH multiplcation order
mat=RVMatMult3 (ymat,mat)
mat=RVMatMult3 (xmat,mat)
mat=RVMatMult3 (zmat,mat)
'''
mat = MAT(mat)
eul = mat.toEuler()
x =- eul[0]/-10
y =- eul[1]/-10
z =- eul[2]/-10
return x, y, z # Returm euler roration values.
#===============================================#
# makeJoint: Here we use the node data #
# from the BVA file to create an empty #
#===============================================#
def makeJoint(name, parent, prefix, offset, channels):
global scale
# Make Empty, with the prefix in front of the name
ob = Object.New('Empty', prefix + name) # New object, ob is shorter and nicer to use.
scn.link(ob) # place the object in the current scene
# Offset Empty
ob.setLocation(offset[0]*scale, offset[1]*scale, offset[2]*scale)
# Make me a child of another empty.
# Vale of None will make the empty a root node (no parent)
if parent[-1] != None:
obParent = Object.Get(prefix + parent[-1]) # We use this a bit so refrence it here.
obParent.makeParent([ob], 0, 1) #ojbs, noninverse, 1 = not fast.
# Add Ipo's for necessary channels
newIpo = Ipo.New('Object', prefix + name)
ob.setIpo(newIpo)
for channelType in channels:
if channelType == 'Xposition':
newIpo.addCurve('LocX')
newIpo.getCurve('LocX').setInterpolation('Linear')
if channelType == 'Yposition':
newIpo.addCurve('LocY')
newIpo.getCurve('LocY').setInterpolation('Linear')
if channelType == 'Zposition':
newIpo.addCurve('LocZ')
newIpo.getCurve('LocZ').setInterpolation('Linear')
if channelType == 'Zrotation':
newIpo.addCurve('RotZ')
newIpo.getCurve('RotZ').setInterpolation('Linear')
if channelType == 'Yrotation':
newIpo.addCurve('RotY')
newIpo.getCurve('RotY').setInterpolation('Linear')
if channelType == 'Xrotation':
newIpo.addCurve('RotX')
newIpo.getCurve('RotX').setInterpolation('Linear')
# Add to object list
objectList.append(ob)
# Redraw if debugging
if debug: Blender.Redraw()
#===============================================#
# makeEnd: Here we make an end node #
# This is needed when adding the last bone #
#===============================================#
def makeEnd(parent, prefix, offset):
# Make Empty, with the prefix in front of the name, end nodes have no name so call it its parents name+'_end'
ob = Object.New('Empty', prefix + parent[-1] + '_end') # New object, ob is shorter and nicer to use.
scn.link(ob)
# Dont check for a parent, an end node MUST have a parent
obParent = Object.Get(prefix + parent[-1]) # We use this a bit so refrence it here.
obParent.makeParent([ob], 0, 1) #ojbs, noninverse, 1 = not fast.
# Offset Empty
ob.setLocation(offset[0]*scale, offset[1]*scale, offset[2]*scale)
# Redraw if debugging
if debug: Blender.Redraw()
#===============================================#
# MAIN FUNCTION - All things are done from here #
#===============================================#
def loadBVH(filename):
global scale
print ''
print 'BVH Importer 1.0 by Campbell Barton (Ideasman) - ideasman@linuxmail.org'
alpha='abcdefghijklmnopqrstuvewxyz'
ALPHA=alpha+alpha.upper()
ALPHA+=' 0123456789+-{}. '
time1 = Blender.sys.time()
tmpScale = getScale()
if tmpScale != None:
scale = tmpScale
# File loading stuff
# Open the file for importing
file = open(filename, 'r')
fileData = file.readlines()
# Make a list of lines
lines = []
for fileLine in fileData:
fileLine=fileLine.replace('..','.')
newLine = string.split(fileLine)
if newLine != []:
t=[]
for n in newLine:
for n0 in n:
if n0 not in ALPHA:
n=n.replace(n0,'')
t.append(n)
lines.append(t)
del fileData
# End file loading code
# Call object names with this prefix, mainly for scenes with multiple BVH's - Can imagine most partr names are the same
# So in future
#prefix = str(len(lines)) + '_'
prefix = '_'
# Create Hirachy as empties
if lines[0][0] == 'HIERARCHY':
print 'Importing the BVH Hierarchy for:', filename
else:
return 'ERROR: This is not a BVH file'
# A liniar list of ancestors to keep track of a single objects heratage
# at any one time, this is appended and removed, dosent store tree- just a liniar list.
# ZERO is a place holder that means we are a root node. (no parents)
parent = [None]
#channelList [(<objectName>, [channelType1, channelType2...]), (<objectName>, [channelType1, channelType2...)]
channelList = []
channelIndex = -1
lineIdx = 1 # An index for the file.
while lineIdx < len(lines) -1:
#...
if lines[lineIdx][0] == 'ROOT' or lines[lineIdx][0] == 'JOINT':
if lines[lineIdx][0] == 'JOINT' and len(lines[lineIdx])>2:
for j in range(2,len(lines[lineIdx])) :
lines[lineIdx][1]+='_'+lines[lineIdx][j]
# MAY NEED TO SUPPORT MULTIPLE ROOT's HERE!!!, Still unsure weather multiple roots are possible.??
print len(parent) * ' ' + 'node:',lines[lineIdx][1],' parent:',parent[-1]
print lineIdx
name = lines[lineIdx][1]
print name,lines[lineIdx+1],lines[lineIdx+2]
lineIdx += 2 # Incriment to the next line (Offset)
offset = ( float(lines[lineIdx][1]), float(lines[lineIdx][2]), float(lines[lineIdx][3]) )
lineIdx += 1 # Incriment to the next line (Channels)
# newChannel[Xposition, Yposition, Zposition, Xrotation, Yrotation, Zrotation]
# newChannel has Indecies to the motiondata,
# -1 refers to the last value that will be added on loading at a value of zero
# We'll add a zero value onto the end of the MotionDATA so this is always refers to a value.
newChannel = [-1, -1, -1, -1, -1, -1]
for channel in lines[lineIdx][2:]:
channelIndex += 1 # So the index points to the right channel
if channel == 'Xposition':
newChannel[0] = channelIndex
elif channel == 'Yposition':
newChannel[1] = channelIndex
elif channel == 'Zposition':
newChannel[2] = channelIndex
elif channel == 'Xrotation':
newChannel[3] = channelIndex
elif channel == 'Yrotation':
newChannel[4] = channelIndex
elif channel == 'Zrotation':
newChannel[5] = channelIndex
channelList.append(newChannel)
channels = lines[lineIdx][2:]
# Call funtion that uses the gatrhered data to make an empty.
makeJoint(name, parent, prefix, offset, channels)
# If we have another child then we can call ourselves a parent, else
parent.append(name)
# Account for an end node
if lines[lineIdx][0] == 'End' and lines[lineIdx][1] == 'Site': # There is somtimes a name afetr 'End Site' but we will ignore it.
lineIdx += 2 # Incriment to the next line (Offset)
offset = ( float(lines[lineIdx][1]), float(lines[lineIdx][2]), float(lines[lineIdx][3]) )
makeEnd(parent, prefix, offset)
# Just so we can remove the Parents in a uniform way- End end never has kids
# so this is a placeholder
parent.append(None)
if lines[lineIdx] == ['}']:
parent = parent[:-1] # Remove the last item
#=============================================#
# BVH Structure loaded, Now import motion #
#=============================================#
if lines[lineIdx] == ['MOTION']:
print '\nImporting motion data'
lineIdx += 3 # Set the cursor to the forst frame
#=============================================#
# Loop through frames, each line a frame #
#=============================================#
currentFrame = 1
print 'frames: ',
#=============================================#
# Add a ZERO keyframe, this keeps the rig #
# so when we export we know where all the #
# joints start from #
#=============================================#
obIdx = 0
while obIdx < len(objectList) -1:
if channelList[obIdx][0] != -1:
objectList[obIdx].getIpo().getCurve('LocX').addBezier((currentFrame,0))
if channelList[obIdx][1] != -1:
objectList[obIdx].getIpo().getCurve('LocY').addBezier((currentFrame,0))
if channelList[obIdx][2] != -1:
objectList[obIdx].getIpo().getCurve('LocZ').addBezier((currentFrame,0))
if channelList[obIdx][3] != '-1' or channelList[obIdx][4] != '-1' or channelList[obIdx][5] != '-1':
objectList[obIdx].getIpo().getCurve('RotX').addBezier((currentFrame,0))
objectList[obIdx].getIpo().getCurve('RotY').addBezier((currentFrame,0))
objectList[obIdx].getIpo().getCurve('RotZ').addBezier((currentFrame,0))
obIdx += 1
while lineIdx < len(lines):
# Exit loop if we are past the motiondata.
# Some BVH's have extra tags like 'CONSTRAINTS and MOTIONTAGS'
# I dont know what they do and I dont care, they'll be ignored here.
if len(lines[lineIdx]) < len(objectList):
print '...ending on unknown tags'
break
currentFrame += 1 # Incriment to next frame
#=============================================#
# Import motion data and assign it to an IPO #
#=============================================#
lines[lineIdx].append('0') # Use this as a dummy var for objects that dont have a rotate channel.
obIdx = 0
if debug: Blender.Redraw()
while obIdx < len(objectList) -1:
if channelList[obIdx][0] != -1:
VAL0=lines[lineIdx][channelList[obIdx][0]]
if VAL0.find('.')==-1:
VAL0=VAL0[:len(VAL0)-6]+'.'+VAL0[-6:]
objectList[obIdx].getIpo().getCurve('LocX').addBezier((currentFrame, scale * float(VAL0)))
if channelList[obIdx][1] != -1:
VAL1=lines[lineIdx][channelList[obIdx][1]]
if VAL1.find('.')==-1:
VAL1=VAL1[:len(VAL1)-6]+'.'+VAL1[-6:]
objectList[obIdx].getIpo().getCurve('LocY').addBezier((currentFrame, scale * float(VAL1)))
if channelList[obIdx][2] != -1:
VAL2=lines[lineIdx][channelList[obIdx][2]]
if VAL2.find('.')==-1:
VAL2=VAL2[:len(VAL2)-6]+'.'+VAL2[-6:]
objectList[obIdx].getIpo().getCurve('LocZ').addBezier((currentFrame, scale * float(VAL2)))
if channelList[obIdx][3] != '-1' or channelList[obIdx][4] != '-1' or channelList[obIdx][5] != '-1':
VAL3=lines[lineIdx][channelList[obIdx][3]]
if VAL3.find('.')==-1:
VAL3=VAL3[:len(VAL3)-6]+'.'+VAL3[-6:]
VAL4=lines[lineIdx][channelList[obIdx][4]]
if VAL4.find('.')==-1:
VAL4=VAL4[:len(VAL4)-6]+'.'+VAL4[-6:]
VAL5=lines[lineIdx][channelList[obIdx][5]]
if VAL5.find('.')==-1:
VAL5=VAL5[:len(VAL5)-6]+'.'+VAL5[-6:]
x, y, z = eulerRotate(float(VAL3), float(VAL4), float(VAL5))
objectList[obIdx].getIpo().getCurve('RotX').addBezier((currentFrame, x))
objectList[obIdx].getIpo().getCurve('RotY').addBezier((currentFrame, y))
objectList[obIdx].getIpo().getCurve('RotZ').addBezier((currentFrame, z))
obIdx += 1
# Done importing motion data #
# lines[lineIdx] = None # Scrap old motion data, save some memory?
lineIdx += 1
# We have finished now
print currentFrame, 'done.'
# No point in looking further, when this loop is done
# There is nothine else left to do
print 'Imported ', currentFrame, ' frames'
break
# Main file loop
lineIdx += 1
print "bvh import time: ", Blender.sys.time() - time1
Blender.Window.FileSelector(loadBVH, "Import BVH")
if channelList[obIdx][2] != -1:
objectMotiondataMapping[obname, 'LocZ'].append((currentFrame, scale * float( line[obChannel[2]] )))
if obChannel[3] != -1 or obChannel[4] != -1 or obChannel[5] != -1:
x, y, z = eulerRotate(float( line[obChannel[3]] ), float( line[obChannel[4]] ), float( line[obChannel[5]] ))
x,y,z = x/10.0, y/10.0, z/10.0 # For IPO's 36 is 360d
motionMappingRotX = objectMotiondataMapping[obname, 'RotX']
motionMappingRotY = objectMotiondataMapping[obname, 'RotY']
motionMappingRotZ = objectMotiondataMapping[obname, 'RotZ']
# Make interpolation not cross between 180d, thjis fixes sub frame interpolation and time scaling.
# Will go from (355d to 365d) rather then to (355d to 5d) - inbetween these 2 there will now be a correct interpolation.
if len(motionMappingRotX) > 1:
while (motionMappingRotX[-1][1] - x) > 18: x+=36
while (motionMappingRotX[-1][1] - x) < -18: x-=36
while (motionMappingRotY[-1][1] - y) > 18: y+=36
while (motionMappingRotY[-1][1] - y) < -18: y-=36
while (motionMappingRotZ[-1][1] - z) > 18: z+=36
while (motionMappingRotZ[-1][1] - z) < -18: z-=36
motionMappingRotX.append((currentFrame, x))
motionMappingRotY.append((currentFrame, y))
motionMappingRotZ.append((currentFrame, z))
# Done importing motion data #
lineIdx += 1
#=======================================#
# Now Write the motion to the IPO's #
#=======================================#
for key, motion_data in objectMotiondataMapping.iteritems():
# Strip the motion data where all the points have the same falue.
i = len(motion_data) -2
while i > 0 and len(motion_data) > 2:
if motion_data[i][1] == motion_data[i-1][1] == motion_data[i+1][1]:
motion_data.pop(i)
i-=1
# Done stripping.
obname, tx_type = key
curve = objectCurveMapping[obname, tx_type]
for point_data in motion_data:
curve.addBezier( point_data )
# Imported motion to an IPO
# No point in looking further, when this loop is done
# There is nothine else left to do
break
# Main file loop
lineIdx += 1
print 'bvh import time for %i frames: %.6f' % (currentFrame, Blender.sys.time() - time1)
Window.RedrawAll()
Window.WaitCursor(0)
Blender.Window.FileSelector(loadBVH, "Import BVH")
#=============#
# TESTING #
#=============#
'''
#loadBVH('/metavr/mocap/bvh/boxer.bvh')
#loadBVH('/metavr/mocap/bvh/dg-306-g.bvh') # Incompleate EOF
#loadBVH('/metavr/mocap/bvh/wa8lk.bvh') # duplicate joint names, \r line endings.
#loadBVH('/metavr/mocap/bvh/walk4.bvh') # 0 channels
scale = 0.01
import os
DIR = '/metavr/mocap/bvh/'
for f in os.listdir(DIR):
if f.endswith('.bvh'):
s = Scene.New(f)
s.makeCurrent()
loadBVH(DIR + f)
'''
if __name__ == '__main__':
main()

View File

@@ -29,6 +29,26 @@ Usage:<br>
__author__ = "Campbell Barton AKA Ideasman"
__url__ = ["http://members.iinet.net.au/~cpbarton/ideasman/", "blender", "elysiun"]
# --------------------------------------------------------------------------
# ***** 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
from Blender import *
import sys as python_sys
@@ -132,7 +152,7 @@ def unzip(list):
this function will fail
"""
if len(list) == 0: return ()
if not list: return ()
l = []
for t in range(len(list[0])):
l.append(map( lambda x,t=t: x[t], list ))
@@ -213,7 +233,7 @@ def rdir(dirString, depth=0):
# Dont bother with this data.
continue
if type(dirItem) != type('str'):
if type(dirItem) != types.StringType:
print dirItem, type(dirItem)
if dirItem not in COLLECTED_VAR_NAMES.keys():
@@ -229,17 +249,17 @@ def rdir(dirString, depth=0):
#print type(dirItem)
#if type(dirData) == types.ClassType or \
# type(dirData) == types.ModuleType:
if type(dirData) != types.StringType and\
type(dirData) != types.DictType and\
type(dirData) != types.DictionaryType and\
type(dirData) != types.FloatType and\
type(dirData) != types.IntType and\
type(dirData) != types.NoneType and\
type(dirData) != types.StringTypes and\
type(dirData) != types.TypeType and\
type(dirData) != types.TupleType and\
type(dirData) != types.BuiltinFunctionType:
type_dirData = type(dirData)
if type_dirData != types.StringType and\
type_dirData != types.DictType and\
type_dirData != types.DictionaryType and\
type_dirData != types.FloatType and\
type_dirData != types.IntType and\
type_dirData != types.NoneType and\
type_dirData != types.StringTypes and\
type_dirData != types.TypeType and\
type_dirData != types.TupleType and\
type_dirData != types.BuiltinFunctionType:
# print type(dirData), dirItem
# Dont loop up dirs for strings ints etc.
if dirItem not in dirStringSplit:
@@ -519,16 +539,17 @@ def handle_event(evt, val):
menuList.sort()
choice = PupMenuLess( # Menu for the user to choose the autocompleate
'Choices (Shift for Whole name, Ctrl for Docs)%t|' + # Title Text
'Choices (Shift for local name, Ctrl for Docs)%t|' + # Title Text
'|'.join(['%s, %s' % m for m in menuList])) # Use Absolute names m[0]
if choice != -1:
if Window.GetKeyQualifiers() & Window.Qual.CTRL: # Help
cmdBuffer[-1].cmd = ('help(%s%s) ' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][0]))
elif Window.GetKeyQualifiers() & Window.Qual.SHIFT: # Put in the long name
cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][0], cmdBuffer[-1].cmd[cursor:]))
else: # Only paste in the Short name
cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][1], cmdBuffer[-1].cmd[cursor:]))
else: # Only paste in the Short name
cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][0], cmdBuffer[-1].cmd[cursor:]))
else:
# print 'NO EDITVAR'
@@ -539,11 +560,8 @@ def handle_event(evt, val):
# Quit from menu only
#if (evt == Draw.ESCKEY and not val):
# Draw.Exit()
if evt == Draw.MOUSEX: # AVOID TOO MANY REDRAWS.
return
elif evt == Draw.MOUSEY:
return
if evt == Draw.MOUSEX or evt == Draw.MOUSEY: # AVOID TOO MANY REDRAWS.
return
global cursor
@@ -805,4 +823,4 @@ cmdBuffer.append(cmdLine(' ', 0, 0))
def main():
Draw.Register(draw_gui, handle_event, handle_button_event)
main()
main()

View File

@@ -11,7 +11,7 @@ __author__ = "Jean-Michel Soler (jms)"
__url__ = ("blender", "elysiun",
"Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_hotkeyscript.htm",
"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
__version__ = "10/04/2005"
__version__ = "12/18/2005"
__bpydoc__ = """\
This script is a reference about all hotkeys and mouse actions in Blender.
@@ -26,10 +26,9 @@ Notes:<br>
"""
# $Id$
#------------------------
# Hotkeys script
# jm soler (2003-->10/2004)
# jm soler (2003-->12/2005)
# -----------------------
# Page officielle :
# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_hotkeyscript.htm
@@ -75,16 +74,17 @@ hotkeys={
['Ctrl-,', 'Set Median Point rotation scaling pivot'],
['.', 'Set 3D cursor as rotation scaling pivot'],
['Ctrl-.', 'Set Individual Object Centers as rotation scaling pivot'],
['~', 'Display all layers (German keys: <20>)'],
['Shift-~', 'Display all/previous layers (German keys: Shift-<2D>)'],
['~', 'Display all layers (German keys: <EFBFBD>,french keyboard: <EFBFBD>)'],
['Shift-~', 'Display all/previous layers (German keys: Shift-<2D>, french keyboard: shift-<2D>)'],
['Space', 'Popup menu'],
['Space', '3D View: camera selected + fly mode, accept'],
['Ctrl-Space', 'Manipulator (transform widget) Menu'],
['TAB', 'Enter/exit Edit Mode'],
['TAB', 'Edit Mode and Numerical Edit (see N key) : move to next input value'],
['TAB', 'Sequencer: Edit meta strip'],
['TAB', 'IPO: Edit selected'],
['Ctrl-TAB', 'Enter/exit Pose Mode'],
['Shift-TAB', 'Enter Object Mode'],
['Ctrl-TAB', 'ARMATURE : Enter/exit Pose Mode'],
['Shift-TAB', 'EDIT MODE : Enter Object Mode'],
['Ctrl-Open menu /', ''],
['Ctrl-Load Image', 'Opens a thumbnail browser instead of file browser for images']
],
@@ -97,20 +97,25 @@ hotkeys={
['LMB hold down', 'Popup menu'],
['LMB hold down drag', 'Gesture'],
['Ctrl-LMB', 'IPO: Add key'],
['Ctrl-LMB', '3D View: OBJECT or EDIT mode, select with the Lasso tool'],
['Ctrl-LMB', '3D View: ARMATURE EDIT mode, add a new bone to the selected end '],
['Shift-LMB','MANIPULATOR (transform widget): select the axe to remove in the current transformation ( if there is a problem with small step adjustment, first select the axe or axes with LBM alone)'],
['MMB', 'Rotate'],
['Ctrl-MMB', 'Zoom view'],
['Shift-MMB', 'Move view'],
['RMB', 'Select'],
['RMB drag', 'Border select circle: subtract from selection'],
['RMB hold down', 'Popup menu'],
['Alt+Ctrl-RMB', 'Edit Mode: Select edge'],
['Alt-RMB', 'Object Mode :Select but in a displayed list of objects located under the mouse cursor'],
['Alt-RMB', 'Edit Mode: Select EDGES LOOP '],
['Alt+Ctrl-RMB', 'Edit Mode: Select FACES LOOP'],
['Alt+Ctrl-RMB', 'UV Image Editor: Select face'],
['Shift-RMB', 'Add/subtract to/from selection'],
['Wheel', 'Zoom view'],
['Transformations:', ''],
['Drag+Ctrl', 'Step adjustment'],
['Drag+Ctrl+Shift', 'Small step adjustment'],
['Drag+Shift', 'Fine adjustment'],
['Drag+Ctrl+Shift', 'Small step adjustment (Transform Widget : first select the axe or axes with LBM alone)'],
['Drag+Shift', 'Fine adjustment (Transform Widget : first select the axe or axes with LBM alone)'],
['LMB', 'Confirm transformation'],
['MMB', 'Toggle optional transform feature'],
['RMB', 'Abort transformation']
@@ -118,33 +123,36 @@ hotkeys={
'F-Keys ':[
['F1', 'Open File'],
['F2', 'Save File'],
['F3', 'Save image'],
['F4', 'Logic Window (may change)'],
['F5', 'Material Window'],
['F6', 'Texture Window'],
['F7', 'Object Window'],
['F8', 'World Window'],
['F9', 'Edit Mode Window'],
['F10', 'Render Window'],
['F11', 'Recall the last rendered image'],
['F12', 'Render current Scene'],
['Ctrl-Shift-F12', 'NLA Editor'],
['Shift-F1', 'Library Data Select'],
['F2', 'Save File'],
['Shift-F2', 'Export DXF'],
['Ctrl-F2', 'Save/export in vrml 1.0 format' ],
['F3', 'Save image'],
['Ctrl-F3', 'Save image : dump 3d view'],
['Ctrl-Shift-F3', 'Save image : dump screen'],
['F4', 'Logic Window (may change)'],
['Shift-F4', 'Object manager Data Select '],
['F5', 'Material Window'],
['Shift-F5', '3D Window'],
['F6', 'Texture Window'],
['Shift-F6', 'IPO Window'],
['F7', 'Object Window'],
['Shift-F7', 'Buttons Window'],
['F8', 'World Window'],
['Shift-F8', 'Video Sequencer Window'],
['F9', 'Edit Mode Window'],
['Shift-F9', 'OOP Window'],
['Alt-Shift-F9', 'OutLiner Window'],
['F10', 'Render Window'],
['Shift-F10', 'UV Image Editor'],
['F11', 'Recall the last rendered image'],
['Shift-F11', 'Text Editor'],
['ctrl-F11', 'replay the last rendered animation'],
['F12', 'Render current Scene'],
['Ctrl-F12', 'Render animation'],
['Ctrl-Shift-F12', 'NLA Editor'],
['Shift-F12', 'Action Editor'],
['Ctrl-F2', 'Save/export in vrml 1.0 format' ],
['Ctrl-F3', 'Save image : dump 3d view'],
['Ctrl-Shift-F3', 'Save image : dump screen']
['Shift-F12', 'Action Editor']
],
'Numbers ':[
@@ -152,7 +160,10 @@ hotkeys={
['1..2..0-=', 'Edit Mode with Size, Grab, rotate tools : enter value'],
['Alt-1..2..0', 'Show layer 11..12..20'],
['Shift-1..2..0-=', 'Toggle layer 1..2..12'],
['Shift-ALT-...', 'Toggle layer 11..12..20']
['Shift-ALT-...', 'Toggle layer 11..12..20'],
['Crtl-Shift-ALT-3', 'Edit Mode & Face Mode : Triangle faces'],
['Crtl-Shift-ALT-4', 'Edit Mode & Face Mode : Quad faces'],
['Crtl-Shift-ALT-5', 'Edit Mode & Face Mode : Non quad or triangle faces'],
],
'Numpad ':[
@@ -167,9 +178,10 @@ hotkeys={
['Numpad +', 'In OutLiner window, Expand one level of the hierarchy'],
['Alt-Numpad -', 'Proportional vertex Edit Mode: Decrease range of influence'],
['Ctrl-Numpad +', 'Edit Mode: Select Less vertices'],
['Numpad INS', 'Set Camera view'],
['Ctrl-Numpad INS', 'Set active object as camera'],
['Alt-Numbad INS', 'Restore old camera'],
['Numpad 0', 'Set Camera view'],
['Ctrl-Numpad 0', 'Set active object as camera'],
['Alt-Numbad 0', 'Restore old camera'],
['Ctrl-Alt-Numpad 0', 'Align active camera to view'],
['Numpad 1', 'Front view'],
['Ctrl-Numpad 1', 'Back view'],
['Numpad 3', 'Right view'],
@@ -179,7 +191,9 @@ hotkeys={
['Numpad 5', 'Toggle orthogonal/perspective view'],
['Numpad 9', 'Redraw view'],
['Numpad 4', 'Rotate view left'],
['ctrl-Shift-Numpad 4', 'Previous Screen'],
['Numpad 6', 'Rotate view right'],
['ctrl-Shift-Numpad 6', 'Next Screen'],
['Numpad 8', 'Rotate view up'],
['Numpad 2', 'Rotate view down']
],
@@ -207,6 +221,7 @@ hotkeys={
['Alt-Up', 'Blender in Fullscreen mode'],
['Ctrl-Left', 'Previous screen'],
['Ctrl-Right', 'Next screen'],
['Ctrl-Alt-C', 'Object Mode : Add Constraint'],
['Ctrl-Down', 'Maximize window toggle'],
['Ctrl-Up', 'Maximize window toggle'],
['Shift-Arrow', 'Toggle first frame/ last frame']
@@ -268,6 +283,12 @@ hotkeys={
['EZ', 'Edit Mode: Extrude along Z axis'],
['Alt-E', 'Edit Mode: exit Edit Mode'],
['Ctrl-E', 'Edit Mode: Edge Specials menu'],
['Ctrl-E', 'Edit Mode: Edge Specials menu, Mark seams'],
['Ctrl-E', 'Edit Mode: Edge Specials menu, Clear seams'],
['Ctrl-E', 'Edit Mode: Edge Specials menu, Rotate Edge CW'],
['Ctrl-E', 'Edit Mode: Edge Specials menu, Rotate Edge CCW'],
['Ctrl-E', 'Edit Mode: Edge Specials menu, Loop Cut'],
['Ctrl-E', 'Edit Mode: Edge Specials menu, Edge Slide'],
['Shift-E', 'Edit Mode: SubSurf Edge Sharpness']
],
@@ -287,6 +308,7 @@ hotkeys={
['Alt-G', 'Clear location'],
['Shift-ALT-G', 'Remove selected objects from group'],
['Ctrl-G', 'Add selected objects to group'],
['Ctrl-Alt-G', 'MANIPULATOR (transform widget): set in Grab Mode'],
['Shift-G', 'Selected Group menu']
],
@@ -295,11 +317,11 @@ hotkeys={
['H', 'Curves: Set handle type'],
['H', 'Action editor: Handle type aligned'],
['H', 'Action editor: Handle type free'],
['Alt-H', 'Show Hidden vertices/faces'],
['Alt-H', 'Edit Mode : Show Hidden vertices/faces'],
['Shift-H', 'Curves: Automatic handle calculation'],
['Shift-H', 'Action editor: Handle type auto'],
['Shift-H', 'Edit Mode, Hide deselected vertices/faces'],
['Ctrl-H', 'Edit Mode, Add a hook on selected points or show the hook menu .']
['Shift-H', 'Edit Mode : Hide deselected vertices/faces'],
['Ctrl-H', 'Edit Mode : Add a hook on selected points or show the hook menu .']
],
"I":[
@@ -329,7 +351,7 @@ hotkeys={
"L":[
['L', 'Make local menu'],
['L', 'Edit mode: Select linked vertices (near mouse pointer)'],
['L', 'Edit Mode: Select linked vertices (near mouse pointer)'],
['L', 'OOPS window: Select linked objects'],
['L', 'UV Face Select: Select linked faces'],
['Ctrl-L', 'Make links menu (for instance : to scene...)'],
@@ -353,7 +375,7 @@ hotkeys={
['N', 'OOPS window: Rename object/linked objects'] ,
['Ctrl-N', 'Armature: Recalculate bone roll angles'] ,
['Ctrl-N', 'Edit Mode: Recalculate normals to outside'] ,
['Ctrl-ALT-N', 'Edit Mode: Recalculate normals to inside'] ],
['Ctrl-Shift-N', 'Edit Mode: Recalculate normals to inside'] ],
"O":[
['O', 'Edit Mode/UV Image Editor: Toggle proportional vertex editing'],
@@ -365,6 +387,7 @@ hotkeys={
"P":[
['P', 'Object Mode: Start realtime engine'],
['P', 'Edit mode: Seperate vertices to new object'],
['shift-P', 'Edit mode: Push-Pull'],
['P', 'UV Image Editor: Pin UVs'],
['Alt-P', 'Clear parent relationship'],
['Alt-P', 'UV Image Editor: Unpin UVs'],
@@ -387,6 +410,7 @@ hotkeys={
['RZZ', "Rotate around object's local Z axis"],
['Alt-R', 'Clear object rotation'],
['Ctrl-R', 'Edit Mode: Knife, cut selected edges, accept left mouse/ cancel right mouse'],
['Ctrl-Alt-R', 'MANIPULATOR (transform widget): set in Rotate Mode'],
['Shift-R', 'Edit Mode: select Face Loop'],
['Shift-R', 'Nurbs: Select row'] ],
@@ -400,8 +424,11 @@ hotkeys={
['SYY', 'Flip around Y axis and show axis'] ,
['SZZ', 'Flip around Z axis and show axis'] ,
['Alt-S', 'Edit mode: Shrink/fatten (Scale along vertex normals)'] ,
['Ctrl-Shift-S', 'Edit mode: To Sphere'] ,
['Ctrl-Alt-Shift-S', 'Edit mode: Shear'] ,
['Alt-S', 'Clear object size'] ,
['Ctrl-S', 'Edit mode: Shear'] ,
['Ctrl-Alt-G', 'MANIPULATOR (transform widget): set in Size Mode'],
['Shift-S', 'Cursor/Grid snap menu'] ],
"T":[
@@ -418,18 +445,18 @@ hotkeys={
"U":[
['U', 'Make single user menu (for import completly linked object to another scene for instance) '] ,
['U', '3D View: Make Single user Menu'] ,
['U', 'Edit Mode: Reload object data from before entering Edit Mode'] ,
['U', 'UV Face Select: Automatic UV calculation menu'] ,
['U', 'Vertex-/Weightpaint mode: Undo'] ,
['Ctrl-U', 'Save current state as user default'],
['Shift-U', 'Edit Mode: Redo Menu'],
['Alt-U', 'Edit Mode: Undo Menu'] ],
['Alt-U', 'Edit Mode & Object Mode: Undo Menu']],
"V":[
['V', 'Curves/Nurbs: Vector handle'],
['V', 'Edit Mode : Rip selected vertices'],
['V', 'Vertexpaint mode'],
['V', 'UV Image Editor: Stitch UVs'],
['V', 'Action editor: Vector'],
['V', 'Action editor: Vector'],
['Alt-V', "Scale object to match image texture's aspect ratio"],
['Shift-V', 'Edit mode: Align view to selected vertices'],
['Shift-V', 'UV Image Editor: Limited Stitch UVs popup'],
@@ -437,13 +464,37 @@ hotkeys={
],
"W":[
['W', 'Object Mode: Boolean operations menu'],
['W', 'Edit mode: Specials menu'],
['W', 'Edit Mode: Specials menu'],
['W', 'Edit Mode: Specials menu, ARMATURE 1 Subdivide'],
['W', 'Edit Mode: Specials menu, ARMATURE 2 Flip Left-Right Name'],
['W', 'Edit Mode: Specials menu, CURVE 1 Subdivide'],
['W', 'Edit Mode: Specials menu, CURVE 2 Swich Direction'],
['W', 'Edit Mode: Specials menu, MESH 1 Subdivide'],
['W', 'Edit Mode: Specials menu, MESH 2 Subdivide Multi'],
['W', 'Edit Mode: Specials menu, MESH 3 Subdivide Multi Fractal'],
['W', 'Edit Mode: Specials menu, MESH 4 Subdivide Smooth'],
['W', 'Edit Mode: Specials menu, MESH 5 Merge'],
['W', 'Edit Mode: Specials menu, MESH 6 Remove Double'],
['W', 'Edit Mode: Specials menu, MESH 7 Hide'],
['W', 'Edit Mode: Specials menu, MESH 8 Reveal'],
['W', 'Edit Mode: Specials menu, MESH 9 Select Swap'],
['W', 'Edit Mode: Specials menu, MESH 10 Flip Normal'],
['W', 'Edit Mode: Specials menu, MESH 11 Smooth'],
['W', 'Edit Mode: Specials menu, MESH 12 Bevel'],
['W', 'Edit Mode: Specials menu, MESH 13 Set Smooth'],
['W', 'Edit Mode : Specials menu, MESH 14 Set Solid'],
['W', 'Object Mode : on MESH objects, Boolean Tools menu'],
['W', 'Object Mode : on MESH objects, Boolean Tools 1 Intersect'],
['W', 'Object Mode : on MESH objects, Boolean Tools 2 union'],
['W', 'Object Mode : on MESH objects, Boolean Tools 3 difference'],
['W', 'Object Mode : on MESH objects, Boolean Tools 4 Add an intersect Modifier'],
['W', 'Object Mode : on MESH objects, Boolean Tools 5 Add an union Modifier'],
['W', 'Object Mode : on MESH objects, Boolean Tools 6 Add a difference Modifier'],
['W', 'Object mode : on TEXT object, Split characters, a new TEXT object by character in the selected string '],
['W', 'UV Image Editor: Weld/Align'],
['WX', 'UV Image Editor: Weld/Align X axis'],
['WY', 'UV Image Editor: Weld/Align Y axis'],
['Ctrl-W', 'Save current file'] ,
['Ctrl-W', 'Nurbs: Switch direction'] ,
['Shift-W', 'Warp/bend selected vertices around cursor'],
['alt-W', 'Export in videoscape format']
],
@@ -456,13 +507,15 @@ hotkeys={
],
"Y":[
['Y', 'Mesh: Split selected vertices/faces from the rest'] ],
['Y', 'Edit Mode & Mesh : Split selected vertices/faces from the rest'],
['Ctrl-Y', 'Object Mode : Redo'],
],
"Z":[
['Z', 'Render Window: 200% zoom from mouse position'],
['Z', 'Switch 3d draw type : solide/ wireframe (see also D)'],
['Alt-Z', 'Switch 3d draw type : solid / textured (see also D)'],
['Ctrl-Z', 'Switch 3d draw type : shaded (see also D)'],
['Ctrl-Z', 'Object Mode : Undo'],
['Shift-Z', 'Switch 3d draw type : shaded / wireframe (see also D)'],
]}]}
@@ -498,12 +551,15 @@ def searchfor(SEARCHLINE):
#print 'k, l : ', k, l, l[1]
if l[1].upper().find(SEARCHLINE.upper())!=-1:
FINDLIST.append(l)
elif k == 'Letters ':
for l in hotL :
for l0 in hotkeys['Letters '][0][l][:-1]:
#print 'k, l : ',l, k, l0
if l0[1].upper().find(SEARCHLINE.upper())!=-1:
FINDLIST.append(l0)
#print 'FINDLIST',FINDLIST
FINDLIST.append(['Find list','Entry'])
return FINDLIST
@@ -569,6 +625,7 @@ def draw():
listed=hot.index(k)
l=0
size[3]=size[3]-4
if hot[listed]!='Letters ' and hot[listed]!='Search ' :
size[3]=size[3]-8
SCROLL=size[3]/21
@@ -594,17 +651,19 @@ def draw():
glRasterPos2f(4+8*15, size[3]-(58+21*l))
Text(' : '+n[1])
l+=1
elif hot[listed]=='Search ' :
r=[0,size[3]-70,
size[2], size[3]-44]
trace_rectangle4(r,c2)
SEARCHLINE=String(' ', LINE, 42, size[3]-68,200,18,SEARCHLINE.val, 256,'')
if len(FINDED)>0:
LEN=len(FINDED)
size[3]=size[3]-8
SCROLL=size[3]/21
END=-1
if SCROLL < len(FINDED):
LEN=len(FINDED)
size[3]=size[3]-8
SCROLL=size[3]/21
END=-1
if SCROLL < len(FINDED):
Button('/\\',up,4,size[3]+8,20,14,'Scroll up')
Button('\\/',down,4,size[3]-8,20,14,'Scroll down')
if (SCROLL+UP)<len(FINDED):
@@ -612,9 +671,9 @@ def draw():
else:
END=-1
#UP=len(FINDED)-SCROLL
else:
UP=0
for n in FINDED[UP:END]:
else:
UP=0
for n in FINDED[UP:END]:
if l%2==0:
r=[0,size[3]-(21*l+66+24),
size[2], size[3]-(21*l+43+24)]
@@ -714,4 +773,4 @@ def bevent(evt):
Blender.Window.Redraw()
Register(draw, event, bevent)
Register(draw, event, bevent)

View File

@@ -46,12 +46,27 @@ v5.5 format.
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | April 21, 2002 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Read and write LightWave Object File Format (*.lwo) |
# +---------------------------------------------------------+
# ***** 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, meshtools
import struct, chunk, os, cStringIO, time, operator

File diff suppressed because it is too large Load Diff

View File

@@ -53,12 +53,27 @@ field.
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | September 25, 2001 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Read and write Nendo File Format (*.nendo) |
# +---------------------------------------------------------+
# ***** 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, meshtools
import struct, time, sys, os

View File

@@ -48,12 +48,27 @@ edges during the course of modeling.
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | September 25, 2001 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Read and write Nendo File Format (*.nendo) |
# +---------------------------------------------------------+
# ***** 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, meshtools
import struct, time, sys, os

View File

@@ -21,7 +21,7 @@ Run this script from "File->Export" menu to export all meshes.
# --------------------------------------------------------------------------
# OBJ Export v0.9b by Campbell Barton (AKA Ideasman)
# OBJ Export v1.0 by Campbell Barton (AKA Ideasman)
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
@@ -42,12 +42,18 @@ Run this script from "File->Export" menu to export all meshes.
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
#==================================================#
# New name based on old with a different extension #
#==================================================#
def newFName(ext):
return Get('filename')[: -len(Get('filename').split('.', -1)[-1]) ] + ext
import Blender
from Blender import Mesh, Scene, Window, sys, Image, Draw
# Returns a tuple - path,extension.
# 'hello.obj' > ('hello', '.obj')
def splitExt(path):
dotidx = path.rfind('.')
if dotidx == -1:
return path, ''
else:
return path[:dotidx], path[dotidx:]
def fixName(name):
if name == None:
@@ -55,10 +61,53 @@ def fixName(name):
else:
return name.replace(' ', '_')
# Used to add the scene name into the filename without using odd chars
def saneFilechars(name):
for ch in ' /\\~!@#$%^&*()+=[];\':",./<>?\t\r\n':
name = name.replace(ch, '_')
return name
def sortPair(a,b):
return min(a,b), max(a,b)
from Blender import *
def getMeshFromObject(object, name=None, mesh=None):
if mesh:
mesh.verts = None # Clear the mesh
else:
if not name:
mesh = Mesh.New()
else:
mesh = Mesh.New(name)
type = object.getType()
dataname = object.getData(1)
try:
mesh.getFromObject(object.name)
except:
return None
if type == 'Mesh':
tempMe = Mesh.Get( dataname )
mesh.materials = tempMe.materials
mesh.degr = tempMe.degr
mesh.mode = tempMe.mode
else:
try:
# Will only work for curves!!
# Text- no material access in python interface.
# Surf- no python interface
# MBall- no material access in python interface.
data = object.getData()
materials = data.getMaterials()
mesh.materials = materials
print 'assigning materials for non mesh'
except:
print 'Cant assign materials to', type
return mesh
global MTL_DICT
@@ -66,17 +115,17 @@ global MTL_DICT
# (material.name, image.name):matname_imagename # matname_imagename has gaps removed.
MTL_DICT = {}
def save_mtl(filename):
def write_mtl(filename):
global MTL_DICT
world = World.GetCurrent()
world = Blender.World.GetCurrent()
if world:
worldAmb = world.getAmb()
else:
worldAmb = (0,0,0) # Default value
file = open(filename, "w")
file.write('# Blender MTL File: %s\n' % Get('filename').split('\\')[-1].split('/')[-1])
file.write('# Blender MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1])
file.write('# Material Count: %i\n' % len(MTL_DICT))
# Write material/image combinations we have used.
for key, mtl_mat_name in MTL_DICT.iteritems():
@@ -96,7 +145,7 @@ def save_mtl(filename):
file.write('illum 2\n') # light normaly
else:
mat = Material.Get(key[0])
mat = Blender.Material.Get(key[0])
file.write('Ns %s\n' % round((mat.getHardness()-1) * 1.9607843137254901 ) ) # Hardness, convert blenders 1-511 to MTL's
file.write('Ka %s %s %s\n' % tuple([round(c*mat.getAmb(), 6) for c in worldAmb]) ) # Ambient, uses mirror colour,
file.write('Kd %s %s %s\n' % tuple([round(c*mat.getRef(), 6) for c in mat.getRGBCol()]) ) # Diffuse
@@ -105,7 +154,7 @@ def save_mtl(filename):
file.write('d %s\n' % round(mat.getAlpha(), 6)) # Alpha (obj uses 'd' for dissolve)
# 0 to disable lighting, 1 for ambient & diffuse only (specular color set to black), 2 for full lighting.
if mat.getMode() & Material.Modes['SHADELESS']:
if mat.getMode() & Blender.Material.Modes['SHADELESS']:
file.write('illum 0\n') # ignore lighting
elif mat.getSpec() == 0:
file.write('illum 1\n') # no specular.
@@ -120,7 +169,7 @@ def save_mtl(filename):
elif key[0] != None: # No face image. if we havea material search for MTex image.
for mtex in mat.getTextures():
if mtex and mtex.tex.type == Texture.Types.IMAGE:
if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE:
try:
filename = mtex.tex.image.filename.split('\\')[-1].split('/')[-1]
file.write('map_Kd %s\n' % filename) # Diffuse mapping image
@@ -133,24 +182,84 @@ def save_mtl(filename):
file.close()
def save_obj(filename):
global MTL_DICT
def copy_file(source, dest):
file = open(source, 'rb')
data = file.read()
file.close()
file = open(dest, 'wb')
file.write(data)
file.close()
def copy_images(dest_dir):
if dest_dir[-1] != sys.sep:
dest_dir += sys.sep
# Get unique image names
uniqueImages = {}
for matname, imagename in MTL_DICT.iterkeys(): # Only use image name
if imagename != None:
uniqueImages[imagename] = None # Should use sets here. wait until Python 2.4 is default.
# Now copy images
copyCount = 0
for imageName in uniqueImages.iterkeys():
print imageName
bImage = Image.Get(imageName)
image_path = sys.expandpath(bImage.filename)
if sys.exists(image_path):
# Make a name for the target path.
dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
if not sys.exists(dest_image_path): # Image isnt alredy there
print '\tCopying "%s" > "%s"' % (image_path, dest_image_path)
copy_file(image_path, dest_image_path)
copyCount+=1
print '\tCopied %d images' % copyCount
def write(filename, objects,\
EXPORT_TRI=False, EXPORT_EDGES=False, EXPORT_NORMALS=False,\
EXPORT_UV=True, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False,\
EXPORT_APPLY_MODIFIERS=True, EXPORT_BLEN_OBS=True,\
EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False):
'''
Basic write function. The context and options must be alredy set
This can be accessed externaly
eg.
write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options.
'''
print 'OBJ Export path: "%s"' % filename
global MTL_DICT
temp_mesh_name = '~tmp-mesh'
time1 = sys.time()
scn = Scene.GetCurrent()
file = open(filename, "w")
# Write Header
file.write('# Blender OBJ File: %s\n' % (Get('filename').split('/')[-1].split('\\')[-1] ))
file.write('# www.blender.org\n')
file.write('# Blender v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] ))
file.write('# www.blender3d.org\n')
# Tell the obj file what material file to use.
mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1])
file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] ))
# Get the container mesh.
if EXPORT_APPLY_MODIFIERS:
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)
del meshName
del tempMesh
# Initialize totals, these are updated each object
totverts = totuvco = totno = 1
@@ -158,28 +267,61 @@ def save_obj(filename):
globalNormals = {}
# Get all meshs
for ob in scn.getChildren():
#for ob in Object.GetSelected():
try:
# Will work for non meshes now! :)
m = NMesh.GetRawFromObject(ob.name)
except:
continue
for ob in objects:
faces = [ f for f in m.faces if len(f) > 2 ]
# Will work for non meshes now! :)
if EXPORT_APPLY_MODIFIERS or ob.getType() != 'Mesh':
m = getMeshFromObject(ob, temp_mesh_name, containerMesh)
if not m:
continue
# We have a valid mesh
if m and EXPORT_APPLY_MODIFIERS and EXPORT_TRI:
# Add a dummy object to it.
oldmode = Mesh.Mode()
Mesh.Mode(Mesh.SelectModes['FACE'])
quadcount = 0
for f in m.faces:
if len(f.v) == 4:
f.sel = 1
quadcount +=1
if quadcount:
tempob = Blender.Object.New('Mesh')
tempob.link(m)
scn.link(tempob)
m.quadToTriangle(0) # more=0 shortest length
oldmode = Mesh.Mode(oldmode)
scn.unlink(tempob)
Mesh.Mode(oldmode)
else: # We are a mesh. get the data.
m = ob.getData(mesh=1)
if not faces: # Make sure there is somthing to write
faces = [ f for f in m.faces ]
if EXPORT_EDGES:
edges = [ ed for ed in m.edges ]
else:
edges = []
if not (len(faces)+len(edges)): # Make sure there is somthing to write
continue # dont bother with this mesh.
m.transform(ob.matrix)
# # Crash Blender
#materials = m.getMaterials(1) # 1 == will return None in the list.
materials = m.getMaterials()
materials = m.materials
materialNames = []
if materials:
materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken.
for mat in materials:
if mat: # !=None
materialNames.append(mat.name)
else:
materialNames.append(None)
# Cant use LC because some materials are None.
# materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken.
else:
materialNames = []
@@ -190,52 +332,62 @@ def save_obj(filename):
# Sort by Material, then images
# so we dont over context switch in the obj file.
faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth)))
if m.faceUV and EXPORT_UV:
faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth)))
else:
faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth)))
# Set the default mat to no material and no image.
contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get.
contextSmooth = None # Will either be true or false, set bad to force initialization switch.
file.write('o %s_%s\n' % (fixName(ob.name), fixName(m.name))) # Write Object name
if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB:
obnamestring = '%s_%s' % (fixName(ob.name), fixName(ob.getData(1)))
if EXPORT_BLEN_OBS:
file.write('o %s\n' % obnamestring) # Write Object name
else: # if EXPORT_GROUP_BY_OB:
file.write('g %s\n' % obnamestring)
# Vert
for v in m.verts:
file.write('v %.6f %.6f %.6f\n' % tuple(v.co))
# UV
if m.hasFaceUV():
if m.faceUV and EXPORT_UV:
for f in faces:
for uvKey in f.uv:
uvKey = tuple(uvKey)
if not globalUVCoords.has_key(uvKey):
globalUVCoords[uvKey] = totuvco
totuvco +=1
file.write('vt %.6f %.6f 0.0\n' % uvKey)
# NORMAL, Smooth/Non smoothed.
for f in faces:
if f.smooth:
for v in f.v:
noKey = tuple(v.no)
if EXPORT_NORMALS:
for f in faces:
if f.smooth:
for v in f.v:
noKey = tuple(v.no)
if not globalNormals.has_key( noKey ):
globalNormals[noKey] = totno
totno +=1
file.write('vn %.6f %.6f %.6f\n' % noKey)
else:
# Hard, 1 normal from the face.
noKey = tuple(f.no)
if not globalNormals.has_key( noKey ):
globalNormals[noKey] = totno
totno +=1
file.write('vn %.6f %.6f %.6f\n' % noKey)
else:
# Hard, 1 normal from the face.
noKey = tuple(f.no)
if not globalNormals.has_key( noKey ):
globalNormals[noKey] = totno
totno +=1
file.write('vn %.6f %.6f %.6f\n' % noKey)
uvIdx = 0
for f in faces:
# MAKE KEY
if f.image: # Object is always true.
if EXPORT_UV and m.faceUV and f.image: # Object is always true.
key = materialNames[f.mat], f.image.name
else:
key = materialNames[f.mat], None # No image, use None instead.
@@ -243,31 +395,34 @@ def save_obj(filename):
# CHECK FOR CONTEXT SWITCH
if key == contextMat:
pass # Context alredy switched, dont do anythoing
elif key[0] == None and key[1] == None:
# Write a null material, since we know the context has changed.
file.write('usemtl (null)\n') # mat, image
else:
try: # Faster to try then 2x dict lookups.
if key[0] == None and key[1] == None:
# Write a null material, since we know the context has changed.
matstring = '(null)'
file.write('usemtl (null)\n') # mat, image
# We have the material, just need to write the context switch,
file.write('usemtl %s\n' % MTL_DICT[key]) # mat, image
except KeyError:
# First add to global dict so we can export to mtl
# Then write mtl
# Make a new names from the mat and image name,
# converting any spaces to underscores with fixName.
# If none image dont bother adding it to the name
if key[1] == None:
tmp_matname = MTL_DICT[key] ='%s' % fixName(key[0])
file.write('usemtl %s\n' % tmp_matname) # mat, image
else:
try: # Faster to try then 2x dict lookups.
# We have the material, just need to write the context switch,
matstring = MTL_DICT[key]
else:
tmp_matname = MTL_DICT[key] = '%s_%s' % (fixName(key[0]), fixName(key[1]))
file.write('usemtl %s\n' % tmp_matname) # mat, image
except KeyError:
# First add to global dict so we can export to mtl
# Then write mtl
# Make a new names from the mat and image name,
# converting any spaces to underscores with fixName.
# If none image dont bother adding it to the name
if key[1] == None:
matstring = MTL_DICT[key] ='%s' % fixName(key[0])
else:
matstring = MTL_DICT[key] = '%s_%s' % (fixName(key[0]), fixName(key[1]))
if EXPORT_GROUP_BY_MAT:
file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), matstring) ) # can be mat_image or (null)
file.write('usemtl %s\n' % matstring) # can be mat_image or (null)
contextMat = key
@@ -279,57 +434,198 @@ def save_obj(filename):
contextSmooth = f.smooth
file.write('f')
if m.hasFaceUV():
if f.smooth: # Smoothed, use vertex normals
if m.faceUV and EXPORT_UV:
if EXPORT_NORMALS:
if f.smooth: # Smoothed, use vertex normals
for vi, v in enumerate(f.v):
file.write( ' %d/%d/%d' % (\
v.index+totverts,\
globalUVCoords[ tuple(f.uv[vi]) ],\
globalNormals[ tuple(v.no) ])) # vert, uv, normal
else: # No smoothing, face normals
no = globalNormals[ tuple(f.no) ]
for vi, v in enumerate(f.v):
file.write( ' %d/%d/%d' % (\
v.index+totverts,\
globalUVCoords[ tuple(f.uv[vi]) ],\
no)) # vert, uv, normal
else: # No Normals
for vi, v in enumerate(f.v):
file.write( ' %d/%d/%d' % (\
file.write( ' %d/%d' % (\
v.index+totverts,\
globalUVCoords[ f.uv[vi] ],\
globalNormals[ tuple(v.no) ])) # vert, uv, normal
else: # No smoothing, face normals
no = globalNormals[ tuple(f.no) ]
for vi, v in enumerate(f.v):
file.write( ' %d/%d/%d' % (\
v.index+totverts,\
globalUVCoords[ f.uv[vi] ],\
no)) # vert, uv, normal
globalUVCoords[ tuple(f.uv[vi])])) # vert, uv
else: # No UV's
if f.smooth: # Smoothed, use vertex normals
if EXPORT_NORMALS:
if f.smooth: # Smoothed, use vertex normals
for v in f.v:
file.write( ' %d//%d' % (\
v.index+totverts,\
globalNormals[ tuple(v.no) ]))
else: # No smoothing, face normals
no = globalNormals[ tuple(f.no) ]
for v in f.v:
file.write( ' %d//%d' % (\
v.index+totverts,\
no))
else: # No Normals
for v in f.v:
file.write( ' %d//%d' % (\
v.index+totverts,\
globalNormals[ tuple(v.no) ]))
else: # No smoothing, face normals
no = globalNormals[ tuple(f.no) ]
for v in f.v:
file.write( ' %d//%d' % (\
v.index+totverts,\
no))
file.write( ' %d' % (\
v.index+totverts))
file.write('\n')
# Write edges.
if EXPORT_EDGES:
edgeUsers = {}
for f in faces:
for i in xrange(len(f.v)):
faceEdgeVKey = sortPair(f.v[i].index, f.v[i-1].index)
# We dont realy need to keep count. Just that a face uses it
# so dont export.
edgeUsers[faceEdgeVKey] = 1
for ed in edges:
edgeVKey = sortPair(ed.v1.index, ed.v2.index)
if not edgeUsers.has_key(edgeVKey): # No users? Write the edge.
file.write('f %d %d\n' % (edgeVKey[0]+totverts, edgeVKey[1]+totverts))
# Make the indicies global rather then per mesh
totverts += len(m.verts)
file.close()
# Now we have all our materials, save them
save_mtl(mtlfilename)
if EXPORT_MTL:
write_mtl(mtlfilename)
if EXPORT_COPY_IMAGES:
dest_dir = filename
# Remove chars until we are just the path.
while dest_dir and dest_dir[-1] not in '\\/':
dest_dir = dest_dir[:-1]
if dest_dir:
copy_images(dest_dir)
else:
print '\tError: "%s" could not be used as a base for an image path.' % filename
print "OBJ Export time: %.2f" % (sys.time() - time1)
print "obj export time: %.2f" % (sys.time() - time1)
Window.FileSelector(save_obj, 'Export Wavefront OBJ', newFName('obj'))
def write_ui(filename):
for s in Window.GetScreenInfo():
Window.QHandle(s['id'])
EXPORT_APPLY_MODIFIERS = Draw.Create(1)
EXPORT_TRI = Draw.Create(0)
EXPORT_EDGES = Draw.Create(0)
EXPORT_NORMALS = Draw.Create(0)
EXPORT_UV = Draw.Create(1)
EXPORT_MTL = Draw.Create(1)
EXPORT_SEL_ONLY = Draw.Create(1)
EXPORT_ALL_SCENES = Draw.Create(0)
EXPORT_ANIMATION = Draw.Create(0)
EXPORT_COPY_IMAGES = Draw.Create(0)
EXPORT_BLEN_OBS = Draw.Create(1)
EXPORT_GROUP_BY_OB = Draw.Create(0)
EXPORT_GROUP_BY_MAT = Draw.Create(0)
# Get USER Options
pup_block = [\
('Mesh Options...'),\
('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data from each object. May break vert order for morph targets.'),\
('Triangulate', EXPORT_TRI, 'Triangulate quads (Depends on "Apply Modifiers").'),\
('Edges', EXPORT_EDGES, 'Edges not connected to faces.'),\
('Normals', EXPORT_NORMALS, 'Export vertex normal data (Ignored on import).'),\
('UVs', EXPORT_UV, 'Export texface UV coords.'),\
('Materials', EXPORT_MTL, 'Write a seperate MTL file with the OBJ.'),\
('Context...'),\
('Selection Only', EXPORT_SEL_ONLY, 'Only export objects in visible selection. Else export whole scene.'),\
('All Scenes', EXPORT_ALL_SCENES, 'Each scene as a seperate OBJ file.'),\
('Animation', EXPORT_ANIMATION, 'Each frame as a numbered OBJ file.'),\
('Copy Images', EXPORT_COPY_IMAGES, 'Copy image files to the export directory, never overwrite.'),\
('Grouping...'),\
('Objects', EXPORT_BLEN_OBS, 'Export blender objects as OBJ objects.'),\
('Object Groups', EXPORT_GROUP_BY_OB, 'Export blender objects as OBJ groups.'),\
('Material Groups', EXPORT_GROUP_BY_MAT, 'Group by materials.'),\
]
if not Draw.PupBlock('Export...', pup_block):
return
Window.WaitCursor(1)
EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val
EXPORT_TRI = EXPORT_TRI.val
EXPORT_EDGES = EXPORT_EDGES.val
EXPORT_NORMALS = EXPORT_NORMALS.val
EXPORT_UV = EXPORT_UV.val
EXPORT_MTL = EXPORT_MTL.val
EXPORT_SEL_ONLY = EXPORT_SEL_ONLY.val
EXPORT_ALL_SCENES = EXPORT_ALL_SCENES.val
EXPORT_ANIMATION = EXPORT_ANIMATION.val
EXPORT_COPY_IMAGES = EXPORT_COPY_IMAGES.val
EXPORT_BLEN_OBS = EXPORT_BLEN_OBS.val
EXPORT_GROUP_BY_OB = EXPORT_GROUP_BY_OB.val
EXPORT_GROUP_BY_MAT = EXPORT_GROUP_BY_MAT.val
base_name, ext = splitExt(filename)
context_name = [base_name, '', '', ext] # basename, scene_name, framenumber, extension
# Use the options to export the data using write()
# def write(filename, objects, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False, EXPORT_APPLY_MODIFIERS=True):
orig_scene = Scene.GetCurrent()
if EXPORT_ALL_SCENES:
export_scenes = Scene.Get()
else:
export_scenes = [orig_scene]
# Export all scenes.
for scn in export_scenes:
scn.makeCurrent() # If alredy current, this is not slow.
context = scn.getRenderingContext()
orig_frame = Blender.Get('curframe')
if EXPORT_ALL_SCENES: # Add scene name into the context_name
context_name[1] = '_%s' % saneFilechars(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied.
# Export an animation?
if EXPORT_ANIMATION:
scene_frames = range(context.startFrame(), context.endFrame()+1) # up to and including the end frame.
else:
scene_frames = [orig_frame] # Dont export an animation.
# Loop through all frames in the scene and export.
for frame in scene_frames:
if EXPORT_ANIMATION: # Add frame to the filename.
context_name[2] = '_%.6d' % frame
Blender.Set('curframe', frame)
if EXPORT_SEL_ONLY:
export_objects = Blender.Object.GetSelected() # Export Context
else:
export_objects = scn.getChildren()
# EXPORT THE FILE.
write(''.join(context_name), export_objects,\
EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\
EXPORT_UV, EXPORT_MTL, EXPORT_COPY_IMAGES,\
EXPORT_APPLY_MODIFIERS,\
EXPORT_BLEN_OBS, EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT)
Blender.Set('curframe', orig_frame)
# Restore old active scene.
orig_scene.makeCurrent()
Window.WaitCursor(0)
'''
TIME = sys.time()
import os
OBJDIR = '/obj_out/'
for scn in Scene.Get():
scn.makeCurrent()
obj = OBJDIR + scn.name
print obj
save_obj(obj)
print "TOTAL EXPORT TIME: ", sys.time() - TIME
'''
if __name__ == '__main__':
Window.FileSelector(write_ui, 'Export Wavefront OBJ', sys.makename(ext='.obj'))

View File

@@ -269,8 +269,6 @@ def comprehansiveImageLoad(imagePath, filePath):
break
return img
# No go.
print '\t\tImage Not Found "%s"' % imagePath
return None
@@ -278,22 +276,6 @@ def comprehansiveImageLoad(imagePath, filePath):
#==================================================================================#
# This function sets textures defined in .mtl file #
@@ -377,9 +359,7 @@ def load_mtl(dir, mtl_file, meshDict, materialDict):
l = fileLines[lIdx].split()
# Detect a line that will be ignored
if len(l) == 0:
pass
elif l[0] == '#' or len(l) == 0:
if len(l) == 0 or l[0].startswith('#'):
pass
elif l[0] == 'newmtl':
currentMat = getMat('_'.join(l[1:]), materialDict) # Material should alredy exist.
@@ -428,30 +408,27 @@ def load_mtl(dir, mtl_file, meshDict, materialDict):
# Returns unique name of object/mesh (preserve overwriting existing meshes) #
#===========================================================================#
def getUniqueName(name):
newName = name
newName = name[:19] # 19 chars is the longest name.
uniqueInt = 0
while 1:
try:
ob = Object.Get(newName)
# Okay, this is working, so lets make a new name
newName = '%s.%d' % (name, uniqueInt)
uniqueInt +=1
except AttributeError:
if newName not in NMesh.GetNames():
return newName
else:
newName = '%s.%d' % (name, uniqueInt)
uniqueInt +=1
while newName in getUniqueName.uniqueNames:
newName = '%s.%.3i' % (name[:15], uniqueInt)
uniqueInt +=1
getUniqueName.uniqueNames.append(newName)
return newName
getUniqueName.uniqueNames = []
#==================================================================================#
# This loads data from .obj file #
#==================================================================================#
def load_obj(file):
def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0):
print '\nImporting OBJ file: "%s"' % file
time1 = sys.time()
getUniqueName.uniqueNames.extend( [ob.name for ob in Object.Get()] )
getUniqueName.uniqueNames.extend( NMesh.GetNames() )
# Deselect all objects in the scene.
# do this first so we dont have to bother, with objects we import
for ob in Scene.GetCurrent().getChildren():
@@ -467,9 +444,9 @@ def load_obj(file):
DIR = stripFile(file)
tempFile = open(file, 'r')
fileLines = tempFile.readlines()
fileLines = tempFile.readlines()
tempFile.close()
del tempFile
uvMapList = [] # store tuple uv pairs here
# This dummy vert makes life a whole lot easier-
@@ -489,7 +466,10 @@ def load_obj(file):
currentMat = nullMat # Use this mat.
currentImg = None # Null image is a string, otherwise this should be set to an image object.\
currentSmooth = False
if IMPORT_SMOOTH_ALL:
currentSmooth = True
else:
currentSmooth = False
# Store a list of unnamed names
currentUnnamedGroupIdx = 1
@@ -503,63 +483,36 @@ def load_obj(file):
#==================================================================================#
# Load all verts first (texture verts too) #
#==================================================================================#
nonVertFileLines = []
smoothingGroups = {}
materialDict = {} # Store all imported materials as unique dict, names are key
lIdx = 0
print '\tfile length: %d' % len(fileLines)
while lIdx < len(fileLines):
# Ignore vert normals
if fileLines[lIdx].startswith('vn'):
lIdx+=1
continue
# Dont Bother splitting empty or comment lines.
if len(fileLines[lIdx]) == 0 or\
fileLines[lIdx][0] == '\n' or\
fileLines[lIdx][0] == '#':
pass
else:
fileLines[lIdx] = fileLines[lIdx].split()
l = fileLines[lIdx]
# Splitting may
if len(l) == 0:
pass
# Verts
elif l[0] == 'v':
vertList.append( NMesh.Vert(float(l[1]), float(l[2]), float(l[3]) ) )
# UV COORDINATE
elif l[0] == 'vt':
uvMapList.append( (float(l[1]), float(l[2])) )
# Smoothing groups, make a list of unique.
elif l[0] == 's':
if len(l) > 1:
smoothingGroups['_'.join(l[1:])] = None # Can we assign something more usefull? cant use sets yet
# Keep Smoothing group line
nonVertFileLines.append(l)
# Smoothing groups, make a list of unique.
elif l[0] == 'usemtl':
if len(l) > 1:
materialDict['_'.join(l[1:])] = None # Can we assign something more usefull? cant use sets yet
# Keep Smoothing group line
nonVertFileLines.append(l)
else:
nonVertFileLines.append(l)
lIdx+=1
# Ignore normals and comments.
fileLines = [lsplit for l in fileLines if not l.startswith('vn') if not l.startswith('#') for lsplit in (l.split(),) if lsplit]
Vert = NMesh.Vert
vertList = [Vert(float(l[1]), float(l[2]), float(l[3]) ) for l in fileLines if l[0] == 'v']
uvMapList = [(float(l[1]), float(l[2])) for l in fileLines if l[0] == 'vt']
smoothingGroups = dict([('_'.join(l[1:]), None) for l in fileLines if l[0] == 's' ])
materialDict = dict([('_'.join(l[1:]), None) for l in fileLines if l[0] == 'usemtl']) # Store all imported materials as unique dict, names are key
print '\tvert:%i texverts:%i smoothgroups:%i materials:%s' % (len(vertList), len(uvMapList), len(smoothingGroups), len(materialDict))
# Replace filelines, Excluding v excludes "v ", "vn " and "vt "
del fileLines
fileLines = nonVertFileLines
del nonVertFileLines
# Remove any variables we may have created.
try: del _dummy
except: pass
try: del _x
except: pass
try: del _y
except: pass
try: del _z
except: pass
try: del lsplit
except: pass
del Vert
# With negative values this is used a lot. make faster access.
len_uvMapList = len(uvMapList)
len_vertList = len(vertList)
# Only want unique keys anyway
smoothingGroups['(null)'] = None # Make sure we have at least 1.
@@ -572,7 +525,7 @@ def load_obj(file):
# Make a list of all unused vert indicies that we can copy from
VERT_USED_LIST = [0]*len(vertList)
VERT_USED_LIST = [0]*len_vertList
# Here we store a boolean list of which verts are used or not
# no we know weather to add them to the current mesh
@@ -584,9 +537,9 @@ def load_obj(file):
# We ignore it when naming the object.
currentObjectName = 'unnamed_obj_0' # If we cant get one, use this
meshDict = {} # The 3 variables below are stored in a tuple within this dict for each mesh
#meshDict = {} # The 3 variables below are stored in a tuple within this dict for each mesh
currentMesh = NMesh.GetRaw() # The NMesh representation of the OBJ group/Object
currentUsedVertList = {} # A Dict of smooth groups, each smooth group has a list of used verts and they are generated on demand so as to save memory.
#currentUsedVertList = {} # A Dict of smooth groups, each smooth group has a list of used verts and they are generated on demand so as to save memory.
currentMaterialMeshMapping = {} # Used to store material indicies so we dont have to search the mesh for materials every time.
# Every mesh has a null smooth group, this is used if there are no smooth groups in the OBJ file.
@@ -595,14 +548,13 @@ def load_obj(file):
# For direct accsess to the Current Meshes, Current Smooth Groups- Used verts.
# This is of course context based and changes on the fly.
currentUsedVertListSmoothGroup = VERT_USED_LIST[:]
# Set the initial '(null)' Smooth group, every mesh has one.
currentUsedVertList[currentSmoothGroup] = currentUsedVertListSmoothGroup
currentUsedVertListSmoothGroup = VERT_USED_LIST[:]
currentUsedVertList= {currentSmoothGroup: currentUsedVertListSmoothGroup }
# 0:NMesh, 1:SmoothGroups[UsedVerts[0,0,0,0]], 2:materialMapping['matname':matIndexForThisNMesh]
meshDict[currentObjectName] = (currentMesh, currentUsedVertList, currentMaterialMeshMapping)
meshDict = {currentObjectName: (currentMesh, currentUsedVertList, currentMaterialMeshMapping) }
# Only show the bad uv error once
badObjUvs = 0
@@ -611,20 +563,23 @@ def load_obj(file):
#currentMesh.verts.append(vertList[0]) # So we can sync with OBJ indicies where 1 is the first item.
if len(uvMapList) > 1:
if len_uvMapList > 1:
currentMesh.hasFaceUV(1) # Turn UV's on if we have ANY texture coords in this obj file.
#==================================================================================#
# Load all faces into objects, main loop #
#==================================================================================#
lIdx = 0
#lIdx = 0
# Face and Object loading LOOP
while lIdx < len(fileLines):
l = fileLines[lIdx]
#while lIdx < len(fileLines):
# l = fileLines[lIdx]
#for lIdx
for l in fileLines:
if len(l) == 0:
continue
# FACE
if l[0] == 'f':
elif l[0] == 'f':
# Make a face with the correct material.
# Add material to mesh
@@ -646,15 +601,19 @@ def load_obj(file):
vtIdxLs = []
fHasUV = len(uvMapList) # Assume the face has a UV until it sho it dosent, if there are no UV coords then this will start as 0.
fHasUV = len_uvMapList # Assume the face has a UV until it sho it dosent, if there are no UV coords then this will start as 0.
for v in l[1:]:
# OBJ files can have // or / to seperate vert/texVert/normal
# this is a bit of a pain but we must deal with it.
objVert = v.split('/')
# Vert Index - OBJ supports negative index assignment (like python)
index = int(objVert[0])-1
# Account for negative indicies.
if index < 0:
index = len_vertList+index+1
vIdxLs.append(int(objVert[0])-1)
vIdxLs.append(index)
if fHasUV:
# UV
index = 0 # Dummy var
@@ -662,15 +621,17 @@ def load_obj(file):
index = vIdxLs[-1]
elif objVert[1]: # != '' # Its possible that theres no texture vert just he vert and normal eg 1//2
index = int(objVert[1])-1
if len(uvMapList) > index:
if index < 0:
index = len_uvMapList+index+1
if len_uvMapList > index:
vtIdxLs.append(index) # Seperate UV coords
else:
# BAD FILE, I have found this so I account for it.
# INVALID UV COORD
# Could ignore this- only happens with 1 in 1000 files.
badObjFaceTexCo +=1
vtIdxLs.append(0)
vtIdxLs.append(1)
fHasUV = 0
@@ -678,12 +639,26 @@ def load_obj(file):
# The OBJ file would have to be corrupt or badly written for thi to happen
# but account for it anyway.
if len(vtIdxLs) > 0:
if vtIdxLs[-1] > len(uvMapList):
if vtIdxLs[-1] > len_uvMapList:
fHasUV = 0
badObjUvs +=1 # ERROR, Cont
# Quads only, we could import quads using the method below but it polite to import a quad as a quad.
if len(vIdxLs) == 4:
#print lIdx, len(vIdxLs), len(currentUsedVertListSmoothGroup)
#print fileLines[lIdx]
if len(vIdxLs) == 2:
if IMPORT_EDGES:
# Edge
for i in (0,1):
if currentUsedVertListSmoothGroup[vIdxLs[i]] == 0:
faceQuadVList[i] = vertList[vIdxLs[i]]
currentMesh.verts.append(faceQuadVList[i])
currentUsedVertListSmoothGroup[vIdxLs[i]] = len(currentMesh.verts)-1
else:
faceQuadVList[i] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[i]]]
currentMesh.addEdge(faceQuadVList[0], faceQuadVList[1])
elif len(vIdxLs) == 4:
# Have found some files where wach face references the same vert
# - This causes a bug and stopts the import so lets check here
@@ -751,22 +726,20 @@ def load_obj(file):
if len(l) == 1:
currentSmooth = True
currentSmoothGroup = '(null)'
try:
currentUsedVertListSmoothGroup = currentUsedVertList[currentSmoothGroup]
except KeyError:
currentUsedVertListSmoothGroup = VERT_USED_LIST[:]
currentUsedVertList[currentSmoothGroup] = currentUsedVertListSmoothGroup
else:
if l[1] == 'off':
currentSmooth = False
if l[1] == 'off': # We all have a null group so dont need to try, will try anyway to avoid code duplication.
if not IMPORT_SMOOTH_ALL:
currentSmooth = False
currentSmoothGroup = '(null)'
# We all have a null group so dont need to try
currentUsedVertListSmoothGroup = currentUsedVertList['(null)']
else:
currentSmooth = True
currentSmoothGroup = '_'.join(l[1:])
try:
currentUsedVertListSmoothGroup = currentUsedVertList[currentSmoothGroup]
except KeyError:
currentUsedVertList[currentSmoothGroup] = currentUsedVertListSmoothGroup = VERT_USED_LIST[:]
# OBJECT / GROUP
elif l[0] == 'o' or l[0] == 'g':
@@ -783,10 +756,10 @@ def load_obj(file):
else: # No name given
# Make a new empty name
if l[0] == 'g': # Make a blank group name
currentObjectName = 'unnamed_grp_%d' % currentUnnamedGroupIdx
currentObjectName = 'unnamed_grp_%.4d' % currentUnnamedGroupIdx
currentUnnamedGroupIdx +=1
else: # is an object.
currentObjectName = 'unnamed_ob_%d' % currentUnnamedObjectIdx
currentObjectName = 'unnamed_ob_%.4d' % currentUnnamedObjectIdx
currentUnnamedObjectIdx +=1
@@ -801,11 +774,10 @@ def load_obj(file):
currentUsedVertList = {}
# Sg is a string
currentSmoothGroup = '(null)'
currentUsedVertListSmoothGroup = VERT_USED_LIST[:]
currentUsedVertList[currentSmoothGroup] = currentUsedVertListSmoothGroup
currentMaterialMeshMapping = {}
########currentSmoothGroup = '(null)' # From examplesm changing the g/o shouldent change the smooth group.
currentUsedVertList[currentSmoothGroup] = currentUsedVertListSmoothGroup = VERT_USED_LIST[:]
currentMaterialMeshMapping = {}
meshDict[currentObjectName] = (currentMesh, currentUsedVertList, currentMaterialMeshMapping)
currentMesh.hasFaceUV(1)
contextMeshMatIdx = -1
@@ -822,8 +794,13 @@ def load_obj(file):
contextMeshMatIdx -1
# For new meshes switch smoothing groups to null
currentSmoothGroup = '(null)'
currentUsedVertListSmoothGroup = currentUsedVertList[currentSmoothGroup]
########currentSmoothGroup = '(null)' # From examplesm changing the g/o shouldent change the smooth group.
try:
currentUsedVertListSmoothGroup = currentUsedVertList[currentSmoothGroup]
except:
currentUsedVertList[currentSmoothGroup] = currentUsedVertListSmoothGroup = VERT_USED_LIST[:]
# MATERIAL
elif l[0] == 'usemtl':
@@ -859,11 +836,12 @@ def load_obj(file):
# MATERIAL FILE
elif l[0] == 'mtllib':
mtl_fileName.append(' '.join(l[1:]) ) # SHOULD SUPPORT MULTIPLE MTL?
lIdx+=1
#lIdx+=1
# Applies material properties to materials alredy on the mesh as well as Textures.
for mtl in mtl_fileName:
load_mtl(DIR, mtl, meshDict, materialDict)
if IMPORT_MTL:
for mtl in mtl_fileName:
load_mtl(DIR, mtl, meshDict, materialDict)
importedObjects = []
@@ -894,45 +872,78 @@ def load_obj(file):
print "obj import time: ", sys.time() - time1
def load_obj_ui(file):
# Batch directory loading.
def load_obj_dir(obj_dir):
IMPORT_MTL = Draw.Create(1)
IMPORT_DIR = Draw.Create(0)
IMPORT_NEW_SCENE = Draw.Create(0)
IMPORT_EDGES = Draw.Create(1)
IMPORT_SMOOTH_ALL = Draw.Create(0)
# Strip file
obj_dir = stripFile(obj_dir)
# Get USER Options
pup_block = [\
('Material (*.mtl)', IMPORT_MTL, 'Imports material settings and images from the obj\'s .mtl file'),\
('All *.obj\'s in dir', IMPORT_DIR, 'Import all obj files in this dir (avoid overlapping data with "Create scene")'),\
('Create scene', IMPORT_NEW_SCENE, 'Imports each obj into its own scene, named from the file'),\
'Geometry...',\
('Edges', IMPORT_EDGES, 'Import faces with 2 verts as in edge'),\
('Smooths all faces', IMPORT_SMOOTH_ALL, 'Smooth all faces even if they are not in a smoothing group'),\
]
if not os:
pup_block.pop(1) # Make sure this is the IMPORT_DIR option that requires OS
if not Draw.PupBlock('Import...', pup_block):
return
Window.WaitCursor(1)
Window.DrawProgressBar(0, '')
time = sys.time()
objFiles = [f for f in os.listdir(obj_dir) if f.lower().endswith('obj')]
IMPORT_MTL = IMPORT_MTL.val
IMPORT_DIR = IMPORT_DIR.val
IMPORT_NEW_SCENE = IMPORT_NEW_SCENE.val
IMPORT_EDGES = IMPORT_EDGES.val
IMPORT_SMOOTH_ALL = IMPORT_SMOOTH_ALL.val
Window.DrawProgressBar(0, '')
#orig_scene = Scene.GetCurrent()
obj_dir = stripFile(file)
if IMPORT_DIR:
obj_files = [(obj_dir,f) for f in os.listdir(obj_dir) if f.lower().endswith('obj')]
else:
obj_files = [(obj_dir,stripPath(file))]
obj_len = len(obj_files)
count = 0
obj_len = len(objFiles)
for obj in objFiles:
count+=1
newScn = Scene.New(obj)
newScn.makeCurrent()
Window.DrawProgressBar((float(count)/obj_len) - 0.01, '%s: %i of %i' % (obj, count, obj_len))
load_obj(obj_dir + obj)
for d, f in obj_files:
count+= 1
if not sys.exists(d+f):
print 'Error: "%s%s" does not exist' % (d,f)
else:
if IMPORT_NEW_SCENE:
scn = Scene.New('.'.join(f.split('.')[0:-1]))
scn.makeCurrent()
Window.DrawProgressBar((float(count)/obj_len) - 0.01, '%s: %i of %i' % (f, count, obj_len))
load_obj(d+f, IMPORT_MTL, IMPORT_EDGES, IMPORT_SMOOTH_ALL)
#orig_scene.makeCurrent() # We can leave them in there new scene.
Window.DrawProgressBar(1, '')
print 'Total obj import "%s" dir: %.2f' % (obj_dir, sys.time() - time)
Window.WaitCursor(0)
if count > 1:
print 'Total obj import "%s" dir: %.2f' % (obj_dir, sys.time() - time)
def main():
TEXT_IMPORT = 'Import a Wavefront OBJ'
TEXT_BATCH_IMPORT = 'Import *.obj to Scenes'
if Window.GetKeyQualifiers() & Window.Qual.SHIFT:
if not os:
Draw.PupMenu('Module "os" not found, needed for batch load, using normal selector.')
Window.FileSelector(load_obj, TEXT_IMPORT)
else:
Window.FileSelector(load_obj_dir, TEXT_BATCH_IMPORT)
else:
Window.FileSelector(load_obj, TEXT_IMPORT)
Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ')
if __name__ == '__main__':
main()
main()

View File

@@ -28,17 +28,34 @@ Notes:<br>
Only exports a single selected mesh.
"""
# $Id:
#
# +---------------------------------------------------------+
# | Copyright (c) 2002 Anthony D'Agostino |
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | February 3, 2001 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Read and write Object File Format (*.off) |
# +---------------------------------------------------------+
# ***** 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, meshtools
#import time

View File

@@ -29,18 +29,34 @@ Notes:<br>
UV Coordinate support has been added.
"""
# $Id:
#
# +---------------------------------------------------------+
# | Copyright (c) 2002 Anthony D'Agostino |
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | February 3, 2001 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Read and write Object File Format (*.off) |
# +---------------------------------------------------------+
# ***** 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, meshtools
#import time

View File

@@ -46,12 +46,27 @@ specular highlights to the vertex colors.
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | April 11, 2002 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Read and write Radiosity File Format (*.radio) |
# +---------------------------------------------------------+
# ***** 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, meshtools
#import time

View File

@@ -31,12 +31,27 @@ file to open.
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | April 11, 2002 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Read and write Radiosity File Format (*.radio) |
# +---------------------------------------------------------+
# ***** 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, meshtools
#import time

View File

@@ -25,7 +25,6 @@ Usage:<br>
Select meshes to be exported and run this script from "File->Export" menu.
"""
# $Id$
#
# +---------------------------------------------------------+
@@ -33,12 +32,27 @@ Usage:<br>
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | April 28, 2002 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Read and write RAW Triangle File Format (*.raw) |
# +---------------------------------------------------------+
# ***** 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, meshtools
import sys
#import time

View File

@@ -38,12 +38,27 @@ tolerance.
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | April 28, 2002 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Read and write RAW Triangle File Format (*.raw) |
# +---------------------------------------------------------+
# ***** 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, meshtools
#import time

View File

@@ -2,14 +2,14 @@
"""
Name: 'Save Current Theme...'
Blender: 237
Blender: 240
Group: 'Export'
Tooltip: 'Save current theme as a bpython script'
Tooltip: 'Save current theme as a BPython script'
"""
__author__ = "Willian P. Germano"
__url__ = ("blender", "elysiun")
__version__ = "2.37 2005/06/06"
__version__ = "2.41 2006/01/16"
__bpydoc__ = """\
This script saves the current Theme in Blender as a Blender Python script.
@@ -39,15 +39,32 @@ some information on it before sharing it with others.
# $Id$
#
# --------------------------------------------------------------------------
# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br
# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig com br
# --------------------------------------------------------------------------
# Released under the Blender Artistic License (BAL):
# http://download.blender.org/documentation/html/x21254.html
#
# The scripts generated by this script are put under Public Domain by
# default, but you are free to edit the ones you generate with this script
# and change their license to another one of your choice.
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2005: Willian P. Germano, wgermano _at_ ig.com.br
#
# 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
from Blender.Window import Theme, FileSelector
@@ -70,13 +87,13 @@ def write_theme(filename):
# \"\"\"
# Name: '%s'
# Blender: 237
# Blender: 241
# Group: 'Themes'
# Tooltip: 'Change current theme'
# \"\"\"
__%s__ = "????"
__%s__ = "2.37"
__%s__ = "2.41"
__%s__ = ["blender"]
__%s__ = \"\"\"\\
You can edit this section to write something about your script that can

View File

@@ -483,7 +483,9 @@ def main():
if choice == 1 and len(edgeOrderedList) > 2: # Loop
skin2EdgeLoops(edgeOrderedList[0], edgeOrderedList[-1], me, ob, 0)
print '\nArray done in %.4f sec.' % (sys.time()-time1)
me.update(1, 1, 0)
if is_editmode: Window.EditMode(1)
main()
if __name__ == '__main__':
main()

View File

@@ -36,12 +36,27 @@ tolerance.
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | May 3, 2004 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Read and write SLP Triangle File Format (*.slp) |
# +---------------------------------------------------------+
# ***** 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, meshtools
#import time

View File

@@ -2,7 +2,7 @@
""" Registration info for Blender menus:
Name: 'Texture Baker'
Blender: 236
Blender: 239
Group: 'UV'
Tooltip: 'Procedural to uvmapped texture baker'
"""
@@ -11,7 +11,7 @@ __author__ = "Jean-Michel Soler (jms)"
__url__ = ("blender", "elysiun",
"Official Page, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_mesh3d2uv2d_en.htm",
"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
__version__ = "0.3.1 2005/10/21"
__version__ = "0.3.2 2005/12/28"
__bpydoc__ = """\
This script "bakes" Blender procedural materials (including textures): it saves
@@ -49,6 +49,10 @@ Notes:<br>
#
# Released under Blender Artistic Licence
#
# 0.3.2
# blender 2.40 update to deal with the new shape
# key system .
#
# 0.3.1
# stupid bug correction
#
@@ -433,6 +437,85 @@ def REST_Shadeless(SHADEDict):
# release : 0.2.6 , 2005/05/29 , end
#-----------------------------------
#-----------------------------------
# release : 0.3.2 , 2005/12/28 , 13h00
#-----------------------------------
def Blender240update(MESH2,FRAME):
"""
# ---------------------------
# Function Blender240update
#
# IN : MESH2 a mesh data bloc
# FRAME , the animation frame limit
#
# ADD : an ipo curve to the shape key
# named "Key 1"
#
# OUT : nothing
# ---------------------------
"""
# ---------------------------
# recuperation des clef de morphing pour ce mesh
# ---------------------------
key = MESH2.getKey()
# ---------------------------
# recuperation de l'Ipo
# ---------------------------
ipo = key.ipo
# ---------------------------
# si l'ipo n'existe pas on la cree
# ---------------------------
if ipo == None:
noipo = Blender.Ipo.New("Key","keyipo")
key.ipo = noipo
# ---------------------------
# raccourci de l'expression
# ---------------------------
ipo = key.ipo
# ---------------------------
# identification de la clef de morphing
# ---------------------------
keyidentity = "Key 1"
# ---------------------------
# recuperation de la courbe correspondante
# c'est toujours la courbe 0
# ---------------------------
ipocurve = ipo.getCurve(0)
# ---------------------------
# si la courbe n'existe pas (normalement, elle n'existe pas mais
# on g<>re le risque pour faciliter une eventuelle r<>cup<75>ration de
# cette fonction dans un autre script ou pour les cas , certe peu
# probable, ou blender viendrait a etre modifie pour les ajouter
# automatiquement ) on la cree ...
# ---------------------------
if ipocurve == None:
ipocurve = ipo.addCurve(keyidentity)
# ---------------------------
# On applique l'attribut d'inetrpolation qui permet d'avoir
# une ligne droite
# ---------------------------
ipocurve.setInterpolation("Linear")
# ---------------------------
# On retire tous les sommets qui pourraient se trouver sur la
# courbe (dans l'<27>tat actuel, cette op<6F>ration est une s<>curit<69>
# superflue ) .
# ---------------------------
while len(ipocurve.getPoints()) > 0:
ipocurve.delBezier(0)
ipocurve.recalc()
# ---------------------------
# On ajouter les sommets necessaires ...
# ---------------------------
ipocurve.addBezier((-1,1))
# ---------------------------
# ... ce dernire n'est peut-<2D>tre pas absolument obligatoire .
# ---------------------------
ipocurve.addBezier((FRAME+1,1))
#-----------------------------------
# release : 0.3.2 , 2005/12/28 , end
#-----------------------------------
def Mesh2UVCoord (LIMIT):
"""
# ---------------------------
@@ -444,7 +527,7 @@ def Mesh2UVCoord (LIMIT):
"""
global PUTRAW, FRAME, SCENELAYERS
try :
try:
MESH3D = Object.GetSelected()[0]
if MESH3D.getType() == 'Mesh':
MESH = MESH3D.getData()
@@ -454,7 +537,8 @@ def Mesh2UVCoord (LIMIT):
CurSCENE=Blender.Scene.getCurrent()
except:
NewOBJECT, CurSCENE = GET_newobject('Mesh','UVOBJECT')
MESH2 = NewOBJECT.getData()
MESH2 = NewOBJECT.getData()
MESH2.edges=[]
NewOBJECT.layers=[RENDERLAYER]
MESH2.faces=[]
@@ -485,13 +569,12 @@ def Mesh2UVCoord (LIMIT):
NewOBJECT.setLocation (OBJPOS, OBJPOS, 0.0)
NewOBJECT.setEuler (0.0, 0.0, 0.0)
MESH2.removeAllKeys()
MESH2.update()
MESH2.insertKey (1, 'absolute')
MESH2.update()
for f in MESH2.faces:
for v in f.v:
for n in [0,1]:
@@ -506,6 +589,14 @@ def Mesh2UVCoord (LIMIT):
MESH2.insertKey (FRAME, 'absolute')
MESH2.update()
#-----------------------------------
# release : 0.3.2 , 2005/12/28 , 13h00
#-----------------------------------
Blender240update(MESH2,FRAME)
#-----------------------------------
# release : 0.3.2 , 2005/12/28 , end
#-----------------------------------
imagename = 'uvtext'
name = "CHANGE IMAGE NAME ? %t | Replace it | No replace | Script help"
@@ -551,4 +642,4 @@ def Mesh2UVCoord (LIMIT):
result = Draw.PupMenu(name)
print 'problem : no object selected or not mesh'
Mesh2UVCoord(LIMIT)
Mesh2UVCoord(LIMIT)

View File

@@ -49,7 +49,6 @@ For Cameras: The matrix here gets a little confusing, and I'm not sure of
how to handle it.
"""
# $Id$
#
# +---------------------------------------------------------+
@@ -57,12 +56,27 @@ how to handle it.
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | June 12, 2001 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Read and write Caligari trueSpace File Format (*.cob) |
# +---------------------------------------------------------+
# ***** 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, meshtools
import struct, os, cStringIO, time

View File

@@ -62,12 +62,27 @@ how to handle it.
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | June 12, 2001 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Read and write Caligari trueSpace File Format (*.cob) |
# +---------------------------------------------------------+
# ***** 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, meshtools
import struct, chunk, os, cStringIO, time

View File

@@ -9,7 +9,7 @@ Tooltip: 'Export the UV face layout of the selected object to a .TGA file'
__author__ = "Martin 'theeth' Poirier"
__url__ = ("http://www.blender.org", "http://www.elysiun.com")
__version__ = "1.3a"
__version__ = "1.4"
__bpydoc__ = """\
This script exports the UV face layout of the selected mesh object to
@@ -26,8 +26,9 @@ There are more options to configure, like setting export path, if image should
use object's name and more.
Notes:<br>
Jean-Michel Soler (jms) wrote TGA functions used by this script.
Zaz added the default path code and Selected Face option.
Jean-Michel Soler (jms) wrote TGA functions used by this script.<br>
Zaz added the default path code and Selected Face option.<br>
Macouno fixed a rounding error in the step calculations<br>
"""
@@ -62,19 +63,22 @@ Notes:<br>
# Communicate problems and errors on:
# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender
# --------------------------
# Version 1.1
# Version 1.1
# Clear a bug that crashed the script when UV coords overlapped in the same faces
# --------------------------
# Version 1.2
# Version 1.2
# Now with option to use the object's name as filename
# --------------------------
# Version 1.3 Updates by Zaz from Elysiun.com
# Version 1.3 Updates by Zaz from Elysiun.com
# Default path is now the directory of the last saved .blend
# New options: Work on selected face only & Scale image when face wraps
# --------------------------
# Version 1.3a
# Version 1.3a
# Corrected a minor typo and added the tga extension to both export call
# --------------------------
# Version 1.4 Updates by Macouno from Elysiun.com
# Fixed rounding error that can cause breaks in lines.
# --------------------------
import Blender
from math import *
@@ -134,42 +138,42 @@ def bevent(evt):
UV_Export(bSize.val, bWSize.val, bFile.val + ".tga")
def Buffer(height=16, width=16, profondeur=3,rvb=255 ):
"""
reserve l'espace memoire necessaire
"""
p=[rvb]
b=p*height*width*profondeur
return b
"""
reserve l'espace memoire necessaire
"""
p=[rvb]
b=p*height*width*profondeur
return b
def write_tgafile(loc2,bitmap,width,height,profondeur):
f=open(loc2,'wb')
f=open(loc2,'wb')
Origine_en_haut_a_gauche=32
Origine_en_bas_a_gauche=0
Origine_en_haut_a_gauche=32
Origine_en_bas_a_gauche=0
Data_Type_2=2
RVB=profondeur*8
RVBA=32
entete0=[]
for t in range(18):
entete0.append(chr(0))
Data_Type_2=2
RVB=profondeur*8
RVBA=32
entete0=[]
for t in range(18):
entete0.append(chr(0))
entete0[2]=chr(Data_Type_2)
entete0[13]=chr(width/256)
entete0[12]=chr(width % 256)
entete0[15]=chr(height/256)
entete0[14]=chr(height % 256)
entete0[16]=chr(RVB)
entete0[17]=chr(Origine_en_bas_a_gauche)
entete0[2]=chr(Data_Type_2)
entete0[13]=chr(width/256)
entete0[12]=chr(width % 256)
entete0[15]=chr(height/256)
entete0[14]=chr(height % 256)
entete0[16]=chr(RVB)
entete0[17]=chr(Origine_en_bas_a_gauche)
#Origine_en_haut_a_gauche
#Origine_en_haut_a_gauche
for t in entete0:
f.write(t)
for t in entete0:
f.write(t)
for t in bitmap:
f.write(chr(t))
f.close()
for t in bitmap:
f.write(chr(t))
f.close()
def UV_Export(size, wsize, file):
obj = Blender.Object.GetSelected()
@@ -238,11 +242,12 @@ def UV_Export(size, wsize, file):
co2 = f[index + 1]
else:
co2 = f[0]
step = int(size*sqrt((co1[0]-co2[0])**2+(co1[1]-co2[1])**2))
step = int(ceil(size*sqrt((co1[0]-co2[0])**2+(co1[1]-co2[1])**2)))
if step:
for t in range(step + 1):
x = int((co1[0] + t*(co2[0]-co1[0])/step) * size)
y = int((co1[1] + t*(co2[1]-co1[1])/step) * size)
for t in range(step):
x = int(floor((co1[0] + t*(co2[0]-co1[0])/step) * size))
y = int(floor((co1[1] + t*(co2[1]-co1[1])/step) * size))
if bWrap.val:
x = x % wrapSize
@@ -251,16 +256,17 @@ def UV_Export(size, wsize, file):
x = int ((x - minx) * scale)
y = int ((y - miny) * scale)
co = x * 3 + y * 3 * size
co = x * 3 + y * 3 * size;
img[co] = 0
img[co+1] = 0
img[co+2] = 255
img[co+2] = 0
if wsize > 1:
for x in range(-1*wsize + 1,wsize):
for y in range(-1*wsize,wsize):
img[co + 3 * x + y * 3 * size] = 0
img[co + 3 * x + y * 3 * size +1] = 0
img[co + 3 * x + y * 3 * size +2] = 255
img[co + 3 * x + y * 3 * size +2] = 0
for v in f:
x = int(v[0] * size)
@@ -276,8 +282,7 @@ def UV_Export(size, wsize, file):
co = x * 3 + y * 3 * size
img[co] = 0
img[co+1] = 0
img[co+2] = 0
img[co+2] = 255
write_tgafile(file,img,size,size,3)

View File

@@ -43,7 +43,6 @@ specular highlights to the vertex colors.
5. The Videoscape format also allows vertex colors to be specified.
"""
# $Id$
#
# +---------------------------------------------------------+
@@ -51,12 +50,27 @@ specular highlights to the vertex colors.
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | June 5, 2001 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Write Videoscape File Format (*.obj NOT WAVEFRONT OBJ) |
# +---------------------------------------------------------+
# ***** 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, meshtools
#import time

View File

@@ -4,6 +4,7 @@ Name: 'VRML97 (.wrl)...'
Blender: 235
Group: 'Export'
Submenu: 'All Objects...' all
Submenu: 'All Objects compressed...' comp
Submenu: 'Selected Objects...' selected
Tooltip: 'Export to VRML97 file (.wrl)'
"""
@@ -12,8 +13,8 @@ __author__ = ("Rick Kimball", "Ken Miller", "Steve Matthews", "Bart")
__url__ = ["blender", "elysiun",
"Author's (Rick) homepage, http://kimballsoftware.com/blender",
"Author's (Bart) homepage, http://www.neeneenee.de/vrml"]
__version__ = "2005/06/03"
__email__ = ["Bart, bart:neeneenee*de"]
__version__ = "2006/01/17"
__bpydoc__ = """\
This script exports to VRML97 format.
@@ -37,8 +38,6 @@ for each texture);<br>
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2003,2004: Rick Kimball rick@vrmlworld.net
#
# 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
@@ -61,7 +60,7 @@ for each texture);<br>
####################################
import Blender
from Blender import Object, NMesh, Lamp, Draw, BGL, Image, Text
from Blender import Object, NMesh, Lamp, Draw, BGL, Image, Text, sys, Mathutils
from Blender.Scene import Render
try:
from os.path import exists, join
@@ -80,15 +79,9 @@ world = Blender.World.Get()
worldmat = Blender.Texture.Get()
filename = Blender.Get('filename')
_safeOverwrite = True
radD=math.pi/180.0
extension = ''
ARG=''
def rad2deg(v):
return round(v*180.0/math.pi,4)
def deg2rad(v):
return (v*math.pi)/180.0;
class DrawTypes:
"""Object DrawTypes enum values
BOUNDS - draw only the bounding box of the object
@@ -161,11 +154,12 @@ class VRML2Export:
##########################################################
def writeHeader(self):
bfile = sys.expandpath(Blender.Get('filename'))
self.file.write("#VRML V2.0 utf8\n\n")
self.file.write("# This file was authored with Blender (http://www.blender.org/)\n")
self.file.write("# Blender version %s\n" % Blender.Get('version'))
self.file.write("# Blender file %s\n" % filename)
self.file.write("# Exported using VRML97 exporter v1.50 (2005/06/03)\n\n")
self.file.write("# Blender file %s\n" % sys.basename(bfile))
self.file.write("# Exported using VRML97 exporter v1.55 (2006/01/17)\n\n")
def writeInline(self):
inlines = Blender.Scene.Get()
@@ -205,9 +199,8 @@ class VRML2Export:
def writeViewpoint(self, thisObj):
context = scene.getRenderingContext()
ratio = float(context.imageSizeY())/float(context.imageSizeX())
lens = (360* (math.atan(ratio *16 / thisObj.data.getLens()) / 3.141593))*(3.141593/180)
if lens > 3.14:
lens = 3.14
lens = (360* (math.atan(ratio *16 / thisObj.data.getLens()) / math.pi))*(math.pi/180)
lens = min(lens, math.pi)
# get the camera location, subtract 90 degress from X to orient like VRML does
loc = self.rotatePointForVRML(thisObj.loc)
rot = [thisObj.RotX - 1.57, thisObj.RotY, thisObj.RotZ]
@@ -271,8 +264,8 @@ class VRML2Export:
ambientIntensity = 0
# compute cutoff and beamwidth
intensity=min(lamp.energy/1.5,1.0)
beamWidth=deg2rad(lamp.spotSize)*.37;
intensity=min(lamp.energy/1.75,1.0)
beamWidth=((lamp.spotSize*math.pi)/180.0)*.37;
cutOffAngle=beamWidth*1.3
(dx,dy,dz)=self.computeDirection(object)
@@ -303,7 +296,7 @@ class VRML2Export:
ambi = 0
ambientIntensity = 0
intensity=min(lamp.energy/1.5, 1.0)
intensity=min(lamp.energy/1.75,1.0)
(dx,dy,dz)=self.computeDirection(object)
self.writeIndented("DEF %s DirectionalLight {\n" % self.cleanStr(object.name),1)
self.writeIndented("ambientIntensity %s\n" % (round(ambientIntensity,self.cp)))
@@ -322,7 +315,7 @@ class VRML2Export:
ambientIntensity = 0
om = object.getMatrix()
location=self.rotVertex(om, (0,0,0));
intensity=min(lamp.energy/1.5,1.0)
intensity=min(lamp.energy/1.75,1.0)
radius = lamp.dist
self.writeIndented("DEF %s PointLight {\n" % self.cleanStr(object.name),1)
self.writeIndented("ambientIntensity %s\n" % (round(ambientIntensity,self.cp)))
@@ -346,28 +339,10 @@ class VRML2Export:
self.writeIndented("# location %s %s %s\n" % (round(location[0],3), round(location[1],3), round(location[2],3)))
self.writeIndented("}\n",-1)
self.writeIndented("\n")
def createDef(self, name):
name = name + str(self.nodeID)
self.nodeID=self.nodeID+1
if len(name) <= 3:
newname = "_" + str(self.nodeID)
return "%s" % (newname)
else:
for bad in [' ','"','#',"'",',','.','[','\\',']','{','}']:
name=name.replace(bad,'_')
if name in self.namesReserved:
newname = name[0:3] + "_" + str(self.nodeID)
return "%s" % (newname)
elif name[0].isdigit():
newname = "_" + name + str(self.nodeID)
return "%s" % (newname)
else:
newname = name
return "%s" % (newname)
def secureName(self, name):
name = name + str(self.nodeID)
self.nodeID=self.nodeID+1
self.nodeID += 1
if len(name) <= 3:
newname = "_" + str(self.nodeID)
return "%s" % (newname)
@@ -385,13 +360,14 @@ class VRML2Export:
return "%s" % (newname)
def writeIndexedFaceSet(self, object, normals = 0):
imageMap={} # set of used images
sided={} # 'one':cnt , 'two':cnt
vColors={} # 'multi':1
meshName = self.cleanStr(object.name)
mesh=object.getData()
meshME = self.cleanStr(mesh.name)
if len(mesh.faces) == 0:
return
for face in mesh.faces:
if face.mode & Blender.NMesh.FaceModes['HALO'] and self.halonode == 0:
self.writeIndented("Billboard {\n",1)
@@ -437,23 +413,22 @@ class VRML2Export:
issmooth=0
if len(maters) > 0 or mesh.hasFaceUV():
self.writeIndented("appearance Appearance {\n", 1)
# right now this script can only handle a single material per mesh.
if len(maters) >= 1:
mat=Blender.Material.Get(maters[0].name)
self.writeMaterial(mat, self.cleanStr(maters[0].name,''))
if len(maters) > 1:
print "Warning: mesh named %s has multiple materials" % meshName
print "Warning: only one material per object handled"
else:
self.writeIndented("material NULL\n")
self.writeIndented("appearance Appearance {\n", 1)
# right now this script can only handle a single material per mesh.
if len(maters) >= 1:
mat=Blender.Material.Get(maters[0].name)
matFlags = mat.getMode()
if not matFlags & Blender.Material.Modes['TEXFACE']:
self.writeMaterial(mat, self.cleanStr(maters[0].name,''))
if len(maters) > 1:
print "Warning: mesh named %s has multiple materials" % meshName
print "Warning: only one material per object handled"
#-- textures
if mesh.hasFaceUV():
for face in mesh.faces:
if (hasImageTexture == 0) and (face.image):
self.writeImageTexture(face.image.name)
self.writeImageTexture(face.image.name, face.image.filename)
hasImageTexture=1 # keep track of face texture
if self.tilenode == 1:
self.writeIndented("textureTransform TextureTransform { scale %s %s }\n" % (face.image.xrep, face.image.yrep))
@@ -501,7 +476,7 @@ class VRML2Export:
if face.smooth:
issmooth=1
if issmooth==1 and self.wire == 0:
creaseAngle=(mesh.getMaxSmoothAngle())*radD
creaseAngle=(mesh.getMaxSmoothAngle())*(math.pi/180.0)
self.writeIndented("creaseAngle %s\n" % (round(creaseAngle,self.cp)))
#--- output vertexColors
@@ -636,22 +611,27 @@ class VRML2Export:
self.matNames[matName]=1
ambient = mat.amb/2
ambient = mat.amb/3
diffuseR, diffuseG, diffuseB = mat.rgbCol[0], mat.rgbCol[1],mat.rgbCol[2]
if len(world) > 0:
ambi = world[0].getAmb()
ambi0, ambi1, ambi2 = ambi[0], ambi[1], ambi[2]
ambi0, ambi1, ambi2 = (ambi[0]*mat.amb)*2, (ambi[1]*mat.amb)*2, (ambi[2]*mat.amb)*2
else:
ambi = 0
ambi0, ambi1, ambi2 = 0, 0, 0
emisR, emisG, emisB = (diffuseR*mat.emit+ambi0)/4, (diffuseG*mat.emit+ambi1)/4, (diffuseB*mat.emit+ambi2)/4
emisR, emisG, emisB = (diffuseR*mat.emit+ambi0)/2, (diffuseG*mat.emit+ambi1)/2, (diffuseB*mat.emit+ambi2)/2
shininess = mat.hard/255.0
specR = (mat.specCol[0]+0.001)/(1.05/(mat.getSpec()+0.001))
specG = (mat.specCol[1]+0.001)/(1.05/(mat.getSpec()+0.001))
specB = (mat.specCol[2]+0.001)/(1.05/(mat.getSpec()+0.001))
shininess = mat.hard/512.0
specR = (mat.specCol[0]+0.001)/(1.25/(mat.getSpec()+0.001))
specG = (mat.specCol[1]+0.001)/(1.25/(mat.getSpec()+0.001))
specB = (mat.specCol[2]+0.001)/(1.25/(mat.getSpec()+0.001))
transp = 1-mat.alpha
matFlags = mat.getMode()
if matFlags & Blender.Material.Modes['SHADELESS']:
ambient = 1
shine = 1
specR = emitR = diffuseR
specG = emitG = diffuseG
specB = emitB = diffuseB
self.writeIndented("material DEF MA_%s Material {\n" % matName, 1)
self.writeIndented("diffuseColor %s %s %s\n" % (round(diffuseR,self.cp), round(diffuseG,self.cp), round(diffuseB,self.cp)))
self.writeIndented("ambientIntensity %s\n" % (round(ambient,self.cp)))
@@ -661,14 +641,14 @@ class VRML2Export:
self.writeIndented("transparency %s\n" % (round(transp,self.cp)))
self.writeIndented("}\n",-1)
def writeImageTexture(self, name):
def writeImageTexture(self, name, filename):
if self.texNames.has_key(name):
self.writeIndented("texture USE %s\n" % self.cleanStr(name))
self.texNames[name] += 1
return
else:
self.writeIndented("texture DEF %s ImageTexture {\n" % self.cleanStr(name), 1)
self.writeIndented("url \"%s\"\n" % name)
self.writeIndented("url \"%s\"\n" % name.split("\\")[-1].split("/")[-1])
self.writeIndented("}\n",-1)
self.texNames[name] = 1
@@ -687,7 +667,7 @@ class VRML2Export:
if worldname in self.namesStandard:
self.writeIndented("Background {\n",1)
else:
self.writeIndented("DEF %s Background {\n" % self.createDef(worldname),1)
self.writeIndented("DEF %s Background {\n" % self.secureName(worldname),1)
# No Skytype - just Hor color
if blending == 0:
self.writeIndented("groundColor %s %s %s\n" % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
@@ -956,11 +936,8 @@ class VRML2Export:
def writeIndented(self, s, inc=0):
if inc < 1:
self.indentLevel = self.indentLevel + inc
spaces=""
for x in xrange(self.indentLevel):
spaces = spaces + "\t"
self.file.write(spaces + s)
self.file.write( self.indentLevel*"\t" + s)
if inc > 0:
self.indentLevel = self.indentLevel + inc
@@ -1016,7 +993,9 @@ def select_file(filename):
if(result != 1):
return
if filename.find('.wrl', -4) < 0: filename += '.wrl'
if not filename.endswith(extension):
filename += extension
wrlexport=VRML2Export(filename)
wrlexport.export(scene, world, worldmat)
@@ -1026,7 +1005,7 @@ def createWRLPath():
if filename.find('.') != -1:
filename = filename.split('.')[0]
filename += ".wrl"
filename += extension
print filename
return filename
@@ -1041,8 +1020,14 @@ except:
print "older version"
if Blender.Get('version') < 235:
print "Warning: VRML97 export failed, wrong blender version!"
print " You aren't running blender version 2.35 or greater"
print " download a newer version from http://blender3d.org/"
print "Warning: VRML97 export failed, wrong blender version!"
print " You aren't running blender version 2.35 or greater"
print " download a newer version from http://blender3d.org/"
else:
Blender.Window.FileSelector(select_file,"Export VRML97",createWRLPath())
if ARG == 'comp':
extension=".wrz"
from gzip import *
else:
extension=".wrl"
Blender.Window.FileSelector(select_file,"Export VRML97",createWRLPath())

View File

@@ -50,12 +50,27 @@ Notes:<br>
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | Feb 19, 2002 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Read and write Wings3D File Format (*.wings) |
# +---------------------------------------------------------+
# ***** 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, meshtools
import struct, time, sys, os, zlib, cStringIO

View File

@@ -11,7 +11,7 @@ __author__ = "Anthony D'Agostino (Scorpius)"
__url__ = ("blender", "elysiun",
"Author's homepage, http://www.redrival.com/scorpius",
"Wings 3D, http://www.wings3d.com")
__version__ = "Part of IOSuite 0.5"
__version__ = "Update on version from IOSuite 0.5"
__bpydoc__ = """\
This script imports Wings3D files to Blender.
@@ -37,7 +37,8 @@ fanning algorithm. Convex polygons (i.e., shaped like the letter "U")
require a different algorithm, and will be triagulated incorrectly.
Notes:<br>
Last tested with Wings 3D 0.98.25 & Blender 2.35a.
Last tested with Wings 3D 0.98.25 & Blender 2.35a.<br>
This version has improvements made by Adam Saltsman (AdamAtomic) and Toastie.
"""
# $Id$
@@ -47,15 +48,29 @@ Notes:<br>
# | http://www.redrival.com/scorpius |
# | scorpius@netzero.com |
# | Feb 19, 2002 |
# | Released under the Blender Artistic Licence (BAL) |
# | Import Export Suite v0.5 |
# +---------------------------------------------------------+
# | Read and write Wings3D File Format (*.wings) |
# +---------------------------------------------------------+
# ***** 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, meshtools
import struct, time, sys, os, zlib, cStringIO
# ==============================================
# === Read The 'Header' Common To All Chunks ===
# ==============================================
@@ -79,26 +94,28 @@ def read_mode(data):
# === Read Hard Edges ===
# =======================
def read_hardedges(data):
hardedge_table = {} # hard edges table
tag = data.read(1)
if tag == '\x6A':
return # There are no hard edges
return hardedge_table # There are no hard edges
elif tag == '\x6B':
numhardedges, = struct.unpack(">H", data.read(2))
print "numhardedges:", numhardedges
#print "numhardedges:", numhardedges
for i in range(numhardedges):
data.read(1)
hardedge_table[i] = struct.unpack(">B", data.read(1))[0]
elif tag == '\x6C':
numhardedges, = struct.unpack(">L", data.read(4))
print "numhardedges:", numhardedges
#print "numhardedges:", numhardedges
for i in range(numhardedges):
misc = data.read(1)
if misc == '\x61': # next value is stored as a byte
data.read(1)
hardedge_table[i] = struct.unpack(">B", data.read(1))[0]
elif misc == '\x62': # next value is stored as a long
data.read(4)
hardedge_table[i] = struct.unpack(">L", data.read(4))[0]
data.read(1) # 6A
else:
print tag
return hardedge_table
# ==================
# === Read Edges ===
@@ -134,6 +151,7 @@ def read_edges(data):
# === Read Faces ===
# ==================
def read_faces(data):
mat_table = {} #list of faces and material names
misc, numfaces = struct.unpack(">BL", data.read(5))
for i in range(numfaces):
if not i%100 and meshtools.show_progress: Blender.Window.DrawProgressBar(float(i)/numfaces, "Reading Faces")
@@ -141,10 +159,10 @@ def read_faces(data):
data.read(4)
read_chunkheader(data)
misc, namelen = struct.unpack(">BH", data.read(3))
materialname = data.read(namelen)
data.read(1)
mat_table[i] = data.read(namelen)
data.read(1) # 6A?
data.read(1) # 6A
return numfaces
return mat_table
# ==================
# === Read Verts ===
@@ -169,8 +187,10 @@ def make_face_table(edge_table): # For Wings
for i in range(len(edge_table)):
Lf = edge_table[i][2]
Rf = edge_table[i][3]
face_table[Lf] = i
face_table[Rf] = i
if Lf >= 0:
face_table[Lf] = i
if Rf >= 0:
face_table[Rf] = i
return face_table
# =======================
@@ -198,14 +218,17 @@ def make_faces(edge_table): # For Wings
if i == edge_table[current_edge][3]:
next_edge = edge_table[current_edge][7] # Right successor edge
next_vert = edge_table[current_edge][0]
else:
elif i == edge_table[current_edge][2]:
next_edge = edge_table[current_edge][5] # Left successor edge
next_vert = edge_table[current_edge][1]
else:
break
face_verts.append(next_vert)
current_edge = next_edge
if current_edge == face_table[i]: break
face_verts.reverse()
faces.append(face_verts)
if len(face_verts) > 0:
face_verts.reverse()
faces.append(face_verts)
return faces
# =======================
@@ -223,7 +246,7 @@ def dump_wings(filename):
file.close()
data = zlib.decompress(data)
if dsize != len(data): print "ERROR: uncompressed size does not match."
data = cStringIO.StringIO(data)
data = cStringIO.StringIO(data)
print "header:", header
print read_chunkheader(data) # === wings chunk ===
data.read(4) # misc bytes
@@ -236,9 +259,10 @@ def dump_wings(filename):
objname = data.read(namelen)
print read_chunkheader(data) # === winged chunk ===
edge_table = read_edges(data)
numfaces = read_faces(data)
mat_table = read_faces(data)
numfaces = len(mat_table)
verts = read_verts(data)
read_hardedges(data)
hardedge_table = read_hardedges(data)
face_table = {} # contains an incident edge
vert_table = {} # contains an incident edge
@@ -255,25 +279,26 @@ def dump_wings(filename):
print
print "<EFBFBD>"*79
print "edge_table:"
pprint.pprint(edge_table)
#pprint.pprint(edge_table)
#for i in range(len(edge_table)): print "%2d" % (i), edge_table[i]
print
print "face_table:"
pprint.pprint(face_table)
#pprint.pprint(face_table)
#for i in range(len(face_table)): print "%2d %2d" % (i, face_table[i])
print
print "vert_table:"
pprint.pprint(vert_table)
#pprint.pprint(vert_table)
#for i in range(len(vert_table)): print "%2d %2d" % (i, vert_table[i])
file.close()
end = time.clock()
print '\a\r',
sys.stderr.write("\nDone in %.2f %s" % (end-start, "seconds"))
sys.stderr.write("\nDone in %.2f %s\a\r" % (end-start, "seconds"))
# =========================
# === Read Wings Format ===
# =========================
def read(filename):
start = time.clock()
file = open(filename, "rb")
header = file.read(15)
@@ -299,9 +324,113 @@ def read(filename):
objname = data.read(namelen)
read_chunkheader(data) # winged chunk
edge_table = read_edges(data)
numfaces = read_faces(data)
mat_table = read_faces(data)
numfaces = len(mat_table)
verts = read_verts(data)
read_hardedges(data)
hardedge_table = read_hardedges(data)
# Manually split hard edges
# TODO: Handle the case where there are 2+ edges on a face
duped = {}
processed = []
cleanup = []
oldedgecount = len(edge_table)
for i in range(len(verts)):
duped[i] = -1
for j in range(len(hardedge_table)):
hardedge = hardedge_table[j]
oldedge = edge_table[hardedge]
newedge = [] # Copy old edge into a new list
for k in range(len(oldedge)):
newedge.append(oldedge[k])
# Duplicate start vert if not duped already
sv = newedge[0]
if duped[sv] == -1:
verts.append(verts[sv])
duped[sv] = len(verts)-1
newedge[0] = duped[sv]
# Duplicate end vert if not duped already
ev = newedge[1]
if duped[ev] == -1:
verts.append(verts[ev])
duped[ev] = len(verts)-1
newedge[1] = duped[ev]
# Decide which way to cut the edge
flip = 0
for v in range(len(processed)):
if processed[v][0] == oldedge[0]:
flip = 1
elif processed[v][1] == oldedge[1]:
flip = 1
if flip == 0:
of = 3
oe1 = 6
oe2 = 7
nf = 2
ne1 = 4
ne2 = 5
else:
of = 2
oe1 = 4
oe2 = 5
nf = 3
ne1 = 6
ne2 = 7
# Fix up side-specific edge fields
oldedge[of] = -1
oldedge[oe1] = -1
oldedge[oe2] = -1
newedge[nf] = -1
newedge[ne1] = -1
newedge[ne2] = -1
# Store new edge's neighbors for cleanup later
cleanup.append(edge_table[newedge[oe1]])
cleanup.append(edge_table[newedge[oe2]])
#DEBUG
# Sv Ev | Lf Rf | Lp Ls | Rp Rs
#print "Old Edge:",hardedge,oldedge
#print "New Edge:",len(edge_table),newedge
# Add this new edge to the edge table
edge_table[len(edge_table)] = newedge
if flip == 0:
processed.append(oldedge) # mark it off as processed
# Cycle through cleanup list and fix it up
for c in range(len(cleanup)):
cleanupedge = cleanup[c]
# Fix up their verts in case they were duped
sv = cleanupedge[0]
if sv < len(duped):
if duped[sv] >= 0:
cleanupedge[0] = duped[sv]
ev = cleanupedge[1]
if ev < len(duped):
if duped[ev] >= 0:
cleanupedge[1] = duped[ev]
# Fix up edge info (in case a hard edge was replaced with a new one)
edgecount = c/2
hardedge = hardedge_table[edgecount] # look up what edge we were replacing
newedgenum = oldedgecount+edgecount # calculate new edge's index
if cleanupedge[4] == hardedge:
cleanupedge[4] = newedgenum
if cleanupedge[5] == hardedge:
cleanupedge[5] = newedgenum
if cleanupedge[6] == hardedge:
cleanupedge[6] = newedgenum
if cleanupedge[7] == hardedge:
cleanupedge[7] = newedgenum
#for i in range(len(edge_table)): print "%2d" % (i), edge_table[i]
read_mode(data)
faces = make_faces(edge_table)
message += "%s %8s %8s %8s\n" % (objname.ljust(15), len(faces), len(edge_table), len(verts))

View File

@@ -4,16 +4,15 @@ Name: 'X3D Extensible 3D (.x3d)...'
Blender: 235
Group: 'Export'
Submenu: 'All Objects...' all
Submenu: 'All Objects compressed...' comp
Submenu: 'Selected Objects...' selected
Tooltip: 'Export to Extensible 3D file (.x3d)'
"""
__author__ = ("Bart")
__email__ = ["Bart, bart:neeneenee*de"]
__url__ = ["Author's (Bart) homepage, http://www.neeneenee.de/vrml"]
__version__ = "2005/06/06"
__version__ = "2006/01/17"
__bpydoc__ = """\
This script exports to X3D format.
@@ -37,8 +36,6 @@ for each texture);<br>
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2003,2004: Bart bart@neeneenee.de
#
# 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
@@ -61,7 +58,7 @@ for each texture);<br>
####################################
import Blender
from Blender import Object, NMesh, Lamp, Draw, BGL, Image, Text
from Blender import Object, NMesh, Lamp, Draw, BGL, Image, Text, sys, Mathutils
from Blender.Scene import Render
try:
from os.path import exists, join
@@ -80,14 +77,8 @@ world = Blender.World.Get()
worldmat = Blender.Texture.Get()
filename = Blender.Get('filename')
_safeOverwrite = True
radD=math.pi/180.0
ARG=''
def rad2deg(v):
return round(v*180.0/math.pi,4)
def deg2rad(v):
return (v*math.pi)/180.0;
extension = ''
class DrawTypes:
"""Object DrawTypes enum values
@@ -177,13 +168,14 @@ class VRML2Export:
##########################################################
def writeHeader(self):
bfile = sys.expandpath(Blender.Get('filename'))
self.file.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
self.file.write("<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D 3.0//EN\" \"http://www.web3d.org/specifications/x3d-3.0.dtd\">\n")
self.file.write("<X3D version=\"3.0\" profile=\"Immersive\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema-instance\" xsd:noNamespaceSchemaLocation=\"http://www.web3d.org/specifications/x3d-3.0.xsd\">\n")
self.file.write("<head>\n")
self.file.write("\t<meta name=\"filename\" content=\"%s\" />\n" % filename)
self.file.write("\t<meta name=\"filename\" content=\"%s\" />\n" % sys.basename(bfile))
self.file.write("\t<meta name=\"generator\" content=\"Blender %s\" />\n" % Blender.Get('version'))
self.file.write("\t<meta name=\"translator\" content=\"X3D exporter v1.50 (2005/06/06)\" />\n")
self.file.write("\t<meta name=\"translator\" content=\"X3D exporter v1.55 (2006/01/17)\" />\n")
self.file.write("</head>\n")
self.file.write("<Scene>\n")
@@ -224,9 +216,8 @@ class VRML2Export:
def writeViewpoint(self, thisObj):
context = scene.getRenderingContext()
ratio = float(context.imageSizeY())/float(context.imageSizeX())
lens = (360* (math.atan(ratio *16 / thisObj.data.getLens()) / 3.141593))*(3.141593/180)
if lens > 3.14:
lens = 3.14
lens = (360* (math.atan(ratio *16 / thisObj.data.getLens()) / math.pi))*(math.pi/180)
lens = min(lens, math.pi)
# get the camera location, subtract 90 degress from X to orient like X3D does
loc = self.rotatePointForVRML(thisObj.loc)
rot = [thisObj.RotX - 1.57, thisObj.RotY, thisObj.RotZ]
@@ -283,8 +274,8 @@ class VRML2Export:
ambientIntensity = 0
# compute cutoff and beamwidth
intensity=min(lamp.energy/1.5,1.0)
beamWidth=deg2rad(lamp.spotSize)*.37;
intensity=min(lamp.energy/1.75,1.0)
beamWidth=((lamp.spotSize*math.pi)/180.0)*.37;
cutOffAngle=beamWidth*1.3
(dx,dy,dz)=self.computeDirection(object)
@@ -314,7 +305,7 @@ class VRML2Export:
ambi = 0
ambientIntensity = 0
intensity=min(lamp.energy/1.5, 1.0)
intensity=min(lamp.energy/1.75,1.0)
(dx,dy,dz)=self.computeDirection(object)
self.file.write("<DirectionalLight DEF=\"%s\" " % safeName)
self.file.write("ambientIntensity=\"%s\" " % (round(ambientIntensity,self.cp)))
@@ -332,7 +323,7 @@ class VRML2Export:
ambientIntensity = 0
om = object.getMatrix()
location=self.rotVertex(om, (0,0,0));
intensity=min(lamp.energy/1.5,1.0)
intensity=min(lamp.energy/1.75,1.0)
radius = lamp.dist
self.file.write("<PointLight DEF=\"%s\" " % safeName)
self.file.write("ambientIntensity=\"%s\" " % (round(ambientIntensity,self.cp)))
@@ -354,24 +345,6 @@ class VRML2Export:
self.writeIndented("# location %s %s %s\n" % (round(location[0],3), round(location[1],3), round(location[2],3)))
self.writeIndented("/>\n",-1)
self.writeIndented("\n")
def createDef(self, name):
name = name + str(self.nodeID)
self.nodeID=self.nodeID+1
if len(name) <= 3:
newname = "_" + str(self.nodeID)
return "%s" % (newname)
else:
for bad in [' ','"','#',"'",',','.','[','\\',']','{','}']:
name=name.replace(bad,'_')
if name in self.namesReserved:
newname = name[0:3] + "_" + str(self.nodeID)
return "%s" % (newname)
elif name[0].isdigit():
newname = "_" + name + str(self.nodeID)
return "%s" % (newname)
else:
newname = name
return "%s" % (newname)
def secureName(self, name):
name = name + str(self.nodeID)
@@ -393,13 +366,14 @@ class VRML2Export:
return "%s" % (newname)
def writeIndexedFaceSet(self, object, normals = 0):
imageMap={} # set of used images
sided={} # 'one':cnt , 'two':cnt
vColors={} # 'multi':1
meshName = self.cleanStr(object.name)
mesh=object.getData()
meshME = self.cleanStr(mesh.name)
if len(mesh.faces) == 0:
return
for face in mesh.faces:
if face.mode & Blender.NMesh.FaceModes['HALO'] and self.halonode == 0:
self.writeIndented("<Billboard axisOfRotation=\"0 0 0\">\n",1)
@@ -436,17 +410,16 @@ class VRML2Export:
issmooth=0
if len(maters) > 0 or mesh.hasFaceUV():
self.writeIndented("<Appearance>\n", 1)
# right now this script can only handle a single material per mesh.
if len(maters) >= 1:
mat=Blender.Material.Get(maters[0].name)
self.writeMaterial(mat, self.cleanStr(maters[0].name,''))
if len(maters) > 1:
print "Warning: mesh named %s has multiple materials" % meshName
print "Warning: only one material per object handled"
else:
self.writeIndented("<material NULL />\n")
self.writeIndented("<Appearance>\n", 1)
# right now this script can only handle a single material per mesh.
if len(maters) >= 1:
mat=Blender.Material.Get(maters[0].name)
matFlags = mat.getMode()
if not matFlags & Blender.Material.Modes['TEXFACE']:
self.writeMaterial(mat, self.cleanStr(maters[0].name,''))
if len(maters) > 1:
print "Warning: mesh named %s has multiple materials" % meshName
print "Warning: only one material per object handled"
#-- textures
if mesh.hasFaceUV():
@@ -489,7 +462,7 @@ class VRML2Export:
if face.smooth:
issmooth=1
if issmooth==1 and self.wire == 0:
creaseAngle=(mesh.getMaxSmoothAngle())*radD
creaseAngle=(mesh.getMaxSmoothAngle())*(math.pi/180.0)
self.file.write("creaseAngle=\"%s\" " % (round(creaseAngle,self.cp)))
#--- output vertexColors
@@ -640,22 +613,27 @@ class VRML2Export:
self.matNames[matName]=1
ambient = mat.amb/2
ambient = mat.amb/3
diffuseR, diffuseG, diffuseB = mat.rgbCol[0], mat.rgbCol[1],mat.rgbCol[2]
if len(world) > 0:
ambi = world[0].getAmb()
ambi0, ambi1, ambi2 = ambi[0], ambi[1], ambi[2]
ambi0, ambi1, ambi2 = (ambi[0]*mat.amb)*2, (ambi[1]*mat.amb)*2, (ambi[2]*mat.amb)*2
else:
ambi = 0
ambi0, ambi1, ambi2 = 0, 0, 0
emisR, emisG, emisB = (diffuseR*mat.emit+ambi0)/4, (diffuseG*mat.emit+ambi1)/4, (diffuseB*mat.emit+ambi2)/4
emisR, emisG, emisB = (diffuseR*mat.emit+ambi0)/2, (diffuseG*mat.emit+ambi1)/2, (diffuseB*mat.emit+ambi2)/2
shininess = mat.hard/255.0
specR = (mat.specCol[0]+0.001)/(1.05/(mat.getSpec()+0.001))
specG = (mat.specCol[1]+0.001)/(1.05/(mat.getSpec()+0.001))
specB = (mat.specCol[2]+0.001)/(1.05/(mat.getSpec()+0.001))
shininess = mat.hard/512.0
specR = (mat.specCol[0]+0.001)/(1.25/(mat.getSpec()+0.001))
specG = (mat.specCol[1]+0.001)/(1.25/(mat.getSpec()+0.001))
specB = (mat.specCol[2]+0.001)/(1.25/(mat.getSpec()+0.001))
transp = 1-mat.alpha
matFlags = mat.getMode()
if matFlags & Blender.Material.Modes['SHADELESS']:
ambient = 1
shine = 1
specR = emitR = diffuseR
specG = emitG = diffuseG
specB = emitB = diffuseB
self.writeIndented("<Material DEF=\"MA_%s\" " % matName, 1)
self.file.write("diffuseColor=\"%s %s %s\" " % (round(diffuseR,self.cp), round(diffuseG,self.cp), round(diffuseB,self.cp)))
self.file.write("specularColor=\"%s %s %s\" " % (round(specR,self.cp), round(specG,self.cp), round(specB,self.cp)))
@@ -690,7 +668,7 @@ class VRML2Export:
mix0, mix1, mix2 = mix0/2, mix1/2, mix2/2
self.file.write("<Background ")
if worldname not in self.namesStandard:
self.file.write("DEF=\"%s\" " % self.createDef(worldname))
self.file.write("DEF=\"%s\" " % self.secureName(worldname))
# No Skytype - just Hor color
if blending == 0:
self.file.write("groundColor=\"%s %s %s\" " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
@@ -1016,7 +994,9 @@ def select_file(filename):
if(result != 1):
return
if filename.find('.x3d', -4) < 0: filename += '.x3d'
if not filename.endswith(extension):
filename += extension
wrlexport=VRML2Export(filename)
wrlexport.export(scene, world, worldmat)
@@ -1026,7 +1006,7 @@ def createWRLPath():
if filename.find('.') != -1:
filename = filename.split('.')[0]
filename += ".x3d"
filename += extension
print filename
return filename
@@ -1041,8 +1021,14 @@ except:
print "older version"
if Blender.Get('version') < 235:
print "Warning: X3D export failed, wrong blender version!"
print " You aren't running blender version 2.35 or greater"
print " download a newer version from http://blender3d.org/"
print "Warning: X3D export failed, wrong blender version!"
print " You aren't running blender version 2.35 or greater"
print " download a newer version from http://blender3d.org/"
else:
Blender.Window.FileSelector(select_file,"Export X3D",createWRLPath())
if ARG == 'comp':
from gzip import *
extension=".x3dz"
else:
extension=".x3d"
Blender.Window.FileSelector(select_file,"Export X3D",createWRLPath())