diff options
author | Peter Kim <pk15950@gmail.com> | 2022-04-03 05:12:03 +0300 |
---|---|---|
committer | Peter Kim <pk15950@gmail.com> | 2022-04-03 05:12:03 +0300 |
commit | e9ef610716dd0958e88cb5e73ed78d24e175f19b (patch) | |
tree | 5d58ea851690f9396ba01baf41bbecc7d54dc79b | |
parent | 4691c6c4a8a946bcf77dd908f2b3d4b0a2c33837 (diff) | |
parent | 787ea78f7fa6f0373d80ba1247768402df93f8ad (diff) |
Merge branch 'master' into xr-dev
26 files changed, 237 insertions, 70 deletions
diff --git a/io_mesh_stl/__init__.py b/io_mesh_stl/__init__.py index 56276e5f..3d1aec5c 100644 --- a/io_mesh_stl/__init__.py +++ b/io_mesh_stl/__init__.py @@ -43,6 +43,7 @@ from bpy.props import ( CollectionProperty, EnumProperty, FloatProperty, + FloatVectorProperty, ) from bpy_extras.io_utils import ( ImportHelper, @@ -227,6 +228,12 @@ class ExportSTL(Operator, ExportHelper): ('OBJECT', "Object", "Each object as a file"), ), ) + global_space: FloatVectorProperty( + name="Global Space", + description="Export in this reference space", + subtype='MATRIX', + size=(4, 4), + ) @property def check_extension(self): @@ -249,7 +256,8 @@ class ExportSTL(Operator, ExportHelper): "filter_glob", "use_scene_unit", "use_mesh_modifiers", - "batch_mode" + "batch_mode", + "global_space", ), ) @@ -269,6 +277,9 @@ class ExportSTL(Operator, ExportHelper): to_up=self.axis_up, ).to_4x4() @ Matrix.Scale(global_scale, 4) + if self.properties.is_property_set("global_space"): + global_matrix = global_matrix @ self.global_space.inverted() + if self.batch_mode == 'OFF': faces = itertools.chain.from_iterable( blender_utils.faces_from_mesh(ob, global_matrix, self.use_mesh_modifiers) diff --git a/io_scene_fbx/__init__.py b/io_scene_fbx/__init__.py index 0abafc33..9933322b 100644 --- a/io_scene_fbx/__init__.py +++ b/io_scene_fbx/__init__.py @@ -5,7 +5,7 @@ bl_info = { "name": "FBX format", "author": "Campbell Barton, Bastien Montagne, Jens Restemeier", - "version": (4, 34, 2), + "version": (4, 35, 0), "blender": (3, 2, 0), "location": "File > Import-Export", "description": "FBX IO meshes, UV's, vertex colors, materials, textures, cameras, lamps and actions", @@ -477,6 +477,11 @@ class ExportFBX(bpy.types.Operator, ExportHelper): "(will only work correctly with tris/quads only meshes!)", default=False, ) + use_triangles: BoolProperty( + name="Triangulate Faces", + description="Convert all faces to triangles", + default=False, + ) use_custom_props: BoolProperty( name="Custom Properties", description="Export custom properties", @@ -754,6 +759,7 @@ class FBX_PT_export_geometry(bpy.types.Panel): #sub.enabled = operator.use_mesh_modifiers and False # disabled in 2.8... #sub.prop(operator, "use_mesh_modifiers_render") layout.prop(operator, "use_mesh_edges") + layout.prop(operator, "use_triangles") sub = layout.row() #~ sub.enabled = operator.mesh_smooth_type in {'OFF'} sub.prop(operator, "use_tspace") diff --git a/io_scene_fbx/export_fbx_bin.py b/io_scene_fbx/export_fbx_bin.py index 50aefe03..b017a400 100644 --- a/io_scene_fbx/export_fbx_bin.py +++ b/io_scene_fbx/export_fbx_bin.py @@ -2266,12 +2266,14 @@ def fbx_data_from_scene(scene, depsgraph, settings): is_ob_material = any(ms.link == 'OBJECT' for ms in ob.material_slots) - if settings.use_mesh_modifiers or ob.type in BLENDER_OTHER_OBJECT_TYPES or is_ob_material: + if settings.use_mesh_modifiers or settings.use_triangles or ob.type in BLENDER_OTHER_OBJECT_TYPES or is_ob_material: # We cannot use default mesh in that case, or material would not be the right ones... use_org_data = not (is_ob_material or ob.type in BLENDER_OTHER_OBJECT_TYPES) backup_pose_positions = [] tmp_mods = [] if use_org_data and ob.type == 'MESH': + if settings.use_triangles: + use_org_data = False # No need to create a new mesh in this case, if no modifier is active! last_subsurf = None for mod in ob.modifiers: @@ -2316,6 +2318,14 @@ def fbx_data_from_scene(scene, depsgraph, settings): # free them afterwards. Not ideal but ensures correct ownerwhip. tmp_me = bpy.data.meshes.new_from_object( ob_to_convert, preserve_all_data_layers=True, depsgraph=depsgraph) + # Triangulate the mesh if requested + if settings.use_triangles: + import bmesh + bm = bmesh.new() + bm.from_mesh(tmp_me) + bmesh.ops.triangulate(bm, faces=bm.faces) + bm.to_mesh(tmp_me) + bm.free() data_meshes[ob_obj] = (get_blenderID_key(tmp_me), tmp_me, True) # Change armatures back. for armature, pose_position in backup_pose_positions: @@ -3008,6 +3018,7 @@ def save_single(operator, scene, depsgraph, filepath="", path_mode='AUTO', use_mesh_edges=True, use_tspace=True, + use_triangles=False, embed_textures=False, use_custom_props=False, bake_space_transform=False, @@ -3074,7 +3085,7 @@ def save_single(operator, scene, depsgraph, filepath="", operator.report, (axis_up, axis_forward), global_matrix, global_scale, apply_unit_scale, unit_scale, bake_space_transform, global_matrix_inv, global_matrix_inv_transposed, context_objects, object_types, use_mesh_modifiers, use_mesh_modifiers_render, - mesh_smooth_type, use_subsurf, use_mesh_edges, use_tspace, + mesh_smooth_type, use_subsurf, use_mesh_edges, use_tspace, use_triangles, armature_nodetype, use_armature_deform_only, add_leaf_bones, bone_correction_matrix, bone_correction_matrix_inv, bake_anim, bake_anim_use_all_bones, bake_anim_use_nla_strips, bake_anim_use_all_actions, @@ -3148,6 +3159,7 @@ def defaults_unity3d(): "mesh_smooth_type": 'FACE', "use_subsurf": False, "use_tspace": False, # XXX Why? Unity is expected to support tspace import... + "use_triangles": False, "use_armature_deform_only": True, diff --git a/io_scene_fbx/fbx_utils.py b/io_scene_fbx/fbx_utils.py index 4fbff329..680ee387 100644 --- a/io_scene_fbx/fbx_utils.py +++ b/io_scene_fbx/fbx_utils.py @@ -1210,7 +1210,7 @@ FBXExportSettings = namedtuple("FBXExportSettings", ( "report", "to_axes", "global_matrix", "global_scale", "apply_unit_scale", "unit_scale", "bake_space_transform", "global_matrix_inv", "global_matrix_inv_transposed", "context_objects", "object_types", "use_mesh_modifiers", "use_mesh_modifiers_render", - "mesh_smooth_type", "use_subsurf", "use_mesh_edges", "use_tspace", + "mesh_smooth_type", "use_subsurf", "use_mesh_edges", "use_tspace", "use_triangles", "armature_nodetype", "use_armature_deform_only", "add_leaf_bones", "bone_correction_matrix", "bone_correction_matrix_inv", "bake_anim", "bake_anim_use_all_bones", "bake_anim_use_nla_strips", "bake_anim_use_all_actions", diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py index fd0687b9..c844838b 100755 --- a/io_scene_gltf2/__init__.py +++ b/io_scene_gltf2/__init__.py @@ -4,7 +4,7 @@ bl_info = { 'name': 'glTF 2.0 format', 'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors', - "version": (3, 2, 15), + "version": (3, 2, 22), 'blender': (3, 1, 0), 'location': 'File > Import-Export', 'description': 'Import-Export as glTF 2.0', @@ -375,8 +375,8 @@ class ExportGLTF2_Base: optimize_animation_size: BoolProperty( name='Optimize Animation Size', description=( - "Reduces exported filesize by removing duplicate keyframes" - "Can cause problems with stepped animation" + "Reduce exported file-size by removing duplicate keyframes" + "(can cause problems with stepped animation)" ), default=True ) diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_extract.py b/io_scene_gltf2/blender/exp/gltf2_blender_extract.py index d81bd706..98e2ac19 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_extract.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_extract.py @@ -82,7 +82,14 @@ def extract_primitives(blender_mesh, uuid_for_skined_data, blender_vertex_groups locs, morph_locs = __get_positions(blender_mesh, key_blocks, armature, blender_object, export_settings) if skin: - vert_bones, num_joint_sets = __get_bone_data(blender_mesh, skin, blender_vertex_groups) + vert_bones, num_joint_sets, need_neutral_bone = __get_bone_data(blender_mesh, skin, blender_vertex_groups) + if need_neutral_bone is True: + # Need to create a fake joint at root of armature + # In order to assign not assigned vertices to it + # But for now, this is not yet possible, we need to wait the armature node is created + # Just store this, to be used later + armature_uuid = export_settings['vtree'].nodes[uuid_for_skined_data].armature + export_settings['vtree'].nodes[armature_uuid].need_neutral_bone = True # In Blender there is both per-vert data, like position, and also per-loop # (loop=corner-of-poly) data, like normals or UVs. glTF only has per-vert @@ -535,6 +542,9 @@ def __get_colors(blender_mesh, color_i): def __get_bone_data(blender_mesh, skin, blender_vertex_groups): + + need_neutral_bone = False + joint_name_to_index = {joint.name: index for index, joint in enumerate(skin.joints)} group_to_joint = [joint_name_to_index.get(g.name) for g in blender_vertex_groups] @@ -557,7 +567,10 @@ def __get_bone_data(blender_mesh, skin, blender_vertex_groups): continue bones.append((joint, weight)) bones.sort(key=lambda x: x[1], reverse=True) - if not bones: bones = ((0, 1.0),) # HACK for verts with zero weight (#308) + if not bones: + # Is not assign to any bone + bones = ((len(skin.joints), 1.0),) # Assign to a joint that will be created later + need_neutral_bone = True vert_bones.append(bones) if len(bones) > max_num_influences: max_num_influences = len(bones) @@ -565,7 +578,7 @@ def __get_bone_data(blender_mesh, skin, blender_vertex_groups): # How many joint sets do we need? 1 set = 4 influences num_joint_sets = (max_num_influences + 3) // 4 - return vert_bones, num_joint_sets + return vert_bones, num_joint_sets, need_neutral_bone def __zup2yup(array): diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather.py index f515da8c..b3f4fd2a 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather.py @@ -68,6 +68,8 @@ def __gather_scene(blender_scene, export_settings): if node is not None: scene.nodes.append(node) + vtree.add_neutral_bones() + export_user_extensions('gather_scene_hook', export_settings, scene, blender_scene) return scene diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py index 66ce11c7..e1ed19ea 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py @@ -132,7 +132,8 @@ def get_object_matrix(blender_obj_uuid: str, bake_range_end: int, current_frame: int, step: int, - export_settings + export_settings, + only_gather_provided=False ): data = {} @@ -144,11 +145,16 @@ def get_object_matrix(blender_obj_uuid: str, start_frame = min([v[0] for v in [a.frame_range for a in bpy.data.actions]]) end_frame = max([v[1] for v in [a.frame_range for a in bpy.data.actions]]) + if only_gather_provided: + obj_uuids = [blender_obj_uuid] + else: + obj_uuids = [uid for (uid, n) in export_settings['vtree'].nodes.items() if n.blender_type not in [VExportNode.BONE]] + frame = start_frame while frame <= end_frame: bpy.context.scene.frame_set(int(frame)) - for obj_uuid in [uid for (uid, n) in export_settings['vtree'].nodes.items() if n.blender_type not in [VExportNode.BONE]]: + for obj_uuid in obj_uuids: blender_obj = export_settings['vtree'].nodes[obj_uuid].blender_object # if this object is not animated, do not skip : diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animations.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animations.py index c56517fb..6dd401e9 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animations.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animations.py @@ -9,6 +9,7 @@ from io_scene_gltf2.blender.exp import gltf2_blender_gather_animation_channels from io_scene_gltf2.io.com.gltf2_io_debug import print_console from ..com.gltf2_blender_extras import generate_extras from io_scene_gltf2.io.exp.gltf2_io_user_extensions import export_user_extensions +from io_scene_gltf2.blender.exp.gltf2_blender_gather_tree import VExportNode def __gather_channels_baked(obj_uuid, export_settings): @@ -307,6 +308,16 @@ def __get_blender_actions(blender_object: bpy.types.Object, blender_tracks[strip.action.name] = track.name # Always set after possible active action -> None will be overwrite action_on_type[strip.action.name] = "SHAPEKEY" + # If there are only 1 armature, include all animations, even if not in NLA + if blender_object.type == "ARMATURE": + if len(export_settings['vtree'].get_all_node_of_type(VExportNode.ARMATURE)) == 1: + # Keep all actions on objects (no keyframe animation) + # Some other object animation can be added here, and will affect armature object itself :-/ + for act in [a for a in bpy.data.actions if a.id_root == "OBJECT"]: + blender_actions.append(act) + blender_tracks[act.name] = None + action_on_type[act.name] = "OBJECT" + export_user_extensions('gather_actions_hook', export_settings, blender_object, blender_actions, blender_tracks, action_on_type) # Remove duplicate actions. diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_cache.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_cache.py index 4f95431c..3539b968 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_cache.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_cache.py @@ -93,7 +93,7 @@ def objectcache(func): # object is in cache, but not this action # We need to keep other actions elif cache_key_args[1] not in func.__objectcache[cache_key_args[0]].keys(): - result = func(*args) + result = func(*args, only_gather_provided=True) func.__objectcache[cache_key_args[0]][cache_key_args[1]] = result[cache_key_args[0]][cache_key_args[1]] return result[cache_key_args[0]][cache_key_args[1]][cache_key_args[4]] # all is already cached diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_materials.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_materials.py index 402e06fa..3805e9bd 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_materials.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_materials.py @@ -248,9 +248,10 @@ def __gather_extensions(blender_material, export_settings): # KHR_materials_transmission - transmission_extension = __gather_transmission_extension(blender_material, export_settings) + transmission_extension, use_actives_uvmap_transmission = __gather_transmission_extension(blender_material, export_settings) if transmission_extension: extensions["KHR_materials_transmission"] = transmission_extension + actives_uvmaps.extend(use_actives_uvmap_transmission) return extensions, actives_uvmaps if extensions else None @@ -429,17 +430,19 @@ def __gather_transmission_extension(blender_material, export_settings): transmission_extension['transmissionFactor'] = transmission_socket.default_value transmission_enabled = transmission_extension['transmissionFactor'] > 0 elif __has_image_node_from_socket(transmission_socket): - transmission_extension['transmissionFactor'] = 1 + transmission_extension['transmissionFactor'] = 1.0 has_transmission_texture = True transmission_enabled = True if not transmission_enabled: - return None + return None, None # Pack transmission channel (R). if has_transmission_texture: transmission_slots = (transmission_socket,) + use_actives_uvmaps = [] + if len(transmission_slots) > 0: combined_texture, use_active_uvmap = gltf2_blender_gather_texture_info.gather_texture_info( transmission_socket, @@ -448,8 +451,10 @@ def __gather_transmission_extension(blender_material, export_settings): ) if has_transmission_texture: transmission_extension['transmissionTexture'] = combined_texture + if use_active_uvmap: + use_actives_uvmaps.append("transmissionTexture") - return Extension('KHR_materials_transmission', transmission_extension, False), ["transmissionTexture"] if use_active_uvmap else [] + return Extension('KHR_materials_transmission', transmission_extension, False), use_actives_uvmaps def __gather_material_unlit(blender_material, active_uvmap_index, export_settings): diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_mesh.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_mesh.py index c8987127..fd334cb3 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_mesh.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_mesh.py @@ -12,7 +12,6 @@ from io_scene_gltf2.io.com.gltf2_io_debug import print_console from io_scene_gltf2.io.exp.gltf2_io_user_extensions import export_user_extensions -@cached def get_mesh_cache_key(blender_mesh, blender_object, vertex_groups, diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py index 25784960..b0b2d4b8 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py @@ -194,28 +194,31 @@ def __gather_mesh(vnode, blender_object, export_settings): if len(modifiers) == 0: modifiers = None - # TODO for objects without any modifiers, we can keep original mesh_data - # It will instance mesh in glTF - if export_settings[gltf2_blender_export_keys.APPLY]: - armature_modifiers = {} - if export_settings[gltf2_blender_export_keys.SKINS]: - # temporarily disable Armature modifiers if exporting skins - for idx, modifier in enumerate(blender_object.modifiers): - if modifier.type == 'ARMATURE': - armature_modifiers[idx] = modifier.show_viewport - modifier.show_viewport = False - - depsgraph = bpy.context.evaluated_depsgraph_get() - blender_mesh_owner = blender_object.evaluated_get(depsgraph) - blender_mesh = blender_mesh_owner.to_mesh(preserve_all_data_layers=True, depsgraph=depsgraph) - for prop in blender_object.data.keys(): - blender_mesh[prop] = blender_object.data[prop] - skip_filter = True - if export_settings[gltf2_blender_export_keys.SKINS]: - # restore Armature modifiers - for idx, show_viewport in armature_modifiers.items(): - blender_object.modifiers[idx].show_viewport = show_viewport + if export_settings[gltf2_blender_export_keys.APPLY]: + if modifiers is None: # If no modifier, use original mesh, it will instance all shared mesh in a single glTF mesh + blender_mesh = blender_object.data + skip_filter = False + else: + armature_modifiers = {} + if export_settings[gltf2_blender_export_keys.SKINS]: + # temporarily disable Armature modifiers if exporting skins + for idx, modifier in enumerate(blender_object.modifiers): + if modifier.type == 'ARMATURE': + armature_modifiers[idx] = modifier.show_viewport + modifier.show_viewport = False + + depsgraph = bpy.context.evaluated_depsgraph_get() + blender_mesh_owner = blender_object.evaluated_get(depsgraph) + blender_mesh = blender_mesh_owner.to_mesh(preserve_all_data_layers=True, depsgraph=depsgraph) + for prop in blender_object.data.keys(): + blender_mesh[prop] = blender_object.data[prop] + skip_filter = True + + if export_settings[gltf2_blender_export_keys.SKINS]: + # restore Armature modifiers + for idx, show_viewport in armature_modifiers.items(): + blender_object.modifiers[idx].show_viewport = show_viewport else: blender_mesh = blender_object.data skip_filter = False @@ -249,7 +252,7 @@ def __gather_mesh(vnode, blender_object, export_settings): None, export_settings) - if export_settings[gltf2_blender_export_keys.APPLY]: + if export_settings[gltf2_blender_export_keys.APPLY] and modifiers is not None: blender_mesh_owner.to_mesh_clear() return result diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_skins.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_skins.py index 136d654d..3e4673e1 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_skins.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_skins.py @@ -73,6 +73,9 @@ def __gather_inverse_bind_matrices(armature_uuid, export_settings): axis_basis_change = mathutils.Matrix( ((1.0, 0.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (0.0, -1.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0))) + # store matrix_world of armature in case we need to add a neutral bone + export_settings['vtree'].nodes[armature_uuid].matrix_world_armature = blender_armature_object.matrix_world.copy() + bones_uuid = export_settings['vtree'].get_all_bones(armature_uuid) def __collect_matrices(bone): inverse_bind_matrix = ( diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_tree.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_tree.py index 643cbea0..cf4983e1 100644 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_tree.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_tree.py @@ -3,10 +3,17 @@ import bpy import uuid +import numpy as np from . import gltf2_blender_export_keys from io_scene_gltf2.io.exp.gltf2_io_user_extensions import export_user_extensions from mathutils import Quaternion, Matrix +from io_scene_gltf2.io.com import gltf2_io +from io_scene_gltf2.io.imp.gltf2_io_binary import BinaryData +from io_scene_gltf2.io.com import gltf2_io_constants +from .gltf2_blender_gather_primitive_attributes import array_to_accessor +from io_scene_gltf2.io.exp import gltf2_io_binary_data +from io_scene_gltf2.blender.exp import gltf2_blender_gather_accessors class VExportNode: @@ -237,6 +244,9 @@ class VExportTree: else: return [] + def get_all_node_of_type(self, node_type): + return [n.uuid for n in self.nodes.values() if n.blender_type == node_type] + def display(self, mode): if mode == "simple": for n in self.roots: @@ -375,6 +385,68 @@ class VExportTree: n.armature = candidates[0].uuid del n.armature_needed + def add_neutral_bones(self): + for n in [n for n in self.nodes.values() if n.armature is not None and n.blender_type == VExportNode.OBJECT and hasattr(self.nodes[n.armature], "need_neutral_bone")]: #all skin meshes objects where neutral bone is needed + # First add a new node + + axis_basis_change = Matrix.Identity(4) + if self.export_settings[gltf2_blender_export_keys.YUP]: + axis_basis_change = Matrix(((1.0, 0.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (0.0, -1.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0))) + + trans, rot, sca = axis_basis_change.decompose() + translation, rotation, scale = (None, None, None) + if trans[0] != 0.0 or trans[1] != 0.0 or trans[2] != 0.0: + translation = [trans[0], trans[1], trans[2]] + if rot[0] != 1.0 or rot[1] != 0.0 or rot[2] != 0.0 or rot[3] != 0.0: + rotation = [rot[1], rot[2], rot[3], rot[0]] + if sca[0] != 1.0 or sca[1] != 1.0 or sca[2] != 1.0: + scale = [sca[0], sca[1], sca[2]] + neutral_bone = gltf2_io.Node( + camera=None, + children=None, + extensions=None, + extras=None, + matrix=None, + mesh=None, + name='neutral_bone', + rotation=rotation, + scale=scale, + skin=None, + translation=translation, + weights=None + ) + # Add it to child list of armature + self.nodes[n.armature].node.children.append(neutral_bone) + # Add it to joint list + n.node.skin.joints.append(neutral_bone) + + # Need to add an InverseBindMatrix + array = BinaryData.decode_accessor_internal(n.node.skin.inverse_bind_matrices) + + axis_basis_change = Matrix.Identity(4) + if self.export_settings[gltf2_blender_export_keys.YUP]: + axis_basis_change = Matrix( + ((1.0, 0.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (0.0, -1.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0))) + + inverse_bind_matrix = ( + axis_basis_change @ self.nodes[n.armature].matrix_world_armature).inverted_safe() + + matrix = [] + for column in range(0, 4): + for row in range(0, 4): + matrix.append(inverse_bind_matrix[row][column]) + + array = np.append(array, np.array([matrix]), axis=0) + binary_data = gltf2_io_binary_data.BinaryData.from_list(array.flatten(), gltf2_io_constants.ComponentType.Float) + n.node.skin.inverse_bind_matrices = gltf2_blender_gather_accessors.gather_accessor( + binary_data, + gltf2_io_constants.ComponentType.Float, + len(array.flatten()) // gltf2_io_constants.DataType.num_elements(gltf2_io_constants.DataType.Mat4), + None, + None, + gltf2_io_constants.DataType.Mat4, + self.export_settings + ) def get_unused_skins(self): from .gltf2_blender_gather_skins import gather_skin skins = [] diff --git a/io_scene_gltf2/io/exp/gltf2_io_buffer.py b/io_scene_gltf2/io/exp/gltf2_io_buffer.py index 0129e85a..5fae3834 100755 --- a/io_scene_gltf2/io/exp/gltf2_io_buffer.py +++ b/io_scene_gltf2/io/exp/gltf2_io_buffer.py @@ -10,8 +10,10 @@ from io_scene_gltf2.io.exp import gltf2_io_binary_data class Buffer: """Class representing binary data for use in a glTF file as 'buffer' property.""" - def __init__(self, buffer_index=0): + def __init__(self, buffer_index=0, initial_data=None): self.__data = bytearray(b"") + if initial_data is not None: + self.__data = bytearray(initial_data.tobytes()) self.__buffer_index = buffer_index def add_and_get_view(self, binary_data: gltf2_io_binary_data.BinaryData) -> gltf2_io.BufferView: diff --git a/io_scene_gltf2/io/imp/gltf2_io_binary.py b/io_scene_gltf2/io/imp/gltf2_io_binary.py index 21bbb41b..995fd3c9 100755 --- a/io_scene_gltf2/io/imp/gltf2_io_binary.py +++ b/io_scene_gltf2/io/imp/gltf2_io_binary.py @@ -77,6 +77,37 @@ class BinaryData(): return array + + @staticmethod + def decode_accessor_internal(accessor): + # Is use internally when accessor binary data is not yet in a glTF buffer_view + # MAT2/3 have special alignment requirements that aren't handled. But it + # doesn't matter because nothing uses them. + assert accessor.type not in ['MAT2', 'MAT3'] + + dtype = ComponentType.to_numpy_dtype(accessor.component_type) + component_nb = DataType.num_elements(accessor.type) + + buffer_data = accessor.buffer_view.data + + accessor_offset = accessor.byte_offset or 0 + buffer_data = buffer_data[accessor_offset:] + + bytes_per_elem = dtype(1).nbytes + default_stride = bytes_per_elem * component_nb + stride = default_stride + + array = np.frombuffer( + buffer_data, + dtype=np.dtype(dtype).newbyteorder('<'), + count=accessor.count * component_nb, + ) + array = array.reshape(accessor.count, component_nb) + + return array + + + @staticmethod def decode_accessor_obj(gltf, accessor): # MAT2/3 have special alignment requirements that aren't handled. But it diff --git a/io_scene_obj/__init__.py b/io_scene_obj/__init__.py index 58f60ba1..8b5dad5f 100644 --- a/io_scene_obj/__init__.py +++ b/io_scene_obj/__init__.py @@ -485,16 +485,12 @@ def register(): bpy.utils.register_class(cls) bpy.types.TOPBAR_MT_file_import.append(menu_func_import) - # Disabling the menu entry for this python exporter now that - # there is a C++ exporter. For now, leaving the actual - # export_scene.obj pointing at the python version. - # bpy.types.TOPBAR_MT_file_export.append(menu_func_export) + bpy.types.TOPBAR_MT_file_export.append(menu_func_export) def unregister(): bpy.types.TOPBAR_MT_file_import.remove(menu_func_import) - # See comment above about menu for the python exporter - # bpy.types.TOPBAR_MT_file_export.remove(menu_func_export) + bpy.types.TOPBAR_MT_file_export.remove(menu_func_export) for cls in classes: bpy.utils.unregister_class(cls) diff --git a/io_scene_x3d/import_x3d.py b/io_scene_x3d/import_x3d.py index 8299faf1..fbde81ad 100644 --- a/io_scene_x3d/import_x3d.py +++ b/io_scene_x3d/import_x3d.py @@ -2007,23 +2007,18 @@ def importMesh_IndexedFaceSet(geom, ancestry): for v in f for co in tex_coord_points[v]] else: - x_min = x_max = y_min = y_max = z_min = z_max = None + x_min = y_min = z_min = math.inf + x_max = y_max = z_max = -math.inf for f in faces: # Unused vertices don't participate in size; X3DOM does so for v in f: (x, y, z) = points[v] - if x_min is None or x < x_min: - x_min = x - if x_max is None or x > x_max: - x_max = x - if y_min is None or y < y_min: - y_min = y - if y_max is None or y > y_max: - y_max = y - if z_min is None or z < z_min: - z_min = z - if z_max is None or z > z_max: - z_max = z + x_min = min(x_min, x) + x_max = max(x_max, x) + y_min = min(y_min, y) + y_max = max(y_max, y) + z_min = min(z_min, z) + z_max = max(z_max, z) mins = (x_min, y_min, z_min) deltas = (x_max - x_min, y_max - y_min, z_max - z_min) diff --git a/object_print3d_utils/operators.py b/object_print3d_utils/operators.py index 50988163..39142dde 100644 --- a/object_print3d_utils/operators.py +++ b/object_print3d_utils/operators.py @@ -781,9 +781,9 @@ class MESH_OT_print3d_align_to_xy(Operator): for name in skip_invalid: print(f"Align to XY: Skipping object {name}. No faces selected.") if len(skip_invalid) == 1: - self.report({'WARNING'}, f"Skipping object {skip_invalid[0]}. No faces selected.") + self.report({'WARNING'}, "Skipping object. No faces selected" % skip_invalid[0]) else: - self.report({'WARNING'}, f"Skipping some objects. No faces selected. See terminal.") + self.report({'WARNING'}, "Skipping some objects. No faces selected. See terminal") return {'FINISHED'} def invoke(self, context, event): diff --git a/presets/interface_theme/Deep_Grey.xml b/presets/interface_theme/Deep_Grey.xml index 2fc6b4ae..85be3a98 100644 --- a/presets/interface_theme/Deep_Grey.xml +++ b/presets/interface_theme/Deep_Grey.xml @@ -464,7 +464,7 @@ </view_3d> <graph_editor> <ThemeGraphEditor - grid="#303030" + grid="#383838" frame_current="#4c9933" time_scrub_background="#333333e6" time_marker_line="#b8b8b880" @@ -955,7 +955,7 @@ matte_node="#0076b6" distor_node="#292929" noodle_curving="2" - grid_levels="2" + grid_levels="3" dash_alpha="0.5" input_node="#3471ae" output_node="#cc6666" diff --git a/presets/interface_theme/Maya.xml b/presets/interface_theme/Maya.xml index 35470fa1..ddfef7b0 100644 --- a/presets/interface_theme/Maya.xml +++ b/presets/interface_theme/Maya.xml @@ -947,7 +947,7 @@ matte_node="#975b5b" distor_node="#749797" noodle_curving="6" - grid_levels="2" + grid_levels="3" input_node="#e64555" output_node="#b33641" filter_node="#584d80" diff --git a/presets/interface_theme/Minimal_Dark.xml b/presets/interface_theme/Minimal_Dark.xml index 6f4b5fa9..269a016e 100644 --- a/presets/interface_theme/Minimal_Dark.xml +++ b/presets/interface_theme/Minimal_Dark.xml @@ -955,7 +955,7 @@ matte_node="#404040" distor_node="#404040" noodle_curving="5" - grid_levels="7" + grid_levels="3" dash_alpha="0.5" input_node="#404040" output_node="#404040" diff --git a/presets/interface_theme/Print_Friendly.xml b/presets/interface_theme/Print_Friendly.xml index 3d71d8b6..66e3c70b 100755 --- a/presets/interface_theme/Print_Friendly.xml +++ b/presets/interface_theme/Print_Friendly.xml @@ -955,7 +955,7 @@ matte_node="#977474"
distor_node="#749797"
noodle_curving="0"
- grid_levels="2"
+ grid_levels="3"
input_node="#ff6675"
output_node="#ff6675"
filter_node="#6c696f"
diff --git a/presets/interface_theme/White.xml b/presets/interface_theme/White.xml index 24cf9bc6..5d84f109 100755 --- a/presets/interface_theme/White.xml +++ b/presets/interface_theme/White.xml @@ -948,7 +948,7 @@ matte_node="#975b5b"
distor_node="#c5ffff"
noodle_curving="3"
- grid_levels="2"
+ grid_levels="3"
input_node="#ff4e5d"
output_node="#0081ff"
filter_node="#b09bff"
diff --git a/presets/interface_theme/XSI.xml b/presets/interface_theme/XSI.xml index 69cb2f6a..a1bd9d13 100644 --- a/presets/interface_theme/XSI.xml +++ b/presets/interface_theme/XSI.xml @@ -948,7 +948,7 @@ matte_node="#79f2a0" distor_node="#eef279" noodle_curving="0" - grid_levels="2" + grid_levels="3" input_node="#ee8513" output_node="#ff8b00" filter_node="#ff0000" |