Skip to content
Snippets Groups Projects
import_fbx.py 133 KiB
Newer Older
  • Learn to ignore specific revisions
  •     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
    
    
                # 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()
    
                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)
    
                    for (fbx_lnk_material, material, fbx_lnk_material_type) in connection_filter_reverse(fbx_lnk_uuid, b'Material'):
    
                        if material not in done_materials:
    
                            done_materials.add(material)
    
                # We have to validate mesh polygons' ma_idx, see T41015!
    
                # 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)
    
            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)))
    
                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
    
                    return
    
                node_texture.translation = loc
                node_texture.rotation = rot
                node_texture.scale = scale
    
    
            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':
    
                            # TODO displacement...
    
                            """
                        else:
                            print("WARNING: material link %r ignored" % lnk_type)
    
                        material_images.setdefault(material, {})[lnk_type] = image
    
    
            # 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)
    
                # 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)
    
                # 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()
    
        perfmon.step("FBX import: Cycles z-offset workaround...")
    
    
        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.cycles_visibility.shadow = False