Newer
Older
Bastien Montagne
committed
if fbx_item is None or not isinstance(fbx_item[1], Camera):
continue
cam = fbx_item[1]
items.append((cam, lnk_prop))
elif lnk_prop == b'DiffuseColor':
from bpy.types import Material
fbx_item = fbx_table_nodes.get(n_uuid, None)
if fbx_item is None or not isinstance(fbx_item[1], Material):
continue
mat = fbx_item[1]
items.append((mat, lnk_prop))
print("WARNING! Importing material's animation is not supported for Nodal materials...")
for al_uuid, al_ctype in fbx_connection_map.get(acn_uuid, ()):
if al_ctype.props[0] != b'OO':
continue
fbx_aldata, _blen_aldata = fbx_alitem = fbx_table_nodes.get(al_uuid, (None, None))
if fbx_aldata is None or fbx_aldata.id != b'AnimationLayer' or fbx_aldata.props[2] != b'':
continue
for as_uuid in get_astacks_from_alayer(al_uuid):
_fbx_alitem, anim_items = stacks[as_uuid][1][al_uuid]
assert(_fbx_alitem == fbx_alitem)
for item, item_prop in items:
# No need to keep curvenode FBX data here, contains nothing useful for us.
anim_items.setdefault(item, {})[acn_uuid] = (cnode, item_prop)
# AnimationCurves (real animation data).
for ac_uuid, fbx_acitem in fbx_table_nodes.items():
fbx_acdata, _blen_data = fbx_acitem
if fbx_acdata.id != b'AnimationCurve' or fbx_acdata.props[2] != b'':
for acn_uuid, acn_ctype in fbx_connection_map.get(ac_uuid, ()):
if acn_ctype.props[0] != b'OP':
continue
fbx_acndata, _bl_acndata = fbx_table_nodes.get(acn_uuid, (None, None))
if (fbx_acndata is None or fbx_acndata.id != b'AnimationCurveNode' or
fbx_acndata.props[2] != b'' or acn_uuid not in curvenodes):
continue
# Note this is an infamous simplification of the compound props stuff,
# seems to be standard naming but we'll probably have to be smarter to handle more exotic files?
Bastien Montagne
committed
channel = {
b'd|X': 0, b'd|Y': 1, b'd|Z': 2,
b'd|DeformPercent': 0,
b'd|FocalLength': 0
}.get(acn_ctype.props[3], None)
if channel is None:
continue
curvenodes[acn_uuid][ac_uuid] = (fbx_acitem, channel)
# And now that we have sorted all this, apply animations!
blen_read_animations(fbx_tmpl_astack, fbx_tmpl_alayer, stacks, scene, settings.anim_offset)
_(); del _
Bastien Montagne
committed
perfmon.step("FBX import: Assign materials...")
def _():
# link Material's to Geometry (via Model's)
for fbx_uuid, fbx_item in fbx_table_nodes.items():
fbx_obj, blen_data = fbx_item
if fbx_obj.id != b'Geometry':
continue
mesh = fbx_table_nodes.get(fbx_uuid, (None, None))[1]
# can happen in rare cases
if mesh is None:
continue
Bastien Montagne
committed
# In Blender, we link materials to data, typically (meshes), while in FBX they are linked to objects...
# So we have to be careful not to re-add endlessly the same material to a mesh!
# This can easily happen with 'baked' dupliobjects, see T44386.
# TODO: add an option to link materials to objects in Blender instead?
done_materials = set()
Bastien Montagne
committed
for (fbx_lnk, fbx_lnk_item, fbx_lnk_type) in connection_filter_forward(fbx_uuid, b'Model'):
# link materials
fbx_lnk_uuid = elem_uuid(fbx_lnk)
Bastien Montagne
committed
for (fbx_lnk_material, material, fbx_lnk_material_type) in connection_filter_reverse(fbx_lnk_uuid, b'Material'):
if material not in done_materials:
Bastien Montagne
committed
mesh.materials.append(material)
done_materials.add(material)
Bastien Montagne
committed
# We have to validate mesh polygons' ma_idx, see T41015!
Bastien Montagne
committed
# Some FBX seem to have an extra 'default' material which is not defined in FBX file.
if mesh.validate_material_indices():
print("WARNING: mesh '%s' had invalid material indices, those were reset to first material" % mesh.name)
_(); del _
Bastien Montagne
committed
perfmon.step("FBX import: Assign textures...")
Campbell Barton
committed
material_images = {}
fbx_tmpl = fbx_template_get((b'Material', b'KFbxSurfacePhong'))
# b'KFbxSurfaceLambert'
def texture_mapping_set(fbx_obj, node_texture):
assert(fbx_obj.id == b'Texture')
fbx_props = (elem_find_first(fbx_obj, b'Properties70'),
elem_find_first(fbx_tmpl, b'Properties70', fbx_elem_nil))
loc = elem_props_get_vector_3d(fbx_props, b'Translation', (0.0, 0.0, 0.0))
rot = tuple(-r for r in elem_props_get_vector_3d(fbx_props, b'Rotation', (0.0, 0.0, 0.0)))
scale = tuple(((1.0 / s) if s != 0.0 else 1.0)
for s in elem_props_get_vector_3d(fbx_props, b'Scaling', (1.0, 1.0, 1.0)))
Brecht Van Lommel
committed
clamp = (bool(elem_props_get_enum(fbx_props, b'WrapModeU', 0)) or
bool(elem_props_get_enum(fbx_props, b'WrapModeV', 0)))
if (loc == (0.0, 0.0, 0.0) and
rot == (0.0, 0.0, 0.0) and
scale == (1.0, 1.0, 1.0) and
Brecht Van Lommel
committed
clamp == False):
return
node_texture.translation = loc
node_texture.rotation = rot
node_texture.scale = scale
Brecht Van Lommel
committed
if clamp:
node_texture.extension = 'EXTEND'
for fbx_uuid, fbx_item in fbx_table_nodes.items():
fbx_obj, blen_data = fbx_item
if fbx_obj.id != b'Material':
continue
material = fbx_table_nodes.get(fbx_uuid, (None, None))[1]
for (fbx_lnk,
image,
fbx_lnk_type) in connection_filter_reverse(fbx_uuid, b'Texture'):
if fbx_lnk_type.props[0] == b'OP':
lnk_type = fbx_lnk_type.props[3]
ma_wrap = nodal_material_wrap_map[material]
if lnk_type in {b'DiffuseColor', b'3dsMax|maps|texmap_diffuse'}:
ma_wrap.base_color_texture.image = image
texture_mapping_set(fbx_lnk, ma_wrap.base_color_texture)
elif lnk_type in {b'SpecularColor', b'SpecularFactor'}:
# Intensity actually, not color...
ma_wrap.specular_texture.image = image
texture_mapping_set(fbx_lnk, ma_wrap.specular_texture)
elif lnk_type in {b'ReflectionColor', b'ReflectionFactor', b'3dsMax|maps|texmap_reflection'}:
# Intensity actually, not color...
ma_wrap.metallic_texture.image = image
texture_mapping_set(fbx_lnk, ma_wrap.metallic_texture)
elif lnk_type in {b'TransparentColor', b'TransparentFactor'}:
ma_wrap.alpha_texture.image = image
texture_mapping_set(fbx_lnk, ma_wrap.alpha_texture)
if use_alpha_decals:
material_decals.add(material)
elif lnk_type == b'ShininessExponent':
# That is probably reversed compared to expected results? TODO...
ma_wrap.roughness_texture.image = image
texture_mapping_set(fbx_lnk, ma_wrap.roughness_texture)
# XXX, applications abuse bump!
elif lnk_type in {b'NormalMap', b'Bump', b'3dsMax|maps|texmap_bump'}:
ma_wrap.normalmap_texture.image = image
texture_mapping_set(fbx_lnk, ma_wrap.normalmap_texture)
"""
elif lnk_type == b'Bump':
Bastien Montagne
committed
elif lnk_type in {b'EmissiveColor'}:
ma_wrap.emission_color_texture.image = image
texture_mapping_set(fbx_lnk, ma_wrap.emission_color_texture)
elif lnk_type in {b'EmissiveFactor'}:
ma_wrap.emission_strength_texture.image = image
texture_mapping_set(fbx_lnk, ma_wrap.emission_strength_texture)
else:
print("WARNING: material link %r ignored" % lnk_type)
Campbell Barton
committed
material_images.setdefault(material, {})[lnk_type] = image
Campbell Barton
committed
# Check if the diffuse image has an alpha channel,
# if so, use the alpha channel.
# Note: this could be made optional since images may have alpha but be entirely opaque
for fbx_uuid, fbx_item in fbx_table_nodes.items():
fbx_obj, blen_data = fbx_item
if fbx_obj.id != b'Material':
continue
material = fbx_table_nodes.get(fbx_uuid, (None, None))[1]
image = material_images.get(material, {}).get(b'DiffuseColor', None)
Campbell Barton
committed
# do we have alpha?
if image and image.depth == 32:
if use_alpha_decals:
material_decals.add(material)
ma_wrap = nodal_material_wrap_map[material]
ma_wrap.alpha_texture.use_alpha = True
ma_wrap.alpha_texture.copy_from(ma_wrap.base_color_texture)
Campbell Barton
committed
# Propagate mapping from diffuse to all other channels which have none defined.
# XXX Commenting for now, I do not really understand the logic here, why should diffuse mapping
# be applied to all others if not defined for them???
# ~ ma_wrap = nodal_material_wrap_map[material]
# ~ ma_wrap.mapping_set_from_diffuse()
_(); del _
Bastien Montagne
committed
perfmon.step("FBX import: Cycles z-offset workaround...")
Campbell Barton
committed
def _():
# Annoying workaround for cycles having no z-offset
if material_decals and use_alpha_decals:
for fbx_uuid, fbx_item in fbx_table_nodes.items():
fbx_obj, blen_data = fbx_item
if fbx_obj.id != b'Geometry':
continue
if fbx_obj.props[-1] == b'Mesh':
mesh = fbx_item[1]
if decal_offset != 0.0:
for material in mesh.materials:
if material in material_decals:
for v in mesh.vertices:
v.co += v.normal * decal_offset
break
for obj in (obj for obj in bpy.data.objects if obj.data == mesh):
obj.visible_shadow = False
Campbell Barton
committed
_(); del _
Bastien Montagne
committed
perfmon.level_down()
perfmon.level_down("Import finished.")
return {'FINISHED'}