Newer
Older
groups.append((fbxGroupName, blenGroup))
tmp_obmapping[ob].fbxGroupNames.append(fbxGroupName) # also adds to the objects fbxGroupNames
groups.sort() # not really needed
# Assign parents using this mapping
for ob_generic in ob_all_typegroups:
for my_ob in ob_generic:
parent = my_ob.blenObject.parent
if parent and parent.tag: # does it exist and is it in the mapping
my_ob.fbxParent = tmp_obmapping[parent]
del tmp_obmapping
# Finished finding groups we use
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]
Campbell Barton
committed
materials.sort(key=lambda m: m[0]) # sort by name
textures.sort(key=lambda m: m[0])
camera_count = 8
file.write('''
; Object definitions
;------------------------------------------------------------------
Definitions: {
Campbell Barton
committed
Version: 100
Count: %i''' % (
1 + camera_count +
len(ob_meshes) +
len(ob_lights) +
len(ob_cameras) +
len(ob_arms) +
len(ob_null) +
len(ob_bones) +
bone_deformer_count +
len(materials) +
(len(textures) * 2))) # add 1 for global settings
del bone_deformer_count
file.write('''
Campbell Barton
committed
ObjectType: "Model" {
Count: %i
}''' % (
camera_count +
len(ob_meshes) +
len(ob_lights) +
len(ob_cameras) +
len(ob_arms) +
len(ob_null) +
file.write('''
Campbell Barton
committed
ObjectType: "Geometry" {
Count: %i
}''' % len(ob_meshes))
if materials:
file.write('''
Campbell Barton
committed
ObjectType: "Material" {
Count: %i
}''' % len(materials))
if textures:
file.write('''
Campbell Barton
committed
ObjectType: "Texture" {
Count: %i
}''' % len(textures)) # add 1 for an empty tex
file.write('''
Campbell Barton
committed
ObjectType: "Video" {
Count: %i
}''' % len(textures)) # add 1 for an empty tex
tmp = 0
# Add deformer nodes
for my_mesh in ob_meshes:
if my_mesh.fbxArm:
tmp += 1
# Add subdeformers
for my_bone in ob_bones:
tmp += len(my_bone.blenMeshes)
if tmp:
file.write('''
Campbell Barton
committed
ObjectType: "Deformer" {
Count: %i
}''' % tmp)
del tmp
# we could avoid writing this possibly but for now just write it
file.write('''
Campbell Barton
committed
ObjectType: "Pose" {
Count: 1
}''')
if groups:
file.write('''
Campbell Barton
committed
ObjectType: "GroupSelection" {
Count: %i
}''' % len(groups))
file.write('''
Campbell Barton
committed
ObjectType: "GlobalSettings" {
Count: 1
}
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
}''')
file.write('''
; Object properties
;------------------------------------------------------------------
Objects: {''')
# To comply with other FBX FILES
write_camera_switch()
for my_null in ob_null:
write_null(my_null)
for my_arm in ob_arms:
write_null(my_arm)
for my_cam in ob_cameras:
write_camera(my_cam)
for my_light in ob_lights:
write_light(my_light)
for my_mesh in ob_meshes:
write_mesh(my_mesh)
#for bonename, bone, obname, me, armob in ob_bones:
for my_bone in ob_bones:
write_bone(my_bone)
write_camera_default()
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)
# 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
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
for groupname, group in groups:
write_group(groupname)
# NOTE - c4d and motionbuilder dont need normalized weights, but deep-exploration 5 does and (max?) do.
# Write armature modifiers
# TODO - add another MODEL? - because of this skin definition.
for my_mesh in ob_meshes:
if my_mesh.fbxArm:
write_deformer_skin(my_mesh.fbxName)
# Get normalized weights for temorary use
if my_mesh.fbxBoneParent:
weights = None
else:
weights = meshNormalizedWeights(my_mesh.blenObject, my_mesh.blenData)
#for bonename, bone, obname, bone_mesh, armob in ob_bones:
for my_bone in ob_bones:
if me in iter(my_bone.blenMeshes.values()):
write_sub_deformer_skin(my_mesh, my_bone, weights)
# Write pose's really weird, only needed when an armature and mesh are used together
# each by themselves dont need pose data. for now only pose meshes and bones
file.write('''
Campbell Barton
committed
Pose: "Pose::BIND_POSES", "BindPose" {
Type: "BindPose"
Version: 100
Properties60: {
}
NbPoseNodes: ''')
file.write(str(len(pose_items)))
for fbxName, matrix in pose_items:
file.write('\n\t\tPoseNode: {')
file.write('\n\t\t\tNode: "Model::%s"' % fbxName)
file.write('\n\t\t\tMatrix: %s' % mat4x4str(matrix if matrix else Matrix()))
file.write('\n\t\t}')
file.write('\n\t}')
# Finish Writing Objects
# Write global settings
file.write('''
Campbell Barton
committed
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
Property: "UnitScaleFactor", "double", "",1
}
}
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
''')
file.write('}')
file.write('''
; Object relations
;------------------------------------------------------------------
Relations: {''')
for my_null in ob_null:
file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_null.fbxName)
for my_arm in ob_arms:
file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_arm.fbxName)
for my_mesh in ob_meshes:
file.write('\n\tModel: "Model::%s", "Mesh" {\n\t}' % my_mesh.fbxName)
# TODO - limbs can have the same name for multiple armatures, should prefix.
#for bonename, bone, obname, me, armob in ob_bones:
for my_bone in ob_bones:
file.write('\n\tModel: "Model::%s", "Limb" {\n\t}' % my_bone.fbxName)
for my_cam in ob_cameras:
file.write('\n\tModel: "Model::%s", "Camera" {\n\t}' % my_cam.fbxName)
for my_light in ob_lights:
file.write('\n\tModel: "Model::%s", "Light" {\n\t}' % my_light.fbxName)
file.write('''
Campbell Barton
committed
Model: "Model::Producer Perspective", "Camera" {
}
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" {
}''')
for matname, (mat, tex) in materials:
file.write('\n\tMaterial: "Material::%s", "" {\n\t}' % matname)
if textures:
for texname, tex in textures:
file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {\n\t}' % texname)
for texname, tex in textures:
file.write('\n\tVideo: "Video::%s", "Clip" {\n\t}' % texname)
# deformers - modifiers
for my_mesh in ob_meshes:
if my_mesh.fbxArm:
file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {\n\t}' % my_mesh.fbxName)
#for bonename, bone, obname, me, armob in ob_bones:
for my_bone in ob_bones:
for fbxMeshObName in my_bone.blenMeshes: # .keys() - fbxMeshObName
# is this bone effecting a mesh?
file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {\n\t}' % (fbxMeshObName, my_bone.fbxName))
# This should be at the end
# file.write('\n\tPose: "Pose::BIND_POSES", "BindPose" {\n\t}')
for groupname, group in groups:
file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {\n\t}' % groupname)
file.write('\n}')
file.write('''
; Object connections
;------------------------------------------------------------------
Connections: {''')
# NOTE - The FBX SDK dosnt care about the order but some importers DO!
# for instance, defining the material->mesh connection
# before the mesh->parent crashes cinema4d
for ob_generic in ob_all_typegroups: # all blender 'Object's we support
for my_ob in ob_generic:
# for deformed meshes, don't have any parents or they can get twice transformed.
if my_ob.fbxParent and (not my_ob.fbxArm):
file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_ob.fbxName, my_ob.fbxParent.fbxName))
else:
file.write('\n\tConnect: "OO", "Model::%s", "Model::Scene"' % my_ob.fbxName)
if materials:
for my_mesh in ob_meshes:
# Connect all materials to all objects, not good form but ok for now.
for mat, tex in my_mesh.blenMaterials:
mat_name = mat.name if mat else None
tex_name = tex.name if tex else None
file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat_name, tex_name], my_mesh.fbxName))
if textures:
for my_mesh in ob_meshes:
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\tConnect: "OO", "Texture::%s", "Model::%s"' % (sane_name_mapping_tex[tex.name], my_mesh.fbxName))
for texname, tex in textures:
file.write('\n\tConnect: "OO", "Video::%s", "Texture::%s"' % (texname, texname))
for my_mesh in ob_meshes:
if my_mesh.fbxArm:
file.write('\n\tConnect: "OO", "Deformer::Skin %s", "Model::%s"' % (my_mesh.fbxName, my_mesh.fbxName))
#for bonename, bone, obname, me, armob in ob_bones:
for my_bone in ob_bones:
for fbxMeshObName in my_bone.blenMeshes: # .keys()
file.write('\n\tConnect: "OO", "SubDeformer::Cluster %s %s", "Deformer::Skin %s"' % (fbxMeshObName, my_bone.fbxName, fbxMeshObName))
# limbs -> deformers
# for bonename, bone, obname, me, armob in ob_bones:
for my_bone in ob_bones:
for fbxMeshObName in my_bone.blenMeshes: # .keys()
file.write('\n\tConnect: "OO", "Model::%s", "SubDeformer::Cluster %s %s"' % (my_bone.fbxName, fbxMeshObName, my_bone.fbxName))
#for bonename, bone, obname, me, armob in ob_bones:
for my_bone in ob_bones:
# Always parent to armature now
if my_bone.parent:
file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.parent.fbxName))
else:
# the armature object is written as an empty and all root level bones connect to it
file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.fbxArm.fbxName))
# groups
if groups:
for ob_generic in ob_all_typegroups:
for ob_base in ob_generic:
for fbxGroupName in ob_base.fbxGroupNames:
file.write('\n\tConnect: "OO", "Model::%s", "GroupSelection::%s"' % (ob_base.fbxName, fbxGroupName))
for my_arm in ob_arms:
file.write('\n\tConnect: "OO", "Model::%s", "Model::Scene"' % my_arm.fbxName)
file.write('\n}')
# Needed for scene footer as well as animation
render = scene.render
# 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)
start = scene.frame_start
end = scene.frame_end
if end < start:
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
# comment the following line, otherwise we dont get the pose
# if start==end: ANIM_ENABLE = False
# animations for these object types
ob_anim_lists = ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms
if ANIM_ENABLE and [tmp for tmp in ob_anim_lists if tmp]:
frame_orig = scene.frame_current
if ANIM_OPTIMIZE:
ANIM_OPTIMIZE_PRECISSION_FLOAT = 0.1 ** ANIM_OPTIMIZE_PRECISSION
# default action, when no actions are avaioable
tmp_actions = []
blenActionDefault = None
action_lastcompat = None
# instead of tagging
tagged_actions = []
if ANIM_ACTION_ALL:
tmp_actions = bpy.data.actions[:]
# find which actions are compatible with the armatures
# blenActions is not yet initialized so do it now.
tmp_act_count = 0
for my_arm in ob_arms:
# get the default name
if not blenActionDefault:
blenActionDefault = my_arm.blenAction
arm_bone_names = set([my_bone.blenName for my_bone in my_arm.fbxBones])
for action in tmp_actions:
action_chan_names = arm_bone_names.intersection(set([g.name for g in action.groups]))
if action_chan_names: # at least one channel matches.
my_arm.blenActionList.append(action)
tagged_actions.append(action.name)
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.
if not blenActionDefault:
blenActionDefault = action_lastcompat
del action_lastcompat
tmp_actions.insert(0, None) # None is the default action
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
file.write('''
;Takes and animation section
;----------------------------------------------------
Takes: {''')
if blenActionDefault:
file.write('\n\tCurrent: "%s"' % sane_takename(blenActionDefault))
else:
file.write('\n\tCurrent: "Default Take"')
for blenAction in tmp_actions:
# we have tagged all actious that are used be selected armatures
if blenAction:
if blenAction.name in tagged_actions:
print('\taction: "%s" exporting...' % blenAction.name)
else:
print('\taction: "%s" has no armature using it, skipping' % blenAction.name)
continue
if blenAction is None:
# Warning, this only accounts for tmp_actions being [None]
file.write('\n\tTake: "Default Take" {')
act_start = start
act_end = end
else:
# use existing name
if blenAction == blenActionDefault: # have we already got the name
file.write('\n\tTake: "%s" {' % sane_name_mapping_take[blenAction.name])
else:
file.write('\n\tTake: "%s" {' % sane_takename(blenAction))
act_start, act_end = blenAction.frame_range
act_start = int(act_start)
act_end = int(act_end)
# Set the action active
for my_arm in ob_arms:
if my_arm.blenObject.animation_data and blenAction in my_arm.blenActionList:
my_arm.blenObject.animation_data.action = blenAction
# print('\t\tSetting Action!', blenAction)
# scene.update(1)
file.write('\n\t\tFileName: "Default_Take.tak"') # ??? - not sure why this is needed
file.write('\n\t\tLocalTime: %i,%i' % (fbx_time(act_start - 1), fbx_time(act_end - 1))) # ??? - not sure why this is needed
file.write('\n\t\tReferenceTime: %i,%i' % (fbx_time(act_start - 1), fbx_time(act_end - 1))) # ??? - not sure why this is needed
file.write('''
Campbell Barton
committed
;Models animation
;----------------------------------------------------''')
# set pose data for all bones
# do this here incase the action changes
'''
for my_bone in ob_bones:
my_bone.flushAnimData()
'''
i = act_start
while i <= act_end:
scene.frame_set(i)
for ob_generic in ob_anim_lists:
for my_ob in ob_generic:
#Blender.Window.RedrawAll()
if ob_generic == ob_meshes and my_ob.fbxArm:
# We cant animate armature meshes!
my_ob.setPoseFrame(i, fake=True)
else:
my_ob.setPoseFrame(i)
i += 1
#for bonename, bone, obname, me, armob in ob_bones:
for ob_generic in (ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms):
for my_ob in ob_generic:
if ob_generic == ob_meshes and my_ob.fbxArm:
# do nothing,
pass
else:
file.write('\n\t\tModel: "Model::%s" {' % my_ob.fbxName) # ??? - not sure why this is needed
file.write('\n\t\t\tVersion: 1.1')
file.write('\n\t\t\tChannel: "Transform" {')
context_bone_anim_mats = [(my_ob.getAnimParRelMatrix(frame), my_ob.getAnimParRelMatrixRot(frame)) for frame in range(act_start, act_end + 1)]
# ----------------
# ----------------
for TX_LAYER, TX_CHAN in enumerate('TRS'): # transform, rotate, scale
if TX_CHAN == 'T':
context_bone_anim_vecs = [mtx[0].to_translation() for mtx in context_bone_anim_mats]
elif TX_CHAN == 'S':
context_bone_anim_vecs = [mtx[0].to_scale() for mtx in context_bone_anim_mats]
elif TX_CHAN == 'R':
# Was....
# elif TX_CHAN=='R': context_bone_anim_vecs = [mtx[1].to_euler() 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].to_euler('XYZ', prev_eul)
else:
prev_eul = mtx[1].to_euler()
context_bone_anim_vecs.append(tuple_rad_to_deg(prev_eul))
file.write('\n\t\t\t\tChannel: "%s" {' % TX_CHAN) # translation
for i in range(3):
# Loop on each axis of the bone
file.write('\n\t\t\t\t\tChannel: "%s" {' % ('XYZ'[i])) # translation
file.write('\n\t\t\t\t\t\tDefault: %.15f' % context_bone_anim_vecs[0][i])
file.write('\n\t\t\t\t\t\tKeyVer: 4005')
if not ANIM_OPTIMIZE:
# Just write all frames, simple but in-eficient
file.write('\n\t\t\t\t\t\tKeyCount: %i' % (1 + act_end - act_start))
file.write('\n\t\t\t\t\t\tKey: ')
frame = act_start
while frame <= act_end:
if frame != act_start:
file.write(',')
# Curve types are 'C,n' for constant, 'L' for linear
# C,n is for bezier? - linear is best for now so we can do simple keyframe removal
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]))
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
#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:
del context_bone_anim_keys[j]
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
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
# better write one, otherwise we loose poses with no animation
file.write('\n\t\t\t\t\t\tKeyCount: 1')
file.write('\n\t\t\t\t\t\tKey: ')
file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(start), context_bone_anim_keys[0][0]))
else:
# We only need to write these if there is at least one
file.write('\n\t\t\t\t\t\tKeyCount: %i' % len(context_bone_anim_keys))
file.write('\n\t\t\t\t\t\tKey: ')
for val, frame in context_bone_anim_keys:
if frame != context_bone_anim_keys[0][1]: # not the first
file.write(',')
# frame is already one less then blenders frame
file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame), val))
if i == 0:
file.write('\n\t\t\t\t\t\tColor: 1,0,0')
elif i == 1:
file.write('\n\t\t\t\t\t\tColor: 0,1,0')
elif i == 2:
file.write('\n\t\t\t\t\t\tColor: 0,0,1')
file.write('\n\t\t\t\t\t}')
file.write('\n\t\t\t\t\tLayerType: %i' % (TX_LAYER + 1))
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
file.write('\n\t\t\t\t}')
# ---------------
file.write('\n\t\t\t}')
file.write('\n\t\t}')
# end the take
file.write('\n\t}')
# end action loop. set original actions
# do this after every loop incase actions effect eachother.
for my_arm in ob_arms:
if my_arm.blenObject.animation_data:
my_arm.blenObject.animation_data.action = my_arm.blenAction
file.write('\n}')
scene.frame_set(frame_orig)
else:
# no animation
file.write('\n;Takes and animation section')
file.write('\n;----------------------------------------------------')
file.write('\n')
file.write('\nTakes: {')
file.write('\n\tCurrent: ""')
file.write('\n}')
# write meshes animation
#for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
# Clear mesh data Only when writing with modifiers applied
for me in meshes_to_clear:
bpy.data.meshes.remove(me)
# --------------------------- Footer
if world:
m = world.mist_settings
has_mist = m.use_mist
mist_intense = m.intensity
mist_start = m.start
mist_end = m.depth
world_hor = world.horizon_color
else:
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
world_hor = 0, 0, 0
file.write('\n;Version 5 settings')
file.write('\n;------------------------------------------------------------------')
file.write('\n')
file.write('\nVersion5: {')
file.write('\n\tAmbientRenderSettings: {')
file.write('\n\t\tVersion: 101')
file.write('\n\t\tAmbientLightColor: %.1f,%.1f,%.1f,0' % tuple(world_amb))
file.write('\n\t}')
file.write('\n\tFogOptions: {')
file.write('\n\t\tFlogEnable: %i' % has_mist)
file.write('\n\t\tFogMode: 0')
file.write('\n\t\tFogDensity: %.3f' % mist_intense)
file.write('\n\t\tFogStart: %.3f' % mist_start)
file.write('\n\t\tFogEnd: %.3f' % mist_end)
file.write('\n\t\tFogColor: %.1f,%.1f,%.1f,1' % tuple(world_hor))
file.write('\n\t}')
file.write('\n\tSettings: {')
file.write('\n\t\tFrameRate: "%i"' % int(fps))
file.write('\n\t\tTimeFormat: 1')
file.write('\n\t\tSnapOnFrames: 0')
file.write('\n\t\tReferenceTimeIndex: -1')
file.write('\n\t\tTimeLineStartTime: %i' % fbx_time(start - 1))
file.write('\n\t\tTimeLineStopTime: %i' % fbx_time(end - 1))
file.write('\n\t}')
file.write('\n\tRendererSetting: {')
file.write('\n\t\tDefaultCamera: "Producer Perspective"')
file.write('\n\t\tDefaultViewingMode: 0')
file.write('\n\t}')
file.write('\n}')
file.write('\n')
# XXX, shouldnt be global!
for mapping in (sane_name_mapping_ob,
sane_name_mapping_ob_unique,
sane_name_mapping_mat,
sane_name_mapping_tex,
sane_name_mapping_take,
sane_name_mapping_group,
):
mapping.clear()
del mapping
ob_arms[:] = []
ob_bones[:] = []
ob_cameras[:] = []
ob_lights[:] = []
ob_meshes[:] = []
ob_null[:] = []
file.close()
# copy all collected files.
Campbell Barton
committed
bpy_extras.io_utils.path_reference_copy(copy_set)
print('export finished in %.4f sec.' % (time.clock() - start_time))
return {'FINISHED'}
filepath="",
use_selection=True,
batch_mode='OFF',
BATCH_OWN_DIR=False,
**kwargs
):
if bpy.ops.object.mode_set.poll():
bpy.ops.object.mode_set(mode='OBJECT')
if batch_mode == 'OFF':
kwargs_mod = kwargs.copy()
if use_selection:
kwargs_mod["context_objects"] = context.selected_objects
else:
kwargs_mod["context_objects"] = context.scene.objects
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
return save_single(operator, context.scene, filepath, **kwargs_mod)
else:
fbxpath = filepath
prefix = os.path.basename(fbxpath)
if prefix:
fbxpath = os.path.dirname(fbxpath)
if not fbxpath.endswith(os.sep):
fbxpath += os.sep
if batch_mode == 'GROUP':
data_seq = bpy.data.groups
else:
data_seq = bpy.data.scenes
# call this function within a loop with BATCH_ENABLE == False
# no scene switching done at the moment.
# orig_sce = context.scene
new_fbxpath = fbxpath # own dir option modifies, we need to keep an original
for data in data_seq: # scene or group
newname = prefix + bpy.path.clean_name(data.name)
if BATCH_OWN_DIR:
new_fbxpath = fbxpath + newname + os.sep
# path may already exist
# TODO - might exist but be a file. unlikely but should probably account for it.
if not os.path.exists(new_fbxpath):
os.makedirs(new_fbxpath)
filepath = new_fbxpath + newname + '.fbx'
print('\nBatch exporting %s as...\n\t%r' % (data, filepath))
# XXX don't know what to do with this, probably do the same? (Arystan)
if batch_mode == 'GROUP': # group
# group, so objects update properly, add a dummy scene.
scene = bpy.data.scenes.new(name="FBX_Temp")
scene.layers = [True] * 20
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
for ob_base in data.objects:
scene.objects.link(ob_base)
scene.update()
else:
scene = data
# 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 already usedt them
kwargs_batch = kwargs.copy()
kwargs_batch["context_objects"] = data.objects
save_single(operator, scene, filepath, **kwargs_batch)
if batch_mode == 'GROUP':
# remove temp group scene
bpy.data.scenes.remove(scene)
# no active scene changing!
# bpy.data.scenes.active = orig_sce
return {'FINISHED'} # so the script wont run after we have batch exported.
# 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 bpy.path.clean_name 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
# - uses bpy.path.abspath, *.relpath - replace at least relpath