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:
authorPeter Kim <pk15950@gmail.com>2022-04-03 05:12:03 +0300
committerPeter Kim <pk15950@gmail.com>2022-04-03 05:12:03 +0300
commite9ef610716dd0958e88cb5e73ed78d24e175f19b (patch)
tree5d58ea851690f9396ba01baf41bbecc7d54dc79b
parent4691c6c4a8a946bcf77dd908f2b3d4b0a2c33837 (diff)
parent787ea78f7fa6f0373d80ba1247768402df93f8ad (diff)
Merge branch 'master' into xr-dev
-rw-r--r--io_mesh_stl/__init__.py13
-rw-r--r--io_scene_fbx/__init__.py8
-rw-r--r--io_scene_fbx/export_fbx_bin.py16
-rw-r--r--io_scene_fbx/fbx_utils.py2
-rwxr-xr-xio_scene_gltf2/__init__.py6
-rwxr-xr-xio_scene_gltf2/blender/exp/gltf2_blender_extract.py19
-rwxr-xr-xio_scene_gltf2/blender/exp/gltf2_blender_gather.py2
-rwxr-xr-xio_scene_gltf2/blender/exp/gltf2_blender_gather_animation_sampler_keyframes.py10
-rwxr-xr-xio_scene_gltf2/blender/exp/gltf2_blender_gather_animations.py11
-rwxr-xr-xio_scene_gltf2/blender/exp/gltf2_blender_gather_cache.py2
-rwxr-xr-xio_scene_gltf2/blender/exp/gltf2_blender_gather_materials.py13
-rwxr-xr-xio_scene_gltf2/blender/exp/gltf2_blender_gather_mesh.py1
-rwxr-xr-xio_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py47
-rwxr-xr-xio_scene_gltf2/blender/exp/gltf2_blender_gather_skins.py3
-rw-r--r--io_scene_gltf2/blender/exp/gltf2_blender_gather_tree.py72
-rwxr-xr-xio_scene_gltf2/io/exp/gltf2_io_buffer.py4
-rwxr-xr-xio_scene_gltf2/io/imp/gltf2_io_binary.py31
-rw-r--r--io_scene_obj/__init__.py8
-rw-r--r--io_scene_x3d/import_x3d.py21
-rw-r--r--object_print3d_utils/operators.py4
-rw-r--r--presets/interface_theme/Deep_Grey.xml4
-rw-r--r--presets/interface_theme/Maya.xml2
-rw-r--r--presets/interface_theme/Minimal_Dark.xml2
-rwxr-xr-xpresets/interface_theme/Print_Friendly.xml2
-rwxr-xr-xpresets/interface_theme/White.xml2
-rw-r--r--presets/interface_theme/XSI.xml2
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"