FBX io: more cleanup.
* Rework unit conversion system to avoid dict lookup each time, also use it in import; * Optimize a bit by removing some double-dict-lookups; * Add basic timing info to importer as well.
This commit is contained in:
parent
a1d1012a0c
commit
fbce6598ea
|
@ -59,7 +59,7 @@ from .fbx_utils import (
|
|||
FBX_LIGHT_TYPES, FBX_LIGHT_DECAY_TYPES,
|
||||
RIGHT_HAND_AXES, FBX_FRAMERATES,
|
||||
# Miscellaneous utils.
|
||||
units_convert, units_convert_iter, matrix_to_array, similar_values,
|
||||
units_convertor, units_convertor_iter, matrix4_to_array, similar_values,
|
||||
# UUID from key.
|
||||
get_fbx_uuid_from_key,
|
||||
# Key generators.
|
||||
|
@ -87,6 +87,16 @@ from .fbx_utils import (
|
|||
FBXSettingsMedia, FBXSettings, FBXData,
|
||||
)
|
||||
|
||||
# Units convertors!
|
||||
convert_sec_to_ktime = units_convertor("second", "ktime")
|
||||
convert_sec_to_ktime_iter = units_convertor_iter("second", "ktime")
|
||||
|
||||
convert_mm_to_inch = units_convertor("millimeter", "inch")
|
||||
|
||||
convert_rad_to_deg = units_convertor("radian", "degree")
|
||||
convert_rad_to_deg_iter = units_convertor_iter("radian", "degree")
|
||||
|
||||
|
||||
##### Templates #####
|
||||
# TODO: check all those "default" values, they should match Blender's default as much as possible, I guess?
|
||||
|
||||
|
@ -609,8 +619,8 @@ def fbx_data_camera_elements(root, cam_obj, scene_data):
|
|||
height = render.resolution_y
|
||||
aspect = width / height
|
||||
# Film width & height from mm to inches
|
||||
filmwidth = units_convert(cam_data.sensor_width, "millimeter", "inch")
|
||||
filmheight = units_convert(cam_data.sensor_height, "millimeter", "inch")
|
||||
filmwidth = convert_mm_to_inch(cam_data.sensor_width)
|
||||
filmheight = convert_mm_to_inch(cam_data.sensor_height)
|
||||
filmaspect = filmwidth / filmheight
|
||||
# Film offset
|
||||
offsetx = filmwidth * cam_data.shift_x
|
||||
|
@ -967,9 +977,8 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
|
|||
del _uvtuples_gen
|
||||
|
||||
# Face's materials.
|
||||
me_fbxmats_idx = None
|
||||
if me in scene_data.mesh_mat_indices:
|
||||
me_fbxmats_idx = scene_data.mesh_mat_indices[me]
|
||||
me_fbxmats_idx = scene_data.mesh_mat_indices.get(me)
|
||||
if me_fbxmats_idx is not None:
|
||||
me_blmats = me.materials
|
||||
if me_fbxmats_idx and me_blmats:
|
||||
lay_mat = elem_data_single_int32(geom, b"LayerElementMaterial", 0)
|
||||
|
@ -1284,7 +1293,7 @@ def fbx_data_armature_elements(root, arm_obj, scene_data):
|
|||
mat_world_obj = ob_obj.fbx_object_matrix(scene_data, global_space=True)
|
||||
fbx_posenode = elem_empty(fbx_pose, b"PoseNode")
|
||||
elem_data_single_int64(fbx_posenode, b"Node", ob_obj.fbx_uuid)
|
||||
elem_data_single_float64_array(fbx_posenode, b"Matrix", matrix_to_array(mat_world_obj))
|
||||
elem_data_single_float64_array(fbx_posenode, b"Matrix", matrix4_to_array(mat_world_obj))
|
||||
# And all bones of armature!
|
||||
mat_world_bones = {}
|
||||
for bo_obj in bones:
|
||||
|
@ -1292,7 +1301,7 @@ def fbx_data_armature_elements(root, arm_obj, scene_data):
|
|||
mat_world_bones[bo_obj] = bomat
|
||||
fbx_posenode = elem_empty(fbx_pose, b"PoseNode")
|
||||
elem_data_single_int64(fbx_posenode, b"Node", bo_obj.fbx_uuid)
|
||||
elem_data_single_float64_array(fbx_posenode, b"Matrix", matrix_to_array(bomat))
|
||||
elem_data_single_float64_array(fbx_posenode, b"Matrix", matrix4_to_array(bomat))
|
||||
|
||||
# Deformer.
|
||||
fbx_skin = elem_data_single_int64(root, b"Deformer", get_fbx_uuid_from_key(skin_key))
|
||||
|
@ -1341,9 +1350,9 @@ def fbx_data_armature_elements(root, arm_obj, scene_data):
|
|||
# http://area.autodesk.com/forum/autodesk-fbx/fbx-sdk/why-the-values-return-
|
||||
# by-fbxcluster-gettransformmatrix-x-not-same-with-the-value-in-ascii-fbx-file/
|
||||
elem_data_single_float64_array(fbx_clstr, b"Transform",
|
||||
matrix_to_array(mat_world_bones[bo_obj].inverted() * mat_world_obj))
|
||||
elem_data_single_float64_array(fbx_clstr, b"TransformLink", matrix_to_array(mat_world_bones[bo_obj]))
|
||||
elem_data_single_float64_array(fbx_clstr, b"TransformAssociateModel", matrix_to_array(mat_world_arm))
|
||||
matrix4_to_array(mat_world_bones[bo_obj].inverted() * mat_world_obj))
|
||||
elem_data_single_float64_array(fbx_clstr, b"TransformLink", matrix4_to_array(mat_world_bones[bo_obj]))
|
||||
elem_data_single_float64_array(fbx_clstr, b"TransformAssociateModel", matrix4_to_array(mat_world_arm))
|
||||
|
||||
|
||||
def fbx_data_object_elements(root, ob_obj, scene_data):
|
||||
|
@ -1368,7 +1377,7 @@ def fbx_data_object_elements(root, ob_obj, scene_data):
|
|||
|
||||
# Object transform info.
|
||||
loc, rot, scale, matrix, matrix_rot = ob_obj.fbx_object_tx(scene_data)
|
||||
rot = tuple(units_convert_iter(rot, "radian", "degree"))
|
||||
rot = tuple(convert_rad_to_deg_iter(rot))
|
||||
|
||||
tmpl = elem_props_template_init(scene_data.templates, b"Model")
|
||||
# For now add only loc/rot/scale...
|
||||
|
@ -1423,7 +1432,7 @@ def fbx_data_animation_elements(root, scene_data):
|
|||
fps = scene.render.fps / scene.render.fps_base
|
||||
|
||||
def keys_to_ktimes(keys):
|
||||
return (int(v) for v in units_convert_iter((f / fps for f, _v in keys), "second", "ktime"))
|
||||
return (int(v) for v in convert_sec_to_ktime_iter((f / fps for f, _v in keys)))
|
||||
|
||||
# Animation stacks.
|
||||
for astack_key, alayers, alayer_key, name, f_start, f_end in animations:
|
||||
|
@ -1435,8 +1444,8 @@ def fbx_data_animation_elements(root, scene_data):
|
|||
astack_props = elem_properties(astack)
|
||||
r = scene_data.scene.render
|
||||
fps = r.fps / r.fps_base
|
||||
start = int(units_convert(f_start / fps, "second", "ktime"))
|
||||
end = int(units_convert(f_end / fps, "second", "ktime"))
|
||||
start = int(convert_sec_to_ktime(f_start / fps))
|
||||
end = int(convert_sec_to_ktime(f_end / fps))
|
||||
elem_props_template_set(astack_tmpl, astack_props, "p_timestamp", b"LocalStart", start)
|
||||
elem_props_template_set(astack_tmpl, astack_props, "p_timestamp", b"LocalStop", end)
|
||||
elem_props_template_set(astack_tmpl, astack_props, "p_timestamp", b"ReferenceStart", start)
|
||||
|
@ -1699,7 +1708,7 @@ def fbx_animations_objects_do(scene_data, ref_id, f_start, f_end, start_zero, ob
|
|||
p_rot = p_rots.get(ob_obj, None)
|
||||
loc, rot, scale, _m, _mr = ob_obj.fbx_object_tx(scene_data, rot_euler_compat=p_rot)
|
||||
p_rots[ob_obj] = rot
|
||||
tx = tuple(loc) + tuple(units_convert_iter(rot, "radian", "degree")) + tuple(scale)
|
||||
tx = tuple(loc) + tuple(convert_rad_to_deg_iter(rot)) + tuple(scale)
|
||||
animdata[ob_obj].append((real_currframe, tx, [False] * len(tx)))
|
||||
for ob_obj in objects:
|
||||
ob_obj.dupli_list_clear()
|
||||
|
@ -1725,7 +1734,7 @@ def fbx_animations_objects_do(scene_data, ref_id, f_start, f_end, start_zero, ob
|
|||
# Get PoseBone from bone...
|
||||
#tobj = bone_map[obj] if isinstance(obj, Bone) else obj
|
||||
#loc, rot, scale, _m, _mr = fbx_object_tx(scene_data, tobj)
|
||||
#tx = tuple(loc) + tuple(units_convert_iter(rot, "radian", "degree")) + tuple(scale)
|
||||
#tx = tuple(loc) + tuple(convert_rad_to_deg_iter(rot)) + tuple(scale)
|
||||
dtx = (0.0, 0.0, 0.0) + (0.0, 0.0, 0.0) + (1.0, 1.0, 1.0)
|
||||
# If animation for a channel, (True, keyframes), else (False, current value).
|
||||
final_keys = OrderedDict()
|
||||
|
@ -1980,8 +1989,9 @@ def fbx_data_from_scene(scene, settings):
|
|||
# We support any kind of 'surface' shader though, better to have some kind of default Lambert than nothing.
|
||||
# TODO: Support nodes (*BIG* todo!).
|
||||
if mat.type in {'SURFACE'} and not mat.use_nodes:
|
||||
if mat in data_materials:
|
||||
data_materials[mat][1].append(ob_obj)
|
||||
mat_data = data_materials.get(mat)
|
||||
if mat_data is not None:
|
||||
mat_data[1].append(ob_obj)
|
||||
else:
|
||||
data_materials[mat] = (get_blenderID_key(mat), [ob_obj])
|
||||
|
||||
|
@ -2009,12 +2019,14 @@ def fbx_data_from_scene(scene, settings):
|
|||
tex_fbx_props = fbx_mat_properties_from_texture(tex)
|
||||
if not tex_fbx_props:
|
||||
continue
|
||||
if tex in data_textures:
|
||||
data_textures[tex][1][mat] = tex_fbx_props
|
||||
tex_data = data_textures.get(tex)
|
||||
if tex_data is not None:
|
||||
tex_data[1][mat] = tex_fbx_props
|
||||
else:
|
||||
data_textures[tex] = (get_blenderID_key(tex), OrderedDict(((mat, tex_fbx_props),)))
|
||||
if img in data_videos:
|
||||
data_videos[img][1].append(tex)
|
||||
vid_data = data_videos.get(img)
|
||||
if vid_data is not None:
|
||||
vid_data[1].append(tex)
|
||||
else:
|
||||
data_videos[img] = (get_blenderID_key(img), [tex])
|
||||
|
||||
|
@ -2461,8 +2473,8 @@ def fbx_takes_elements(root, scene_data):
|
|||
for astack_key, animations, alayer_key, name, f_start, f_end in animations:
|
||||
scene = scene_data.scene
|
||||
fps = scene.render.fps / scene.render.fps_base
|
||||
start_ktime = int(units_convert(f_start / fps, "second", "ktime"))
|
||||
end_ktime = int(units_convert(f_end / fps, "second", "ktime")) # +1 is unity hack...
|
||||
start_ktime = int(convert_sec_to_ktime(f_start / fps))
|
||||
end_ktime = int(convert_sec_to_ktime(f_end / fps))
|
||||
|
||||
take = elem_data_single_string(takes, b"Take", name)
|
||||
elem_data_single_string(take, b"FileName", name + b".tak")
|
||||
|
|
|
@ -159,24 +159,33 @@ UNITS = {
|
|||
}
|
||||
|
||||
|
||||
def units_convert(val, u_from, u_to):
|
||||
"""Convert value."""
|
||||
def units_convertor(u_from, u_to):
|
||||
"""Return a convertor between specified units."""
|
||||
conv = UNITS[u_to] / UNITS[u_from]
|
||||
return val * conv
|
||||
return lambda v: v * conv
|
||||
|
||||
|
||||
def units_convert_iter(it, u_from, u_to):
|
||||
"""Convert value."""
|
||||
conv = UNITS[u_to] / UNITS[u_from]
|
||||
return (v * conv for v in it)
|
||||
def units_convertor_iter(u_from, u_to):
|
||||
"""Return an iterable convertor between specified units."""
|
||||
conv = units_convertor(u_from, u_to)
|
||||
def convertor(it):
|
||||
for v in it:
|
||||
yield(conv(v))
|
||||
return convertor
|
||||
|
||||
|
||||
def matrix_to_array(mat):
|
||||
def matrix4_to_array(mat):
|
||||
"""Concatenate matrix's columns into a single, flat tuple"""
|
||||
# blender matrix is row major, fbx is col major so transpose on write
|
||||
return tuple(f for v in mat.transposed() for f in v)
|
||||
|
||||
|
||||
def array_to_matrix4(arr):
|
||||
"""Convert a single 16-len tuple into a valid 4D Blender matrix"""
|
||||
# Blender matrix is row major, fbx is col major so transpose on read
|
||||
return Matrix(tuple(zip(*[iter(arr)]*4))).transposed()
|
||||
|
||||
|
||||
def similar_values(v1, v2, e=1e-6):
|
||||
"""Return True if v1 and v2 are nearly the same."""
|
||||
if v1 == v2:
|
||||
|
@ -184,6 +193,16 @@ def similar_values(v1, v2, e=1e-6):
|
|||
return ((abs(v1 - v2) / max(abs(v1), abs(v2))) <= e)
|
||||
|
||||
|
||||
def similar_values_iter(v1, v2, e=1e-6):
|
||||
"""Return True if iterables v1 and v2 are nearly the same."""
|
||||
if v1 == v2:
|
||||
return True
|
||||
for v1, v2 in zip(v1, v2):
|
||||
if (abs(v1 - v2) / max(abs(v1), abs(v2))) > e:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
##### UIDs code. #####
|
||||
|
||||
# ID class (mere int).
|
||||
|
@ -489,13 +508,13 @@ def elem_props_template_init(templates, template_type):
|
|||
"""
|
||||
Init a writing template of given type, for *one* element's properties.
|
||||
"""
|
||||
ret = None
|
||||
if template_type in templates:
|
||||
tmpl = templates[template_type]
|
||||
ret = OrderedDict()
|
||||
tmpl = templates.get(template_type)
|
||||
if tmpl is not None:
|
||||
written = tmpl.written[0]
|
||||
props = tmpl.properties
|
||||
ret = OrderedDict((name, [val, ptype, anim, written]) for name, (val, ptype, anim) in props.items())
|
||||
return ret or OrderedDict()
|
||||
return ret
|
||||
|
||||
|
||||
def elem_props_template_set(template, elem, ptype_name, name, value, animatable=False):
|
||||
|
@ -547,11 +566,12 @@ def fbx_templates_generate(root, fbx_templates):
|
|||
|
||||
templates = OrderedDict()
|
||||
for type_name, prop_type_name, properties, nbr_users, _written in fbx_templates.values():
|
||||
if type_name not in templates:
|
||||
tmpl = templates.get(type_name)
|
||||
if tmpl is None:
|
||||
templates[type_name] = [OrderedDict(((prop_type_name, (properties, nbr_users)),)), nbr_users]
|
||||
else:
|
||||
templates[type_name][0][prop_type_name] = (properties, nbr_users)
|
||||
templates[type_name][1] += nbr_users
|
||||
tmpl[0][prop_type_name] = (properties, nbr_users)
|
||||
tmpl[1] += nbr_users
|
||||
|
||||
for type_name, (subprops, nbr_users) in templates.items():
|
||||
template = elem_data_single_string(root, b"ObjectType", type_name)
|
||||
|
@ -612,8 +632,8 @@ class MetaObjectWrapper(type):
|
|||
cache = getattr(cls, "_cache", None)
|
||||
if cache is None:
|
||||
cache = cls._cache = {}
|
||||
if key in cache:
|
||||
instance = cache[key]
|
||||
instance = cache.get(key)
|
||||
if instance is not None:
|
||||
# Duplis hack: since duplis are not persistent in Blender (we have to re-create them to get updated
|
||||
# info like matrix...), we *always* need to reset that matrix when calling ObjectWrapper() (all
|
||||
# other data is supposed valid during whole cache live, so we can skip resetting it).
|
||||
|
|
|
@ -34,18 +34,21 @@ import bpy
|
|||
|
||||
# -----
|
||||
# Utils
|
||||
from . import parse_fbx
|
||||
from . import parse_fbx, fbx_utils
|
||||
|
||||
from .parse_fbx import data_types, FBXElem
|
||||
from .fbx_utils import (
|
||||
units_convertor_iter,
|
||||
array_to_matrix4,
|
||||
similar_values,
|
||||
similar_values_iter,
|
||||
)
|
||||
|
||||
# global singleton, assign on execution
|
||||
fbx_elem_nil = None
|
||||
|
||||
|
||||
def tuple_deg_to_rad(eul):
|
||||
return (eul[0] / 57.295779513,
|
||||
eul[1] / 57.295779513,
|
||||
eul[2] / 57.295779513)
|
||||
# Units convertors...
|
||||
convert_deg_to_rad_iter = units_convertor_iter("degree", "radian")
|
||||
|
||||
|
||||
def elem_find_first(elem, id_search, default=None):
|
||||
|
@ -95,6 +98,13 @@ def elem_split_name_class(elem):
|
|||
return elem_name, elem_class
|
||||
|
||||
|
||||
def elem_name_ensure_class(elem, clss=...):
|
||||
elem_name, elem_class = elem_split_name_class(elem)
|
||||
if clss is not ...:
|
||||
assert(elem_class == clss)
|
||||
return elem_name.decode('utf-8')
|
||||
|
||||
|
||||
def elem_split_name_class_nodeattr(elem):
|
||||
assert(elem.props_type[-2] == data_types.STRING)
|
||||
elem_name, elem_class = elem.props[-2].split(b'\x00\x01')
|
||||
|
@ -109,8 +119,8 @@ def elem_uuid(elem):
|
|||
return elem.props[0]
|
||||
|
||||
|
||||
def elem_prop_first(elem):
|
||||
return elem.props[0] if (elem is not None) and elem.props else None
|
||||
def elem_prop_first(elem, default=None):
|
||||
return elem.props[0] if (elem is not None) and elem.props else default
|
||||
|
||||
|
||||
# ----
|
||||
|
@ -317,9 +327,9 @@ def blen_read_object(fbx_tmpl, fbx_obj, object_data):
|
|||
rot_alt_mat = Matrix()
|
||||
|
||||
# rotation
|
||||
lcl_rot = Euler(tuple_deg_to_rad(rot), rot_ord).to_matrix().to_4x4() * rot_alt_mat
|
||||
pre_rot = Euler(tuple_deg_to_rad(pre_rot), rot_ord).to_matrix().to_4x4()
|
||||
pst_rot = Euler(tuple_deg_to_rad(pst_rot), rot_ord).to_matrix().to_4x4()
|
||||
lcl_rot = Euler(convert_deg_to_rad_iter(rot), rot_ord).to_matrix().to_4x4() * rot_alt_mat
|
||||
pre_rot = Euler(convert_deg_to_rad_iter(pre_rot), rot_ord).to_matrix().to_4x4()
|
||||
pst_rot = Euler(convert_deg_to_rad_iter(pst_rot), rot_ord).to_matrix().to_4x4()
|
||||
|
||||
rot_ofs = Matrix.Translation(rot_ofs)
|
||||
rot_piv = Matrix.Translation(rot_piv)
|
||||
|
@ -646,9 +656,7 @@ def blen_read_geom_layer_normal(fbx_obj, mesh):
|
|||
|
||||
def blen_read_geom(fbx_tmpl, fbx_obj):
|
||||
# TODO, use 'fbx_tmpl'
|
||||
elem_name, elem_class = elem_split_name_class(fbx_obj)
|
||||
assert(elem_class == b'Geometry')
|
||||
elem_name_utf8 = elem_name.decode('utf-8')
|
||||
elem_name_utf8 = elem_name_ensure_class(fbx_obj, b'Geometry')
|
||||
|
||||
fbx_verts = elem_prop_first(elem_find_first(fbx_obj, b'Vertices'))
|
||||
fbx_polys = elem_prop_first(elem_find_first(fbx_obj, b'PolygonVertexIndex'))
|
||||
|
@ -733,14 +741,45 @@ def blen_read_geom(fbx_tmpl, fbx_obj):
|
|||
return mesh
|
||||
|
||||
|
||||
def blen_read_shape(fbx_tmpl, fbx_sdata, fbx_bcdata, meshes, scene, global_matrix):
|
||||
from mathutils import Vector
|
||||
|
||||
elem_name_utf8 = elem_name_ensure_class(fbx_sdata, b'Geometry')
|
||||
indices = elem_prop_first(elem_find_first(fbx_sdata, b'Indexes'), default=())
|
||||
dvcos = tuple(co for co in zip(*[iter(elem_prop_first(elem_find_first(fbx_sdata, b'Vertices'), default=()))] * 3))
|
||||
# We completely ignore normals here!
|
||||
weight = elem_prop_first(elem_find_first(fbx_bcdata, b'DeformPercent'), default=100.0) / 100.0
|
||||
vgweights = tuple(vgw / 100.0 for vgw in elem_prop_first(elem_find_first(fbx_bcdata, b'FullWeights'), default=()))
|
||||
|
||||
assert(len(vgweights) == len(indices) == len(dvcos))
|
||||
create_vg = bool(set(vgweights) - {1.0})
|
||||
|
||||
for me, objects in meshes:
|
||||
vcos = tuple((idx, me.vertices[idx].co + Vector(dvco)) for idx, dvco in zip(indices, dvcos))
|
||||
objects = list({blen_o for fbx_o, blen_o in objects})
|
||||
assert(objects)
|
||||
|
||||
if me.shape_keys is None:
|
||||
objects[0].shape_key_add(name="Basis", from_mix=False)
|
||||
objects[0].shape_key_add(name=elem_name_utf8, from_mix=False)
|
||||
me.shape_keys.use_relative = True # Should already be set as such.
|
||||
|
||||
kb = me.shape_keys.key_blocks[elem_name_utf8]
|
||||
for idx, co in vcos:
|
||||
kb.data[idx].co[:] = co
|
||||
kb.value = weight
|
||||
|
||||
# Add vgroup if necessary.
|
||||
if create_vg:
|
||||
add_vgroup_to_objects(indices, vgweights, elem_name_utf8, objects)
|
||||
kb.vertex_group = elem_name_utf8
|
||||
|
||||
|
||||
# --------
|
||||
# Material
|
||||
|
||||
def blen_read_material(fbx_tmpl, fbx_obj,
|
||||
cycles_material_wrap_map, use_cycles):
|
||||
elem_name, elem_class = elem_split_name_class(fbx_obj)
|
||||
assert(elem_class == b'Material')
|
||||
elem_name_utf8 = elem_name.decode('utf-8')
|
||||
def blen_read_material(fbx_tmpl, fbx_obj, cycles_material_wrap_map, use_cycles):
|
||||
elem_name_utf8 = elem_name_ensure_class(fbx_obj, b'Material')
|
||||
|
||||
ma = bpy.data.materials.new(name=elem_name_utf8)
|
||||
|
||||
|
@ -796,9 +835,7 @@ def blen_read_texture(fbx_tmpl, fbx_obj, basedir, image_cache,
|
|||
import os
|
||||
from bpy_extras import image_utils
|
||||
|
||||
elem_name, elem_class = elem_split_name_class(fbx_obj)
|
||||
assert(elem_class == b'Texture')
|
||||
elem_name_utf8 = elem_name.decode('utf-8')
|
||||
elem_name_utf8 = elem_name_ensure_class(fbx_obj, b'Texture')
|
||||
|
||||
filepath = elem_find_first_string(fbx_obj, b'FileName')
|
||||
if os.sep == '/':
|
||||
|
@ -828,9 +865,7 @@ def blen_read_camera(fbx_tmpl, fbx_obj, global_scale):
|
|||
# meters to inches
|
||||
M2I = 0.0393700787
|
||||
|
||||
elem_name, elem_class = elem_split_name_class_nodeattr(fbx_obj)
|
||||
assert(elem_class == b'Camera')
|
||||
elem_name_utf8 = elem_name.decode('utf-8')
|
||||
elem_name_utf8 = elem_name_ensure_class(fbx_obj, b'NodeAttribute')
|
||||
|
||||
fbx_props = (elem_find_first(fbx_obj, b'Properties70'),
|
||||
elem_find_first(fbx_tmpl, b'Properties70', fbx_elem_nil))
|
||||
|
@ -855,9 +890,7 @@ def blen_read_camera(fbx_tmpl, fbx_obj, global_scale):
|
|||
|
||||
def blen_read_light(fbx_tmpl, fbx_obj, global_scale):
|
||||
import math
|
||||
elem_name, elem_class = elem_split_name_class_nodeattr(fbx_obj)
|
||||
assert(elem_class == b'Light')
|
||||
elem_name_utf8 = elem_name.decode('utf-8')
|
||||
elem_name_utf8 = elem_name_ensure_class(fbx_obj, b'NodeAttribute')
|
||||
|
||||
fbx_props = (elem_find_first(fbx_obj, b'Properties70'),
|
||||
elem_find_first(fbx_tmpl, b'Properties70', fbx_elem_nil))
|
||||
|
@ -920,13 +953,15 @@ def load(operator, context, filepath="",
|
|||
global fbx_elem_nil
|
||||
fbx_elem_nil = FBXElem('', (), (), ())
|
||||
|
||||
import os
|
||||
import os, time
|
||||
from bpy_extras.io_utils import axis_conversion
|
||||
from mathutils import Matrix
|
||||
|
||||
from . import parse_fbx
|
||||
from .fbx_utils import RIGHT_HAND_AXES, FBX_FRAMERATES
|
||||
|
||||
start_time = time.process_time()
|
||||
|
||||
# detect ascii files
|
||||
if is_ascii(filepath, 24):
|
||||
operator.report({'ERROR'}, "ASCII FBX files are not supported %r" % filepath)
|
||||
|
@ -1483,4 +1518,5 @@ def load(operator, context, filepath="",
|
|||
material.use_raytrace = False
|
||||
_(); del _
|
||||
|
||||
print('Import finished in %.4f sec.' % (time.process_time() - start_time))
|
||||
return {'FINISHED'}
|
||||
|
|
Loading…
Reference in New Issue