Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2018-09-21 16:12:27 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2018-09-21 16:12:27 +0300
commit2bfab056d2655bddf3612dbe7644bce9ad1b581b (patch)
tree6e7b4b450c96c5414c7fae6c8515fb6bf5a8e89e /io_scene_fbx/fbx_utils.py
parentb5328b13c54bdd3419d48373e3f54f22e2501396 (diff)
Initial port of FBX to 2.8.
Default cube scene exports and imports ok (besides missing features like nodal material handling). Anything else is either known broken, or yet to be tested. :P Note that I raised main number of addon version, so that we can keep track of smaller fixes that can be done in both 2.7x and 2.8 versions of the addon.
Diffstat (limited to 'io_scene_fbx/fbx_utils.py')
-rw-r--r--io_scene_fbx/fbx_utils.py109
1 files changed, 61 insertions, 48 deletions
diff --git a/io_scene_fbx/fbx_utils.py b/io_scene_fbx/fbx_utils.py
index 25f5759b..8de8e8f8 100644
--- a/io_scene_fbx/fbx_utils.py
+++ b/io_scene_fbx/fbx_utils.py
@@ -30,7 +30,7 @@ from itertools import zip_longest, chain
import bpy
import bpy_extras
-from bpy.types import Object, Bone, PoseBone, DupliObject
+from bpy.types import Object, Bone, PoseBone, DepsgraphObjectInstance
from mathutils import Vector, Matrix
from . import encode_bin, data_types
@@ -271,14 +271,14 @@ def similar_values_iter(v1, v2, e=1e-6):
def vcos_transformed_gen(raw_cos, m=None):
# Note: we could most likely get much better performances with numpy, but will leave this as TODO for now.
gen = zip(*(iter(raw_cos),) * 3)
- return gen if m is None else (m * Vector(v) for v in gen)
+ return gen if m is None else (m @ Vector(v) for v in gen)
def nors_transformed_gen(raw_nors, m=None):
# Great, now normals are also expected 4D!
# XXX Back to 3D normals for now!
# gen = zip(*(iter(raw_nors),) * 3 + (_infinite_gen(1.0),))
gen = zip(*(iter(raw_nors),) * 3)
- return gen if m is None else (m * Vector(v) for v in gen)
+ return gen if m is None else (m @ Vector(v) for v in gen)
# ##### UIDs code. #####
@@ -856,7 +856,7 @@ class AnimationCurveNodeWrapper:
# ##### FBX objects generators. #####
-# FBX Model-like data (i.e. Blender objects, dupliobjects and bones) are wrapped in ObjectWrapper.
+# FBX Model-like data (i.e. Blender objects, depsgraph instances and bones) are wrapped in ObjectWrapper.
# This allows us to have a (nearly) same code FBX-wise for all those types.
# The wrapper tries to stay as small as possible, by mostly using callbacks (property(get...))
# to actual Blender data it contains.
@@ -870,9 +870,12 @@ class MetaObjectWrapper(type):
dup_mat = None
if isinstance(bdata, Object):
key = get_blenderID_key(bdata)
- elif isinstance(bdata, DupliObject):
- key = "|".join((get_blenderID_key((bdata.id_data, bdata.object)), cls._get_dup_num_id(bdata)))
- dup_mat = bdata.matrix.copy()
+ elif isinstance(bdata, DepsgraphObjectInstance):
+ if bdata.is_instance:
+ key = "|".join((get_blenderID_key((bdata.parent, bdata.object_instance)), cls._get_dup_num_id(bdata)))
+ dup_mat = bdata.matrix_world.copy()
+ else:
+ key = get_blenderID_key(bdata.object)
else: # isinstance(bdata, (Bone, PoseBone)):
if isinstance(bdata, PoseBone):
bdata = armature.data.bones[bdata.name]
@@ -883,9 +886,9 @@ class MetaObjectWrapper(type):
cache = cls._cache = {}
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
+ # Duplis hack: since dupli instances 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).
+ # other data is supposed valid during whole cache live span, so we can skip resetting it).
instance._dupli_matrix = dup_mat
return instance
@@ -902,7 +905,7 @@ class ObjectWrapper(metaclass=MetaObjectWrapper):
This class provides a same common interface for all (FBX-wise) object-like elements:
* Blender Object
* Blender Bone and PoseBone
- * Blender DupliObject
+ * Blender DepsgraphObjectInstance (for dulis).
Note since a same Blender object might be 'mapped' to several FBX models (esp. with duplis),
we need to use a key to identify each.
"""
@@ -918,24 +921,42 @@ class ObjectWrapper(metaclass=MetaObjectWrapper):
@staticmethod
def _get_dup_num_id(bdata):
- return ".".join(str(i) for i in bdata.persistent_id if i != 2147483647)
+ INVALID_IDS = {2147483647, 0}
+ pids = tuple(bdata.persistent_id)
+ idx_valid = 0
+ prev_i = ...
+ for idx, i in enumerate(pids[::-1]):
+ if i not in INVALID_IDS or (idx == len(pids) and i == 0 and prev_i != 0):
+ idx_valid = len(pids) - idx
+ break
+ prev_i = i
+ return ".".join(str(i) for i in pids[:idx_valid])
def __init__(self, bdata, armature=None):
"""
- bdata might be an Object, DupliObject, Bone or PoseBone.
+ bdata might be an Object (deprecated), DepsgraphObjectInstance, Bone or PoseBone.
If Bone or PoseBone, armature Object must be provided.
"""
- if isinstance(bdata, Object):
+ # Note: DepsgraphObjectInstance are purely runtime data, they become invalid as soon as we step to the next item!
+ # Hence we have to immediately copy *all* needed data...
+ if isinstance(bdata, Object): # DEPRECATED
self._tag = 'OB'
self.name = get_blenderID_name(bdata)
self.bdata = bdata
self._ref = None
- elif isinstance(bdata, DupliObject):
- self._tag = 'DP'
- self.name = "|".join((get_blenderID_name((bdata.id_data, bdata.object)),
- "Dupli", self._get_dup_num_id(bdata)))
- self.bdata = bdata.object
- self._ref = bdata.id_data
+ elif isinstance(bdata, DepsgraphObjectInstance):
+ if bdata.is_instance:
+ # Note that dupli instance matrix is set by meta-class initialization.
+ self._tag = 'DP'
+ self.name = "|".join((get_blenderID_name((bdata.parent, bdata.object)),
+ "Dupli", self._get_dup_num_id(bdata)))
+ self.bdata = bdata.object
+ self._ref = bdata.parent
+ else:
+ self._tag = 'OB'
+ self.name = get_blenderID_name(bdata)
+ self.bdata = bdata
+ self._ref = None
else: # isinstance(bdata, (Bone, PoseBone)):
if isinstance(bdata, PoseBone):
bdata = armature.data.bones[bdata.name]
@@ -956,8 +977,9 @@ class ObjectWrapper(metaclass=MetaObjectWrapper):
return get_fbx_uuid_from_key(self.key)
fbx_uuid = property(get_fbx_uuid)
+ # XXX Not sure how much that’s useful now... :/
def get_hide(self):
- return self.bdata.hide
+ return self.bdata.hide_viewport if self._tag in {'OB', 'DP'} else self.bdata.hide
hide = property(get_hide)
def get_parent(self):
@@ -974,7 +996,7 @@ class ObjectWrapper(metaclass=MetaObjectWrapper):
# Mere object parenting.
return ObjectWrapper(self.bdata.parent)
elif self._tag == 'DP':
- return ObjectWrapper(self.bdata.parent or self._ref)
+ return ObjectWrapper(self._ref)
else: # self._tag == 'BO'
return ObjectWrapper(self.bdata.parent, self._ref) or ObjectWrapper(self._ref)
parent = property(get_parent)
@@ -983,12 +1005,12 @@ class ObjectWrapper(metaclass=MetaObjectWrapper):
if self._tag == 'OB':
return self.bdata.matrix_local.copy()
elif self._tag == 'DP':
- return self._ref.matrix_world.inverted_safe() * self._dupli_matrix
+ return self._ref.matrix_world.inverted_safe() @ self._dupli_matrix
else: # 'BO', current pose
# PoseBone.matrix is in armature space, bring in back in real local one!
par = self.bdata.parent
par_mat_inv = self._ref.pose.bones[par.name].matrix.inverted_safe() if par else Matrix()
- return par_mat_inv * self._ref.pose.bones[self.bdata.name].matrix
+ return par_mat_inv @ self._ref.pose.bones[self.bdata.name].matrix
matrix_local = property(get_matrix_local)
def get_matrix_global(self):
@@ -997,7 +1019,7 @@ class ObjectWrapper(metaclass=MetaObjectWrapper):
elif self._tag == 'DP':
return self._dupli_matrix
else: # 'BO', current pose
- return self._ref.matrix_world * self._ref.pose.bones[self.bdata.name].matrix
+ return self._ref.matrix_world @ self._ref.pose.bones[self.bdata.name].matrix
matrix_global = property(get_matrix_global)
def get_matrix_rest_local(self):
@@ -1005,14 +1027,14 @@ class ObjectWrapper(metaclass=MetaObjectWrapper):
# Bone.matrix_local is in armature space, bring in back in real local one!
par = self.bdata.parent
par_mat_inv = par.matrix_local.inverted_safe() if par else Matrix()
- return par_mat_inv * self.bdata.matrix_local
+ return par_mat_inv @ self.bdata.matrix_local
else:
return self.matrix_local.copy()
matrix_rest_local = property(get_matrix_rest_local)
def get_matrix_rest_global(self):
if self._tag == 'BO':
- return self._ref.matrix_world * self.bdata.matrix_local
+ return self._ref.matrix_world @ self.bdata.matrix_local
else:
return self.matrix_global.copy()
matrix_rest_global = property(get_matrix_rest_global)
@@ -1065,41 +1087,41 @@ class ObjectWrapper(metaclass=MetaObjectWrapper):
if self._tag == 'BO':
# If we have a bone parent we need to undo the parent correction.
if not is_global and scene_data.settings.bone_correction_matrix_inv and parent and parent.is_bone:
- matrix = scene_data.settings.bone_correction_matrix_inv * matrix
+ matrix = scene_data.settings.bone_correction_matrix_inv @ matrix
# Apply the bone correction.
if scene_data.settings.bone_correction_matrix:
- matrix = matrix * scene_data.settings.bone_correction_matrix
+ matrix = matrix @ scene_data.settings.bone_correction_matrix
elif self.bdata.type == 'LIGHT':
- matrix = matrix * MAT_CONVERT_LIGHT
+ matrix = matrix @ MAT_CONVERT_LIGHT
elif self.bdata.type == 'CAMERA':
- matrix = matrix * MAT_CONVERT_CAMERA
+ matrix = matrix @ MAT_CONVERT_CAMERA
if self._tag in {'DP', 'OB'} and parent:
if parent._tag == 'BO':
# In bone parent case, we get transformation in **bone tip** space (sigh).
# Have to bring it back into bone root, which is FBX expected value.
- matrix = Matrix.Translation((0, (parent.bdata.tail - parent.bdata.head).length, 0)) * matrix
+ matrix = Matrix.Translation((0, (parent.bdata.tail - parent.bdata.head).length, 0)) @ matrix
# Our matrix is in local space, time to bring it in its final desired space.
if parent:
if is_global:
# Move matrix to global Blender space.
- matrix = (parent.matrix_rest_global if rest else parent.matrix_global) * matrix
+ matrix = (parent.matrix_rest_global if rest else parent.matrix_global) @ matrix
elif parent.use_bake_space_transform(scene_data):
# Blender's and FBX's local space of parent may differ if we use bake_space_transform...
# Apply parent's *Blender* local space...
- matrix = (parent.matrix_rest_local if rest else parent.matrix_local) * matrix
+ matrix = (parent.matrix_rest_local if rest else parent.matrix_local) @ matrix
# ...and move it back into parent's *FBX* local space.
par_mat = parent.fbx_object_matrix(scene_data, rest=rest, local_space=True)
- matrix = par_mat.inverted_safe() * matrix
+ matrix = par_mat.inverted_safe() @ matrix
if self.use_bake_space_transform(scene_data):
# If we bake the transforms we need to post-multiply inverse global transform.
# This means that the global transform will not apply to children of this transform.
- matrix = matrix * scene_data.settings.global_matrix_inv
+ matrix = matrix @ scene_data.settings.global_matrix_inv
if is_global:
# In any case, pre-multiply the global matrix to get it in FBX global space!
- matrix = scene_data.settings.global_matrix * matrix
+ matrix = scene_data.settings.global_matrix @ matrix
return matrix
@@ -1164,19 +1186,10 @@ class ObjectWrapper(metaclass=MetaObjectWrapper):
return True
# #### Duplis...
- def dupli_list_create(self, scene, settings='PREVIEW'):
+ def dupli_list_gen(self, depsgraph):
if self._tag == 'OB' and self.bdata.is_duplicator:
- self.bdata.dupli_list_create(scene, settings)
-
- def dupli_list_clear(self):
- if self._tag == 'OB'and self.bdata.is_duplicator:
- self.bdata.dupli_list_clear()
-
- def get_dupli_list(self):
- if self._tag == 'OB'and self.bdata.is_duplicator:
- return (ObjectWrapper(dup) for dup in self.bdata.dupli_list)
+ return (ObjectWrapper(dup) for dup in depsgraph.object_instances if dup.parent == self.bdata)
return ()
- dupli_list = property(get_dupli_list)
def fbx_name_class(name, cls):
@@ -1213,7 +1226,7 @@ FBXExportSettings = namedtuple("FBXExportSettings", (
# * animations.
FBXExportData = namedtuple("FBXExportData", (
"templates", "templates_users", "connections",
- "settings", "scene", "objects", "animations", "animated", "frame_start", "frame_end",
+ "settings", "scene", "depsgraph", "objects", "animations", "animated", "frame_start", "frame_end",
"data_empties", "data_lights", "data_cameras", "data_meshes", "mesh_mat_indices",
"data_bones", "data_leaf_bones", "data_deformers_skin", "data_deformers_shape",
"data_world", "data_materials", "data_textures", "data_videos",