* added some missing tooltips

* made name string cleaning function allow chars ,.()[]{} in fbx model names
* clamped export lamp intensity to 200
* each mesh only links to the image-textures it uses. (before it linked to ALL textures)
* added support for AllSame mapping, this means when a material or texture only uses one, a single mapping index can be given rather then a big list with the same value in it.
* improved material and texture mapping method
This commit is contained in:
Campbell Barton 2007-08-29 03:56:22 +00:00
parent 1e3b8dc5d7
commit 99493ef6d9

@ -72,6 +72,18 @@ import BPyMessages
import sys
## 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
del v, i
def copy_file(source, dest):
file = open(source, 'rb')
data = file.read()
@ -171,7 +183,8 @@ def sane_name(data, dct):
if not name:
name = 'unnamed' # blank string, ASKING FOR TROUBLE!
else:
name = BPySys.cleanName(name)
#name = BPySys.cleanName(name)
name = cleanName(name) # use our own
while name in dct.itervalues(): name = increment_string(name)
@ -284,6 +297,7 @@ def write(filename, batch_objects = None, \
for data in data_seq: # scene or group
newname = BATCH_FILE_PREFIX + BPySys.cleanName(data.name)
if BATCH_OWN_DIR:
new_fbxpath = fbxpath + newname + Blender.sys.sep
# path may alredy exist
@ -345,9 +359,6 @@ def write(filename, batch_objects = None, \
# end batch support
# ----------------------------------------------
# storage classes
class my_bone_class:
@ -941,11 +952,11 @@ def write(filename, batch_objects = None, \
file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0')
file.write('\n\t\t\tProperty: "GoboProperty", "object", ""')
file.write('\n\t\t\tProperty: "Color", "Color", "A+",1,1,1')
file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (light.energy*100))
file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200
file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % light.spotSize)
file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50')
file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.col))
file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (light.energy*100))
file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200
file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % light.spotSize)
file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50')
file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type)
@ -973,14 +984,21 @@ def write(filename, batch_objects = None, \
file.write('\n\t\tGeometryVersion: 124')
file.write('\n\t}')
def write_null(my_null, fbxName = None):
# matrixOnly is not used at the moment
def write_null(my_null = None, fbxName = None, matrixOnly = None):
# ob can be null
if not fbxName: fbxName = my_null.fbxName
file.write('\n\tModel: "Model::%s", "Null" {' % fbxName)
file.write('\n\t\tVersion: 232')
if my_null: write_object_props(my_null.blenObject)
else: write_object_props()
# only use this for the root matrix at the moment
if matrixOnly:
write_object_props(None, None, matrixOnly)
else: # all other Null's
if my_null: write_object_props(my_null.blenObject)
else: write_object_props()
file.write('''
}
@ -1251,6 +1269,15 @@ def write(filename, batch_objects = None, \
#def write_mesh(obname, ob, mtx, me, mats, arm, armname):
def write_mesh(my_mesh):
# if there are non NULL materials on this mesh
if [mat for mat in my_mesh.blenMaterials if mat]: do_materials = True
else: do_materials = False
if my_mesh.blenTextures: do_textures = True
else: do_textures = False
file.write('\n\tModel: "Model::%s", "Mesh" {' % my_mesh.fbxName)
file.write('\n\t\tVersion: 232') # newline is added in write_object_props
@ -1441,32 +1468,47 @@ def write(filename, batch_objects = None, \
file.write('\n\t\t}')
if textures:
if do_textures:
file.write('\n\t\tLayerElementTexture: %i {' % uvindex)
file.write('\n\t\t\tVersion: 101')
file.write('\n\t\t\tName: "%s"' % uvlayer)
file.write('''
MappingInformationType: "ByPolygon"
ReferenceInformationType: "IndexToDirect"
BlendMode: "Translucent"
TextureAlpha: 1
TextureId: ''')
i=-1
for f in me.faces:
img_key = f.image
if img_key: img_key = img_key.name
if len(my_mesh.blenTextures) == 1:
file.write('\n\t\t\tMappingInformationType: "AllSame"')
else:
file.write('\n\t\t\tMappingInformationType: "ByPolygon"')
file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"')
file.write('\n\t\t\tBlendMode: "Translucent"')
file.write('\n\t\t\tTextureAlpha: 1')
file.write('\n\t\t\tTextureId: ')
if len(my_mesh.blenTextures) == 1:
file.write('0')
else:
#texture_mapping_local = {None:0}
texture_mapping_local = {None:-1}
if i==-1:
i=0
file.write( '%s' % texture_mapping_local[img_key])
else:
if i==55:
file.write('\n ')
i=0
i = 0 # 1 for dummy
for tex in my_mesh.blenTextures:
texture_mapping_local[tex] = i
i+=1
i=-1
for f in me.faces:
img_key = f.image
file.write(',%s' % texture_mapping_local[img_key])
i+=1
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
else:
file.write('''
LayerElementTexture: 0 {
@ -1483,47 +1525,50 @@ def write(filename, batch_objects = None, \
# Done with UV/textures.
if materials:
file.write('''
LayerElementMaterial: 0 {
Version: 101
Name: ""
MappingInformationType: "ByPolygon"
ReferenceInformationType: "IndexToDirect"
Materials: ''')
if do_materials:
file.write('\n\t\tLayerElementMaterial: 0 {')
file.write('\n\t\t\tVersion: 101')
file.write('\n\t\t\tName: ""')
# Build a material mapping for this
material_mapping_local = [-1] * 16 # local-index : global index.
i= 0
for j, mat in enumerate(my_mesh.blenMaterials):
if mat:
material_mapping_local[j] = i
i+=1
# else leave as -1
if len(my_mesh.blenMaterials) == 1:
file.write('\n\t\t\tMappingInformationType: "AllSame"')
else:
file.write('\n\t\t\tMappingInformationType: "ByPolygon"')
if not material_mapping_local:
material_mapping_local[0] = 0
file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"')
file.write('\n\t\t\tMaterials: ')
len_material_mapping_local = len(material_mapping_local)
i=-1
for f in me.faces:
f_mat = f.mat
if f_mat >= len_material_mapping_local:
f_mat = 0
if len(my_mesh.blenMaterials) == 1:
file.write('0')
else:
# Build a material mapping for this
#material_mapping_local = [0] * 16 # local-index : global index.
material_mapping_local = [-1] * 16 # local-index : global index.
i= 0 # 1
for j, mat in enumerate(my_mesh.blenMaterials):
if mat:
material_mapping_local[j] = i
i+=1
# else leave as -1
if i==-1:
i=0
file.write( '%s' % (material_mapping_local[f_mat]))
#file.write( '%s' % -1)
else:
if i==55:
file.write('\n\t\t\t\t')
i=0
len_material_mapping_local = len(material_mapping_local)
i=-1
for f in me.faces:
f_mat = f.mat
if f_mat >= len_material_mapping_local:
f_mat = 0
file.write(',%s' % (material_mapping_local[f_mat]))
#file.write(',%s' % -1)
i+=1
if i==-1:
i=0
file.write( '%s' % (material_mapping_local[f_mat]))
else:
if i==55:
file.write('\n\t\t\t\t')
i=0
file.write(',%s' % (material_mapping_local[f_mat]))
i+=1
file.write('\n\t\t}')
@ -1535,7 +1580,7 @@ def write(filename, batch_objects = None, \
TypedIndex: 0
}''')
if materials:
if do_materials:
file.write('''
LayerElement: {
Type: "LayerElementMaterial"
@ -1543,7 +1588,7 @@ def write(filename, batch_objects = None, \
}''')
# Always write this
if textures:
if do_textures:
file.write('''
LayerElement: {
Type: "LayerElementTexture"
@ -1580,7 +1625,7 @@ def write(filename, batch_objects = None, \
file.write('\n\t\t\t\tTypedIndex: %i' % i)
file.write('\n\t\t\t}')
if textures:
if do_textures:
file.write('''
LayerElement: {
@ -1719,15 +1764,16 @@ def write(filename, batch_objects = None, \
for mat in mats:
# 2.44 use mat.lib too for uniqueness
if mat: materials[mat.name] = mat
if mat: materials[mat] = mat
texture_mapping_local = {}
if me.faceUV:
uvlayer_orig = me.activeUVLayer
for uvlayer in me.getUVLayerNames():
me.activeUVLayer = uvlayer
for f in me.faces:
img = f.image
if img: textures[img.name] = img
textures[img] = texture_mapping_local[img] = img
me.activeUVLayer = uvlayer_orig
@ -1757,6 +1803,12 @@ def write(filename, batch_objects = None, \
my_mesh = my_object_generic(ob)
my_mesh.blenData = me
my_mesh.blenMaterials = mats
my_mesh.blenTextures = texture_mapping_local.values()
# if only 1 null texture then empty the list
if len(my_mesh.blenTextures) == 1 and my_mesh.blenTextures[0] == None:
my_mesh.blenTextures = []
my_mesh.fbxArm = armob # replace with my_object_generic armature instance later
my_mesh.fbxBoneParent = blenParentBoneName # replace with my_bone instance later
@ -1835,29 +1887,11 @@ def write(filename, batch_objects = None, \
del my_bone_blenParent
materials = [(sane_matname(mat), mat) for mat in materials.itervalues()]
textures = [(sane_texname(img), img) for img in textures.itervalues()]
materials = [(sane_matname(mat), mat) for mat in materials.itervalues() if mat]
textures = [(sane_texname(img), img) for img in textures.itervalues() if img]
materials.sort() # sort by name
textures.sort()
if not materials:
materials = [('null', None)]
material_mapping = {} # blen name : index
if textures:
texture_mapping_local = {None:-1} # ditto
i = 0
for texname, tex in textures:
texture_mapping_local[tex.name] = i
i+=1
#textures.insert(0, ('_empty_', None))
i = 0
for matname, mat in materials:
if mat: mat = mat.name
material_mapping[mat] = i
i+=1
camera_count = 8
file.write('''
@ -1955,7 +1989,7 @@ Objects: {''')
write_camera_switch()
# Write the null object
write_null(None, 'blend_root')
write_null(None, 'blend_root')# , GLOBAL_MATRIX)
for my_null in ob_null:
write_null(my_null)
@ -1971,7 +2005,6 @@ Objects: {''')
write_light(my_light)
for my_mesh in ob_meshes:
#write_mesh(obname, ob, mtx, me, mats, arm, armname)
write_mesh(my_mesh)
#for bonename, bone, obname, me, armob in ob_bones:
@ -2159,16 +2192,21 @@ Connections: {''')
for my_light in ob_lights:
file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_light.fbxName)
for my_mesh in ob_meshes:
# Connect all materials to all objects, not good form but ok for now.
for mat in my_mesh.blenMaterials:
if mat:
file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat.name], my_mesh.fbxName))
if materials:
for my_mesh in ob_meshes:
# Connect all materials to all objects, not good form but ok for now.
for mat in my_mesh.blenMaterials:
if mat:
file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat.name], my_mesh.fbxName))
if textures:
for my_mesh in ob_meshes:
for texname, tex in textures:
file.write('\n\tConnect: "OO", "Texture::%s", "Model::%s"' % (texname, my_mesh.fbxName))
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))
@ -2634,10 +2672,10 @@ def fbx_ui():
Draw.EndAlign()
Draw.BeginAlign()
GLOBALS['_SCALE'] = Draw.Number('Scale:', EVENT_NONE, x+20, y+120, 140, 20, GLOBALS['_SCALE'].val, 0.01, 1000.0, 'Export empty objects')
GLOBALS['_XROT90'] = Draw.Toggle('Rot X90', EVENT_NONE, x+160, y+120, 60, 20, GLOBALS['_XROT90'].val, 'Export empty objects')
GLOBALS['_YROT90'] = Draw.Toggle('Rot Y90', EVENT_NONE, x+220, y+120, 60, 20, GLOBALS['_YROT90'].val, 'Export empty objects')
GLOBALS['_ZROT90'] = Draw.Toggle('Rot Z90', EVENT_NONE, x+280, y+120, 60, 20, GLOBALS['_ZROT90'].val, 'Export empty objects')
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')
Draw.EndAlign()
y -= 35