2009-11-01 15:21:20 +00:00
# ##### 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 LICENSE BLOCK #####
2007-03-31 12:23:46 +00:00
__author__ = " Campbell Barton "
2007-03-28 07:08:18 +00:00
__url__ = [ ' www.blender.org ' , ' blenderartists.org ' ]
2009-05-06 04:24:01 +00:00
__version__ = " 1.2 "
2007-03-28 07:08:18 +00:00
__bpydoc__ = """ \
This script is an exporter to the FBX file format .
2007-09-08 08:49:56 +00:00
http : / / wiki . blender . org / index . php / Scripts / Manual / Export / autodesk_fbx
2007-03-28 07:08:18 +00:00
"""
# --------------------------------------------------------------------------
# FBX Export v0.1 by Campbell Barton (AKA Ideasman)
# --------------------------------------------------------------------------
# ***** 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 *****
# --------------------------------------------------------------------------
2009-09-29 15:27:00 +00:00
import os
import time
import math # math.pi
import shutil # for file copying
# try:
# import time
# # import os # only needed for batch export, nbot used yet
# except:
# time = None # use this to check if they have python modules installed
2007-08-24 12:13:34 +00:00
# for python 2.3 support
try :
set ( )
except :
try :
from sets import Set as set
except :
set = None # so it complains you dont have a !
2007-08-23 16:34:15 +00:00
2009-09-29 15:27:00 +00:00
# # os is only needed for batch 'own dir' option
# try:
# import os
# except:
# os = None
2007-08-28 02:11:49 +00:00
2009-09-29 15:27:00 +00:00
# import Blender
2007-08-23 16:34:15 +00:00
import bpy
2009-09-29 15:27:00 +00:00
import Mathutils
# from Blender.Mathutils import Matrix, Vector, RotationMatrix
2007-08-23 16:34:15 +00:00
2009-09-29 15:27:00 +00:00
# import BPyObject
# import BPyMesh
# import BPySys
# import BPyMessages
2007-08-23 16:34:15 +00:00
2007-08-29 03:56:22 +00:00
## This was used to make V, but faster not to do all that
##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_,.()[]{}'
##v = range(255)
##for c in valid: v.remove(ord(c))
v = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 42 , 43 , 47 , 58 , 59 , 60 , 61 , 62 , 63 , 64 , 92 , 94 , 96 , 124 , 126 , 127 , 128 , 129 , 130 , 131 , 132 , 133 , 134 , 135 , 136 , 137 , 138 , 139 , 140 , 141 , 142 , 143 , 144 , 145 , 146 , 147 , 148 , 149 , 150 , 151 , 152 , 153 , 154 , 155 , 156 , 157 , 158 , 159 , 160 , 161 , 162 , 163 , 164 , 165 , 166 , 167 , 168 , 169 , 170 , 171 , 172 , 173 , 174 , 175 , 176 , 177 , 178 , 179 , 180 , 181 , 182 , 183 , 184 , 185 , 186 , 187 , 188 , 189 , 190 , 191 , 192 , 193 , 194 , 195 , 196 , 197 , 198 , 199 , 200 , 201 , 202 , 203 , 204 , 205 , 206 , 207 , 208 , 209 , 210 , 211 , 212 , 213 , 214 , 215 , 216 , 217 , 218 , 219 , 220 , 221 , 222 , 223 , 224 , 225 , 226 , 227 , 228 , 229 , 230 , 231 , 232 , 233 , 234 , 235 , 236 , 237 , 238 , 239 , 240 , 241 , 242 , 243 , 244 , 245 , 246 , 247 , 248 , 249 , 250 , 251 , 252 , 253 , 254 ]
invalid = ' ' . join ( [ chr ( i ) for i in v ] )
def cleanName ( name ) :
for ch in invalid : name = name . replace ( ch , ' _ ' )
return name
2009-09-29 15:27:00 +00:00
# del v, i
2007-08-29 03:56:22 +00:00
2007-08-23 16:34:15 +00:00
def copy_file ( source , dest ) :
file = open ( source , ' rb ' )
data = file . read ( )
file . close ( )
file = open ( dest , ' wb ' )
file . write ( data )
file . close ( )
2009-09-29 15:27:00 +00:00
# XXX not used anymore, images are copied one at a time
2007-08-23 16:34:15 +00:00
def copy_images ( dest_dir , textures ) :
2009-09-29 15:27:00 +00:00
if not dest_dir . endswith ( os . sep ) :
dest_dir + = os . sep
2007-08-23 16:34:15 +00:00
2007-08-28 05:32:00 +00:00
image_paths = set ( )
2009-05-06 06:01:09 +00:00
for tex in textures :
image_paths . add ( Blender . sys . expandpath ( tex . filename ) )
2007-08-28 05:32:00 +00:00
2007-08-23 16:34:15 +00:00
# Now copy images
copyCount = 0
2007-08-28 05:32:00 +00:00
for image_path in image_paths :
2007-08-23 16:34:15 +00:00
if Blender . sys . exists ( image_path ) :
# Make a name for the target path.
dest_image_path = dest_dir + image_path . split ( ' \\ ' ) [ - 1 ] . split ( ' / ' ) [ - 1 ]
if not Blender . sys . exists ( dest_image_path ) : # Image isnt alredy there
2009-09-29 15:27:00 +00:00
print ( ' \t Copying " %s " > " %s " ' % ( image_path , dest_image_path ) )
2007-08-23 16:34:15 +00:00
try :
copy_file ( image_path , dest_image_path )
copyCount + = 1
except :
2009-09-29 15:27:00 +00:00
print ( ' \t \t Warning, file failed to copy, skipping. ' )
2007-08-23 16:34:15 +00:00
2009-09-29 15:27:00 +00:00
print ( ' \t Copied %d images ' % copyCount )
# I guess FBX uses degrees instead of radians (Arystan).
# Call this function just before writing to FBX.
def eulerRadToDeg ( eul ) :
ret = Mathutils . Euler ( )
2007-08-15 00:48:33 +00:00
2009-09-29 15:27:00 +00:00
ret . x = 180 / math . pi * eul [ 0 ]
ret . y = 180 / math . pi * eul [ 1 ]
ret . z = 180 / math . pi * eul [ 2 ]
return ret
mtx4_identity = Mathutils . Matrix ( )
2007-08-29 09:50:08 +00:00
2007-08-15 00:48:33 +00:00
# testing
2009-09-29 15:27:00 +00:00
mtx_x90 = Mathutils . RotationMatrix ( math . pi / 2 , 3 , ' x ' ) # used
2007-09-08 08:49:56 +00:00
#mtx_x90n = RotationMatrix(-90, 3, 'x')
#mtx_y90 = RotationMatrix( 90, 3, 'y')
#mtx_y90n = RotationMatrix(-90, 3, 'y')
#mtx_z90 = RotationMatrix( 90, 3, 'z')
#mtx_z90n = RotationMatrix(-90, 3, 'z')
#mtx4_x90 = RotationMatrix( 90, 4, 'x')
2009-09-29 15:27:00 +00:00
mtx4_x90n = Mathutils . RotationMatrix ( - math . pi / 2 , 4 , ' x ' ) # used
2007-09-08 08:49:56 +00:00
#mtx4_y90 = RotationMatrix( 90, 4, 'y')
2009-09-29 15:27:00 +00:00
mtx4_y90n = Mathutils . RotationMatrix ( - math . pi / 2 , 4 , ' y ' ) # used
mtx4_z90 = Mathutils . RotationMatrix ( math . pi / 2 , 4 , ' z ' ) # used
mtx4_z90n = Mathutils . RotationMatrix ( - math . pi / 2 , 4 , ' z ' ) # used
2007-08-15 00:48:33 +00:00
2009-09-29 15:27:00 +00:00
# def strip_path(p):
# return p.split('\\')[-1].split('/')[-1]
2007-08-26 01:35:03 +00:00
# Used to add the scene name into the filename without using odd chars
2007-08-15 00:48:33 +00:00
sane_name_mapping_ob = { }
sane_name_mapping_mat = { }
sane_name_mapping_tex = { }
2007-08-23 16:34:15 +00:00
sane_name_mapping_take = { }
2007-08-30 17:16:09 +00:00
sane_name_mapping_group = { }
2007-08-20 23:38:39 +00:00
2007-08-26 01:35:03 +00:00
# Make sure reserved names are not used
sane_name_mapping_ob [ ' Scene ' ] = ' Scene_ '
sane_name_mapping_ob [ ' blend_root ' ] = ' blend_root_ '
def increment_string ( t ) :
name = t
num = ' '
while name and name [ - 1 ] . isdigit ( ) :
num = name [ - 1 ] + num
name = name [ : - 1 ]
if num : return ' %s %d ' % ( name , int ( num ) + 1 )
else : return name + ' _0 '
2007-08-15 00:48:33 +00:00
2007-08-28 02:11:49 +00:00
2007-08-15 00:48:33 +00:00
# todo - Disallow the name 'Scene' and 'blend_root' - it will bugger things up.
def sane_name ( data , dct ) :
2007-08-26 01:35:03 +00:00
#if not data: return None
2009-05-06 06:01:09 +00:00
if type ( data ) == tuple : # materials are paired up with images
data , other = data
use_other = True
else :
other = None
use_other = False
if data : name = data . name
else : name = None
orig_name = name
if other :
orig_name_other = other . name
name = ' %s # %s ' % ( name , orig_name_other )
else :
orig_name_other = None
2007-08-26 01:35:03 +00:00
# dont cache, only ever call once for each data type now,
# so as to avoid namespace collision between types - like with objects <-> bones
#try: return dct[name]
#except: pass
2007-08-15 00:48:33 +00:00
2007-08-23 16:34:15 +00:00
if not name :
name = ' unnamed ' # blank string, ASKING FOR TROUBLE!
else :
2007-08-29 03:56:22 +00:00
#name = BPySys.cleanName(name)
name = cleanName ( name ) # use our own
2007-08-26 01:35:03 +00:00
2009-09-29 15:27:00 +00:00
while name in iter ( dct . values ( ) ) : name = increment_string ( name )
2007-08-23 16:34:15 +00:00
2009-05-06 06:01:09 +00:00
if use_other : # even if other is None - orig_name_other will be a string or None
dct [ orig_name , orig_name_other ] = name
else :
dct [ orig_name ] = name
2007-08-15 00:48:33 +00:00
return name
def sane_obname ( data ) : return sane_name ( data , sane_name_mapping_ob )
def sane_matname ( data ) : return sane_name ( data , sane_name_mapping_mat )
def sane_texname ( data ) : return sane_name ( data , sane_name_mapping_tex )
2007-08-23 16:34:15 +00:00
def sane_takename ( data ) : return sane_name ( data , sane_name_mapping_take )
2007-08-30 17:16:09 +00:00
def sane_groupname ( data ) : return sane_name ( data , sane_name_mapping_group )
2007-08-23 16:34:15 +00:00
2009-09-29 15:27:00 +00:00
# def derived_paths(fname_orig, basepath, FORCE_CWD=False):
# '''
# fname_orig - blender path, can be relative
# basepath - fname_rel will be relative to this
# FORCE_CWD - dont use the basepath, just add a ./ to the filename.
# use when we know the file will be in the basepath.
# '''
2009-11-03 18:08:25 +00:00
# fname = bpy.utils.expandpath(fname_orig)
2009-09-29 15:27:00 +00:00
# # fname = Blender.sys.expandpath(fname_orig)
# fname_strip = os.path.basename(fname)
# # fname_strip = strip_path(fname)
# if FORCE_CWD:
# fname_rel = '.' + os.sep + fname_strip
# else:
2009-11-03 18:08:25 +00:00
# fname_rel = bpy.utils.relpath(fname, basepath)
2009-09-29 15:27:00 +00:00
# # fname_rel = Blender.sys.relpath(fname, basepath)
# if fname_rel.startswith('//'): fname_rel = '.' + os.sep + fname_rel[2:]
# return fname, fname_strip, fname_rel
2007-08-26 01:35:03 +00:00
2007-08-09 13:34:44 +00:00
def mat4x4str ( mat ) :
return ' %.15f , %.15f , %.15f , %.15f , %.15f , %.15f , %.15f , %.15f , %.15f , %.15f , %.15f , %.15f , %.15f , %.15f , %.15f , %.15f ' % tuple ( [ f for v in mat for f in v ] )
2007-04-20 18:48:30 +00:00
2009-09-29 15:27:00 +00:00
# XXX not used
# duplicated in OBJ exporter
def getVertsFromGroup ( me , group_index ) :
ret = [ ]
for i , v in enumerate ( me . verts ) :
for g in v . groups :
if g . group == group_index :
ret . append ( ( i , g . weight ) )
return ret
# ob must be OB_MESH
def BPyMesh_meshWeight2List ( ob ) :
''' Takes a mesh and return its group names and a list of lists, one list per vertex.
aligning the each vert list with the group names , each list contains float value for the weight .
These 2 lists can be modified and then used with list2MeshWeight to apply the changes .
'''
me = ob . data
# Clear the vert group.
groupNames = [ g . name for g in ob . vertex_groups ]
len_groupNames = len ( groupNames )
if not len_groupNames :
# no verts? return a vert aligned empty list
return [ [ ] for i in range ( len ( me . verts ) ) ] , [ ]
else :
vWeightList = [ [ 0.0 ] * len_groupNames for i in range ( len ( me . verts ) ) ]
for i , v in enumerate ( me . verts ) :
for g in v . groups :
vWeightList [ i ] [ g . group ] = g . weight
return groupNames , vWeightList
2007-08-24 07:07:18 +00:00
def meshNormalizedWeights ( me ) :
try : # account for old bad BPyMesh
2009-09-29 15:27:00 +00:00
groupNames , vWeightList = BPyMesh_meshWeight2List ( me )
# groupNames, vWeightList = BPyMesh.meshWeight2List(me)
2007-08-24 07:07:18 +00:00
except :
return [ ] , [ ]
if not groupNames :
return [ ] , [ ]
for i , vWeights in enumerate ( vWeightList ) :
tot = 0.0
for w in vWeights :
tot + = w
if tot :
for j , w in enumerate ( vWeights ) :
vWeights [ j ] = w / tot
return groupNames , vWeightList
2007-04-20 18:48:30 +00:00
header_comment = \
''' ; FBX 6.1.0 project file
; Created by Blender FBX Exporter
2007-08-20 23:38:39 +00:00
; for support mail : ideasman42 @gmail.com
2007-04-20 18:48:30 +00:00
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
'''
2007-08-23 16:34:15 +00:00
# This func can be called with just the filename
def write ( filename , batch_objects = None , \
2009-09-29 15:27:00 +00:00
context = None ,
2007-08-23 16:34:15 +00:00
EXP_OBS_SELECTED = True ,
EXP_MESH = True ,
EXP_MESH_APPLY_MOD = True ,
2009-09-29 15:27:00 +00:00
# EXP_MESH_HQ_NORMALS = False,
2007-08-23 16:34:15 +00:00
EXP_ARMATURE = True ,
EXP_LAMP = True ,
EXP_CAMERA = True ,
EXP_EMPTY = True ,
EXP_IMAGE_COPY = False ,
2009-09-29 15:27:00 +00:00
GLOBAL_MATRIX = Mathutils . Matrix ( ) ,
2007-08-23 16:34:15 +00:00
ANIM_ENABLE = True ,
ANIM_OPTIMIZE = True ,
ANIM_OPTIMIZE_PRECISSION = 6 ,
2007-08-28 02:11:49 +00:00
ANIM_ACTION_ALL = False ,
2007-08-23 16:34:15 +00:00
BATCH_ENABLE = False ,
BATCH_GROUP = True ,
BATCH_FILE_PREFIX = ' ' ,
BATCH_OWN_DIR = False
) :
# ----------------- Batch support!
if BATCH_ENABLE :
2007-08-28 02:11:49 +00:00
if os == None : BATCH_OWN_DIR = False
fbxpath = filename
2007-08-23 16:34:15 +00:00
# get the path component of filename
2009-11-03 18:08:25 +00:00
tmp_exists = bpy . utils . exists ( fbxpath )
2009-09-29 15:27:00 +00:00
# tmp_exists = Blender.sys.exists(fbxpath)
2007-08-28 02:11:49 +00:00
if tmp_exists != 2 : # a file, we want a path
2009-09-29 15:27:00 +00:00
fbxpath = os . path . dirname ( fbxpath )
# while fbxpath and fbxpath[-1] not in ('/', '\\'):
# fbxpath = fbxpath[:-1]
if not fbxpath :
# if not filename:
# XXX
print ( ' Error % t|Directory does not exist! ' )
# Draw.PupMenu('Error%t|Directory does not exist!')
2007-08-28 02:11:49 +00:00
return
2009-09-29 15:27:00 +00:00
2009-11-03 18:08:25 +00:00
tmp_exists = bpy . utils . exists ( fbxpath )
2009-09-29 15:27:00 +00:00
# tmp_exists = Blender.sys.exists(fbxpath)
2007-08-28 02:11:49 +00:00
if tmp_exists != 2 :
2009-09-29 15:27:00 +00:00
# XXX
print ( ' Error % t|Directory does not exist! ' )
# Draw.PupMenu('Error%t|Directory does not exist!')
2007-08-28 02:11:49 +00:00
return
2009-09-29 15:27:00 +00:00
if not fbxpath . endswith ( os . sep ) :
fbxpath + = os . sep
2007-08-28 02:11:49 +00:00
del tmp_exists
2007-08-23 16:34:15 +00:00
if BATCH_GROUP :
data_seq = bpy . data . groups
2007-08-28 02:11:49 +00:00
else :
2007-08-23 16:34:15 +00:00
data_seq = bpy . data . scenes
2007-08-28 02:11:49 +00:00
# call this function within a loop with BATCH_ENABLE == False
2009-09-29 15:27:00 +00:00
orig_sce = context . scene
# orig_sce = bpy.data.scenes.active
2007-08-23 16:34:15 +00:00
2007-08-28 02:11:49 +00:00
new_fbxpath = fbxpath # own dir option modifies, we need to keep an original
2007-08-23 16:34:15 +00:00
for data in data_seq : # scene or group
2009-09-29 15:27:00 +00:00
newname = BATCH_FILE_PREFIX + cleanName ( data . name )
# newname = BATCH_FILE_PREFIX + BPySys.cleanName(data.name)
2007-08-23 16:34:15 +00:00
2007-08-29 03:56:22 +00:00
2007-08-23 16:34:15 +00:00
if BATCH_OWN_DIR :
2009-09-29 15:27:00 +00:00
new_fbxpath = fbxpath + newname + os . sep
2007-08-28 02:11:49 +00:00
# path may alredy exist
# TODO - might exist but be a file. unlikely but should probably account for it.
2009-09-29 15:27:00 +00:00
2009-11-03 18:08:25 +00:00
if bpy . utils . exists ( new_fbxpath ) == 0 :
2009-09-29 15:27:00 +00:00
# if Blender.sys.exists(new_fbxpath) == 0:
2007-08-28 02:11:49 +00:00
os . mkdir ( new_fbxpath )
filename = new_fbxpath + newname + ' .fbx '
2009-09-29 15:27:00 +00:00
print ( ' \n Batch exporting %s as... \n \t " %s " ' % ( data , filename ) )
# XXX don't know what to do with this, probably do the same? (Arystan)
2007-08-28 02:11:49 +00:00
if BATCH_GROUP : #group
# group, so objects update properly, add a dummy scene.
sce = bpy . data . scenes . new ( )
sce . Layers = ( 1 << 20 ) - 1
bpy . data . scenes . active = sce
for ob_base in data . objects :
sce . objects . link ( ob_base )
sce . update ( 1 )
# TODO - BUMMER! Armatures not in the group wont animate the mesh
else : # scene
data_seq . active = data
# Call self with modified args
# Dont pass batch options since we alredy usedt them
write ( filename , data . objects ,
2009-09-29 15:27:00 +00:00
context ,
2007-08-28 02:11:49 +00:00
False ,
EXP_MESH ,
EXP_MESH_APPLY_MOD ,
2009-09-29 15:27:00 +00:00
# EXP_MESH_HQ_NORMALS,
2007-08-28 02:11:49 +00:00
EXP_ARMATURE ,
EXP_LAMP ,
EXP_CAMERA ,
EXP_EMPTY ,
EXP_IMAGE_COPY ,
GLOBAL_MATRIX ,
ANIM_ENABLE ,
ANIM_OPTIMIZE ,
ANIM_OPTIMIZE_PRECISSION ,
ANIM_ACTION_ALL
)
if BATCH_GROUP :
# remove temp group scene
2009-09-29 15:27:00 +00:00
bpy . data . remove_scene ( sce )
# bpy.data.scenes.unlink(sce)
2007-08-28 02:11:49 +00:00
bpy . data . scenes . active = orig_sce
return # so the script wont run after we have batch exported.
2007-08-23 16:34:15 +00:00
# end batch support
2007-08-28 02:11:49 +00:00
2008-12-03 07:45:52 +00:00
# Use this for working out paths relative to the export location
2009-09-29 15:27:00 +00:00
basepath = os . path . dirname ( filename ) or ' . '
basepath + = os . sep
# basepath = Blender.sys.dirname(filename)
2007-08-28 02:11:49 +00:00
# ----------------------------------------------
# storage classes
class my_bone_class :
__slots__ = ( \
' blenName ' , \
' blenBone ' , \
' blenMeshes ' , \
' restMatrix ' , \
' parent ' , \
' blenName ' , \
' fbxName ' , \
' fbxArm ' , \
' __pose_bone ' , \
' __anim_poselist ' )
def __init__ ( self , blenBone , fbxArm ) :
# This is so 2 armatures dont have naming conflicts since FBX bones use object namespace
self . fbxName = sane_obname ( blenBone )
self . blenName = blenBone . name
self . blenBone = blenBone
self . blenMeshes = { } # fbxMeshObName : mesh
self . fbxArm = fbxArm
2009-12-02 10:32:39 +00:00
self . restMatrix = blenBone . matrix_local
2009-09-29 15:27:00 +00:00
# self.restMatrix = blenBone.matrix['ARMATURESPACE']
2007-08-28 02:11:49 +00:00
# not used yet
# self.restMatrixInv = self.restMatrix.copy().invert()
# self.restMatrixLocal = None # set later, need parent matrix
self . parent = None
# not public
2009-09-29 15:27:00 +00:00
pose = fbxArm . blenObject . pose
# pose = fbxArm.blenObject.getPose()
2009-11-18 11:50:31 +00:00
self . __pose_bone = pose . bones [ self . blenName ]
2007-08-28 02:11:49 +00:00
# store a list if matricies here, (poseMatrix, head, tail)
# {frame:posematrix, frame:posematrix, ...}
self . __anim_poselist = { }
'''
def calcRestMatrixLocal ( self ) :
if self . parent :
self . restMatrixLocal = self . restMatrix * self . parent . restMatrix . copy ( ) . invert ( )
else :
self . restMatrixLocal = self . restMatrix . copy ( )
'''
def setPoseFrame ( self , f ) :
# cache pose info here, frame must be set beforehand
# Didnt end up needing head or tail, if we do - here it is.
'''
self . __anim_poselist [ f ] = ( \
self . __pose_bone . poseMatrix . copy ( ) , \
self . __pose_bone . head . copy ( ) , \
self . __pose_bone . tail . copy ( ) )
'''
2009-09-29 15:27:00 +00:00
self . __anim_poselist [ f ] = self . __pose_bone . pose_matrix . copy ( )
# self.__anim_poselist[f] = self.__pose_bone.poseMatrix.copy()
2007-08-28 02:11:49 +00:00
# get pose from frame.
def getPoseMatrix ( self , f ) : # ----------------------------------------------
return self . __anim_poselist [ f ]
'''
def getPoseHead ( self , f ) :
#return self.__pose_bone.head.copy()
return self . __anim_poselist [ f ] [ 1 ] . copy ( )
def getPoseTail ( self , f ) :
#return self.__pose_bone.tail.copy()
return self . __anim_poselist [ f ] [ 2 ] . copy ( )
'''
# end
2007-09-08 08:49:56 +00:00
def getAnimParRelMatrix ( self , frame ) :
#arm_mat = self.fbxArm.matrixWorld
#arm_mat = self.fbxArm.parRelMatrix()
2007-08-28 02:11:49 +00:00
if not self . parent :
2007-09-08 08:49:56 +00:00
#return mtx4_z90 * (self.getPoseMatrix(frame) * arm_mat) # dont apply arm matrix anymore
return mtx4_z90 * self . getPoseMatrix ( frame )
2007-08-28 02:11:49 +00:00
else :
2007-09-08 08:49:56 +00:00
#return (mtx4_z90 * ((self.getPoseMatrix(frame) * arm_mat))) * (mtx4_z90 * (self.parent.getPoseMatrix(frame) * arm_mat)).invert()
return ( mtx4_z90 * ( self . getPoseMatrix ( frame ) ) ) * ( mtx4_z90 * self . parent . getPoseMatrix ( frame ) ) . invert ( )
2007-08-28 02:11:49 +00:00
2007-08-29 09:50:08 +00:00
# we need thes because cameras and lights modified rotations
2007-09-08 08:49:56 +00:00
def getAnimParRelMatrixRot ( self , frame ) :
return self . getAnimParRelMatrix ( frame )
2007-08-29 09:50:08 +00:00
2007-08-28 02:11:49 +00:00
def flushAnimData ( self ) :
self . __anim_poselist . clear ( )
class my_object_generic :
# Other settings can be applied for each type - mesh, armature etc.
2007-08-30 17:16:09 +00:00
def __init__ ( self , ob , matrixWorld = None ) :
2007-08-28 02:11:49 +00:00
self . fbxName = sane_obname ( ob )
self . blenObject = ob
2007-08-30 17:16:09 +00:00
self . fbxGroupNames = [ ]
2007-09-08 08:49:56 +00:00
self . fbxParent = None # set later on IF the parent is in the selection.
2007-08-30 17:16:09 +00:00
if matrixWorld : self . matrixWorld = matrixWorld * GLOBAL_MATRIX
2009-09-29 15:27:00 +00:00
else : self . matrixWorld = ob . matrix * GLOBAL_MATRIX
# else: self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX
2007-09-08 08:49:56 +00:00
self . __anim_poselist = { } # we should only access this
def parRelMatrix ( self ) :
if self . fbxParent :
return self . matrixWorld * self . fbxParent . matrixWorld . copy ( ) . invert ( )
else :
return self . matrixWorld
2007-08-29 09:50:08 +00:00
def setPoseFrame ( self , f ) :
2009-09-29 15:27:00 +00:00
self . __anim_poselist [ f ] = self . blenObject . matrix . copy ( )
# self.__anim_poselist[f] = self.blenObject.matrixWorld.copy()
2007-08-29 09:50:08 +00:00
2007-09-08 08:49:56 +00:00
def getAnimParRelMatrix ( self , frame ) :
if self . fbxParent :
#return (self.__anim_poselist[frame] * self.fbxParent.__anim_poselist[frame].copy().invert() ) * GLOBAL_MATRIX
return ( self . __anim_poselist [ frame ] * GLOBAL_MATRIX ) * ( self . fbxParent . __anim_poselist [ frame ] * GLOBAL_MATRIX ) . invert ( )
else :
return self . __anim_poselist [ frame ] * GLOBAL_MATRIX
2007-08-29 09:50:08 +00:00
2007-09-08 08:49:56 +00:00
def getAnimParRelMatrixRot ( self , frame ) :
2007-08-29 09:50:08 +00:00
type = self . blenObject . type
2007-09-08 08:49:56 +00:00
if self . fbxParent :
matrix_rot = ( ( ( self . __anim_poselist [ frame ] * GLOBAL_MATRIX ) * ( self . fbxParent . __anim_poselist [ frame ] * GLOBAL_MATRIX ) . invert ( ) ) ) . rotationPart ( )
else :
matrix_rot = ( self . __anim_poselist [ frame ] * GLOBAL_MATRIX ) . rotationPart ( )
2007-08-29 09:50:08 +00:00
# Lamps need to be rotated
2009-09-29 15:27:00 +00:00
if type == ' LAMP ' :
2007-08-29 09:50:08 +00:00
matrix_rot = mtx_x90 * matrix_rot
2009-09-29 15:27:00 +00:00
elif type == ' CAMERA ' :
# elif ob and type =='Camera':
y = Mathutils . Vector ( 0 , 1 , 0 ) * matrix_rot
matrix_rot = matrix_rot * Mathutils . RotationMatrix ( math . pi / 2 , 3 , ' r ' , y )
2007-08-29 09:50:08 +00:00
return matrix_rot
2007-08-28 02:11:49 +00:00
# ----------------------------------------------
2007-08-23 16:34:15 +00:00
2009-09-29 15:27:00 +00:00
print ( ' \n FBX export starting... ' , filename )
start_time = time . clock ( )
# start_time = Blender.sys.time()
2007-09-08 08:49:56 +00:00
try :
file = open ( filename , ' w ' )
except :
return False
2009-09-29 15:27:00 +00:00
sce = context . scene
# sce = bpy.data.scenes.active
2007-08-23 16:34:15 +00:00
world = sce . world
# ---------------------------- Write the header first
2007-04-20 18:48:30 +00:00
file . write ( header_comment )
2007-08-24 12:13:34 +00:00
if time :
curtime = time . localtime ( ) [ 0 : 6 ]
else :
2009-05-04 21:49:25 +00:00
curtime = ( 0 , 0 , 0 , 0 , 0 , 0 )
2007-04-20 18:48:30 +00:00
#
file . write ( \
''' FBXHeaderExtension: {
FBXHeaderVersion : 1003
FBXVersion : 6100
CreationTimeStamp : {
Version : 1000
Year : % .4 i
Month : % .2 i
Day : % .2 i
Hour : % .2 i
Minute : % .2 i
Second : % .2 i
Millisecond : 0
2007-03-28 07:08:18 +00:00
}
2007-04-20 18:48:30 +00:00
Creator : " FBX SDK/FBX Plugins build 20070228 "
OtherFlags : {
FlagPLE : 0
2007-03-28 07:08:18 +00:00
}
2007-04-21 11:23:45 +00:00
} ''' % (curtime))
2007-04-20 18:48:30 +00:00
2007-04-21 11:23:45 +00:00
file . write ( ' \n CreationTime: " %.4i - %.2i - %.2i %.2i : %.2i : %.2i :000 " ' % curtime )
2009-09-29 15:27:00 +00:00
file . write ( ' \n Creator: " Blender3D version 2.5 " ' )
# file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version'))
2007-04-20 18:48:30 +00:00
2007-08-29 05:42:39 +00:00
pose_items = [ ] # list of (fbxName, matrix) to write pose data for, easier to collect allong the way
2007-08-23 16:34:15 +00:00
# --------------- funcs for exporting
2007-08-09 13:34:44 +00:00
def object_tx ( ob , loc , matrix , matrix_mod = None ) :
2007-04-20 23:33:56 +00:00
'''
2007-08-09 13:34:44 +00:00
Matrix mod is so armature objects can modify their bone matricies
2007-04-20 23:33:56 +00:00
'''
2009-09-29 15:27:00 +00:00
if isinstance ( ob , bpy . types . Bone ) :
# if isinstance(ob, Blender.Types.BoneType):
2007-08-09 13:34:44 +00:00
2007-08-06 20:20:20 +00:00
# we know we have a matrix
2007-09-08 08:49:56 +00:00
# matrix = mtx4_z90 * (ob.matrix['ARMATURESPACE'] * matrix_mod)
2009-12-02 10:32:39 +00:00
matrix = mtx4_z90 * ob . matrix_local # dont apply armature matrix anymore
2009-09-29 15:27:00 +00:00
# matrix = mtx4_z90 * ob.matrix['ARMATURESPACE'] # dont apply armature matrix anymore
2007-08-06 20:20:20 +00:00
parent = ob . parent
if parent :
2007-09-08 08:49:56 +00:00
#par_matrix = mtx4_z90 * (parent.matrix['ARMATURESPACE'] * matrix_mod)
2009-12-02 10:32:39 +00:00
par_matrix = mtx4_z90 * parent . matrix_local # dont apply armature matrix anymore
2009-09-29 15:27:00 +00:00
# par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'] # dont apply armature matrix anymore
2007-08-06 20:20:20 +00:00
matrix = matrix * par_matrix . copy ( ) . invert ( )
matrix_rot = matrix . rotationPart ( )
loc = tuple ( matrix . translationPart ( ) )
scale = tuple ( matrix . scalePart ( ) )
rot = tuple ( matrix_rot . toEuler ( ) )
2007-04-21 11:23:45 +00:00
2007-04-20 23:33:56 +00:00
else :
2007-09-08 08:49:56 +00:00
# This is bad because we need the parent relative matrix from the fbx parent (if we have one), dont use anymore
#if ob and not matrix: matrix = ob.matrixWorld * GLOBAL_MATRIX
2009-09-29 15:27:00 +00:00
if ob and not matrix : raise Exception ( " error: this should never happen! " )
2007-09-08 08:49:56 +00:00
2007-08-06 20:20:20 +00:00
matrix_rot = matrix
#if matrix:
# matrix = matrix_scale * matrix
if matrix :
loc = tuple ( matrix . translationPart ( ) )
scale = tuple ( matrix . scalePart ( ) )
matrix_rot = matrix . rotationPart ( )
# Lamps need to be rotated
if ob and ob . type == ' Lamp ' :
2007-08-29 09:50:08 +00:00
matrix_rot = mtx_x90 * matrix_rot
2007-08-06 20:20:20 +00:00
rot = tuple ( matrix_rot . toEuler ( ) )
elif ob and ob . type == ' Camera ' :
2009-09-29 15:27:00 +00:00
y = Mathutils . Vector ( 0 , 1 , 0 ) * matrix_rot
matrix_rot = matrix_rot * Mathutils . RotationMatrix ( math . pi / 2 , 3 , ' r ' , y )
2007-08-06 20:20:20 +00:00
rot = tuple ( matrix_rot . toEuler ( ) )
else :
rot = tuple ( matrix_rot . toEuler ( ) )
else :
if not loc :
loc = 0 , 0 , 0
scale = 1 , 1 , 1
rot = 0 , 0 , 0
2007-04-21 11:23:45 +00:00
2007-08-09 13:34:44 +00:00
return loc , rot , scale , matrix , matrix_rot
def write_object_tx ( ob , loc , matrix , matrix_mod = None ) :
'''
We have loc to set the location if non blender objects that have a location
matrix_mod is only used for bones at the moment
'''
loc , rot , scale , matrix , matrix_rot = object_tx ( ob , loc , matrix , matrix_mod )
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t \t \t Property: " Lcl Translation " , " Lcl Translation " , " A+ " , %.15f , %.15f , %.15f ' % loc )
2009-09-29 15:27:00 +00:00
file . write ( ' \n \t \t \t Property: " Lcl Rotation " , " Lcl Rotation " , " A+ " , %.15f , %.15f , %.15f ' % tuple ( eulerRadToDeg ( rot ) ) )
# file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % rot)
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t \t \t Property: " Lcl Scaling " , " Lcl Scaling " , " A+ " , %.15f , %.15f , %.15f ' % scale )
2007-04-27 17:19:26 +00:00
return loc , rot , scale , matrix , matrix_rot
2007-04-20 23:33:56 +00:00
2007-08-09 13:34:44 +00:00
def write_object_props ( ob = None , loc = None , matrix = None , matrix_mod = None ) :
2007-04-20 23:33:56 +00:00
# if the type is 0 its an empty otherwise its a mesh
# only difference at the moment is one has a color
2007-04-20 18:48:30 +00:00
file . write ( '''
2007-03-28 07:08:18 +00:00
Properties60 : {
Property : " QuaternionInterpolate " , " bool " , " " , 0
2007-04-20 23:33:56 +00:00
Property : " Visibility " , " Visibility " , " A+ " , 1 ''' )
2007-08-09 13:34:44 +00:00
loc , rot , scale , matrix , matrix_rot = write_object_tx ( ob , loc , matrix , matrix_mod )
2007-04-21 11:23:45 +00:00
2007-08-20 23:38:39 +00:00
# Rotation order, note, for FBX files Iv loaded normal order is 1
# setting to zero.
# eEULER_XYZ = 0
2007-04-21 11:23:45 +00:00
# eEULER_XZY
# eEULER_YZX
# eEULER_YXZ
# eEULER_ZXY
2007-08-20 23:38:39 +00:00
# eEULER_ZYX
2007-04-20 23:33:56 +00:00
file . write ( '''
2007-03-28 07:08:18 +00:00
Property : " RotationOffset " , " Vector3D " , " " , 0 , 0 , 0
Property : " RotationPivot " , " Vector3D " , " " , 0 , 0 , 0
Property : " ScalingOffset " , " Vector3D " , " " , 0 , 0 , 0
Property : " ScalingPivot " , " Vector3D " , " " , 0 , 0 , 0
Property : " TranslationActive " , " bool " , " " , 0
Property : " TranslationMin " , " Vector3D " , " " , 0 , 0 , 0
Property : " TranslationMax " , " Vector3D " , " " , 0 , 0 , 0
Property : " TranslationMinX " , " bool " , " " , 0
Property : " TranslationMinY " , " bool " , " " , 0
Property : " TranslationMinZ " , " bool " , " " , 0
Property : " TranslationMaxX " , " bool " , " " , 0
Property : " TranslationMaxY " , " bool " , " " , 0
Property : " TranslationMaxZ " , " bool " , " " , 0
2007-08-20 23:38:39 +00:00
Property : " RotationOrder " , " enum " , " " , 0
2007-03-28 07:08:18 +00:00
Property : " RotationSpaceForLimitOnly " , " bool " , " " , 0
Property : " AxisLen " , " double " , " " , 10
Property : " PreRotation " , " Vector3D " , " " , 0 , 0 , 0
Property : " PostRotation " , " Vector3D " , " " , 0 , 0 , 0
Property : " RotationActive " , " bool " , " " , 0
Property : " RotationMin " , " Vector3D " , " " , 0 , 0 , 0
Property : " RotationMax " , " Vector3D " , " " , 0 , 0 , 0
Property : " RotationMinX " , " bool " , " " , 0
Property : " RotationMinY " , " bool " , " " , 0
Property : " RotationMinZ " , " bool " , " " , 0
Property : " RotationMaxX " , " bool " , " " , 0
Property : " RotationMaxY " , " bool " , " " , 0
Property : " RotationMaxZ " , " bool " , " " , 0
Property : " RotationStiffnessX " , " double " , " " , 0
Property : " RotationStiffnessY " , " double " , " " , 0
Property : " RotationStiffnessZ " , " double " , " " , 0
Property : " MinDampRangeX " , " double " , " " , 0
Property : " MinDampRangeY " , " double " , " " , 0
Property : " MinDampRangeZ " , " double " , " " , 0
Property : " MaxDampRangeX " , " double " , " " , 0
Property : " MaxDampRangeY " , " double " , " " , 0
Property : " MaxDampRangeZ " , " double " , " " , 0
Property : " MinDampStrengthX " , " double " , " " , 0
Property : " MinDampStrengthY " , " double " , " " , 0
Property : " MinDampStrengthZ " , " double " , " " , 0
Property : " MaxDampStrengthX " , " double " , " " , 0
Property : " MaxDampStrengthY " , " double " , " " , 0
Property : " MaxDampStrengthZ " , " double " , " " , 0
Property : " PreferedAngleX " , " double " , " " , 0
Property : " PreferedAngleY " , " double " , " " , 0
Property : " PreferedAngleZ " , " double " , " " , 0
Property : " InheritType " , " enum " , " " , 0
Property : " ScalingActive " , " bool " , " " , 0
Property : " ScalingMin " , " Vector3D " , " " , 1 , 1 , 1
Property : " ScalingMax " , " Vector3D " , " " , 1 , 1 , 1
Property : " ScalingMinX " , " bool " , " " , 0
Property : " ScalingMinY " , " bool " , " " , 0
Property : " ScalingMinZ " , " bool " , " " , 0
Property : " ScalingMaxX " , " bool " , " " , 0
Property : " ScalingMaxY " , " bool " , " " , 0
Property : " ScalingMaxZ " , " bool " , " " , 0
Property : " GeometricTranslation " , " Vector3D " , " " , 0 , 0 , 0
Property : " GeometricRotation " , " Vector3D " , " " , 0 , 0 , 0
Property : " GeometricScaling " , " Vector3D " , " " , 1 , 1 , 1
Property : " LookAtProperty " , " object " , " "
Property : " UpVectorProperty " , " object " , " "
2007-04-20 23:33:56 +00:00
Property : " Show " , " bool " , " " , 1
2007-03-28 07:08:18 +00:00
Property : " NegativePercentShapeSupport " , " bool " , " " , 1
2007-04-20 23:33:56 +00:00
Property : " DefaultAttributeIndex " , " int " , " " , 0 ''' )
2009-09-29 15:27:00 +00:00
if ob and not isinstance ( ob , bpy . types . Bone ) :
# if ob and type(ob) != Blender.Types.BoneType:
2007-04-20 23:33:56 +00:00
# Only mesh objects have color
file . write ( ' \n \t \t \t Property: " Color " , " Color " , " A " ,0.8,0.8,0.8 ' )
file . write ( ' \n \t \t \t Property: " Size " , " double " , " " ,100 ' )
file . write ( ' \n \t \t \t Property: " Look " , " enum " , " " ,1 ' )
2007-04-27 00:33:07 +00:00
2007-04-27 17:19:26 +00:00
return loc , rot , scale , matrix , matrix_rot
2007-04-20 23:33:56 +00:00
2007-08-06 20:20:20 +00:00
# -------------------------------------------- Armatures
2007-08-26 01:35:03 +00:00
#def write_bone(bone, name, matrix_mod):
def write_bone ( my_bone ) :
file . write ( ' \n \t Model: " Model:: %s " , " Limb " { ' % my_bone . fbxName )
2007-08-06 20:20:20 +00:00
file . write ( ' \n \t \t Version: 232 ' )
2007-09-08 08:49:56 +00:00
#poseMatrix = write_object_props(my_bone.blenBone, None, None, my_bone.fbxArm.parRelMatrix())[3]
poseMatrix = write_object_props ( my_bone . blenBone ) [ 3 ] # dont apply bone matricies anymore
2007-08-29 05:42:39 +00:00
pose_items . append ( ( my_bone . fbxName , poseMatrix ) )
2007-08-09 13:34:44 +00:00
2007-09-08 08:49:56 +00:00
# file.write('\n\t\t\tProperty: "Size", "double", "",%.6f' % ((my_bone.blenData.head['ARMATURESPACE'] - my_bone.blenData.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length)
2007-08-20 23:38:39 +00:00
file . write ( ' \n \t \t \t Property: " Size " , " double " , " " ,1 ' )
2007-08-26 01:35:03 +00:00
2007-09-08 08:49:56 +00:00
#((my_bone.blenData.head['ARMATURESPACE'] * my_bone.fbxArm.matrixWorld) - (my_bone.blenData.tail['ARMATURESPACE'] * my_bone.fbxArm.parRelMatrix())).length)
2007-08-26 01:35:03 +00:00
2007-08-28 02:11:49 +00:00
"""
2007-08-26 01:35:03 +00:00
file . write ( ' \n \t \t \t Property: " LimbLength " , " double " , " " , %.6f ' % \
2007-09-08 08:49:56 +00:00
( ( my_bone . blenBone . head [ ' ARMATURESPACE ' ] - my_bone . blenBone . tail [ ' ARMATURESPACE ' ] ) * my_bone . fbxArm . parRelMatrix ( ) ) . length )
2007-08-28 02:11:49 +00:00
"""
2009-09-29 15:27:00 +00:00
file . write ( ' \n \t \t \t Property: " LimbLength " , " double " , " " , %.6f ' %
2009-12-02 10:32:39 +00:00
( my_bone . blenBone . head_local - my_bone . blenBone . tail_local ) . length )
2009-09-29 15:27:00 +00:00
# (my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']).length)
2007-08-26 01:35:03 +00:00
2007-08-20 23:38:39 +00:00
#file.write('\n\t\t\tProperty: "LimbLength", "double", "",1')
2007-08-06 20:20:20 +00:00
file . write ( ' \n \t \t \t Property: " Color " , " ColorRGB " , " " ,0.8,0.8,0.8 ' )
file . write ( ' \n \t \t \t Property: " Color " , " Color " , " A " ,0.8,0.8,0.8 ' )
file . write ( ' \n \t \t } ' )
file . write ( ' \n \t \t MultiLayer: 0 ' )
file . write ( ' \n \t \t MultiTake: 1 ' )
file . write ( ' \n \t \t Shading: Y ' )
file . write ( ' \n \t \t Culling: " CullingOff " ' )
file . write ( ' \n \t \t TypeFlags: " Skeleton " ' )
file . write ( ' \n \t } ' )
2007-04-20 23:33:56 +00:00
def write_camera_switch ( ) :
file . write ( '''
Model : " Model::Camera Switcher " , " CameraSwitcher " {
2007-04-21 11:23:45 +00:00
Version : 232 ''' )
2007-04-20 23:33:56 +00:00
write_object_props ( )
file . write ( '''
2007-03-28 07:08:18 +00:00
Property : " Color " , " Color " , " A " , 0.8 , 0.8 , 0.8
2007-04-20 18:48:30 +00:00
Property : " Camera Index " , " Integer " , " A+ " , 100
2007-03-28 07:08:18 +00:00
}
MultiLayer : 0
2007-04-20 18:48:30 +00:00
MultiTake : 1
2007-03-28 07:08:18 +00:00
Hidden : " True "
2007-04-20 18:48:30 +00:00
Shading : W
2007-03-28 07:08:18 +00:00
Culling : " CullingOff "
2007-04-20 18:48:30 +00:00
Version : 101
Name : " Model::Camera Switcher "
CameraId : 0
CameraName : 100
CameraIndexName :
2007-03-28 07:08:18 +00:00
} ''' )
2007-04-27 00:33:07 +00:00
def write_camera_dummy ( name , loc , near , far , proj_type , up ) :
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t Model: " Model:: %s " , " Camera " { ' % name )
file . write ( ' \n \t \t Version: 232 ' )
2007-04-20 23:33:56 +00:00
write_object_props ( None , loc )
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t \t \t Property: " Color " , " Color " , " A " ,0.8,0.8,0.8 ' )
file . write ( ' \n \t \t \t Property: " Roll " , " Roll " , " A+ " ,0 ' )
file . write ( ' \n \t \t \t Property: " FieldOfView " , " FieldOfView " , " A+ " ,40 ' )
file . write ( ' \n \t \t \t Property: " FieldOfViewX " , " FieldOfView " , " A+ " ,1 ' )
file . write ( ' \n \t \t \t Property: " FieldOfViewY " , " FieldOfView " , " A+ " ,1 ' )
file . write ( ' \n \t \t \t Property: " OpticalCenterX " , " Real " , " A+ " ,0 ' )
file . write ( ' \n \t \t \t Property: " OpticalCenterY " , " Real " , " A+ " ,0 ' )
file . write ( ' \n \t \t \t Property: " BackgroundColor " , " Color " , " A+ " ,0.63,0.63,0.63 ' )
file . write ( ' \n \t \t \t Property: " TurnTable " , " Real " , " A+ " ,0 ' )
file . write ( ' \n \t \t \t Property: " DisplayTurnTableIcon " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " Motion Blur Intensity " , " Real " , " A+ " ,1 ' )
file . write ( ' \n \t \t \t Property: " UseMotionBlur " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " UseRealTimeMotionBlur " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " ResolutionMode " , " enum " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " ApertureMode " , " enum " , " " ,2 ' )
file . write ( ' \n \t \t \t Property: " GateFit " , " enum " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " FocalLength " , " Real " , " A+ " ,21.3544940948486 ' )
file . write ( ' \n \t \t \t Property: " CameraFormat " , " enum " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " AspectW " , " double " , " " ,320 ' )
file . write ( ' \n \t \t \t Property: " AspectH " , " double " , " " ,200 ' )
file . write ( ' \n \t \t \t Property: " PixelAspectRatio " , " double " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " UseFrameColor " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " FrameColor " , " ColorRGB " , " " ,0.3,0.3,0.3 ' )
file . write ( ' \n \t \t \t Property: " ShowName " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " ShowGrid " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " ShowOpticalCenter " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " ShowAzimut " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " ShowTimeCode " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " NearPlane " , " double " , " " , %.6f ' % near )
file . write ( ' \n \t \t \t Property: " FarPlane " , " double " , " " , %.6f ' % far )
file . write ( ' \n \t \t \t Property: " FilmWidth " , " double " , " " ,0.816 ' )
file . write ( ' \n \t \t \t Property: " FilmHeight " , " double " , " " ,0.612 ' )
file . write ( ' \n \t \t \t Property: " FilmAspectRatio " , " double " , " " ,1.33333333333333 ' )
file . write ( ' \n \t \t \t Property: " FilmSqueezeRatio " , " double " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " FilmFormatIndex " , " enum " , " " ,4 ' )
file . write ( ' \n \t \t \t Property: " ViewFrustum " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " ViewFrustumNearFarPlane " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " ViewFrustumBackPlaneMode " , " enum " , " " ,2 ' )
file . write ( ' \n \t \t \t Property: " BackPlaneDistance " , " double " , " " ,100 ' )
file . write ( ' \n \t \t \t Property: " BackPlaneDistanceMode " , " enum " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " ViewCameraToLookAt " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " LockMode " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " LockInterestNavigation " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " FitImage " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " Crop " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " Center " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " KeepRatio " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " BackgroundMode " , " enum " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " BackgroundAlphaTreshold " , " double " , " " ,0.5 ' )
file . write ( ' \n \t \t \t Property: " ForegroundTransparent " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " DisplaySafeArea " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " SafeAreaDisplayStyle " , " enum " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " SafeAreaAspectRatio " , " double " , " " ,1.33333333333333 ' )
file . write ( ' \n \t \t \t Property: " Use2DMagnifierZoom " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " 2D Magnifier Zoom " , " Real " , " A+ " ,100 ' )
file . write ( ' \n \t \t \t Property: " 2D Magnifier X " , " Real " , " A+ " ,50 ' )
file . write ( ' \n \t \t \t Property: " 2D Magnifier Y " , " Real " , " A+ " ,50 ' )
file . write ( ' \n \t \t \t Property: " CameraProjectionType " , " enum " , " " , %i ' % proj_type )
file . write ( ' \n \t \t \t Property: " UseRealTimeDOFAndAA " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " UseDepthOfField " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " FocusSource " , " enum " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " FocusAngle " , " double " , " " ,3.5 ' )
file . write ( ' \n \t \t \t Property: " FocusDistance " , " double " , " " ,200 ' )
file . write ( ' \n \t \t \t Property: " UseAntialiasing " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " AntialiasingIntensity " , " double " , " " ,0.77777 ' )
file . write ( ' \n \t \t \t Property: " UseAccumulationBuffer " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " FrameSamplingCount " , " int " , " " ,7 ' )
file . write ( ' \n \t \t } ' )
file . write ( ' \n \t \t MultiLayer: 0 ' )
file . write ( ' \n \t \t MultiTake: 0 ' )
file . write ( ' \n \t \t Hidden: " True " ' )
file . write ( ' \n \t \t Shading: Y ' )
file . write ( ' \n \t \t Culling: " CullingOff " ' )
file . write ( ' \n \t \t TypeFlags: " Camera " ' )
file . write ( ' \n \t \t GeometryVersion: 124 ' )
file . write ( ' \n \t \t Position: %.6f , %.6f , %.6f ' % loc )
file . write ( ' \n \t \t Up: %i , %i , %i ' % up )
file . write ( ' \n \t \t LookAt: 0,0,0 ' )
file . write ( ' \n \t \t ShowInfoOnMoving: 1 ' )
file . write ( ' \n \t \t ShowAudio: 0 ' )
file . write ( ' \n \t \t AudioColor: 0,1,0 ' )
file . write ( ' \n \t \t CameraOrthoZoom: 1 ' )
file . write ( ' \n \t } ' )
2007-04-20 18:48:30 +00:00
def write_camera_default ( ) :
# This sucks but to match FBX converter its easier to
# write the cameras though they are not needed.
2007-04-27 00:33:07 +00:00
write_camera_dummy ( ' Producer Perspective ' , ( 0 , 71.3 , 287.5 ) , 10 , 4000 , 0 , ( 0 , 1 , 0 ) )
write_camera_dummy ( ' Producer Top ' , ( 0 , 4000 , 0 ) , 1 , 30000 , 1 , ( 0 , 0 , - 1 ) )
write_camera_dummy ( ' Producer Bottom ' , ( 0 , - 4000 , 0 ) , 1 , 30000 , 1 , ( 0 , 0 , - 1 ) )
write_camera_dummy ( ' Producer Front ' , ( 0 , 0 , 4000 ) , 1 , 30000 , 1 , ( 0 , 1 , 0 ) )
write_camera_dummy ( ' Producer Back ' , ( 0 , 0 , - 4000 ) , 1 , 30000 , 1 , ( 0 , 1 , 0 ) )
write_camera_dummy ( ' Producer Right ' , ( 4000 , 0 , 0 ) , 1 , 30000 , 1 , ( 0 , 1 , 0 ) )
write_camera_dummy ( ' Producer Left ' , ( - 4000 , 0 , 0 ) , 1 , 30000 , 1 , ( 0 , 1 , 0 ) )
2007-03-28 07:08:18 +00:00
2007-08-26 01:35:03 +00:00
def write_camera ( my_cam ) :
2007-04-27 00:33:07 +00:00
'''
Write a blender camera
'''
2009-09-29 15:27:00 +00:00
render = sce . render_data
width = render . resolution_x
height = render . resolution_y
# render = sce.render
# width = render.sizeX
# height = render.sizeY
2007-04-27 00:33:07 +00:00
aspect = float ( width ) / height
2007-08-26 01:35:03 +00:00
data = my_cam . blenObject . data
2007-04-27 17:19:26 +00:00
2007-08-26 01:35:03 +00:00
file . write ( ' \n \t Model: " Model:: %s " , " Camera " { ' % my_cam . fbxName )
2007-04-27 00:33:07 +00:00
file . write ( ' \n \t \t Version: 232 ' )
2007-09-08 08:49:56 +00:00
loc , rot , scale , matrix , matrix_rot = write_object_props ( my_cam . blenObject , None , my_cam . parRelMatrix ( ) )
2007-04-27 00:33:07 +00:00
file . write ( ' \n \t \t \t Property: " Roll " , " Roll " , " A+ " ,0 ' )
2007-04-28 17:21:00 +00:00
file . write ( ' \n \t \t \t Property: " FieldOfView " , " FieldOfView " , " A+ " , %.6f ' % data . angle )
2007-04-27 00:33:07 +00:00
file . write ( ' \n \t \t \t Property: " FieldOfViewX " , " FieldOfView " , " A+ " ,1 ' )
file . write ( ' \n \t \t \t Property: " FieldOfViewY " , " FieldOfView " , " A+ " ,1 ' )
file . write ( ' \n \t \t \t Property: " FocalLength " , " Real " , " A+ " ,14.0323972702026 ' )
2009-09-29 15:27:00 +00:00
file . write ( ' \n \t \t \t Property: " OpticalCenterX " , " Real " , " A+ " , %.6f ' % data . shift_x ) # not sure if this is in the correct units?
# file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shiftX) # not sure if this is in the correct units?
file . write ( ' \n \t \t \t Property: " OpticalCenterY " , " Real " , " A+ " , %.6f ' % data . shift_y ) # ditto
# file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shiftY) # ditto
2007-04-27 00:33:07 +00:00
file . write ( ' \n \t \t \t Property: " BackgroundColor " , " Color " , " A+ " ,0,0,0 ' )
file . write ( ' \n \t \t \t Property: " TurnTable " , " Real " , " A+ " ,0 ' )
file . write ( ' \n \t \t \t Property: " DisplayTurnTableIcon " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " Motion Blur Intensity " , " Real " , " A+ " ,1 ' )
file . write ( ' \n \t \t \t Property: " UseMotionBlur " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " UseRealTimeMotionBlur " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " ResolutionMode " , " enum " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " ApertureMode " , " enum " , " " ,2 ' )
file . write ( ' \n \t \t \t Property: " GateFit " , " enum " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " CameraFormat " , " enum " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " AspectW " , " double " , " " , %i ' % width )
file . write ( ' \n \t \t \t Property: " AspectH " , " double " , " " , %i ' % height )
''' Camera aspect ratio modes.
0 If the ratio mode is eWINDOW_SIZE , both width and height values aren ' t relevant.
1 If the ratio mode is eFIXED_RATIO , the height value is set to 1.0 and the width value is relative to the height value .
2 If the ratio mode is eFIXED_RESOLUTION , both width and height values are in pixels .
3 If the ratio mode is eFIXED_WIDTH , the width value is in pixels and the height value is relative to the width value .
4 If the ratio mode is eFIXED_HEIGHT , the height value is in pixels and the width value is relative to the height value .
Definition at line 234 of file kfbxcamera . h . '''
file . write ( ' \n \t \t \t Property: " PixelAspectRatio " , " double " , " " ,2 ' )
file . write ( ' \n \t \t \t Property: " UseFrameColor " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " FrameColor " , " ColorRGB " , " " ,0.3,0.3,0.3 ' )
file . write ( ' \n \t \t \t Property: " ShowName " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " ShowGrid " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " ShowOpticalCenter " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " ShowAzimut " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " ShowTimeCode " , " bool " , " " ,0 ' )
2009-09-29 15:27:00 +00:00
file . write ( ' \n \t \t \t Property: " NearPlane " , " double " , " " , %.6f ' % data . clip_start )
# file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clipStart)
file . write ( ' \n \t \t \t Property: " FarPlane " , " double " , " " , %.6f ' % data . clip_end )
# file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clipStart)
2007-04-27 00:33:07 +00:00
file . write ( ' \n \t \t \t Property: " FilmWidth " , " double " , " " ,1.0 ' )
file . write ( ' \n \t \t \t Property: " FilmHeight " , " double " , " " ,1.0 ' )
file . write ( ' \n \t \t \t Property: " FilmAspectRatio " , " double " , " " , %.6f ' % aspect )
file . write ( ' \n \t \t \t Property: " FilmSqueezeRatio " , " double " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " FilmFormatIndex " , " enum " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " ViewFrustum " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " ViewFrustumNearFarPlane " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " ViewFrustumBackPlaneMode " , " enum " , " " ,2 ' )
file . write ( ' \n \t \t \t Property: " BackPlaneDistance " , " double " , " " ,100 ' )
file . write ( ' \n \t \t \t Property: " BackPlaneDistanceMode " , " enum " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " ViewCameraToLookAt " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " LockMode " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " LockInterestNavigation " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " FitImage " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " Crop " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " Center " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " KeepRatio " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " BackgroundMode " , " enum " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " BackgroundAlphaTreshold " , " double " , " " ,0.5 ' )
file . write ( ' \n \t \t \t Property: " ForegroundTransparent " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " DisplaySafeArea " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " SafeAreaDisplayStyle " , " enum " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " SafeAreaAspectRatio " , " double " , " " , %.6f ' % aspect )
file . write ( ' \n \t \t \t Property: " Use2DMagnifierZoom " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " 2D Magnifier Zoom " , " Real " , " A+ " ,100 ' )
file . write ( ' \n \t \t \t Property: " 2D Magnifier X " , " Real " , " A+ " ,50 ' )
file . write ( ' \n \t \t \t Property: " 2D Magnifier Y " , " Real " , " A+ " ,50 ' )
file . write ( ' \n \t \t \t Property: " CameraProjectionType " , " enum " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " UseRealTimeDOFAndAA " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " UseDepthOfField " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " FocusSource " , " enum " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " FocusAngle " , " double " , " " ,3.5 ' )
file . write ( ' \n \t \t \t Property: " FocusDistance " , " double " , " " ,200 ' )
file . write ( ' \n \t \t \t Property: " UseAntialiasing " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " AntialiasingIntensity " , " double " , " " ,0.77777 ' )
file . write ( ' \n \t \t \t Property: " UseAccumulationBuffer " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " FrameSamplingCount " , " int " , " " ,7 ' )
file . write ( ' \n \t \t } ' )
file . write ( ' \n \t \t MultiLayer: 0 ' )
file . write ( ' \n \t \t MultiTake: 0 ' )
file . write ( ' \n \t \t Shading: Y ' )
file . write ( ' \n \t \t Culling: " CullingOff " ' )
file . write ( ' \n \t \t TypeFlags: " Camera " ' )
file . write ( ' \n \t \t GeometryVersion: 124 ' )
file . write ( ' \n \t \t Position: %.6f , %.6f , %.6f ' % loc )
2009-09-29 15:27:00 +00:00
file . write ( ' \n \t \t Up: %.6f , %.6f , %.6f ' % tuple ( Mathutils . Vector ( 0 , 1 , 0 ) * matrix_rot ) )
file . write ( ' \n \t \t LookAt: %.6f , %.6f , %.6f ' % tuple ( Mathutils . Vector ( 0 , 0 , - 1 ) * matrix_rot ) )
2007-04-27 17:19:26 +00:00
#file.write('\n\t\tUp: 0,0,0' )
#file.write('\n\t\tLookAt: 0,0,0' )
2007-04-27 00:33:07 +00:00
file . write ( ' \n \t \t ShowInfoOnMoving: 1 ' )
file . write ( ' \n \t \t ShowAudio: 0 ' )
file . write ( ' \n \t \t AudioColor: 0,1,0 ' )
file . write ( ' \n \t \t CameraOrthoZoom: 1 ' )
file . write ( ' \n \t } ' )
2007-04-20 23:33:56 +00:00
2007-08-26 01:35:03 +00:00
def write_light ( my_light ) :
light = my_light . blenObject . data
file . write ( ' \n \t Model: " Model:: %s " , " Light " { ' % my_light . fbxName )
2007-04-20 23:33:56 +00:00
file . write ( ' \n \t \t Version: 232 ' )
2007-04-05 17:55:07 +00:00
2007-09-08 08:49:56 +00:00
write_object_props ( my_light . blenObject , None , my_light . parRelMatrix ( ) )
2007-04-05 17:55:07 +00:00
2007-04-20 23:33:56 +00:00
# Why are these values here twice?????? - oh well, follow the holy sdk's output
2007-03-28 07:08:18 +00:00
2007-04-20 23:33:56 +00:00
# Blender light types match FBX's, funny coincidence, we just need to
# be sure that all unsupported types are made into a point light
#ePOINT,
#eDIRECTIONAL
#eSPOT
2009-09-29 15:27:00 +00:00
light_type_items = { ' POINT ' : 0 , ' SUN ' : 1 , ' SPOT ' : 2 , ' HEMI ' : 3 , ' AREA ' : 4 }
light_type = light_type_items [ light . type ]
# light_type = light.type
2009-05-06 21:47:24 +00:00
if light_type > 2 : light_type = 1 # hemi and area lights become directional
2009-09-29 15:27:00 +00:00
# mode = light.mode
if light . shadow_method == ' RAY_SHADOW ' or light . shadow_method == ' BUFFER_SHADOW ' :
# if mode & Blender.Lamp.Modes.RayShadow or mode & Blender.Lamp.Modes.Shadows:
2007-08-28 02:11:49 +00:00
do_shadow = 1
else :
do_shadow = 0
2009-09-29 15:27:00 +00:00
if light . only_shadow or ( not light . diffuse and not light . specular ) :
# if mode & Blender.Lamp.Modes.OnlyShadow or (mode & Blender.Lamp.Modes.NoDiffuse and mode & Blender.Lamp.Modes.NoSpecular):
2007-08-28 02:11:49 +00:00
do_light = 0
else :
do_light = 1
2007-09-08 08:49:56 +00:00
scale = abs ( GLOBAL_MATRIX . scalePart ( ) [ 0 ] ) # scale is always uniform in this case
2007-04-20 23:33:56 +00:00
file . write ( ' \n \t \t \t Property: " LightType " , " enum " , " " , %i ' % light_type )
file . write ( ' \n \t \t \t Property: " CastLightOnObject " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " DrawVolumetricLight " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " DrawGroundProjection " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " DrawFrontFacingVolumetricLight " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " GoboProperty " , " object " , " " ' )
file . write ( ' \n \t \t \t Property: " Color " , " Color " , " A+ " ,1,1,1 ' )
2007-08-29 03:56:22 +00:00
file . write ( ' \n \t \t \t Property: " Intensity " , " Intensity " , " A+ " , %.2f ' % ( min ( light . energy * 100 , 200 ) ) ) # clamp below 200
2009-09-29 15:27:00 +00:00
if light . type == ' SPOT ' :
file . write ( ' \n \t \t \t Property: " Cone angle " , " Cone angle " , " A+ " , %.2f ' % ( light . spot_size * scale ) )
# file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale))
2007-04-20 23:33:56 +00:00
file . write ( ' \n \t \t \t Property: " Fog " , " Fog " , " A+ " ,50 ' )
2009-09-29 15:27:00 +00:00
file . write ( ' \n \t \t \t Property: " Color " , " Color " , " A " , %.2f , %.2f , %.2f ' % tuple ( light . color ) )
# file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.col))
2007-08-29 03:56:22 +00:00
file . write ( ' \n \t \t \t Property: " Intensity " , " Intensity " , " A+ " , %.2f ' % ( min ( light . energy * 100 , 200 ) ) ) # clamp below 200
2009-09-29 15:27:00 +00:00
#
# duplication? see ^ (Arystan)
# file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale))
2007-04-20 23:33:56 +00:00
file . write ( ' \n \t \t \t Property: " Fog " , " Fog " , " A+ " ,50 ' )
file . write ( ' \n \t \t \t Property: " LightType " , " enum " , " " , %i ' % light_type )
2007-08-28 02:11:49 +00:00
file . write ( ' \n \t \t \t Property: " CastLightOnObject " , " bool " , " " , %i ' % do_light )
2007-04-20 23:33:56 +00:00
file . write ( ' \n \t \t \t Property: " DrawGroundProjection " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " DrawFrontFacingVolumetricLight " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " DrawVolumetricLight " , " bool " , " " ,1 ' )
file . write ( ' \n \t \t \t Property: " GoboProperty " , " object " , " " ' )
file . write ( ' \n \t \t \t Property: " DecayType " , " enum " , " " ,0 ' )
2009-09-29 15:27:00 +00:00
file . write ( ' \n \t \t \t Property: " DecayStart " , " double " , " " , %.2f ' % light . distance )
# file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.dist)
2007-04-20 23:33:56 +00:00
file . write ( ' \n \t \t \t Property: " EnableNearAttenuation " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " NearAttenuationStart " , " double " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " NearAttenuationEnd " , " double " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " EnableFarAttenuation " , " bool " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " FarAttenuationStart " , " double " , " " ,0 ' )
file . write ( ' \n \t \t \t Property: " FarAttenuationEnd " , " double " , " " ,0 ' )
2007-08-28 02:11:49 +00:00
file . write ( ' \n \t \t \t Property: " CastShadows " , " bool " , " " , %i ' % do_shadow )
2007-04-20 23:33:56 +00:00
file . write ( ' \n \t \t \t Property: " ShadowColor " , " ColorRGBA " , " " ,0,0,0,1 ' )
file . write ( ' \n \t \t } ' )
file . write ( ' \n \t \t MultiLayer: 0 ' )
file . write ( ' \n \t \t MultiTake: 0 ' )
file . write ( ' \n \t \t Shading: Y ' )
file . write ( ' \n \t \t Culling: " CullingOff " ' )
file . write ( ' \n \t \t TypeFlags: " Light " ' )
file . write ( ' \n \t \t GeometryVersion: 124 ' )
file . write ( ' \n \t } ' )
2007-03-28 07:08:18 +00:00
2007-08-29 03:56:22 +00:00
# matrixOnly is not used at the moment
def write_null ( my_null = None , fbxName = None , matrixOnly = None ) :
2007-08-09 13:34:44 +00:00
# ob can be null
2007-08-26 01:35:03 +00:00
if not fbxName : fbxName = my_null . fbxName
file . write ( ' \n \t Model: " Model:: %s " , " Null " { ' % fbxName )
2007-08-09 13:34:44 +00:00
file . write ( ' \n \t \t Version: 232 ' )
2007-08-29 03:56:22 +00:00
# only use this for the root matrix at the moment
if matrixOnly :
2007-08-29 05:42:39 +00:00
poseMatrix = write_object_props ( None , None , matrixOnly ) [ 3 ]
2007-08-29 03:56:22 +00:00
else : # all other Null's
2007-09-08 08:49:56 +00:00
if my_null : poseMatrix = write_object_props ( my_null . blenObject , None , my_null . parRelMatrix ( ) ) [ 3 ]
2007-08-29 05:42:39 +00:00
else : poseMatrix = write_object_props ( ) [ 3 ]
pose_items . append ( ( fbxName , poseMatrix ) )
2007-08-09 13:34:44 +00:00
file . write ( '''
}
MultiLayer : 0
MultiTake : 1
Shading : Y
Culling : " CullingOff "
TypeFlags : " Null "
} ''' )
2007-03-28 07:08:18 +00:00
# Material Settings
2009-09-29 15:27:00 +00:00
if world : world_amb = tuple ( world . ambient_color )
# if world: world_amb = world.getAmb()
2007-08-15 00:48:33 +00:00
else : world_amb = ( 0 , 0 , 0 ) # Default value
2007-03-28 07:08:18 +00:00
def write_material ( matname , mat ) :
2007-04-19 17:27:18 +00:00
file . write ( ' \n \t Material: " Material:: %s " , " " { ' % matname )
2007-03-28 07:08:18 +00:00
# Todo, add more material Properties.
if mat :
2009-09-29 15:27:00 +00:00
mat_cold = tuple ( mat . diffuse_color )
# mat_cold = tuple(mat.rgbCol)
mat_cols = tuple ( mat . specular_color )
# mat_cols = tuple(mat.specCol)
2007-04-27 17:19:26 +00:00
#mat_colm = tuple(mat.mirCol) # we wont use the mirror color
2009-09-29 15:27:00 +00:00
mat_colamb = world_amb
# mat_colamb = tuple([c for c in world_amb])
mat_dif = mat . diffuse_intensity
# mat_dif = mat.ref
mat_amb = mat . ambient
# mat_amb = mat.amb
mat_hard = ( float ( mat . specular_hardness ) - 1 ) / 5.10
# mat_hard = (float(mat.hard)-1)/5.10
mat_spec = mat . specular_intensity / 2.0
# mat_spec = mat.spec/2.0
2007-04-19 17:27:18 +00:00
mat_alpha = mat . alpha
2007-08-29 05:42:39 +00:00
mat_emit = mat . emit
2009-09-29 15:27:00 +00:00
mat_shadeless = mat . shadeless
# mat_shadeless = mat.mode & Blender.Material.Modes.SHADELESS
2007-04-19 17:27:18 +00:00
if mat_shadeless :
mat_shader = ' Lambert '
else :
2009-09-29 15:27:00 +00:00
if mat . diffuse_shader == ' LAMBERT ' :
# if mat.diffuseShader == Blender.Material.Shaders.DIFFUSE_LAMBERT:
2007-04-19 17:27:18 +00:00
mat_shader = ' Lambert '
else :
mat_shader = ' Phong '
2007-03-28 07:08:18 +00:00
else :
mat_cols = mat_cold = 0.8 , 0.8 , 0.8
2007-04-19 17:27:18 +00:00
mat_colamb = 0.0 , 0.0 , 0.0
# mat_colm
mat_dif = 1.0
mat_amb = 0.5
mat_hard = 20.0
mat_spec = 0.2
mat_alpha = 1.0
2007-08-29 05:42:39 +00:00
mat_emit = 0.0
2007-04-19 17:27:18 +00:00
mat_shadeless = False
mat_shader = ' Phong '
2007-03-28 07:08:18 +00:00
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t \t Version: 102 ' )
file . write ( ' \n \t \t ShadingModel: " %s " ' % mat_shader . lower ( ) )
file . write ( ' \n \t \t MultiLayer: 0 ' )
file . write ( ' \n \t \t Properties60: { ' )
file . write ( ' \n \t \t \t Property: " ShadingModel " , " KString " , " " , " %s " ' % mat_shader )
file . write ( ' \n \t \t \t Property: " MultiLayer " , " bool " , " " ,0 ' )
2007-08-29 05:42:39 +00:00
file . write ( ' \n \t \t \t Property: " EmissiveColor " , " ColorRGB " , " " , %.4f , %.4f , %.4f ' % mat_cold ) # emit and diffuse color are he same in blender
2008-05-24 12:22:53 +00:00
file . write ( ' \n \t \t \t Property: " EmissiveFactor " , " double " , " " , %.4f ' % mat_emit )
2007-04-19 17:27:18 +00:00
2007-08-29 05:42:39 +00:00
file . write ( ' \n \t \t \t Property: " AmbientColor " , " ColorRGB " , " " , %.4f , %.4f , %.4f ' % mat_colamb )
file . write ( ' \n \t \t \t Property: " AmbientFactor " , " double " , " " , %.4f ' % mat_amb )
file . write ( ' \n \t \t \t Property: " DiffuseColor " , " ColorRGB " , " " , %.4f , %.4f , %.4f ' % mat_cold )
2008-05-24 12:22:53 +00:00
file . write ( ' \n \t \t \t Property: " DiffuseFactor " , " double " , " " , %.4f ' % mat_dif )
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t \t \t Property: " Bump " , " Vector3D " , " " ,0,0,0 ' )
file . write ( ' \n \t \t \t Property: " TransparentColor " , " ColorRGB " , " " ,1,1,1 ' )
2007-08-29 05:42:39 +00:00
file . write ( ' \n \t \t \t Property: " TransparencyFactor " , " double " , " " , %.4f ' % ( 1.0 - mat_alpha ) )
2007-04-19 17:27:18 +00:00
if not mat_shadeless :
2007-08-29 05:42:39 +00:00
file . write ( ' \n \t \t \t Property: " SpecularColor " , " ColorRGB " , " " , %.4f , %.4f , %.4f ' % mat_cols )
file . write ( ' \n \t \t \t Property: " SpecularFactor " , " double " , " " , %.4f ' % mat_spec )
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t \t \t Property: " ShininessExponent " , " double " , " " ,80.0 ' )
file . write ( ' \n \t \t \t Property: " ReflectionColor " , " ColorRGB " , " " ,0,0,0 ' )
file . write ( ' \n \t \t \t Property: " ReflectionFactor " , " double " , " " ,1 ' )
2007-08-20 23:38:39 +00:00
file . write ( ' \n \t \t \t Property: " Emissive " , " ColorRGB " , " " ,0,0,0 ' )
file . write ( ' \n \t \t \t Property: " Ambient " , " ColorRGB " , " " , %.1f , %.1f , %.1f ' % mat_colamb )
file . write ( ' \n \t \t \t Property: " Diffuse " , " ColorRGB " , " " , %.1f , %.1f , %.1f ' % mat_cold )
2007-04-19 17:27:18 +00:00
if not mat_shadeless :
2007-08-20 23:38:39 +00:00
file . write ( ' \n \t \t \t Property: " Specular " , " ColorRGB " , " " , %.1f , %.1f , %.1f ' % mat_cols )
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t \t \t Property: " Shininess " , " double " , " " , %.1f ' % mat_hard )
file . write ( ' \n \t \t \t Property: " Opacity " , " double " , " " , %.1f ' % mat_alpha )
2007-04-19 17:27:18 +00:00
if not mat_shadeless :
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t \t \t Property: " Reflectivity " , " double " , " " ,0 ' )
2007-04-19 17:27:18 +00:00
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t \t } ' )
file . write ( ' \n \t } ' )
2009-09-29 15:27:00 +00:00
def copy_image ( image ) :
rel = image . get_export_path ( basepath , True )
base = os . path . basename ( rel )
if EXP_IMAGE_COPY :
absp = image . get_export_path ( basepath , False )
if not os . path . exists ( absp ) :
shutil . copy ( image . get_abs_filename ( ) , absp )
return ( rel , base )
# tex is an Image (Arystan)
2007-03-28 07:08:18 +00:00
def write_video ( texname , tex ) :
# Same as texture really!
2007-03-29 17:51:32 +00:00
file . write ( ' \n \t Video: " Video:: %s " , " Clip " { ' % texname )
2007-03-28 07:08:18 +00:00
file . write ( '''
Type : " Clip "
Properties60 : {
Property : " FrameRate " , " double " , " " , 0
Property : " LastFrame " , " int " , " " , 0
Property : " Width " , " int " , " " , 0
Property : " Height " , " int " , " " , 0 ''' )
if tex :
2009-09-29 15:27:00 +00:00
fname_rel , fname_strip = copy_image ( tex )
# fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY)
2007-03-28 07:08:18 +00:00
else :
2008-12-03 07:45:52 +00:00
fname = fname_strip = fname_rel = ' '
2007-03-28 07:08:18 +00:00
2007-03-29 17:51:32 +00:00
file . write ( ' \n \t \t \t Property: " Path " , " charptr " , " " , " %s " ' % fname_strip )
2007-03-28 07:08:18 +00:00
file . write ( '''
Property : " StartFrame " , " int " , " " , 0
Property : " StopFrame " , " int " , " " , 0
Property : " PlaySpeed " , " double " , " " , 1
Property : " Offset " , " KTime " , " " , 0
Property : " InterlaceMode " , " enum " , " " , 0
Property : " FreeRunning " , " bool " , " " , 0
Property : " Loop " , " bool " , " " , 0
Property : " AccessMode " , " enum " , " " , 0
}
UseMipMap : 0 ''' )
2007-03-29 17:51:32 +00:00
file . write ( ' \n \t \t Filename: " %s " ' % fname_strip )
2007-03-28 07:08:18 +00:00
if fname_strip : fname_strip = ' / ' + fname_strip
2008-12-03 07:45:52 +00:00
file . write ( ' \n \t \t RelativeFilename: " %s " ' % fname_rel ) # make relative
2007-03-29 17:51:32 +00:00
file . write ( ' \n \t } ' )
2007-03-28 07:08:18 +00:00
def write_texture ( texname , tex , num ) :
# if tex == None then this is a dummy tex
2007-03-29 17:51:32 +00:00
file . write ( ' \n \t Texture: " Texture:: %s " , " TextureVideoClip " { ' % texname )
file . write ( ' \n \t \t Type: " TextureVideoClip " ' )
file . write ( ' \n \t \t Version: 202 ' )
2007-03-28 07:08:18 +00:00
# TODO, rare case _empty_ exists as a name.
2007-03-29 17:51:32 +00:00
file . write ( ' \n \t \t TextureName: " Texture:: %s " ' % texname )
2007-03-28 07:08:18 +00:00
file . write ( '''
Properties60 : {
Property : " Translation " , " Vector " , " A+ " , 0 , 0 , 0
Property : " Rotation " , " Vector " , " A+ " , 0 , 0 , 0
Property : " Scaling " , " Vector " , " A+ " , 1 , 1 , 1 ''' )
2007-03-29 17:51:32 +00:00
file . write ( ' \n \t \t \t Property: " Texture alpha " , " Number " , " A+ " , %i ' % num )
2007-08-28 05:32:00 +00:00
# WrapModeU/V 0==rep, 1==clamp, TODO add support
2007-03-28 07:08:18 +00:00
file . write ( '''
Property : " TextureTypeUse " , " enum " , " " , 0
Property : " CurrentTextureBlendMode " , " enum " , " " , 1
Property : " UseMaterial " , " bool " , " " , 0
Property : " UseMipMap " , " bool " , " " , 0
Property : " CurrentMappingType " , " enum " , " " , 0
2007-08-28 05:32:00 +00:00
Property : " UVSwap " , " bool " , " " , 0 ''' )
2009-09-29 15:27:00 +00:00
file . write ( ' \n \t \t \t Property: " WrapModeU " , " enum " , " " , %i ' % tex . clamp_x )
# file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clampX)
file . write ( ' \n \t \t \t Property: " WrapModeV " , " enum " , " " , %i ' % tex . clamp_y )
# file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clampY)
2007-08-28 05:32:00 +00:00
file . write ( '''
2007-03-28 07:08:18 +00:00
Property : " TextureRotationPivot " , " Vector3D " , " " , 0 , 0 , 0
Property : " TextureScalingPivot " , " Vector3D " , " " , 0 , 0 , 0
Property : " VideoProperty " , " object " , " "
} ''' )
2007-03-29 17:51:32 +00:00
file . write ( ' \n \t \t Media: " Video:: %s " ' % texname )
2008-12-03 07:45:52 +00:00
2007-03-28 07:08:18 +00:00
if tex :
2009-09-29 15:27:00 +00:00
fname_rel , fname_strip = copy_image ( tex )
# fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY)
2007-03-28 07:08:18 +00:00
else :
2008-12-03 07:45:52 +00:00
fname = fname_strip = fname_rel = ' '
file . write ( ' \n \t \t FileName: " %s " ' % fname_strip )
file . write ( ' \n \t \t RelativeFilename: " %s " ' % fname_rel ) # need some make relative command
2007-03-28 07:08:18 +00:00
file . write ( '''
ModelUVTranslation : 0 , 0
ModelUVScaling : 1 , 1
Texture_Alpha_Source : " None "
Cropping : 0 , 0 , 0 , 0
} ''' )
2007-08-15 00:48:33 +00:00
2007-08-09 13:34:44 +00:00
def write_deformer_skin ( obname ) :
2007-08-23 16:34:15 +00:00
'''
Each mesh has its own deformer
'''
2007-08-09 13:34:44 +00:00
file . write ( ' \n \t Deformer: " Deformer::Skin %s " , " Skin " { ' % obname )
file . write ( '''
2007-08-20 23:38:39 +00:00
Version : 100
2007-08-09 13:34:44 +00:00
MultiLayer : 0
Type : " Skin "
Properties60 : {
}
Link_DeformAcuracy : 50
} ''' )
# in the example was 'Bip01 L Thigh_2'
2007-08-26 01:35:03 +00:00
def write_sub_deformer_skin ( my_mesh , my_bone , weights ) :
2007-08-23 16:34:15 +00:00
'''
Each subdeformer is spesific to a mesh , but the bone it links to can be used by many sub - deformers
So the SubDeformer needs the mesh - object name as a prefix to make it unique
Its possible that there is no matching vgroup in this mesh , in that case no verts are in the subdeformer ,
a but silly but dosnt really matter
'''
2007-08-26 01:35:03 +00:00
file . write ( ' \n \t Deformer: " SubDeformer::Cluster %s %s " , " Cluster " { ' % ( my_mesh . fbxName , my_bone . fbxName ) )
2007-08-23 16:34:15 +00:00
2007-08-09 13:34:44 +00:00
file . write ( '''
Version : 100
MultiLayer : 0
Type : " Cluster "
Properties60 : {
Property : " SrcModel " , " object " , " "
Property : " SrcModelReference " , " object " , " "
}
UserData : " " , " " ''' )
2007-08-28 02:11:49 +00:00
# Support for bone parents
if my_mesh . fbxBoneParent :
if my_mesh . fbxBoneParent == my_bone :
# TODO - this is a bit lazy, we could have a simple write loop
# for this case because all weights are 1.0 but for now this is ok
# Parent Bones arent used all that much anyway.
2009-09-29 15:27:00 +00:00
vgroup_data = [ ( j , 1.0 ) for j in range ( len ( my_mesh . blenData . verts ) ) ]
2007-08-28 02:11:49 +00:00
else :
# This bone is not a parent of this mesh object, no weights
vgroup_data = [ ]
else :
# Normal weight painted mesh
if my_bone . blenName in weights [ 0 ] :
# Before we used normalized wright list
#vgroup_data = me.getVertsFromGroup(bone.name, 1)
group_index = weights [ 0 ] . index ( my_bone . blenName )
vgroup_data = [ ( j , weight [ group_index ] ) for j , weight in enumerate ( weights [ 1 ] ) if weight [ group_index ] ]
else :
vgroup_data = [ ]
2007-08-09 13:34:44 +00:00
file . write ( ' \n \t \t Indexes: ' )
i = - 1
for vg in vgroup_data :
if i == - 1 :
file . write ( ' %i ' % vg [ 0 ] )
i = 0
else :
2007-08-24 07:07:18 +00:00
if i == 23 :
2007-08-09 13:34:44 +00:00
file . write ( ' \n \t \t ' )
i = 0
file . write ( ' , %i ' % vg [ 0 ] )
i + = 1
file . write ( ' \n \t \t Weights: ' )
i = - 1
for vg in vgroup_data :
if i == - 1 :
file . write ( ' %.8f ' % vg [ 1 ] )
i = 0
else :
if i == 38 :
file . write ( ' \n \t \t ' )
i = 0
file . write ( ' , %.8f ' % vg [ 1 ] )
i + = 1
2007-09-08 08:49:56 +00:00
if my_mesh . fbxParent :
# TODO FIXME, this case is broken in some cases. skinned meshes just shouldnt have parents where possible!
m = mtx4_z90 * ( my_bone . restMatrix * my_bone . fbxArm . matrixWorld . copy ( ) * my_mesh . matrixWorld . copy ( ) . invert ( ) )
else :
# Yes! this is it... - but dosnt work when the mesh is a.
m = mtx4_z90 * ( my_bone . restMatrix * my_bone . fbxArm . matrixWorld . copy ( ) * my_mesh . matrixWorld . copy ( ) . invert ( ) )
2007-08-20 23:38:39 +00:00
2007-09-08 08:49:56 +00:00
#m = mtx4_z90 * my_bone.restMatrix
2007-08-09 13:34:44 +00:00
matstr = mat4x4str ( m )
matstr_i = mat4x4str ( m . invert ( ) )
2007-08-20 23:38:39 +00:00
2007-08-09 13:34:44 +00:00
file . write ( ' \n \t \t Transform: %s ' % matstr_i ) # THIS IS __NOT__ THE GLOBAL MATRIX AS DOCUMENTED :/
file . write ( ' \n \t \t TransformLink: %s ' % matstr )
file . write ( ' \n \t } ' )
2007-08-26 01:35:03 +00:00
def write_mesh ( my_mesh ) :
2007-08-29 03:56:22 +00:00
2007-08-29 09:50:08 +00:00
me = my_mesh . blenData
2007-08-29 03:56:22 +00:00
# if there are non NULL materials on this mesh
2009-05-06 06:01:09 +00:00
if my_mesh . blenMaterials : do_materials = True
else : do_materials = False
2007-08-29 03:56:22 +00:00
if my_mesh . blenTextures : do_textures = True
2009-05-06 06:01:09 +00:00
else : do_textures = False
2009-09-29 15:27:00 +00:00
do_uvs = len ( me . uv_textures ) > 0
# do_uvs = me.faceUV
2007-08-29 03:56:22 +00:00
2007-08-26 01:35:03 +00:00
file . write ( ' \n \t Model: " Model:: %s " , " Mesh " { ' % my_mesh . fbxName )
2007-08-15 00:48:33 +00:00
file . write ( ' \n \t \t Version: 232 ' ) # newline is added in write_object_props
2007-08-24 12:13:34 +00:00
2009-05-18 04:33:33 +00:00
poseMatrix = write_object_props ( my_mesh . blenObject , None , my_mesh . parRelMatrix ( ) ) [ 3 ]
pose_items . append ( ( my_mesh . fbxName , poseMatrix ) )
2007-08-24 12:13:34 +00:00
2007-08-15 00:48:33 +00:00
file . write ( ' \n \t \t } ' )
file . write ( ' \n \t \t MultiLayer: 0 ' )
file . write ( ' \n \t \t MultiTake: 1 ' )
file . write ( ' \n \t \t Shading: Y ' )
file . write ( ' \n \t \t Culling: " CullingOff " ' )
2007-08-09 13:34:44 +00:00
2007-08-26 01:35:03 +00:00
2007-08-15 00:48:33 +00:00
# Write the Real Mesh data here
file . write ( ' \n \t \t Vertices: ' )
i = - 1
2007-08-29 09:50:08 +00:00
2007-09-08 08:49:56 +00:00
for v in me . verts :
if i == - 1 :
file . write ( ' %.6f , %.6f , %.6f ' % tuple ( v . co ) ) ; i = 0
else :
if i == 7 :
file . write ( ' \n \t \t ' ) ; i = 0
file . write ( ' , %.6f , %.6f , %.6f ' % tuple ( v . co ) )
i + = 1
2007-08-29 09:50:08 +00:00
2007-03-29 17:51:32 +00:00
file . write ( ' \n \t \t PolygonVertexIndex: ' )
2007-03-28 07:08:18 +00:00
i = - 1
for f in me . faces :
2009-09-29 15:27:00 +00:00
fi = f . verts
# fi = [v_index for j, v_index in enumerate(f.verts) if v_index != 0 or j != 3]
# fi = [v.index for v in f]
2007-03-28 07:08:18 +00:00
# flip the last index, odd but it looks like
# this is how fbx tells one face from another
fi [ - 1 ] = - ( fi [ - 1 ] + 1 )
fi = tuple ( fi )
if i == - 1 :
2009-09-29 15:27:00 +00:00
if len ( fi ) == 3 : file . write ( ' %i , %i , %i ' % fi )
# if len(f) == 3: file.write('%i,%i,%i' % fi )
2007-03-28 07:08:18 +00:00
else : file . write ( ' %i , %i , %i , %i ' % fi )
i = 0
else :
if i == 13 :
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t \t ' )
2007-03-28 07:08:18 +00:00
i = 0
2009-09-29 15:27:00 +00:00
if len ( fi ) == 3 : file . write ( ' , %i , %i , %i ' % fi )
# if len(f) == 3: file.write(',%i,%i,%i' % fi )
2007-03-28 07:08:18 +00:00
else : file . write ( ' , %i , %i , %i , %i ' % fi )
i + = 1
2009-05-06 04:24:01 +00:00
file . write ( ' \n \t \t Edges: ' )
i = - 1
2007-04-21 11:23:45 +00:00
for ed in me . edges :
if i == - 1 :
2009-09-29 15:27:00 +00:00
file . write ( ' %i , %i ' % ( ed . verts [ 0 ] , ed . verts [ 1 ] ) )
# file.write('%i,%i' % (ed.v1.index, ed.v2.index))
2007-04-21 11:23:45 +00:00
i = 0
else :
if i == 13 :
file . write ( ' \n \t \t ' )
i = 0
2009-09-29 15:27:00 +00:00
file . write ( ' , %i , %i ' % ( ed . verts [ 0 ] , ed . verts [ 1 ] ) )
# file.write(',%i,%i' % (ed.v1.index, ed.v2.index))
2007-04-21 11:23:45 +00:00
i + = 1
2007-03-29 17:51:32 +00:00
file . write ( ' \n \t \t GeometryVersion: 124 ' )
2007-03-28 07:08:18 +00:00
2007-03-29 17:51:32 +00:00
file . write ( '''
2007-03-28 07:08:18 +00:00
LayerElementNormal : 0 {
Version : 101
Name : " "
MappingInformationType : " ByVertice "
ReferenceInformationType : " Direct "
Normals : ''' )
2007-08-24 12:13:34 +00:00
2007-03-28 07:08:18 +00:00
i = - 1
2007-09-08 08:49:56 +00:00
for v in me . verts :
if i == - 1 :
2009-09-29 15:27:00 +00:00
file . write ( ' %.15f , %.15f , %.15f ' % tuple ( v . normal ) ) ; i = 0
# file.write('%.15f,%.15f,%.15f' % tuple(v.no)); i=0
2007-09-08 08:49:56 +00:00
else :
if i == 2 :
file . write ( ' \n ' ) ; i = 0
2009-09-29 15:27:00 +00:00
file . write ( ' , %.15f , %.15f , %.15f ' % tuple ( v . normal ) )
# file.write(',%.15f,%.15f,%.15f' % tuple(v.no))
2007-09-08 08:49:56 +00:00
i + = 1
file . write ( ' \n \t \t } ' )
2007-03-28 07:08:18 +00:00
2009-05-06 04:24:01 +00:00
# Write Face Smoothing
file . write ( '''
LayerElementSmoothing : 0 {
Version : 102
Name : " "
MappingInformationType : " ByPolygon "
ReferenceInformationType : " Direct "
Smoothing : ''' )
i = - 1
for f in me . faces :
if i == - 1 :
file . write ( ' %i ' % f . smooth ) ; i = 0
else :
if i == 54 :
file . write ( ' \n ' ) ; i = 0
file . write ( ' , %i ' % f . smooth )
i + = 1
file . write ( ' \n \t \t } ' )
# Write Edge Smoothing
file . write ( '''
2009-09-29 15:27:00 +00:00
LayerElementSmoothing : 0 {
2009-05-06 04:24:01 +00:00
Version : 101
Name : " "
MappingInformationType : " ByEdge "
ReferenceInformationType : " Direct "
Smoothing : ''' )
2009-09-29 15:27:00 +00:00
# SHARP = Blender.Mesh.EdgeFlags.SHARP
2009-05-06 04:24:01 +00:00
i = - 1
for ed in me . edges :
if i == - 1 :
2009-09-29 15:27:00 +00:00
file . write ( ' %i ' % ( ed . sharp ) ) ; i = 0
# file.write('%i' % ((ed.flag&SHARP)!=0)); i=0
2009-05-06 04:24:01 +00:00
else :
if i == 54 :
file . write ( ' \n ' ) ; i = 0
2009-09-29 15:27:00 +00:00
file . write ( ' , %i ' % ( ed . sharp ) )
# file.write(',%i' % ((ed.flag&SHARP)!=0))
2009-05-06 04:24:01 +00:00
i + = 1
file . write ( ' \n \t \t } ' )
2009-09-29 15:27:00 +00:00
# del SHARP
# small utility function
# returns a slice of data depending on number of face verts
# data is either a MeshTextureFace or MeshColor
def face_data ( data , face ) :
totvert = len ( f . verts )
return data [ : totvert ]
2009-05-06 04:24:01 +00:00
2007-03-31 12:23:46 +00:00
# Write VertexColor Layers
2007-09-08 08:49:56 +00:00
# note, no programs seem to use this info :/
2007-03-31 12:23:46 +00:00
collayers = [ ]
2009-09-29 15:27:00 +00:00
if len ( me . vertex_colors ) :
# if me.vertexColors:
collayers = me . vertex_colors
# collayers = me.getColorLayerNames()
collayer_orig = me . active_vertex_color
# collayer_orig = me.activeColorLayer
2007-03-31 12:23:46 +00:00
for colindex , collayer in enumerate ( collayers ) :
2009-09-29 15:27:00 +00:00
# me.activeColorLayer = collayer
2007-03-31 12:23:46 +00:00
file . write ( ' \n \t \t LayerElementColor: %i { ' % colindex )
file . write ( ' \n \t \t \t Version: 101 ' )
2009-09-29 15:27:00 +00:00
file . write ( ' \n \t \t \t Name: " %s " ' % collayer . name )
# file.write('\n\t\t\tName: "%s"' % collayer)
2007-03-31 12:23:46 +00:00
file . write ( '''
MappingInformationType : " ByPolygonVertex "
ReferenceInformationType : " IndexToDirect "
Colors : ''' )
i = - 1
ii = 0 # Count how many Colors we write
2009-09-29 15:27:00 +00:00
for f , cf in zip ( me . faces , collayer . data ) :
colors = [ cf . color1 , cf . color2 , cf . color3 , cf . color4 ]
# determine number of verts
colors = face_data ( colors , f )
for col in colors :
2007-03-31 12:23:46 +00:00
if i == - 1 :
2009-09-29 15:27:00 +00:00
file . write ( ' %.4f , %.4f , %.4f ,1 ' % tuple ( col ) )
2007-03-31 12:23:46 +00:00
i = 0
else :
if i == 7 :
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t \t \t \t ' )
2007-03-31 12:23:46 +00:00
i = 0
2009-09-29 15:27:00 +00:00
file . write ( ' , %.4f , %.4f , %.4f ,1 ' % tuple ( col ) )
2007-03-31 12:23:46 +00:00
i + = 1
ii + = 1 # One more Color
2009-09-29 15:27:00 +00:00
# for f in me.faces:
# for col in f.col:
# if i==-1:
# file.write('%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0))
# i=0
# else:
# if i==7:
# file.write('\n\t\t\t\t')
# i=0
# file.write(',%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0))
# i+=1
# ii+=1 # One more Color
2007-03-31 12:23:46 +00:00
file . write ( ' \n \t \t \t ColorIndex: ' )
i = - 1
2009-09-29 15:27:00 +00:00
for j in range ( ii ) :
2007-03-31 12:23:46 +00:00
if i == - 1 :
file . write ( ' %i ' % j )
i = 0
else :
if i == 55 :
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t \t \t \t ' )
2007-03-31 12:23:46 +00:00
i = 0
file . write ( ' , %i ' % j )
i + = 1
file . write ( ' \n \t \t } ' )
2007-03-29 17:51:32 +00:00
# Write UV and texture layers.
2007-03-31 12:23:46 +00:00
uvlayers = [ ]
2009-05-06 06:01:09 +00:00
if do_uvs :
2009-09-29 15:27:00 +00:00
uvlayers = me . uv_textures
# uvlayers = me.getUVLayerNames()
uvlayer_orig = me . active_uv_texture
# uvlayer_orig = me.activeUVLayer
for uvindex , uvlayer in enumerate ( me . uv_textures ) :
# for uvindex, uvlayer in enumerate(uvlayers):
# me.activeUVLayer = uvlayer
2007-03-29 17:51:32 +00:00
file . write ( ' \n \t \t LayerElementUV: %i { ' % uvindex )
file . write ( ' \n \t \t \t Version: 101 ' )
2009-09-29 15:27:00 +00:00
file . write ( ' \n \t \t \t Name: " %s " ' % uvlayer . name )
# file.write('\n\t\t\tName: "%s"' % uvlayer)
2007-03-29 17:51:32 +00:00
file . write ( '''
2007-03-28 07:08:18 +00:00
MappingInformationType : " ByPolygonVertex "
ReferenceInformationType : " IndexToDirect "
UV : ''' )
2007-03-29 17:51:32 +00:00
i = - 1
ii = 0 # Count how many UVs we write
2009-09-29 15:27:00 +00:00
for uf in uvlayer . data :
# for f in me.faces:
for uv in uf . uv :
# for uv in f.uv:
2007-03-29 17:51:32 +00:00
if i == - 1 :
file . write ( ' %.6f , %.6f ' % tuple ( uv ) )
i = 0
else :
if i == 7 :
file . write ( ' \n ' )
i = 0
file . write ( ' , %.6f , %.6f ' % tuple ( uv ) )
i + = 1
ii + = 1 # One more UV
2007-03-31 12:23:46 +00:00
file . write ( ' \n \t \t \t UVIndex: ' )
2007-03-29 17:51:32 +00:00
i = - 1
2009-09-29 15:27:00 +00:00
for j in range ( ii ) :
2007-03-29 17:51:32 +00:00
if i == - 1 :
file . write ( ' %i ' % j )
2007-03-28 07:08:18 +00:00
i = 0
else :
2007-03-29 17:51:32 +00:00
if i == 55 :
2007-03-31 12:23:46 +00:00
file . write ( ' \n \t \t \t \t ' )
2007-03-28 07:08:18 +00:00
i = 0
2007-03-29 17:51:32 +00:00
file . write ( ' , %i ' % j )
2007-03-28 07:08:18 +00:00
i + = 1
2007-03-29 17:51:32 +00:00
2007-03-31 12:23:46 +00:00
file . write ( ' \n \t \t } ' )
2007-03-29 17:51:32 +00:00
2007-08-29 03:56:22 +00:00
if do_textures :
2007-03-29 17:51:32 +00:00
file . write ( ' \n \t \t LayerElementTexture: %i { ' % uvindex )
file . write ( ' \n \t \t \t Version: 101 ' )
2009-09-29 15:27:00 +00:00
file . write ( ' \n \t \t \t Name: " %s " ' % uvlayer . name )
# file.write('\n\t\t\tName: "%s"' % uvlayer)
2007-03-29 17:51:32 +00:00
2007-08-29 03:56:22 +00:00
if len ( my_mesh . blenTextures ) == 1 :
file . write ( ' \n \t \t \t MappingInformationType: " AllSame " ' )
else :
file . write ( ' \n \t \t \t MappingInformationType: " ByPolygon " ' )
file . write ( ' \n \t \t \t ReferenceInformationType: " IndexToDirect " ' )
file . write ( ' \n \t \t \t BlendMode: " Translucent " ' )
file . write ( ' \n \t \t \t TextureAlpha: 1 ' )
file . write ( ' \n \t \t \t TextureId: ' )
if len ( my_mesh . blenTextures ) == 1 :
file . write ( ' 0 ' )
else :
texture_mapping_local = { None : - 1 }
2007-03-29 17:51:32 +00:00
2007-08-29 03:56:22 +00:00
i = 0 # 1 for dummy
for tex in my_mesh . blenTextures :
2009-05-04 21:49:25 +00:00
if tex : # None is set above
texture_mapping_local [ tex ] = i
i + = 1
2007-08-29 03:56:22 +00:00
i = - 1
2009-09-29 15:27:00 +00:00
for f in uvlayer . data :
# for f in me.faces:
2007-08-29 03:56:22 +00:00
img_key = f . image
2007-03-29 17:51:32 +00:00
2007-08-29 03:56:22 +00:00
if i == - 1 :
i = 0
file . write ( ' %s ' % texture_mapping_local [ img_key ] )
else :
if i == 55 :
file . write ( ' \n ' )
i = 0
file . write ( ' , %s ' % texture_mapping_local [ img_key ] )
i + = 1
2007-03-29 06:01:03 +00:00
else :
2007-03-29 17:51:32 +00:00
file . write ( '''
LayerElementTexture : 0 {
Version : 101
Name : " "
MappingInformationType : " NoMappingInformation "
ReferenceInformationType : " IndexToDirect "
BlendMode : " Translucent "
TextureAlpha : 1
TextureId : ''' )
file . write ( ' \n \t \t } ' )
2007-03-28 07:08:18 +00:00
2009-09-29 15:27:00 +00:00
# me.activeUVLayer = uvlayer_orig
2007-03-29 17:51:32 +00:00
# Done with UV/textures.
2007-03-28 07:08:18 +00:00
2007-08-29 03:56:22 +00:00
if do_materials :
file . write ( ' \n \t \t LayerElementMaterial: 0 { ' )
file . write ( ' \n \t \t \t Version: 101 ' )
file . write ( ' \n \t \t \t Name: " " ' )
2007-03-28 07:08:18 +00:00
2007-08-29 03:56:22 +00:00
if len ( my_mesh . blenMaterials ) == 1 :
file . write ( ' \n \t \t \t MappingInformationType: " AllSame " ' )
else :
file . write ( ' \n \t \t \t MappingInformationType: " ByPolygon " ' )
2007-03-28 07:08:18 +00:00
2007-08-29 03:56:22 +00:00
file . write ( ' \n \t \t \t ReferenceInformationType: " IndexToDirect " ' )
file . write ( ' \n \t \t \t Materials: ' )
2007-03-29 06:01:03 +00:00
2007-08-29 03:56:22 +00:00
if len ( my_mesh . blenMaterials ) == 1 :
file . write ( ' 0 ' )
else :
# Build a material mapping for this
2009-05-06 06:01:09 +00:00
material_mapping_local = { } # local-mat & tex : global index.
for j , mat_tex_pair in enumerate ( my_mesh . blenMaterials ) :
material_mapping_local [ mat_tex_pair ] = j
2007-04-21 11:23:45 +00:00
2007-08-29 03:56:22 +00:00
len_material_mapping_local = len ( material_mapping_local )
2009-05-06 06:01:09 +00:00
mats = my_mesh . blenMaterialList
2009-09-29 15:27:00 +00:00
if me . active_uv_texture :
uv_faces = me . active_uv_texture . data
else :
uv_faces = [ None ] * len ( me . faces )
2009-05-06 06:01:09 +00:00
2007-08-29 03:56:22 +00:00
i = - 1
2009-09-29 15:27:00 +00:00
for f , uf in zip ( me . faces , uv_faces ) :
# for f in me.faces:
try : mat = mats [ f . material_index ]
# try: mat = mats[f.mat]
2009-05-06 06:01:09 +00:00
except : mat = None
2009-09-29 15:27:00 +00:00
if do_uvs : tex = uf . image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/
# if do_uvs: tex = f.image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/
2009-05-06 06:01:09 +00:00
else : tex = None
2007-03-29 06:01:03 +00:00
2007-08-29 03:56:22 +00:00
if i == - 1 :
i = 0
2009-05-06 06:01:09 +00:00
file . write ( ' %s ' % ( material_mapping_local [ mat , tex ] ) ) # None for mat or tex is ok
2007-08-29 03:56:22 +00:00
else :
if i == 55 :
file . write ( ' \n \t \t \t \t ' )
i = 0
2009-05-06 06:01:09 +00:00
file . write ( ' , %s ' % ( material_mapping_local [ mat , tex ] ) )
2007-08-29 03:56:22 +00:00
i + = 1
2007-03-28 07:08:18 +00:00
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t \t } ' )
2007-03-28 07:08:18 +00:00
file . write ( '''
Layer : 0 {
Version : 100
LayerElement : {
Type : " LayerElementNormal "
TypedIndex : 0
} ''' )
2007-08-29 03:56:22 +00:00
if do_materials :
2007-03-28 07:08:18 +00:00
file . write ( '''
LayerElement : {
Type : " LayerElementMaterial "
TypedIndex : 0
} ''' )
# Always write this
2007-08-29 03:56:22 +00:00
if do_textures :
2007-03-28 07:08:18 +00:00
file . write ( '''
LayerElement : {
Type : " LayerElementTexture "
TypedIndex : 0
} ''' )
2007-03-31 12:23:46 +00:00
2009-09-29 15:27:00 +00:00
if me . vertex_colors :
# if me.vertexColors:
2007-03-31 12:23:46 +00:00
file . write ( '''
LayerElement : {
Type : " LayerElementColor "
TypedIndex : 0
} ''' )
2009-05-06 06:01:09 +00:00
if do_uvs : # same as me.faceUV
2007-03-28 07:08:18 +00:00
file . write ( '''
LayerElement : {
Type : " LayerElementUV "
TypedIndex : 0
} ''' )
2007-03-29 17:51:32 +00:00
file . write ( ' \n \t \t } ' )
2007-03-31 12:23:46 +00:00
if len ( uvlayers ) > 1 :
2009-09-29 15:27:00 +00:00
for i in range ( 1 , len ( uvlayers ) ) :
2007-03-29 17:51:32 +00:00
file . write ( ' \n \t \t Layer: %i { ' % i )
file . write ( ' \n \t \t \t Version: 100 ' )
file . write ( '''
LayerElement : {
Type : " LayerElementUV " ''' )
file . write ( ' \n \t \t \t \t TypedIndex: %i ' % i )
file . write ( ' \n \t \t \t } ' )
2007-08-29 03:56:22 +00:00
if do_textures :
2007-03-29 17:51:32 +00:00
file . write ( '''
LayerElement : {
Type : " LayerElementTexture " ''' )
file . write ( ' \n \t \t \t \t TypedIndex: %i ' % i )
file . write ( ' \n \t \t \t } ' )
file . write ( ' \n \t \t } ' )
2007-03-31 12:23:46 +00:00
if len ( collayers ) > 1 :
# Take into account any UV layers
layer_offset = 0
if uvlayers : layer_offset = len ( uvlayers ) - 1
2009-09-29 15:27:00 +00:00
for i in range ( layer_offset , len ( collayers ) + layer_offset ) :
2007-03-31 12:23:46 +00:00
file . write ( ' \n \t \t Layer: %i { ' % i )
file . write ( ' \n \t \t \t Version: 100 ' )
file . write ( '''
LayerElement : {
Type : " LayerElementColor " ''' )
file . write ( ' \n \t \t \t \t TypedIndex: %i ' % i )
file . write ( ' \n \t \t \t } ' )
file . write ( ' \n \t \t } ' )
2007-08-09 13:34:44 +00:00
file . write ( ' \n \t } ' )
2007-08-30 17:16:09 +00:00
def write_group ( name ) :
file . write ( ' \n \t GroupSelection: " GroupSelection:: %s " , " Default " { ' % name )
file . write ( '''
Properties60 : {
Property : " MultiLayer " , " bool " , " " , 0
Property : " Pickable " , " bool " , " " , 1
Property : " Transformable " , " bool " , " " , 1
Property : " Show " , " bool " , " " , 1
}
MultiLayer : 0
} ''' )
2007-08-20 23:38:39 +00:00
# add meshes here to clear because they are not used anywhere.
meshes_to_clear = [ ]
2007-08-15 00:48:33 +00:00
2007-08-20 23:38:39 +00:00
ob_meshes = [ ]
2007-08-15 00:48:33 +00:00
ob_lights = [ ]
ob_cameras = [ ]
# in fbx we export bones as children of the mesh
# armatures not a part of a mesh, will be added to ob_arms
ob_bones = [ ]
ob_arms = [ ]
ob_null = [ ] # emptys
2007-08-30 17:16:09 +00:00
2007-09-08 08:49:56 +00:00
# List of types that have blender objects (not bones)
ob_all_typegroups = [ ob_meshes , ob_lights , ob_cameras , ob_arms , ob_null ]
2007-08-30 17:16:09 +00:00
groups = [ ] # blender groups, only add ones that have objects in the selections
2009-05-06 06:01:09 +00:00
materials = { } # (mat, image) keys, should be a set()
textures = { } # should be a set()
2007-08-15 00:48:33 +00:00
2007-08-23 16:34:15 +00:00
tmp_ob_type = ob_type = None # incase no objects are exported, so as not to raise an error
# if EXP_OBS_SELECTED is false, use sceens objects
2007-08-28 02:11:49 +00:00
if not batch_objects :
2009-09-29 15:27:00 +00:00
if EXP_OBS_SELECTED : tmp_objects = context . selected_objects
# if EXP_OBS_SELECTED: tmp_objects = sce.objects.context
2007-08-28 02:11:49 +00:00
else : tmp_objects = sce . objects
else :
tmp_objects = batch_objects
2007-08-15 00:48:33 +00:00
2007-08-28 02:11:49 +00:00
if EXP_ARMATURE :
# This is needed so applying modifiers dosnt apply the armature deformation, its also needed
# ...so mesh objects return their rest worldspace matrix when bone-parents are exported as weighted meshes.
# set every armature to its rest, backup the original values so we done mess up the scene
2009-09-29 15:27:00 +00:00
ob_arms_orig_rest = [ arm . rest_position for arm in bpy . data . armatures ]
# ob_arms_orig_rest = [arm.restPosition for arm in bpy.data.armatures]
2007-08-28 02:11:49 +00:00
for arm in bpy . data . armatures :
2009-09-29 15:27:00 +00:00
arm . rest_position = True
# arm.restPosition = True
2007-08-28 02:11:49 +00:00
if ob_arms_orig_rest :
for ob_base in bpy . data . objects :
#if ob_base.type == 'Armature':
2009-09-29 15:27:00 +00:00
ob_base . make_display_list ( )
# ob_base.makeDisplayList()
2007-08-28 02:11:49 +00:00
# This causes the makeDisplayList command to effect the mesh
2009-09-29 15:27:00 +00:00
sce . set_frame ( sce . current_frame )
# Blender.Set('curframe', Blender.Get('curframe'))
2007-08-28 02:11:49 +00:00
2007-09-08 08:49:56 +00:00
2007-08-23 16:34:15 +00:00
for ob_base in tmp_objects :
2009-09-29 15:27:00 +00:00
# ignore dupli children
if ob_base . parent and ob_base . parent . dupli_type != ' NONE ' :
continue
obs = [ ( ob_base , ob_base . matrix ) ]
if ob_base . dupli_type != ' NONE ' :
ob_base . create_dupli_list ( )
obs = [ ( dob . object , dob . matrix ) for dob in ob_base . dupli_list ]
for ob , mtx in obs :
# for ob, mtx in BPyObject.getDerivedObjects(ob_base):
2007-08-23 16:34:15 +00:00
tmp_ob_type = ob . type
2009-09-29 15:27:00 +00:00
if tmp_ob_type == ' CAMERA ' :
# if tmp_ob_type == 'Camera':
2007-08-23 16:34:15 +00:00
if EXP_CAMERA :
2007-08-30 17:16:09 +00:00
ob_cameras . append ( my_object_generic ( ob , mtx ) )
2009-09-29 15:27:00 +00:00
elif tmp_ob_type == ' LAMP ' :
# elif tmp_ob_type == 'Lamp':
2007-08-23 16:34:15 +00:00
if EXP_LAMP :
2007-08-30 17:16:09 +00:00
ob_lights . append ( my_object_generic ( ob , mtx ) )
2009-09-29 15:27:00 +00:00
elif tmp_ob_type == ' ARMATURE ' :
# elif tmp_ob_type == 'Armature':
2007-08-23 16:34:15 +00:00
if EXP_ARMATURE :
2007-08-30 17:16:09 +00:00
# TODO - armatures dont work in dupligroups!
2007-08-23 16:34:15 +00:00
if ob not in ob_arms : ob_arms . append ( ob )
# ob_arms.append(ob) # replace later. was "ob_arms.append(sane_obname(ob), ob)"
2009-09-29 15:27:00 +00:00
elif tmp_ob_type == ' EMPTY ' :
# elif tmp_ob_type == 'Empty':
2007-08-23 16:34:15 +00:00
if EXP_EMPTY :
2007-08-30 17:16:09 +00:00
ob_null . append ( my_object_generic ( ob , mtx ) )
2007-08-23 16:34:15 +00:00
elif EXP_MESH :
2007-08-29 09:50:08 +00:00
origData = True
2009-09-29 15:27:00 +00:00
if tmp_ob_type != ' MESH ' :
# if tmp_ob_type != 'Mesh':
# me = bpy.data.meshes.new()
try : me = ob . create_mesh ( True , ' PREVIEW ' )
# try: me.getFromObject(ob)
2007-08-28 02:11:49 +00:00
except : me = None
2007-08-20 23:38:39 +00:00
if me :
meshes_to_clear . append ( me )
2007-08-28 02:11:49 +00:00
mats = me . materials
2007-08-29 09:50:08 +00:00
origData = False
2007-08-20 23:38:39 +00:00
else :
2007-08-28 02:11:49 +00:00
# Mesh Type!
if EXP_MESH_APPLY_MOD :
2009-09-29 15:27:00 +00:00
# me = bpy.data.meshes.new()
me = ob . create_mesh ( True , ' PREVIEW ' )
# me.getFromObject(ob)
2007-08-28 02:11:49 +00:00
# so we keep the vert groups
2009-09-29 15:27:00 +00:00
# if EXP_ARMATURE:
# orig_mesh = ob.getData(mesh=1)
# if orig_mesh.getVertGroupNames():
# ob.copy().link(me)
# # If new mesh has no vgroups we can try add if verts are teh same
# if not me.getVertGroupNames(): # vgroups were not kept by the modifier
# if len(me.verts) == len(orig_mesh.verts):
# groupNames, vWeightDict = BPyMesh.meshWeight2Dict(orig_mesh)
# BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
2007-08-28 02:11:49 +00:00
# print ob, me, me.getVertGroupNames()
2007-08-20 23:38:39 +00:00
meshes_to_clear . append ( me )
2007-08-29 09:50:08 +00:00
origData = False
2007-08-28 02:11:49 +00:00
mats = me . materials
else :
2009-09-29 15:27:00 +00:00
me = ob . data
# me = ob.getData(mesh=1)
2007-08-28 02:11:49 +00:00
mats = me . materials
2009-09-29 15:27:00 +00:00
# # Support object colors
# tmp_colbits = ob.colbits
# if tmp_colbits:
# tmp_ob_mats = ob.getMaterials(1) # 1 so we get None's too.
# for i in xrange(16):
# if tmp_colbits & (1<<i):
# mats[i] = tmp_ob_mats[i]
# del tmp_ob_mats
# del tmp_colbits
2007-08-28 02:11:49 +00:00
2007-08-15 00:48:33 +00:00
if me :
2009-09-29 15:27:00 +00:00
# # This WILL modify meshes in blender if EXP_MESH_APPLY_MOD is disabled.
# # so strictly this is bad. but only in rare cases would it have negative results
# # say with dupliverts the objects would rotate a bit differently
# if EXP_MESH_HQ_NORMALS:
# BPyMesh.meshCalcNormals(me) # high quality normals nice for realtime engines.
2007-08-20 23:38:39 +00:00
2007-08-29 03:56:22 +00:00
texture_mapping_local = { }
2009-05-06 06:01:09 +00:00
material_mapping_local = { }
2009-09-29 15:27:00 +00:00
if len ( me . uv_textures ) > 0 :
# if me.faceUV:
uvlayer_orig = me . active_uv_texture
# uvlayer_orig = me.activeUVLayer
for uvlayer in me . uv_textures :
# for uvlayer in me.getUVLayerNames():
# me.activeUVLayer = uvlayer
for f , uf in zip ( me . faces , uvlayer . data ) :
# for f in me.faces:
tex = uf . image
# tex = f.image
2009-05-06 06:01:09 +00:00
textures [ tex ] = texture_mapping_local [ tex ] = None
2009-09-29 15:27:00 +00:00
try : mat = mats [ f . material_index ]
# try: mat = mats[f.mat]
2009-05-06 06:01:09 +00:00
except : mat = None
materials [ mat , tex ] = material_mapping_local [ mat , tex ] = None # should use sets, wait for blender 2.5
2007-08-15 00:48:33 +00:00
2009-09-29 15:27:00 +00:00
# me.activeUVLayer = uvlayer_orig
2009-05-06 06:01:09 +00:00
else :
for mat in mats :
# 2.44 use mat.lib too for uniqueness
materials [ mat , None ] = material_mapping_local [ mat , None ] = None
else :
materials [ None , None ] = None
2007-08-15 00:48:33 +00:00
2007-08-23 16:34:15 +00:00
if EXP_ARMATURE :
2009-09-29 15:27:00 +00:00
armob = ob . find_armature ( )
2007-08-28 02:11:49 +00:00
blenParentBoneName = None
2007-08-24 12:13:34 +00:00
2007-08-28 02:11:49 +00:00
# parent bone - special case
2009-09-29 15:27:00 +00:00
if ( not armob ) and ob . parent and ob . parent . type == ' ARMATURE ' and \
ob . parent_type == ' BONE ' :
# if (not armob) and ob.parent and ob.parent.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.BONE:
2007-08-28 02:11:49 +00:00
armob = ob . parent
2009-09-29 15:27:00 +00:00
blenParentBoneName = ob . parent_bone
# blenParentBoneName = ob.parentbonename
2007-08-15 00:48:33 +00:00
2007-08-28 02:11:49 +00:00
if armob and armob not in ob_arms :
ob_arms . append ( armob )
2007-08-29 19:53:49 +00:00
2007-08-15 00:48:33 +00:00
else :
2007-08-28 02:11:49 +00:00
blenParentBoneName = armob = None
2007-08-15 00:48:33 +00:00
2007-08-30 17:16:09 +00:00
my_mesh = my_object_generic ( ob , mtx )
2007-08-26 01:35:03 +00:00
my_mesh . blenData = me
2007-08-29 09:50:08 +00:00
my_mesh . origData = origData
2009-09-29 15:27:00 +00:00
my_mesh . blenMaterials = list ( material_mapping_local . keys ( ) )
2009-05-06 06:01:09 +00:00
my_mesh . blenMaterialList = mats
2009-09-29 15:27:00 +00:00
my_mesh . blenTextures = list ( texture_mapping_local . keys ( ) )
2007-08-29 03:56:22 +00:00
# if only 1 null texture then empty the list
if len ( my_mesh . blenTextures ) == 1 and my_mesh . blenTextures [ 0 ] == None :
my_mesh . blenTextures = [ ]
2007-08-28 02:11:49 +00:00
my_mesh . fbxArm = armob # replace with my_object_generic armature instance later
my_mesh . fbxBoneParent = blenParentBoneName # replace with my_bone instance later
2007-08-26 01:35:03 +00:00
ob_meshes . append ( my_mesh )
2009-09-29 15:27:00 +00:00
# not forgetting to free dupli_list
if ob_base . dupli_list : ob_base . free_dupli_list ( )
2007-08-28 02:11:49 +00:00
if EXP_ARMATURE :
# now we have the meshes, restore the rest arm position
for i , arm in enumerate ( bpy . data . armatures ) :
2009-09-29 15:27:00 +00:00
arm . rest_position = ob_arms_orig_rest [ i ]
# arm.restPosition = ob_arms_orig_rest[i]
2007-08-28 02:11:49 +00:00
if ob_arms_orig_rest :
for ob_base in bpy . data . objects :
2009-09-29 15:27:00 +00:00
if ob_base . type == ' ARMATURE ' :
# if ob_base.type == 'Armature':
ob_base . make_display_list ( )
# ob_base.makeDisplayList()
2007-08-28 02:11:49 +00:00
# This causes the makeDisplayList command to effect the mesh
2009-09-29 15:27:00 +00:00
sce . set_frame ( sce . current_frame )
# Blender.Set('curframe', Blender.Get('curframe'))
2007-08-15 00:48:33 +00:00
2007-08-28 02:11:49 +00:00
del tmp_ob_type , tmp_objects
2007-08-15 00:48:33 +00:00
2007-08-23 16:34:15 +00:00
# now we have collected all armatures, add bones
2007-08-15 00:48:33 +00:00
for i , ob in enumerate ( ob_arms ) :
2007-08-23 16:34:15 +00:00
2007-08-26 01:35:03 +00:00
ob_arms [ i ] = my_arm = my_object_generic ( ob )
2007-08-15 00:48:33 +00:00
2007-08-26 01:35:03 +00:00
my_arm . fbxBones = [ ]
my_arm . blenData = ob . data
2009-09-29 15:27:00 +00:00
if ob . animation_data :
my_arm . blenAction = ob . animation_data . action
else :
my_arm . blenAction = None
# my_arm.blenAction = ob.action
2007-08-26 01:35:03 +00:00
my_arm . blenActionList = [ ]
# fbxName, blenderObject, my_bones, blenderActions
#ob_arms[i] = fbxArmObName, ob, arm_my_bones, (ob.action, [])
2009-09-29 15:27:00 +00:00
for bone in my_arm . blenData . bones :
# for bone in my_arm.blenData.bones.values():
2007-08-26 01:35:03 +00:00
my_bone = my_bone_class ( bone , my_arm )
my_arm . fbxBones . append ( my_bone )
ob_bones . append ( my_bone )
2007-08-20 23:38:39 +00:00
2007-08-26 01:35:03 +00:00
# add the meshes to the bones and replace the meshes armature with own armature class
#for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
for my_mesh in ob_meshes :
# Replace
# ...this could be sped up with dictionary mapping but its unlikely for
# it ever to be a bottleneck - (would need 100+ meshes using armatures)
if my_mesh . fbxArm :
for my_arm in ob_arms :
if my_arm . blenObject == my_mesh . fbxArm :
my_mesh . fbxArm = my_arm
break
for my_bone in ob_bones :
2007-08-28 02:11:49 +00:00
# The mesh uses this bones armature!
2007-08-26 01:35:03 +00:00
if my_bone . fbxArm == my_mesh . fbxArm :
my_bone . blenMeshes [ my_mesh . fbxName ] = me
2007-08-28 02:11:49 +00:00
# parent bone: replace bone names with our class instances
# my_mesh.fbxBoneParent is None or a blender bone name initialy, replacing if the names match.
if my_mesh . fbxBoneParent == my_bone . blenName :
my_mesh . fbxBoneParent = my_bone
2007-08-20 23:38:39 +00:00
bone_deformer_count = 0 # count how many bones deform a mesh
2007-08-26 01:35:03 +00:00
my_bone_blenParent = None
for my_bone in ob_bones :
my_bone_blenParent = my_bone . blenBone . parent
if my_bone_blenParent :
for my_bone_parent in ob_bones :
2007-08-20 23:38:39 +00:00
# Note 2.45rc2 you can compare bones normally
2007-08-26 01:35:03 +00:00
if my_bone_blenParent . name == my_bone_parent . blenName and my_bone . fbxArm == my_bone_parent . fbxArm :
my_bone . parent = my_bone_parent
2007-08-15 00:48:33 +00:00
break
2007-08-23 16:34:15 +00:00
# Not used at the moment
2007-08-26 01:35:03 +00:00
# my_bone.calcRestMatrixLocal()
bone_deformer_count + = len ( my_bone . blenMeshes )
2007-08-15 00:48:33 +00:00
2007-08-26 01:35:03 +00:00
del my_bone_blenParent
2007-08-15 00:48:33 +00:00
2007-08-30 17:16:09 +00:00
2007-09-08 08:49:56 +00:00
# Build blenObject -> fbxObject mapping
# this is needed for groups as well as fbxParenting
2009-09-29 15:27:00 +00:00
# for ob in bpy.data.objects: ob.tag = False
# bpy.data.objects.tag = False
# using a list of object names for tagging (Arystan)
tagged_objects = [ ]
2007-08-30 17:16:09 +00:00
tmp_obmapping = { }
2007-09-08 08:49:56 +00:00
for ob_generic in ob_all_typegroups :
2007-08-30 17:16:09 +00:00
for ob_base in ob_generic :
2009-09-29 15:27:00 +00:00
tagged_objects . append ( ob_base . blenObject . name )
# ob_base.blenObject.tag = True
2007-09-08 08:49:56 +00:00
tmp_obmapping [ ob_base . blenObject ] = ob_base
2007-08-30 17:16:09 +00:00
2007-09-08 08:49:56 +00:00
# Build Groups from objects we export
2007-08-30 17:16:09 +00:00
for blenGroup in bpy . data . groups :
fbxGroupName = None
for ob in blenGroup . objects :
2009-09-29 15:27:00 +00:00
if ob . name in tagged_objects :
# if ob.tag:
2007-08-30 17:16:09 +00:00
if fbxGroupName == None :
fbxGroupName = sane_groupname ( blenGroup )
groups . append ( ( fbxGroupName , blenGroup ) )
2007-09-08 08:49:56 +00:00
tmp_obmapping [ ob ] . fbxGroupNames . append ( fbxGroupName ) # also adds to the objects fbxGroupNames
2007-08-30 17:16:09 +00:00
groups . sort ( ) # not really needed
2007-09-08 08:49:56 +00:00
# Assign parents using this mapping
for ob_generic in ob_all_typegroups :
for my_ob in ob_generic :
parent = my_ob . blenObject . parent
2009-09-29 15:27:00 +00:00
if parent and parent . name in tagged_objects : # does it exist and is it in the mapping
# if parent and parent.tag: # does it exist and is it in the mapping
2007-09-08 08:49:56 +00:00
my_ob . fbxParent = tmp_obmapping [ parent ]
2007-08-30 17:16:09 +00:00
del tmp_obmapping
# Finished finding groups we use
2009-09-29 15:27:00 +00:00
materials = [ ( sane_matname ( mat_tex_pair ) , mat_tex_pair ) for mat_tex_pair in materials . keys ( ) ]
textures = [ ( sane_texname ( tex ) , tex ) for tex in textures . keys ( ) if tex ]
2007-08-15 00:48:33 +00:00
materials . sort ( ) # sort by name
textures . sort ( )
camera_count = 8
file . write ( '''
; Object definitions
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Definitions : {
Version : 100
Count : % i ''' % ( \
1 + 1 + camera_count + \
len ( ob_meshes ) + \
len ( ob_lights ) + \
len ( ob_cameras ) + \
len ( ob_arms ) + \
len ( ob_null ) + \
len ( ob_bones ) + \
2007-08-20 23:38:39 +00:00
bone_deformer_count + \
2007-08-15 00:48:33 +00:00
len ( materials ) + \
( len ( textures ) * 2 ) ) ) # add 1 for the root model 1 for global settings
2007-08-20 23:38:39 +00:00
del bone_deformer_count
2007-08-15 00:48:33 +00:00
file . write ( '''
ObjectType : " Model " {
Count : % i
} ''' % ( \
1 + camera_count + \
len ( ob_meshes ) + \
len ( ob_lights ) + \
len ( ob_cameras ) + \
len ( ob_arms ) + \
len ( ob_null ) + \
len ( ob_bones ) ) ) # add 1 for the root model
file . write ( '''
ObjectType : " Geometry " {
Count : % i
} ''' % le n(ob_meshes))
if materials :
file . write ( '''
ObjectType : " Material " {
Count : % i
} ''' % le n(materials))
if textures :
file . write ( '''
ObjectType : " Texture " {
Count : % i
} ''' % le n(textures)) # add 1 for an empty tex
file . write ( '''
ObjectType : " Video " {
Count : % i
} ''' % le n(textures)) # add 1 for an empty tex
tmp = 0
2007-08-23 16:34:15 +00:00
# Add deformer nodes
2007-08-26 01:35:03 +00:00
for my_mesh in ob_meshes :
if my_mesh . fbxArm :
2007-08-15 00:48:33 +00:00
tmp + = 1
2007-08-26 01:35:03 +00:00
2007-08-23 16:34:15 +00:00
# Add subdeformers
2007-08-26 01:35:03 +00:00
for my_bone in ob_bones :
tmp + = len ( my_bone . blenMeshes )
2007-08-15 00:48:33 +00:00
if tmp :
file . write ( '''
ObjectType : " Deformer " {
Count : % i
} ''' % tmp)
del tmp
# we could avoid writing this possibly but for now just write it
2007-08-29 05:42:39 +00:00
2007-08-15 00:48:33 +00:00
file . write ( '''
ObjectType : " Pose " {
Count : 1
} ''' )
2007-08-29 05:42:39 +00:00
2007-08-30 17:16:09 +00:00
if groups :
file . write ( '''
ObjectType : " GroupSelection " {
Count : % i
} ''' % le n(groups))
2007-08-15 00:48:33 +00:00
file . write ( '''
ObjectType : " GlobalSettings " {
Count : 1
}
} ''' )
2007-08-26 01:35:03 +00:00
2007-08-15 00:48:33 +00:00
file . write ( '''
; Object properties
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Objects : { ''' )
# To comply with other FBX FILES
write_camera_switch ( )
# Write the null object
2007-08-29 03:56:22 +00:00
write_null ( None , ' blend_root ' ) # , GLOBAL_MATRIX)
2007-08-15 00:48:33 +00:00
2007-08-26 01:35:03 +00:00
for my_null in ob_null :
write_null ( my_null )
2007-08-15 00:48:33 +00:00
2007-08-26 01:35:03 +00:00
for my_arm in ob_arms :
2007-09-08 08:49:56 +00:00
write_null ( my_arm )
2007-08-15 00:48:33 +00:00
2007-08-26 01:35:03 +00:00
for my_cam in ob_cameras :
write_camera ( my_cam )
2007-08-15 00:48:33 +00:00
2007-08-26 01:35:03 +00:00
for my_light in ob_lights :
write_light ( my_light )
2007-08-15 00:48:33 +00:00
2007-08-26 01:35:03 +00:00
for my_mesh in ob_meshes :
write_mesh ( my_mesh )
2007-08-15 00:48:33 +00:00
#for bonename, bone, obname, me, armob in ob_bones:
2007-08-26 01:35:03 +00:00
for my_bone in ob_bones :
write_bone ( my_bone )
2007-04-20 18:48:30 +00:00
write_camera_default ( )
2007-03-28 07:08:18 +00:00
2009-05-06 06:01:09 +00:00
for matname , ( mat , tex ) in materials :
write_material ( matname , mat ) # We only need to have a material per image pair, but no need to write any image info into the material (dumb fbx standard)
2007-03-28 07:08:18 +00:00
# each texture uses a video, odd
for texname , tex in textures :
write_video ( texname , tex )
i = 0
for texname , tex in textures :
write_texture ( texname , tex , i )
i + = 1
2007-08-30 17:16:09 +00:00
for groupname , group in groups :
write_group ( groupname )
2007-08-24 07:07:18 +00:00
# NOTE - c4d and motionbuilder dont need normalized weights, but deep-exploration 5 does and (max?) do.
2007-08-09 13:34:44 +00:00
# Write armature modifiers
# TODO - add another MODEL? - because of this skin definition.
2007-08-26 01:35:03 +00:00
for my_mesh in ob_meshes :
if my_mesh . fbxArm :
write_deformer_skin ( my_mesh . fbxName )
# Get normalized weights for temorary use
2007-08-28 02:11:49 +00:00
if my_mesh . fbxBoneParent :
weights = None
else :
2009-09-29 15:27:00 +00:00
weights = meshNormalizedWeights ( my_mesh . blenObject )
# weights = meshNormalizedWeights(my_mesh.blenData)
2007-08-26 01:35:03 +00:00
#for bonename, bone, obname, bone_mesh, armob in ob_bones:
for my_bone in ob_bones :
2009-09-29 15:27:00 +00:00
if me in iter ( my_bone . blenMeshes . values ( ) ) :
2007-08-26 01:35:03 +00:00
write_sub_deformer_skin ( my_mesh , my_bone , weights )
2007-08-09 13:34:44 +00:00
# Write pose's really weired, only needed when an armature and mesh are used together
# each by themselves dont need pose data. for now only pose meshes and bones
2007-08-29 05:42:39 +00:00
2007-08-09 13:34:44 +00:00
file . write ( '''
Pose : " Pose::BIND_POSES " , " BindPose " {
Type : " BindPose "
Version : 100
Properties60 : {
}
NbPoseNodes : ''' )
2007-08-29 05:42:39 +00:00
file . write ( str ( len ( pose_items ) ) )
2007-08-09 13:34:44 +00:00
2007-08-29 05:42:39 +00:00
for fbxName , matrix in pose_items :
file . write ( ' \n \t \t PoseNode: { ' )
file . write ( ' \n \t \t \t Node: " Model:: %s " ' % fbxName )
if matrix : file . write ( ' \n \t \t \t Matrix: %s ' % mat4x4str ( matrix ) )
2007-08-29 09:50:08 +00:00
else : file . write ( ' \n \t \t \t Matrix: %s ' % mat4x4str ( mtx4_identity ) )
2007-08-29 05:42:39 +00:00
file . write ( ' \n \t \t } ' )
2007-08-09 13:34:44 +00:00
file . write ( ' \n \t } ' )
2007-03-28 07:08:18 +00:00
# Finish Writing Objects
# Write global settings
file . write ( '''
GlobalSettings : {
Version : 1000
Properties60 : {
Property : " UpAxis " , " int " , " " , 1
Property : " UpAxisSign " , " int " , " " , 1
Property : " FrontAxis " , " int " , " " , 2
Property : " FrontAxisSign " , " int " , " " , 1
Property : " CoordAxis " , " int " , " " , 0
Property : " CoordAxisSign " , " int " , " " , 1
2007-08-29 19:53:49 +00:00
Property : " UnitScaleFactor " , " double " , " " , 100
2007-03-28 07:08:18 +00:00
}
}
''' )
2007-04-21 11:23:45 +00:00
file . write ( ' } ' )
2007-03-28 07:08:18 +00:00
2007-04-21 11:23:45 +00:00
file . write ( '''
; Object relations
2007-03-28 07:08:18 +00:00
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2007-04-21 11:23:45 +00:00
Relations : { ''' )
2007-03-28 07:08:18 +00:00
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t Model: " Model::blend_root " , " Null " { \n \t } ' )
2007-08-09 13:34:44 +00:00
2007-08-26 01:35:03 +00:00
for my_null in ob_null :
file . write ( ' \n \t Model: " Model:: %s " , " Null " { \n \t } ' % my_null . fbxName )
2007-08-09 13:34:44 +00:00
2007-08-26 01:35:03 +00:00
for my_arm in ob_arms :
file . write ( ' \n \t Model: " Model:: %s " , " Null " { \n \t } ' % my_arm . fbxName )
2007-08-09 13:34:44 +00:00
2007-08-26 01:35:03 +00:00
for my_mesh in ob_meshes :
file . write ( ' \n \t Model: " Model:: %s " , " Mesh " { \n \t } ' % my_mesh . fbxName )
2007-08-09 13:34:44 +00:00
# TODO - limbs can have the same name for multiple armatures, should prefix.
2007-08-15 00:48:33 +00:00
#for bonename, bone, obname, me, armob in ob_bones:
2007-08-26 01:35:03 +00:00
for my_bone in ob_bones :
file . write ( ' \n \t Model: " Model:: %s " , " Limb " { \n \t } ' % my_bone . fbxName )
2007-08-06 20:20:20 +00:00
2007-08-26 01:35:03 +00:00
for my_cam in ob_cameras :
file . write ( ' \n \t Model: " Model:: %s " , " Camera " { \n \t } ' % my_cam . fbxName )
2007-04-27 17:19:26 +00:00
2007-08-26 01:35:03 +00:00
for my_light in ob_lights :
file . write ( ' \n \t Model: " Model:: %s " , " Light " { \n \t } ' % my_light . fbxName )
2007-03-28 07:08:18 +00:00
2007-04-21 11:23:45 +00:00
file . write ( '''
Model : " Model::Producer Perspective " , " Camera " {
2007-03-28 07:08:18 +00:00
}
Model : " Model::Producer Top " , " Camera " {
}
Model : " Model::Producer Bottom " , " Camera " {
}
Model : " Model::Producer Front " , " Camera " {
}
Model : " Model::Producer Back " , " Camera " {
}
Model : " Model::Producer Right " , " Camera " {
}
Model : " Model::Producer Left " , " Camera " {
}
Model : " Model::Camera Switcher " , " CameraSwitcher " {
2007-04-21 11:23:45 +00:00
} ''' )
2007-03-28 07:08:18 +00:00
2009-05-06 06:01:09 +00:00
for matname , ( mat , tex ) in materials :
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t Material: " Material:: %s " , " " { \n \t } ' % matname )
2007-03-28 07:08:18 +00:00
if textures :
for texname , tex in textures :
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t Texture: " Texture:: %s " , " TextureVideoClip " { \n \t } ' % texname )
2007-03-28 07:08:18 +00:00
for texname , tex in textures :
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t Video: " Video:: %s " , " Clip " { \n \t } ' % texname )
2007-08-09 13:34:44 +00:00
# deformers - modifiers
2007-08-26 01:35:03 +00:00
for my_mesh in ob_meshes :
if my_mesh . fbxArm :
file . write ( ' \n \t Deformer: " Deformer::Skin %s " , " Skin " { \n \t } ' % my_mesh . fbxName )
2007-08-09 13:34:44 +00:00
2007-08-15 00:48:33 +00:00
#for bonename, bone, obname, me, armob in ob_bones:
2007-08-26 01:35:03 +00:00
for my_bone in ob_bones :
for fbxMeshObName in my_bone . blenMeshes : # .keys() - fbxMeshObName
2007-08-23 16:34:15 +00:00
# is this bone effecting a mesh?
2007-08-26 01:35:03 +00:00
file . write ( ' \n \t Deformer: " SubDeformer::Cluster %s %s " , " Cluster " { \n \t } ' % ( fbxMeshObName , my_bone . fbxName ) )
2007-08-09 13:34:44 +00:00
# This should be at the end
# file.write('\n\tPose: "Pose::BIND_POSES", "BindPose" {\n\t}')
2007-08-30 17:16:09 +00:00
for groupname , group in groups :
file . write ( ' \n \t GroupSelection: " GroupSelection:: %s " , " Default " { \n \t } ' % groupname )
2007-04-21 11:23:45 +00:00
file . write ( ' \n } ' )
file . write ( '''
2007-03-28 07:08:18 +00:00
; Object connections
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2007-04-21 11:23:45 +00:00
Connections : { ''' )
2007-08-20 23:38:39 +00:00
# NOTE - The FBX SDK dosnt care about the order but some importers DO!
# for instance, defining the material->mesh connection
# before the mesh->blend_root crashes cinema4d
2007-08-09 13:34:44 +00:00
2007-03-28 07:08:18 +00:00
# write the fake root node
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t Connect: " OO " , " Model::blend_root " , " Model::Scene " ' )
2007-03-28 07:08:18 +00:00
2007-09-08 08:49:56 +00:00
for ob_generic in ob_all_typegroups : # all blender 'Object's we support
for my_ob in ob_generic :
if my_ob . fbxParent :
file . write ( ' \n \t Connect: " OO " , " Model:: %s " , " Model:: %s " ' % ( my_ob . fbxName , my_ob . fbxParent . fbxName ) )
else :
file . write ( ' \n \t Connect: " OO " , " Model:: %s " , " Model::blend_root " ' % my_ob . fbxName )
2007-04-20 23:33:56 +00:00
2007-08-29 03:56:22 +00:00
if materials :
for my_mesh in ob_meshes :
# Connect all materials to all objects, not good form but ok for now.
2009-05-06 06:01:09 +00:00
for mat , tex in my_mesh . blenMaterials :
if mat : mat_name = mat . name
else : mat_name = None
if tex : tex_name = tex . name
else : tex_name = None
file . write ( ' \n \t Connect: " OO " , " Material:: %s " , " Model:: %s " ' % ( sane_name_mapping_mat [ mat_name , tex_name ] , my_mesh . fbxName ) )
2007-03-28 07:08:18 +00:00
if textures :
2007-08-26 01:35:03 +00:00
for my_mesh in ob_meshes :
2007-08-29 03:56:22 +00:00
if my_mesh . blenTextures :
# file.write('\n\tConnect: "OO", "Texture::_empty_", "Model::%s"' % my_mesh.fbxName)
for tex in my_mesh . blenTextures :
if tex :
file . write ( ' \n \t Connect: " OO " , " Texture:: %s " , " Model:: %s " ' % ( sane_name_mapping_tex [ tex . name ] , my_mesh . fbxName ) )
2007-03-28 07:08:18 +00:00
for texname , tex in textures :
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t Connect: " OO " , " Video:: %s " , " Texture:: %s " ' % ( texname , texname ) )
2007-03-28 07:08:18 +00:00
2007-08-26 01:35:03 +00:00
for my_mesh in ob_meshes :
if my_mesh . fbxArm :
file . write ( ' \n \t Connect: " OO " , " Deformer::Skin %s " , " Model:: %s " ' % ( my_mesh . fbxName , my_mesh . fbxName ) )
2007-08-09 13:34:44 +00:00
2007-08-15 00:48:33 +00:00
#for bonename, bone, obname, me, armob in ob_bones:
2007-08-26 01:35:03 +00:00
for my_bone in ob_bones :
for fbxMeshObName in my_bone . blenMeshes : # .keys()
file . write ( ' \n \t Connect: " OO " , " SubDeformer::Cluster %s %s " , " Deformer::Skin %s " ' % ( fbxMeshObName , my_bone . fbxName , fbxMeshObName ) )
2007-08-09 13:34:44 +00:00
# limbs -> deformers
2007-08-15 00:48:33 +00:00
# for bonename, bone, obname, me, armob in ob_bones:
2007-08-26 01:35:03 +00:00
for my_bone in ob_bones :
for fbxMeshObName in my_bone . blenMeshes : # .keys()
file . write ( ' \n \t Connect: " OO " , " Model:: %s " , " SubDeformer::Cluster %s %s " ' % ( my_bone . fbxName , fbxMeshObName , my_bone . fbxName ) )
2007-08-09 13:34:44 +00:00
2007-08-15 00:48:33 +00:00
#for bonename, bone, obname, me, armob in ob_bones:
2007-08-26 01:35:03 +00:00
for my_bone in ob_bones :
2007-08-23 16:34:15 +00:00
# Always parent to armature now
2007-08-26 01:35:03 +00:00
if my_bone . parent :
file . write ( ' \n \t Connect: " OO " , " Model:: %s " , " Model:: %s " ' % ( my_bone . fbxName , my_bone . parent . fbxName ) )
2007-08-09 13:34:44 +00:00
else :
# the armature object is written as an empty and all root level bones connect to it
2007-08-26 01:35:03 +00:00
file . write ( ' \n \t Connect: " OO " , " Model:: %s " , " Model:: %s " ' % ( my_bone . fbxName , my_bone . fbxArm . fbxName ) )
2007-08-09 13:34:44 +00:00
2007-08-30 17:16:09 +00:00
# groups
if groups :
2007-09-08 08:49:56 +00:00
for ob_generic in ob_all_typegroups :
2007-08-30 17:16:09 +00:00
for ob_base in ob_generic :
for fbxGroupName in ob_base . fbxGroupNames :
file . write ( ' \n \t Connect: " OO " , " Model:: %s " , " GroupSelection:: %s " ' % ( ob_base . fbxName , fbxGroupName ) )
for my_arm in ob_arms :
file . write ( ' \n \t Connect: " OO " , " Model:: %s " , " Model::blend_root " ' % my_arm . fbxName )
2007-04-21 11:23:45 +00:00
file . write ( ' \n } ' )
2007-03-29 06:01:03 +00:00
2007-08-23 16:34:15 +00:00
# Needed for scene footer as well as animation
2009-09-29 15:27:00 +00:00
render = sce . render_data
# render = sce.render
2007-08-23 16:34:15 +00:00
# from the FBX sdk
#define KTIME_ONE_SECOND KTime (K_LONGLONG(46186158000))
def fbx_time ( t ) :
# 0.5 + val is the same as rounding.
return int ( 0.5 + ( ( t / fps ) * 46186158000 ) )
fps = float ( render . fps )
2009-09-29 15:27:00 +00:00
start = sce . start_frame
# start = render.sFrame
end = sce . end_frame
# end = render.eFrame
2007-08-23 16:34:15 +00:00
if end < start : start , end = end , start
2007-09-08 08:49:56 +00:00
if start == end : ANIM_ENABLE = False
2007-08-23 16:34:15 +00:00
2007-08-29 19:53:49 +00:00
# animations for these object types
2007-09-08 08:49:56 +00:00
ob_anim_lists = ob_bones , ob_meshes , ob_null , ob_cameras , ob_lights , ob_arms
2007-08-29 19:53:49 +00:00
if ANIM_ENABLE and [ tmp for tmp in ob_anim_lists if tmp ] :
2007-08-15 00:48:33 +00:00
2009-09-29 15:27:00 +00:00
frame_orig = sce . current_frame
# frame_orig = Blender.Get('curframe')
2007-08-20 23:38:39 +00:00
2007-08-23 16:34:15 +00:00
if ANIM_OPTIMIZE :
ANIM_OPTIMIZE_PRECISSION_FLOAT = 0.1 * * ANIM_OPTIMIZE_PRECISSION
2007-08-20 23:38:39 +00:00
2007-08-23 16:34:15 +00:00
# default action, when no actions are avaioable
tmp_actions = [ None ] # None is the default action
2007-08-26 01:35:03 +00:00
blenActionDefault = None
2007-08-23 16:34:15 +00:00
action_lastcompat = None
2009-09-29 15:27:00 +00:00
# instead of tagging
tagged_actions = [ ]
2007-08-20 23:38:39 +00:00
2007-08-23 16:34:15 +00:00
if ANIM_ACTION_ALL :
2009-09-29 15:27:00 +00:00
# bpy.data.actions.tag = False
2007-08-23 16:34:15 +00:00
tmp_actions = list ( bpy . data . actions )
# find which actions are compatible with the armatures
# blenActions is not yet initialized so do it now.
tmp_act_count = 0
2007-08-26 01:35:03 +00:00
for my_arm in ob_arms :
2007-08-23 16:34:15 +00:00
# get the default name
2007-08-26 01:35:03 +00:00
if not blenActionDefault :
blenActionDefault = my_arm . blenAction
2007-08-23 16:34:15 +00:00
2007-08-26 01:35:03 +00:00
arm_bone_names = set ( [ my_bone . blenName for my_bone in my_arm . fbxBones ] )
2007-08-24 12:13:34 +00:00
2007-08-23 16:34:15 +00:00
for action in tmp_actions :
2009-09-29 15:27:00 +00:00
action_chan_names = arm_bone_names . intersection ( set ( [ g . name for g in action . groups ] ) )
# action_chan_names = arm_bone_names.intersection( set(action.getChannelNames()) )
2007-08-23 16:34:15 +00:00
if action_chan_names : # at least one channel matches.
2007-08-26 01:35:03 +00:00
my_arm . blenActionList . append ( action )
2009-09-29 15:27:00 +00:00
tagged_actions . append ( action . name )
# action.tag = True
2007-08-23 16:34:15 +00:00
tmp_act_count + = 1
# incase there is no actions applied to armatures
action_lastcompat = action
if tmp_act_count :
# unlikely to ever happen but if no actions applied to armatures, just use the last compatible armature.
2007-08-26 01:35:03 +00:00
if not blenActionDefault :
blenActionDefault = action_lastcompat
2007-08-15 00:48:33 +00:00
2007-08-23 16:34:15 +00:00
del action_lastcompat
2007-08-15 00:48:33 +00:00
file . write ( '''
; Takes and animation section
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Takes : { ''' )
2007-08-26 01:35:03 +00:00
if blenActionDefault :
file . write ( ' \n \t Current: " %s " ' % sane_takename ( blenActionDefault ) )
2007-08-24 07:07:18 +00:00
else :
file . write ( ' \n \t Current: " Default Take " ' )
2007-08-23 16:34:15 +00:00
for blenAction in tmp_actions :
# we have tagged all actious that are used be selected armatures
if blenAction :
2009-09-29 15:27:00 +00:00
if blenAction . name in tagged_actions :
# if blenAction.tag:
print ( ' \t action: " %s " exporting... ' % blenAction . name )
2007-08-23 16:34:15 +00:00
else :
2009-09-29 15:27:00 +00:00
print ( ' \t action: " %s " has no armature using it, skipping ' % blenAction . name )
2007-08-23 16:34:15 +00:00
continue
if blenAction == None :
# Warning, this only accounts for tmp_actions being [None]
file . write ( ' \n \t Take: " Default Take " { ' )
act_start = start
act_end = end
else :
2007-08-26 01:35:03 +00:00
# use existing name
if blenAction == blenActionDefault : # have we alredy got the name
file . write ( ' \n \t Take: " %s " { ' % sane_name_mapping_take [ blenAction . name ] )
else :
file . write ( ' \n \t Take: " %s " { ' % sane_takename ( blenAction ) )
2009-09-29 15:27:00 +00:00
act_start , act_end = blenAction . get_frame_range ( )
# tmp = blenAction.getFrameNumbers()
# if tmp:
# act_start = min(tmp)
# act_end = max(tmp)
# del tmp
# else:
# # Fallback on this, theres not much else we can do? :/
# # when an action has no length
# act_start = start
# act_end = end
2007-08-23 16:34:15 +00:00
# Set the action active
2007-08-26 01:35:03 +00:00
for my_bone in ob_arms :
if blenAction in my_bone . blenActionList :
2007-08-23 16:34:15 +00:00
ob . action = blenAction
# print '\t\tSetting Action!', blenAction
# sce.update(1)
2007-08-24 07:07:18 +00:00
file . write ( ' \n \t \t FileName: " Default_Take.tak " ' ) # ??? - not sure why this is needed
file . write ( ' \n \t \t LocalTime: %i , %i ' % ( fbx_time ( act_start - 1 ) , fbx_time ( act_end - 1 ) ) ) # ??? - not sure why this is needed
file . write ( ' \n \t \t ReferenceTime: %i , %i ' % ( fbx_time ( act_start - 1 ) , fbx_time ( act_end - 1 ) ) ) # ??? - not sure why this is needed
2007-08-23 16:34:15 +00:00
file . write ( '''
2007-08-15 00:48:33 +00:00
; Models animation
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' )
2007-08-23 16:34:15 +00:00
# set pose data for all bones
# do this here incase the action changes
'''
2007-08-26 01:35:03 +00:00
for my_bone in ob_bones :
my_bone . flushAnimData ( )
2007-08-23 16:34:15 +00:00
'''
i = act_start
while i < = act_end :
2009-09-29 15:27:00 +00:00
sce . set_frame ( i )
# Blender.Set('curframe', i)
2007-08-29 19:53:49 +00:00
for ob_generic in ob_anim_lists :
2007-08-29 09:50:08 +00:00
for my_ob in ob_generic :
#Blender.Window.RedrawAll()
if ob_generic == ob_meshes and my_ob . fbxArm :
# We cant animate armature meshes!
pass
else :
my_ob . setPoseFrame ( i )
2007-08-23 16:34:15 +00:00
i + = 1
#for bonename, bone, obname, me, armob in ob_bones:
2007-09-08 08:49:56 +00:00
for ob_generic in ( ob_bones , ob_meshes , ob_null , ob_cameras , ob_lights , ob_arms ) :
2007-08-15 00:48:33 +00:00
2007-08-29 09:50:08 +00:00
for my_ob in ob_generic :
2007-08-15 00:48:33 +00:00
2007-08-29 09:50:08 +00:00
if ob_generic == ob_meshes and my_ob . fbxArm :
# do nothing,
pass
else :
file . write ( ' \n \t \t Model: " Model:: %s " { ' % my_ob . fbxName ) # ??? - not sure why this is needed
file . write ( ' \n \t \t \t Version: 1.1 ' )
file . write ( ' \n \t \t \t Channel: " Transform " { ' )
2007-08-23 16:34:15 +00:00
2009-09-29 15:27:00 +00:00
context_bone_anim_mats = [ ( my_ob . getAnimParRelMatrix ( frame ) , my_ob . getAnimParRelMatrixRot ( frame ) ) for frame in range ( act_start , act_end + 1 ) ]
2007-08-29 09:50:08 +00:00
# ----------------
# ----------------
for TX_LAYER , TX_CHAN in enumerate ( ' TRS ' ) : # transform, rotate, scale
2007-08-23 16:34:15 +00:00
2007-08-29 09:50:08 +00:00
if TX_CHAN == ' T ' : context_bone_anim_vecs = [ mtx [ 0 ] . translationPart ( ) for mtx in context_bone_anim_mats ]
2009-05-18 04:11:54 +00:00
elif TX_CHAN == ' S ' : context_bone_anim_vecs = [ mtx [ 0 ] . scalePart ( ) for mtx in context_bone_anim_mats ]
elif TX_CHAN == ' R ' :
# Was....
# elif TX_CHAN=='R': context_bone_anim_vecs = [mtx[1].toEuler() for mtx in context_bone_anim_mats]
#
# ...but we need to use the previous euler for compatible conversion.
context_bone_anim_vecs = [ ]
prev_eul = None
for mtx in context_bone_anim_mats :
if prev_eul : prev_eul = mtx [ 1 ] . toEuler ( prev_eul )
else : prev_eul = mtx [ 1 ] . toEuler ( )
2009-09-29 15:27:00 +00:00
context_bone_anim_vecs . append ( eulerRadToDeg ( prev_eul ) )
# context_bone_anim_vecs.append(prev_eul)
2007-08-23 16:34:15 +00:00
2007-08-29 09:50:08 +00:00
file . write ( ' \n \t \t \t \t Channel: " %s " { ' % TX_CHAN ) # translation
2009-09-29 15:27:00 +00:00
for i in range ( 3 ) :
2007-08-29 09:50:08 +00:00
# Loop on each axis of the bone
file . write ( ' \n \t \t \t \t \t Channel: " %s " { ' % ( ' XYZ ' [ i ] ) ) # translation
file . write ( ' \n \t \t \t \t \t \t Default: %.15f ' % context_bone_anim_vecs [ 0 ] [ i ] )
file . write ( ' \n \t \t \t \t \t \t KeyVer: 4005 ' )
if not ANIM_OPTIMIZE :
# Just write all frames, simple but in-eficient
file . write ( ' \n \t \t \t \t \t \t KeyCount: %i ' % ( 1 + act_end - act_start ) )
file . write ( ' \n \t \t \t \t \t \t Key: ' )
frame = act_start
while frame < = act_end :
if frame != act_start :
file . write ( ' , ' )
2009-05-13 22:52:31 +00:00
# Curve types are 'C,n' for constant, 'L' for linear
2007-08-29 09:50:08 +00:00
# C,n is for bezier? - linear is best for now so we can do simple keyframe removal
2009-05-13 22:52:31 +00:00
file . write ( ' \n \t \t \t \t \t \t \t %i , %.15f ,L ' % ( fbx_time ( frame - 1 ) , context_bone_anim_vecs [ frame - act_start ] [ i ] ) )
2007-08-29 09:50:08 +00:00
frame + = 1
else :
# remove unneeded keys, j is the frame, needed when some frames are removed.
context_bone_anim_keys = [ ( vec [ i ] , j ) for j , vec in enumerate ( context_bone_anim_vecs ) ]
# last frame to fisrt frame, missing 1 frame on either side.
# removeing in a backwards loop is faster
2009-05-13 22:52:31 +00:00
#for j in xrange( (act_end-act_start)-1, 0, -1 ):
# j = (act_end-act_start)-1
j = len ( context_bone_anim_keys ) - 2
while j > 0 and len ( context_bone_anim_keys ) > 2 :
# print j, len(context_bone_anim_keys)
# Is this key the same as the ones next to it?
# co-linear horizontal...
if abs ( context_bone_anim_keys [ j ] [ 0 ] - context_bone_anim_keys [ j - 1 ] [ 0 ] ) < ANIM_OPTIMIZE_PRECISSION_FLOAT and \
abs ( context_bone_anim_keys [ j ] [ 0 ] - context_bone_anim_keys [ j + 1 ] [ 0 ] ) < ANIM_OPTIMIZE_PRECISSION_FLOAT :
2007-08-29 09:50:08 +00:00
del context_bone_anim_keys [ j ]
2009-05-13 22:52:31 +00:00
else :
frame_range = float ( context_bone_anim_keys [ j + 1 ] [ 1 ] - context_bone_anim_keys [ j - 1 ] [ 1 ] )
frame_range_fac1 = ( context_bone_anim_keys [ j + 1 ] [ 1 ] - context_bone_anim_keys [ j ] [ 1 ] ) / frame_range
frame_range_fac2 = 1.0 - frame_range_fac1
if abs ( ( ( context_bone_anim_keys [ j - 1 ] [ 0 ] * frame_range_fac1 + context_bone_anim_keys [ j + 1 ] [ 0 ] * frame_range_fac2 ) ) - context_bone_anim_keys [ j ] [ 0 ] ) < ANIM_OPTIMIZE_PRECISSION_FLOAT :
del context_bone_anim_keys [ j ]
else :
j - = 1
# keep the index below the list length
if j > len ( context_bone_anim_keys ) - 2 :
j = len ( context_bone_anim_keys ) - 2
2007-08-29 09:50:08 +00:00
if len ( context_bone_anim_keys ) == 2 and context_bone_anim_keys [ 0 ] [ 0 ] == context_bone_anim_keys [ 1 ] [ 0 ] :
# This axis has no moton, its okay to skip KeyCount and Keys in this case
pass
else :
# We only need to write these if there is at least one
file . write ( ' \n \t \t \t \t \t \t KeyCount: %i ' % len ( context_bone_anim_keys ) )
2007-09-07 00:36:56 +00:00
file . write ( ' \n \t \t \t \t \t \t Key: ' )
for val , frame in context_bone_anim_keys :
if frame != context_bone_anim_keys [ 0 ] [ 1 ] : # not the first
2007-08-29 09:50:08 +00:00
file . write ( ' , ' )
# frame is alredy one less then blenders frame
2009-05-13 22:52:31 +00:00
file . write ( ' \n \t \t \t \t \t \t \t %i , %.15f ,L ' % ( fbx_time ( frame ) , val ) )
2007-08-29 09:50:08 +00:00
if i == 0 : file . write ( ' \n \t \t \t \t \t \t Color: 1,0,0 ' )
elif i == 1 : file . write ( ' \n \t \t \t \t \t \t Color: 0,1,0 ' )
elif i == 2 : file . write ( ' \n \t \t \t \t \t \t Color: 0,0,1 ' )
file . write ( ' \n \t \t \t \t \t } ' )
file . write ( ' \n \t \t \t \t \t LayerType: %i ' % ( TX_LAYER + 1 ) )
file . write ( ' \n \t \t \t \t } ' )
2007-08-23 16:34:15 +00:00
2007-08-29 09:50:08 +00:00
# ---------------
2007-08-23 16:34:15 +00:00
2007-08-29 09:50:08 +00:00
file . write ( ' \n \t \t \t } ' )
file . write ( ' \n \t \t } ' )
2007-08-15 00:48:33 +00:00
2007-08-23 16:34:15 +00:00
# end the take
file . write ( ' \n \t } ' )
2007-08-15 00:48:33 +00:00
2007-08-23 16:34:15 +00:00
# end action loop. set original actions
# do this after every loop incase actions effect eachother.
2007-08-26 01:35:03 +00:00
for my_bone in ob_arms :
my_bone . blenObject . action = my_bone . blenAction
2007-08-15 00:48:33 +00:00
file . write ( ' \n } ' )
2009-09-29 15:27:00 +00:00
sce . set_frame ( frame_orig )
# Blender.Set('curframe', frame_orig)
2007-08-23 16:34:15 +00:00
2007-08-15 00:48:33 +00:00
else :
# no animation
file . write ( ' \n ;Takes and animation section ' )
file . write ( ' \n ;---------------------------------------------------- ' )
file . write ( ' \n ' )
file . write ( ' \n Takes: { ' )
file . write ( ' \n \t Current: " " ' )
file . write ( ' \n } ' )
# write meshes animation
#for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
2007-04-20 18:48:30 +00:00
# Clear mesh data Only when writing with modifiers applied
2007-08-20 23:38:39 +00:00
for me in meshes_to_clear :
2009-09-29 15:27:00 +00:00
bpy . data . remove_mesh ( me )
# me.verts = None
2007-08-23 16:34:15 +00:00
# --------------------------- Footer
2007-08-28 02:11:49 +00:00
if world :
2009-09-29 15:27:00 +00:00
m = world . mist
has_mist = m . enabled
# has_mist = world.mode & 1
mist_intense = m . intensity
mist_start = m . start
mist_end = m . depth
mist_height = m . height
# mist_intense, mist_start, mist_end, mist_height = world.mist
world_hor = world . horizon_color
# world_hor = world.hor
2007-08-28 02:11:49 +00:00
else :
has_mist = mist_intense = mist_start = mist_end = mist_height = 0
world_hor = 0 , 0 , 0
2007-04-20 18:48:30 +00:00
2007-04-21 11:23:45 +00:00
file . write ( ' \n ;Version 5 settings ' )
file . write ( ' \n ;------------------------------------------------------------------ ' )
2007-04-20 18:48:30 +00:00
file . write ( ' \n ' )
2007-04-21 11:23:45 +00:00
file . write ( ' \n Version5: { ' )
file . write ( ' \n \t AmbientRenderSettings: { ' )
file . write ( ' \n \t \t Version: 101 ' )
2007-08-28 02:11:49 +00:00
file . write ( ' \n \t \t AmbientLightColor: %.1f , %.1f , %.1f ,0 ' % tuple ( world_amb ) )
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t } ' )
file . write ( ' \n \t FogOptions: { ' )
file . write ( ' \n \t \t FlogEnable: %i ' % has_mist )
file . write ( ' \n \t \t FogMode: 0 ' )
file . write ( ' \n \t \t FogDensity: %.3f ' % mist_intense )
file . write ( ' \n \t \t FogStart: %.3f ' % mist_start )
file . write ( ' \n \t \t FogEnd: %.3f ' % mist_end )
2007-08-28 02:11:49 +00:00
file . write ( ' \n \t \t FogColor: %.1f , %.1f , %.1f ,1 ' % tuple ( world_hor ) )
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t } ' )
file . write ( ' \n \t Settings: { ' )
2007-08-20 23:38:39 +00:00
file . write ( ' \n \t \t FrameRate: " %i " ' % int ( fps ) )
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t \t TimeFormat: 1 ' )
file . write ( ' \n \t \t SnapOnFrames: 0 ' )
file . write ( ' \n \t \t ReferenceTimeIndex: -1 ' )
2007-08-23 16:34:15 +00:00
file . write ( ' \n \t \t TimeLineStartTime: %i ' % fbx_time ( start - 1 ) )
file . write ( ' \n \t \t TimeLineStopTime: %i ' % fbx_time ( end - 1 ) )
2007-04-21 11:23:45 +00:00
file . write ( ' \n \t } ' )
file . write ( ' \n \t RendererSetting: { ' )
file . write ( ' \n \t \t DefaultCamera: " Producer Perspective " ' )
file . write ( ' \n \t \t DefaultViewingMode: 0 ' )
file . write ( ' \n \t } ' )
file . write ( ' \n } ' )
2007-04-20 18:48:30 +00:00
file . write ( ' \n ' )
2007-04-27 00:33:07 +00:00
# Incase sombody imports this, clean up by clearing global dicts
sane_name_mapping_ob . clear ( )
sane_name_mapping_mat . clear ( )
sane_name_mapping_tex . clear ( )
2007-08-28 02:11:49 +00:00
ob_arms [ : ] = [ ]
ob_bones [ : ] = [ ]
ob_cameras [ : ] = [ ]
ob_lights [ : ] = [ ]
ob_meshes [ : ] = [ ]
ob_null [ : ] = [ ]
2007-08-26 01:35:03 +00:00
2007-08-28 02:11:49 +00:00
# copy images if enabled
2009-09-29 15:27:00 +00:00
# if EXP_IMAGE_COPY:
# # copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ])
# bpy.util.copy_images( [ tex[1] for tex in textures if tex[1] != None ], basepath)
2007-08-26 01:35:03 +00:00
2009-09-29 15:27:00 +00:00
print ( ' export finished in %.4f sec. ' % ( time . clock ( ) - start_time ) )
# print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time)
2007-09-08 08:49:56 +00:00
return True
2007-08-20 23:38:39 +00:00
2007-08-23 16:34:15 +00:00
# --------------------------------------------
# UI Function - not a part of the exporter.
# this is to seperate the user interface from the rest of the exporter.
2009-09-29 15:27:00 +00:00
# from Blender import Draw, Window
2007-08-23 16:34:15 +00:00
EVENT_NONE = 0
EVENT_EXIT = 1
EVENT_REDRAW = 2
EVENT_FILESEL = 3
GLOBALS = { }
# export opts
def do_redraw ( e , v ) : GLOBALS [ ' EVENT ' ] = e
# toggle between these 2, only allow one on at once
def do_obs_sel ( e , v ) :
GLOBALS [ ' EVENT ' ] = e
GLOBALS [ ' EXP_OBS_SCENE ' ] . val = 0
GLOBALS [ ' EXP_OBS_SELECTED ' ] . val = 1
def do_obs_sce ( e , v ) :
GLOBALS [ ' EVENT ' ] = e
GLOBALS [ ' EXP_OBS_SCENE ' ] . val = 1
GLOBALS [ ' EXP_OBS_SELECTED ' ] . val = 0
def do_batch_type_grp ( e , v ) :
GLOBALS [ ' EVENT ' ] = e
GLOBALS [ ' BATCH_GROUP ' ] . val = 1
GLOBALS [ ' BATCH_SCENE ' ] . val = 0
def do_batch_type_sce ( e , v ) :
GLOBALS [ ' EVENT ' ] = e
GLOBALS [ ' BATCH_GROUP ' ] . val = 0
GLOBALS [ ' BATCH_SCENE ' ] . val = 1
def do_anim_act_all ( e , v ) :
GLOBALS [ ' EVENT ' ] = e
GLOBALS [ ' ANIM_ACTION_ALL ' ] [ 0 ] . val = 1
GLOBALS [ ' ANIM_ACTION_ALL ' ] [ 1 ] . val = 0
def do_anim_act_cur ( e , v ) :
2007-08-28 02:11:49 +00:00
if GLOBALS [ ' BATCH_ENABLE ' ] . val and GLOBALS [ ' BATCH_GROUP ' ] . val :
Draw . PupMenu ( ' Warning % t|Cant use this with batch export group option ' )
else :
GLOBALS [ ' EVENT ' ] = e
GLOBALS [ ' ANIM_ACTION_ALL ' ] [ 0 ] . val = 0
GLOBALS [ ' ANIM_ACTION_ALL ' ] [ 1 ] . val = 1
2007-08-23 16:34:15 +00:00
def fbx_ui_exit ( e , v ) :
GLOBALS [ ' EVENT ' ] = e
2007-08-28 02:11:49 +00:00
def do_help ( e , v ) :
2009-05-05 21:51:54 +00:00
url = ' http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx '
2009-09-29 15:27:00 +00:00
print ( ' Trying to open web browser with documentation at this address... ' )
print ( ' \t ' + url )
2009-05-05 21:51:54 +00:00
try :
import webbrowser
webbrowser . open ( url )
except :
Blender . Draw . PupMenu ( " Error % t|Opening a webbrowser requires a full python installation " )
2009-09-29 15:27:00 +00:00
print ( ' ...could not open a browser window. ' )
2007-08-28 02:11:49 +00:00
2007-08-23 16:34:15 +00:00
# run when export is pressed
#def fbx_ui_write(e,v):
2009-09-29 15:27:00 +00:00
def fbx_ui_write ( filename , context ) :
2007-08-28 02:11:49 +00:00
# Dont allow overwriting files when saving normally
if not GLOBALS [ ' BATCH_ENABLE ' ] . val :
if not BPyMessages . Warning_SaveOver ( filename ) :
return
2007-08-23 16:34:15 +00:00
GLOBALS [ ' EVENT ' ] = EVENT_EXIT
# Keep the order the same as above for simplicity
# the [] is a dummy arg used for objects
2007-08-24 07:07:18 +00:00
2007-08-24 12:13:34 +00:00
Blender . Window . WaitCursor ( 1 )
2007-08-28 02:11:49 +00:00
# Make the matrix
2007-08-29 09:50:08 +00:00
GLOBAL_MATRIX = mtx4_identity
2007-08-28 02:11:49 +00:00
GLOBAL_MATRIX [ 0 ] [ 0 ] = GLOBAL_MATRIX [ 1 ] [ 1 ] = GLOBAL_MATRIX [ 2 ] [ 2 ] = GLOBALS [ ' _SCALE ' ] . val
if GLOBALS [ ' _XROT90 ' ] . val : GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n
if GLOBALS [ ' _YROT90 ' ] . val : GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n
if GLOBALS [ ' _ZROT90 ' ] . val : GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_z90n
2007-09-08 08:49:56 +00:00
ret = write ( \
2007-08-23 16:34:15 +00:00
filename , None , \
2009-09-29 15:27:00 +00:00
context ,
2007-08-23 16:34:15 +00:00
GLOBALS [ ' EXP_OBS_SELECTED ' ] . val , \
GLOBALS [ ' EXP_MESH ' ] . val , \
GLOBALS [ ' EXP_MESH_APPLY_MOD ' ] . val , \
GLOBALS [ ' EXP_MESH_HQ_NORMALS ' ] . val , \
GLOBALS [ ' EXP_ARMATURE ' ] . val , \
GLOBALS [ ' EXP_LAMP ' ] . val , \
GLOBALS [ ' EXP_CAMERA ' ] . val , \
GLOBALS [ ' EXP_EMPTY ' ] . val , \
GLOBALS [ ' EXP_IMAGE_COPY ' ] . val , \
2007-08-28 02:11:49 +00:00
GLOBAL_MATRIX , \
2007-08-23 16:34:15 +00:00
GLOBALS [ ' ANIM_ENABLE ' ] . val , \
GLOBALS [ ' ANIM_OPTIMIZE ' ] . val , \
GLOBALS [ ' ANIM_OPTIMIZE_PRECISSION ' ] . val , \
GLOBALS [ ' ANIM_ACTION_ALL ' ] [ 0 ] . val , \
GLOBALS [ ' BATCH_ENABLE ' ] . val , \
GLOBALS [ ' BATCH_GROUP ' ] . val , \
GLOBALS [ ' BATCH_SCENE ' ] . val , \
GLOBALS [ ' BATCH_FILE_PREFIX ' ] . val , \
GLOBALS [ ' BATCH_OWN_DIR ' ] . val , \
)
2007-08-24 12:13:34 +00:00
Blender . Window . WaitCursor ( 0 )
2007-08-23 16:34:15 +00:00
GLOBALS . clear ( )
2007-09-08 08:49:56 +00:00
if ret == False :
Draw . PupMenu ( ' Error % t|Path cannot be written to! ' )
2007-08-28 02:11:49 +00:00
2007-03-28 07:08:18 +00:00
2007-08-23 16:34:15 +00:00
def fbx_ui ( ) :
# Only to center the UI
x , y = GLOBALS [ ' MOUSE ' ]
x - = 180 ; y - = 0 # offset... just to get it centered
Draw . Label ( ' Export Objects... ' , x + 20 , y + 165 , 200 , 20 )
2007-08-28 02:11:49 +00:00
if not GLOBALS [ ' BATCH_ENABLE ' ] . val :
Draw . BeginAlign ( )
GLOBALS [ ' EXP_OBS_SELECTED ' ] = Draw . Toggle ( ' Selected Objects ' , EVENT_REDRAW , x + 20 , y + 145 , 160 , 20 , GLOBALS [ ' EXP_OBS_SELECTED ' ] . val , ' Export selected objects on visible layers ' , do_obs_sel )
GLOBALS [ ' EXP_OBS_SCENE ' ] = Draw . Toggle ( ' Scene Objects ' , EVENT_REDRAW , x + 180 , y + 145 , 160 , 20 , GLOBALS [ ' EXP_OBS_SCENE ' ] . val , ' Export all objects in this scene ' , do_obs_sce )
Draw . EndAlign ( )
2007-08-23 16:34:15 +00:00
Draw . BeginAlign ( )
2007-08-29 03:56:22 +00:00
GLOBALS [ ' _SCALE ' ] = Draw . Number ( ' Scale: ' , EVENT_NONE , x + 20 , y + 120 , 140 , 20 , GLOBALS [ ' _SCALE ' ] . val , 0.01 , 1000.0 , ' Scale all data, (Note! some imports dont support scaled armatures) ' )
GLOBALS [ ' _XROT90 ' ] = Draw . Toggle ( ' Rot X90 ' , EVENT_NONE , x + 160 , y + 120 , 60 , 20 , GLOBALS [ ' _XROT90 ' ] . val , ' Rotate all objects 90 degrese about the X axis ' )
GLOBALS [ ' _YROT90 ' ] = Draw . Toggle ( ' Rot Y90 ' , EVENT_NONE , x + 220 , y + 120 , 60 , 20 , GLOBALS [ ' _YROT90 ' ] . val , ' Rotate all objects 90 degrese about the Y axis ' )
GLOBALS [ ' _ZROT90 ' ] = Draw . Toggle ( ' Rot Z90 ' , EVENT_NONE , x + 280 , y + 120 , 60 , 20 , GLOBALS [ ' _ZROT90 ' ] . val , ' Rotate all objects 90 degrese about the Z axis ' )
2007-08-23 16:34:15 +00:00
Draw . EndAlign ( )
2007-08-28 02:11:49 +00:00
y - = 35
2007-08-23 16:34:15 +00:00
Draw . BeginAlign ( )
GLOBALS [ ' EXP_EMPTY ' ] = Draw . Toggle ( ' Empty ' , EVENT_NONE , x + 20 , y + 120 , 60 , 20 , GLOBALS [ ' EXP_EMPTY ' ] . val , ' Export empty objects ' )
GLOBALS [ ' EXP_CAMERA ' ] = Draw . Toggle ( ' Camera ' , EVENT_NONE , x + 80 , y + 120 , 60 , 20 , GLOBALS [ ' EXP_CAMERA ' ] . val , ' Export camera objects ' )
GLOBALS [ ' EXP_LAMP ' ] = Draw . Toggle ( ' Lamp ' , EVENT_NONE , x + 140 , y + 120 , 60 , 20 , GLOBALS [ ' EXP_LAMP ' ] . val , ' Export lamp objects ' )
GLOBALS [ ' EXP_ARMATURE ' ] = Draw . Toggle ( ' Armature ' , EVENT_NONE , x + 200 , y + 120 , 60 , 20 , GLOBALS [ ' EXP_ARMATURE ' ] . val , ' Export armature objects ' )
GLOBALS [ ' EXP_MESH ' ] = Draw . Toggle ( ' Mesh ' , EVENT_REDRAW , x + 260 , y + 120 , 80 , 20 , GLOBALS [ ' EXP_MESH ' ] . val , ' Export mesh objects ' , do_redraw ) #, do_axis_z)
Draw . EndAlign ( )
if GLOBALS [ ' EXP_MESH ' ] . val :
# below mesh but
Draw . BeginAlign ( )
GLOBALS [ ' EXP_MESH_APPLY_MOD ' ] = Draw . Toggle ( ' Modifiers ' , EVENT_NONE , x + 260 , y + 100 , 80 , 20 , GLOBALS [ ' EXP_MESH_APPLY_MOD ' ] . val , ' Apply modifiers to mesh objects ' ) #, do_axis_z)
GLOBALS [ ' EXP_MESH_HQ_NORMALS ' ] = Draw . Toggle ( ' HQ Normals ' , EVENT_NONE , x + 260 , y + 80 , 80 , 20 , GLOBALS [ ' EXP_MESH_HQ_NORMALS ' ] . val , ' Generate high quality normals ' ) #, do_axis_z)
Draw . EndAlign ( )
GLOBALS [ ' EXP_IMAGE_COPY ' ] = Draw . Toggle ( ' Copy Image Files ' , EVENT_NONE , x + 20 , y + 80 , 160 , 20 , GLOBALS [ ' EXP_IMAGE_COPY ' ] . val , ' Copy image files to the destination path ' ) #, do_axis_z)
Draw . Label ( ' Export Armature Animation... ' , x + 20 , y + 45 , 300 , 20 )
GLOBALS [ ' ANIM_ENABLE ' ] = Draw . Toggle ( ' Enable Animation ' , EVENT_REDRAW , x + 20 , y + 25 , 160 , 20 , GLOBALS [ ' ANIM_ENABLE ' ] . val , ' Export keyframe animation ' , do_redraw )
if GLOBALS [ ' ANIM_ENABLE ' ] . val :
Draw . BeginAlign ( )
GLOBALS [ ' ANIM_OPTIMIZE ' ] = Draw . Toggle ( ' Optimize Keyframes ' , EVENT_REDRAW , x + 20 , y + 0 , 160 , 20 , GLOBALS [ ' ANIM_OPTIMIZE ' ] . val , ' Remove double keyframes ' , do_redraw )
if GLOBALS [ ' ANIM_OPTIMIZE ' ] . val :
2009-05-13 22:52:31 +00:00
GLOBALS [ ' ANIM_OPTIMIZE_PRECISSION ' ] = Draw . Number ( ' Precission: ' , EVENT_NONE , x + 180 , y + 0 , 160 , 20 , GLOBALS [ ' ANIM_OPTIMIZE_PRECISSION ' ] . val , 1 , 16 , ' Tolerence for comparing double keyframes (higher for greater accuracy) ' )
2007-08-23 16:34:15 +00:00
Draw . EndAlign ( )
Draw . BeginAlign ( )
GLOBALS [ ' ANIM_ACTION_ALL ' ] [ 1 ] = Draw . Toggle ( ' Current Action ' , EVENT_REDRAW , x + 20 , y - 25 , 160 , 20 , GLOBALS [ ' ANIM_ACTION_ALL ' ] [ 1 ] . val , ' Use actions currently applied to the armatures (use scene start/end frame) ' , do_anim_act_cur )
GLOBALS [ ' ANIM_ACTION_ALL ' ] [ 0 ] = Draw . Toggle ( ' All Actions ' , EVENT_REDRAW , x + 180 , y - 25 , 160 , 20 , GLOBALS [ ' ANIM_ACTION_ALL ' ] [ 0 ] . val , ' Use all actions for armatures ' , do_anim_act_all )
Draw . EndAlign ( )
2007-08-28 02:11:49 +00:00
Draw . Label ( ' Export Batch... ' , x + 20 , y - 60 , 300 , 20 )
GLOBALS [ ' BATCH_ENABLE ' ] = Draw . Toggle ( ' Enable Batch ' , EVENT_REDRAW , x + 20 , y - 80 , 160 , 20 , GLOBALS [ ' BATCH_ENABLE ' ] . val , ' Automate exporting multiple scenes or groups to files ' , do_redraw )
2007-08-23 16:34:15 +00:00
if GLOBALS [ ' BATCH_ENABLE ' ] . val :
Draw . BeginAlign ( )
GLOBALS [ ' BATCH_GROUP ' ] = Draw . Toggle ( ' Group > File ' , EVENT_REDRAW , x + 20 , y - 105 , 160 , 20 , GLOBALS [ ' BATCH_GROUP ' ] . val , ' Export each group as an FBX file ' , do_batch_type_grp )
GLOBALS [ ' BATCH_SCENE ' ] = Draw . Toggle ( ' Scene > File ' , EVENT_REDRAW , x + 180 , y - 105 , 160 , 20 , GLOBALS [ ' BATCH_SCENE ' ] . val , ' Export each scene as an FBX file ' , do_batch_type_sce )
2007-08-28 02:11:49 +00:00
# Own dir requires OS module
if os :
GLOBALS [ ' BATCH_OWN_DIR ' ] = Draw . Toggle ( ' Own Dir ' , EVENT_NONE , x + 20 , y - 125 , 80 , 20 , GLOBALS [ ' BATCH_OWN_DIR ' ] . val , ' Create a dir for each exported file ' )
GLOBALS [ ' BATCH_FILE_PREFIX ' ] = Draw . String ( ' Prefix: ' , EVENT_NONE , x + 100 , y - 125 , 240 , 20 , GLOBALS [ ' BATCH_FILE_PREFIX ' ] . val , 64 , ' Prefix each file with this name ' )
else :
GLOBALS [ ' BATCH_FILE_PREFIX ' ] = Draw . String ( ' Prefix: ' , EVENT_NONE , x + 20 , y - 125 , 320 , 20 , GLOBALS [ ' BATCH_FILE_PREFIX ' ] . val , 64 , ' Prefix each file with this name ' )
2007-08-23 16:34:15 +00:00
Draw . EndAlign ( )
2007-08-28 02:11:49 +00:00
#y+=80
2007-08-23 16:34:15 +00:00
'''
Draw . BeginAlign ( )
GLOBALS [ ' FILENAME ' ] = Draw . String ( ' path: ' , EVENT_NONE , x + 20 , y - 170 , 300 , 20 , GLOBALS [ ' FILENAME ' ] . val , 64 , ' Prefix each file with this name ' )
Draw . PushButton ( ' .. ' , EVENT_FILESEL , x + 320 , y - 170 , 20 , 20 , ' Select the path ' , do_redraw )
'''
# Until batch is added
2007-08-28 02:11:49 +00:00
#
2007-08-23 16:34:15 +00:00
2007-08-28 02:11:49 +00:00
#Draw.BeginAlign()
Draw . PushButton ( ' Online Help ' , EVENT_REDRAW , x + 20 , y - 160 , 100 , 20 , ' Open online help in a browser window ' , do_help )
Draw . PushButton ( ' Cancel ' , EVENT_EXIT , x + 130 , y - 160 , 100 , 20 , ' Exit the exporter ' , fbx_ui_exit )
Draw . PushButton ( ' Export ' , EVENT_FILESEL , x + 240 , y - 160 , 100 , 20 , ' Export the fbx file ' , do_redraw )
2007-08-23 16:34:15 +00:00
#Draw.PushButton('Export', EVENT_EXIT, x+180, y-160, 160, 20, 'Export the fbx file', fbx_ui_write)
2007-08-28 02:11:49 +00:00
#Draw.EndAlign()
2007-08-23 16:34:15 +00:00
# exit when mouse out of the view?
# GLOBALS['EVENT'] = EVENT_EXIT
#def write_ui(filename):
def write_ui ( ) :
# globals
2008-10-19 15:53:22 +00:00
GLOBALS [ ' EVENT ' ] = EVENT_REDRAW
2007-08-23 16:34:15 +00:00
#GLOBALS['MOUSE'] = Window.GetMouseCoords()
GLOBALS [ ' MOUSE ' ] = [ i / 2 for i in Window . GetScreenSize ( ) ]
GLOBALS [ ' FILENAME ' ] = ' '
'''
# IF called from the fileselector
if filename == None :
GLOBALS [ ' FILENAME ' ] = filename # Draw.Create(Blender.sys.makename(ext='.fbx'))
else :
GLOBALS [ ' FILENAME ' ] . val = filename
'''
GLOBALS [ ' EXP_OBS_SELECTED ' ] = Draw . Create ( 1 ) # dont need 2 variables but just do this for clarity
GLOBALS [ ' EXP_OBS_SCENE ' ] = Draw . Create ( 0 )
GLOBALS [ ' EXP_MESH ' ] = Draw . Create ( 1 )
2007-08-28 02:11:49 +00:00
GLOBALS [ ' EXP_MESH_APPLY_MOD ' ] = Draw . Create ( 1 )
2007-08-23 16:34:15 +00:00
GLOBALS [ ' EXP_MESH_HQ_NORMALS ' ] = Draw . Create ( 0 )
GLOBALS [ ' EXP_ARMATURE ' ] = Draw . Create ( 1 )
GLOBALS [ ' EXP_LAMP ' ] = Draw . Create ( 1 )
GLOBALS [ ' EXP_CAMERA ' ] = Draw . Create ( 1 )
GLOBALS [ ' EXP_EMPTY ' ] = Draw . Create ( 1 )
GLOBALS [ ' EXP_IMAGE_COPY ' ] = Draw . Create ( 0 )
# animation opts
GLOBALS [ ' ANIM_ENABLE ' ] = Draw . Create ( 1 )
GLOBALS [ ' ANIM_OPTIMIZE ' ] = Draw . Create ( 1 )
2009-05-13 22:52:31 +00:00
GLOBALS [ ' ANIM_OPTIMIZE_PRECISSION ' ] = Draw . Create ( 4 ) # decimal places
2007-08-23 16:34:15 +00:00
GLOBALS [ ' ANIM_ACTION_ALL ' ] = [ Draw . Create ( 0 ) , Draw . Create ( 1 ) ] # not just the current action
# batch export options
GLOBALS [ ' BATCH_ENABLE ' ] = Draw . Create ( 0 )
GLOBALS [ ' BATCH_GROUP ' ] = Draw . Create ( 1 ) # cant have both of these enabled at once.
GLOBALS [ ' BATCH_SCENE ' ] = Draw . Create ( 0 ) # see above
GLOBALS [ ' BATCH_FILE_PREFIX ' ] = Draw . Create ( Blender . sys . makename ( ext = ' _ ' ) . split ( ' \\ ' ) [ - 1 ] . split ( ' / ' ) [ - 1 ] )
GLOBALS [ ' BATCH_OWN_DIR ' ] = Draw . Create ( 0 )
# done setting globals
2007-08-28 02:11:49 +00:00
# Used by the user interface
2007-08-29 00:10:23 +00:00
GLOBALS [ ' _SCALE ' ] = Draw . Create ( 1.0 )
2007-08-28 02:11:49 +00:00
GLOBALS [ ' _XROT90 ' ] = Draw . Create ( True )
GLOBALS [ ' _YROT90 ' ] = Draw . Create ( False )
GLOBALS [ ' _ZROT90 ' ] = Draw . Create ( False )
2007-08-23 16:34:15 +00:00
# best not do move the cursor
# Window.SetMouseCoords(*[i/2 for i in Window.GetScreenSize()])
# hack so the toggle buttons redraw. this is not nice at all
while GLOBALS [ ' EVENT ' ] != EVENT_EXIT :
2007-08-28 02:11:49 +00:00
if GLOBALS [ ' BATCH_ENABLE ' ] . val and GLOBALS [ ' BATCH_GROUP ' ] . val and GLOBALS [ ' ANIM_ACTION_ALL ' ] [ 1 ] . val :
#Draw.PupMenu("Warning%t|Cant batch export groups with 'Current Action' ")
GLOBALS [ ' ANIM_ACTION_ALL ' ] [ 0 ] . val = 1
GLOBALS [ ' ANIM_ACTION_ALL ' ] [ 1 ] . val = 0
2007-08-23 16:34:15 +00:00
if GLOBALS [ ' EVENT ' ] == EVENT_FILESEL :
2007-08-28 02:11:49 +00:00
if GLOBALS [ ' BATCH_ENABLE ' ] . val :
txt = ' Batch FBX Dir '
2007-08-29 19:53:49 +00:00
name = Blender . sys . expandpath ( ' // ' )
2007-08-28 02:11:49 +00:00
else :
txt = ' Export FBX '
name = Blender . sys . makename ( ext = ' .fbx ' )
Blender . Window . FileSelector ( fbx_ui_write , txt , name )
2007-09-08 08:49:56 +00:00
#fbx_ui_write('/test.fbx')
2007-08-23 16:34:15 +00:00
break
2008-10-22 08:21:43 +00:00
Draw . UIBlock ( fbx_ui , 0 )
2007-08-23 16:34:15 +00:00
# GLOBALS.clear()
define operator properties in the class, similar to django fields
# Before
[
bpy.props.StringProperty(attr="path", name="File Path", description="File path used for exporting the PLY file", maxlen= 1024, default= ""),
bpy.props.BoolProperty(attr="use_modifiers", name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default= True),
bpy.props.BoolProperty(attr="use_normals", name="Export Normals", description="Export Normals for smooth and hard shaded faces", default= True),
bpy.props.BoolProperty(attr="use_uvs", name="Export UVs", description="Exort the active UV layer", default= True),
bpy.props.BoolProperty(attr="use_colors", name="Export Vertex Colors", description="Exort the active vertex color layer", default= True)
]
# After
path = StringProperty(attr="", name="File Path", description="File path used for exporting the PLY file", maxlen= 1024, default= "")
use_modifiers = BoolProperty(attr="", name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default= True)
use_normals = BoolProperty(attr="", name="Export Normals", description="Export Normals for smooth and hard shaded faces", default= True)
use_uvs = BoolProperty(attr="", name="Export UVs", description="Exort the active UV layer", default= True)
use_colors = BoolProperty(attr="", name="Export Vertex Colors", description="Exort the active vertex color layer", default= True)
2009-10-31 16:40:14 +00:00
from bpy . props import *
2009-11-04 18:35:32 +00:00
class ExportFBX ( bpy . types . Operator ) :
- add torus back from 2.4x as an operator
bpy.ops.mesh.primitive_torus_add(major_radius=1, minor_radius=0.25, major_segments=48, minor_segments=16)
- experemental dynamic menus, used for INFO_MT_file, INFO_MT_file_import, INFO_MT_file_export and INFO_MT_mesh_add. these can have items added from python.
eg.
- removed OBJECT_OT_mesh_add, use the python add menu instead.
- made mesh primitive ops - MESH_OT_primitive_plane_add, ...cube_add, etc. work in object mode.
- RNA scene.active_object wrapped
- bugfix [#19466] 2.5: Tweak menu only available for mesh objects added within Edit Mode
ED_object_exit_editmode was always doing an undo push, made this optional using the existing flag - EM_DO_UNDO, called everywhere except when adding primitives.
2009-10-10 21:23:20 +00:00
''' Selection to an ASCII Autodesk FBX '''
2009-10-31 13:31:23 +00:00
bl_idname = " export.fbx "
bl_label = " Export FBX "
2009-09-29 15:27:00 +00:00
# List of operator properties, the attributes will be assigned
# to the class instance from the operator settings before calling.
define operator properties in the class, similar to django fields
# Before
[
bpy.props.StringProperty(attr="path", name="File Path", description="File path used for exporting the PLY file", maxlen= 1024, default= ""),
bpy.props.BoolProperty(attr="use_modifiers", name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default= True),
bpy.props.BoolProperty(attr="use_normals", name="Export Normals", description="Export Normals for smooth and hard shaded faces", default= True),
bpy.props.BoolProperty(attr="use_uvs", name="Export UVs", description="Exort the active UV layer", default= True),
bpy.props.BoolProperty(attr="use_colors", name="Export Vertex Colors", description="Exort the active vertex color layer", default= True)
]
# After
path = StringProperty(attr="", name="File Path", description="File path used for exporting the PLY file", maxlen= 1024, default= "")
use_modifiers = BoolProperty(attr="", name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default= True)
use_normals = BoolProperty(attr="", name="Export Normals", description="Export Normals for smooth and hard shaded faces", default= True)
use_uvs = BoolProperty(attr="", name="Export UVs", description="Exort the active UV layer", default= True)
use_colors = BoolProperty(attr="", name="Export Vertex Colors", description="Exort the active vertex color layer", default= True)
2009-10-31 16:40:14 +00:00
path = StringProperty ( name = " File Path " , description = " File path used for exporting the FBX file " , maxlen = 1024 , default = " " )
EXP_OBS_SELECTED = BoolProperty ( name = " Selected Objects " , description = " Export selected objects on visible layers " , default = True )
# EXP_OBS_SCENE = BoolProperty(name="Scene Objects", description="Export all objects in this scene", default=True)
_SCALE = FloatProperty ( name = " Scale " , description = " Scale all data, (Note! some imports dont support scaled armatures) " , min = 0.01 , max = 1000.0 , soft_min = 0.01 , soft_max = 1000.0 , default = 1.0 )
_XROT90 = BoolProperty ( name = " Rot X90 " , description = " Rotate all objects 90 degrese about the X axis " , default = True )
_YROT90 = BoolProperty ( name = " Rot Y90 " , description = " Rotate all objects 90 degrese about the Y axis " , default = False )
_ZROT90 = BoolProperty ( name = " Rot Z90 " , description = " Rotate all objects 90 degrese about the Z axis " , default = False )
EXP_EMPTY = BoolProperty ( name = " Empties " , description = " Export empty objects " , default = True )
EXP_CAMERA = BoolProperty ( name = " Cameras " , description = " Export camera objects " , default = True )
EXP_LAMP = BoolProperty ( name = " Lamps " , description = " Export lamp objects " , default = True )
EXP_ARMATURE = BoolProperty ( name = " Armatures " , description = " Export armature objects " , default = True )
EXP_MESH = BoolProperty ( name = " Meshes " , description = " Export mesh objects " , default = True )
EXP_MESH_APPLY_MOD = BoolProperty ( name = " Modifiers " , description = " Apply modifiers to mesh objects " , default = True )
EXP_MESH_HQ_NORMALS = BoolProperty ( name = " HQ Normals " , description = " Generate high quality normals " , default = True )
EXP_IMAGE_COPY = BoolProperty ( name = " Copy Image Files " , description = " Copy image files to the destination path " , default = False )
# armature animation
ANIM_ENABLE = BoolProperty ( name = " Enable Animation " , description = " Export keyframe animation " , default = True )
ANIM_OPTIMIZE = BoolProperty ( name = " Optimize Keyframes " , description = " Remove double keyframes " , default = True )
ANIM_OPTIMIZE_PRECISSION = FloatProperty ( name = " Precision " , description = " Tolerence for comparing double keyframes (higher for greater accuracy) " , min = 1 , max = 16 , soft_min = 1 , soft_max = 16 , default = 6.0 )
# ANIM_ACTION_ALL = BoolProperty(name="Current Action", description="Use actions currently applied to the armatures (use scene start/end frame)", default=True)
ANIM_ACTION_ALL = BoolProperty ( name = " All Actions " , description = " Use all actions for armatures, if false, use current action " , default = False )
# batch
BATCH_ENABLE = BoolProperty ( name = " Enable Batch " , description = " Automate exporting multiple scenes or groups to files " , default = False )
BATCH_GROUP = BoolProperty ( name = " Group > File " , description = " Export each group as an FBX file, if false, export each scene as an FBX file " , default = False )
BATCH_OWN_DIR = BoolProperty ( name = " Own Dir " , description = " Create a dir for each exported file " , default = True )
BATCH_FILE_PREFIX = StringProperty ( name = " Prefix " , description = " Prefix each file with this name " , maxlen = 1024 , default = " " )
2009-09-29 15:27:00 +00:00
def poll ( self , context ) :
print ( " Poll " )
return context . active_object != None
def execute ( self , context ) :
2009-11-19 17:12:08 +00:00
if not self . properties . path :
2009-09-29 15:27:00 +00:00
raise Exception ( " path not set " )
GLOBAL_MATRIX = mtx4_identity
2009-11-19 17:12:08 +00:00
GLOBAL_MATRIX [ 0 ] [ 0 ] = GLOBAL_MATRIX [ 1 ] [ 1 ] = GLOBAL_MATRIX [ 2 ] [ 2 ] = self . properties . _SCALE
if self . properties . _XROT90 : GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n
if self . properties . _YROT90 : GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n
if self . properties . _ZROT90 : GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_z90n
2009-09-29 15:27:00 +00:00
2009-11-19 17:12:08 +00:00
write ( self . properties . path ,
2009-09-29 15:27:00 +00:00
None , # XXX
context ,
2009-11-19 17:12:08 +00:00
self . properties . EXP_OBS_SELECTED ,
self . properties . EXP_MESH ,
self . properties . EXP_MESH_APPLY_MOD ,
# self.properties.EXP_MESH_HQ_NORMALS,
self . properties . EXP_ARMATURE ,
self . properties . EXP_LAMP ,
self . properties . EXP_CAMERA ,
self . properties . EXP_EMPTY ,
self . properties . EXP_IMAGE_COPY ,
2009-09-29 15:27:00 +00:00
GLOBAL_MATRIX ,
2009-11-19 17:12:08 +00:00
self . properties . ANIM_ENABLE ,
self . properties . ANIM_OPTIMIZE ,
self . properties . ANIM_OPTIMIZE_PRECISSION ,
self . properties . ANIM_ACTION_ALL ,
self . properties . BATCH_ENABLE ,
self . properties . BATCH_GROUP ,
self . properties . BATCH_FILE_PREFIX ,
self . properties . BATCH_OWN_DIR )
2009-09-29 15:27:00 +00:00
return ( ' FINISHED ' , )
def invoke ( self , context , event ) :
wm = context . manager
2009-11-02 08:32:00 +00:00
wm . add_fileselect ( self )
2009-09-29 15:27:00 +00:00
return ( ' RUNNING_MODAL ' , )
2009-11-04 18:35:32 +00:00
bpy . ops . add ( ExportFBX )
2009-09-29 15:27:00 +00:00
# if __name__ == "__main__":
# bpy.ops.EXPORT_OT_ply(filename="/tmp/test.ply")
# NOTES (all line numbers correspond to original export_fbx.py (under release/scripts)
# - Draw.PupMenu alternative in 2.5?, temporarily replaced PupMenu with print
# - get rid of cleanName somehow
# + fixed: isinstance(inst, bpy.types.*) doesn't work on RNA objects: line 565
# + get rid of BPyObject_getObjectArmature, move it in RNA?
# - BATCH_ENABLE and BATCH_GROUP options: line 327
# - implement all BPyMesh_* used here with RNA
# - getDerivedObjects is not fully replicated with .dupli* funcs
# - talk to Campbell, this code won't work? lines 1867-1875
# - don't know what those colbits are, do we need them? they're said to be deprecated in DNA_object_types.h: 1886-1893
# - no hq normals: 1900-1901
# TODO
# - bpy.data.remove_scene: line 366
# - bpy.sys.time move to bpy.sys.util?
# - new scene creation, activation: lines 327-342, 368
2009-11-03 18:08:25 +00:00
# - uses bpy.utils.expandpath, *.relpath - replace at least relpath
2009-09-29 15:27:00 +00:00
# SMALL or COSMETICAL
# - find a way to get blender version, and put it in bpy.util?, old was Blender.Get('version')
- add torus back from 2.4x as an operator
bpy.ops.mesh.primitive_torus_add(major_radius=1, minor_radius=0.25, major_segments=48, minor_segments=16)
- experemental dynamic menus, used for INFO_MT_file, INFO_MT_file_import, INFO_MT_file_export and INFO_MT_mesh_add. these can have items added from python.
eg.
- removed OBJECT_OT_mesh_add, use the python add menu instead.
- made mesh primitive ops - MESH_OT_primitive_plane_add, ...cube_add, etc. work in object mode.
- RNA scene.active_object wrapped
- bugfix [#19466] 2.5: Tweak menu only available for mesh objects added within Edit Mode
ED_object_exit_editmode was always doing an undo push, made this optional using the existing flag - EM_DO_UNDO, called everywhere except when adding primitives.
2009-10-10 21:23:20 +00:00
# Add to a menu
import dynamic_menu
2009-11-04 18:35:32 +00:00
def menu_func ( self , context ) :
default_path = bpy . data . filename . replace ( " .blend " , " .fbx " )
2009-11-23 11:43:38 +00:00
self . layout . operator ( ExportFBX . bl_idname , text = " Autodesk FBX... " ) . path = default_path
2009-11-04 18:35:32 +00:00
- add torus back from 2.4x as an operator
bpy.ops.mesh.primitive_torus_add(major_radius=1, minor_radius=0.25, major_segments=48, minor_segments=16)
- experemental dynamic menus, used for INFO_MT_file, INFO_MT_file_import, INFO_MT_file_export and INFO_MT_mesh_add. these can have items added from python.
eg.
- removed OBJECT_OT_mesh_add, use the python add menu instead.
- made mesh primitive ops - MESH_OT_primitive_plane_add, ...cube_add, etc. work in object mode.
- RNA scene.active_object wrapped
- bugfix [#19466] 2.5: Tweak menu only available for mesh objects added within Edit Mode
ED_object_exit_editmode was always doing an undo push, made this optional using the existing flag - EM_DO_UNDO, called everywhere except when adding primitives.
2009-10-10 21:23:20 +00:00
menu_item = dynamic_menu . add ( bpy . types . INFO_MT_file_export , menu_func )