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:
Diffstat (limited to 'io_scene_gltf2/blender/exp/gltf2_blender_extract.py')
-rwxr-xr-xio_scene_gltf2/blender/exp/gltf2_blender_extract.py1116
1 files changed, 1116 insertions, 0 deletions
diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_extract.py b/io_scene_gltf2/blender/exp/gltf2_blender_extract.py
new file mode 100755
index 00000000..87c9d426
--- /dev/null
+++ b/io_scene_gltf2/blender/exp/gltf2_blender_extract.py
@@ -0,0 +1,1116 @@
+# Copyright 2018 The glTF-Blender-IO authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Imports
+#
+
+from mathutils import Vector, Quaternion
+from mathutils.geometry import tessellate_polygon
+
+from . import gltf2_blender_export_keys
+from ...io.com.gltf2_io_debug import print_console
+from io_scene_gltf2.blender.exp import gltf2_blender_gather_skins
+
+#
+# Globals
+#
+
+INDICES_ID = 'indices'
+MATERIAL_ID = 'material'
+ATTRIBUTES_ID = 'attributes'
+
+COLOR_PREFIX = 'COLOR_'
+MORPH_TANGENT_PREFIX = 'MORPH_TANGENT_'
+MORPH_NORMAL_PREFIX = 'MORPH_NORMAL_'
+MORPH_POSITION_PREFIX = 'MORPH_POSITION_'
+TEXCOORD_PREFIX = 'TEXCOORD_'
+WEIGHTS_PREFIX = 'WEIGHTS_'
+JOINTS_PREFIX = 'JOINTS_'
+
+TANGENT_ATTRIBUTE = 'TANGENT'
+NORMAL_ATTRIBUTE = 'NORMAL'
+POSITION_ATTRIBUTE = 'POSITION'
+
+GLTF_MAX_COLORS = 2
+
+
+#
+# Classes
+#
+
+class ShapeKey:
+ def __init__(self, shape_key, vertex_normals, polygon_normals):
+ self.shape_key = shape_key
+ self.vertex_normals = vertex_normals
+ self.polygon_normals = polygon_normals
+
+
+#
+# Functions
+#
+
+def convert_swizzle_location(loc, export_settings):
+ """Convert a location from Blender coordinate system to glTF coordinate system."""
+ if export_settings[gltf2_blender_export_keys.YUP]:
+ return Vector((loc[0], loc[2], -loc[1]))
+ else:
+ return Vector((loc[0], loc[1], loc[2]))
+
+
+def convert_swizzle_tangent(tan, export_settings):
+ """Convert a tangent from Blender coordinate system to glTF coordinate system."""
+ if tan[0] == 0.0 and tan[1] == 0.0 and tan[2] == 0.0:
+ print_console('WARNING', 'Tangent has zero length.')
+
+ if export_settings[gltf2_blender_export_keys.YUP]:
+ return Vector((tan[0], tan[2], -tan[1], 1.0))
+ else:
+ return Vector((tan[0], tan[1], tan[2], 1.0))
+
+
+def convert_swizzle_rotation(rot, export_settings):
+ """
+ Convert a quaternion rotation from Blender coordinate system to glTF coordinate system.
+
+ 'w' is still at first position.
+ """
+ if export_settings[gltf2_blender_export_keys.YUP]:
+ return Quaternion((rot[0], rot[1], rot[3], -rot[2]))
+ else:
+ return Quaternion((rot[0], rot[1], rot[2], rot[3]))
+
+
+def convert_swizzle_scale(scale, export_settings):
+ """Convert a scale from Blender coordinate system to glTF coordinate system."""
+ if export_settings[gltf2_blender_export_keys.YUP]:
+ return Vector((scale[0], scale[2], scale[1]))
+ else:
+ return Vector((scale[0], scale[1], scale[2]))
+
+
+def decompose_transition(matrix, context, export_settings):
+ translation, rotation, scale = matrix.decompose()
+ """Decompose a matrix depending if it is associated to a joint or node."""
+ if context == 'NODE':
+ translation = convert_swizzle_location(translation, export_settings)
+ rotation = convert_swizzle_rotation(rotation, export_settings)
+ scale = convert_swizzle_scale(scale, export_settings)
+
+ # Put w at the end.
+ rotation = Quaternion((rotation[1], rotation[2], rotation[3], rotation[0]))
+
+ return translation, rotation, scale
+
+
+def color_srgb_to_scene_linear(c):
+ """
+ Convert from sRGB to scene linear color space.
+
+ Source: Cycles addon implementation, node_color.h.
+ """
+ if c < 0.04045:
+ return 0.0 if c < 0.0 else c * (1.0 / 12.92)
+ else:
+ return pow((c + 0.055) * (1.0 / 1.055), 2.4)
+
+
+def extract_primitive_floor(a, indices, use_tangents):
+ """Shift indices, that the first one starts with 0. It is assumed, that the indices are packed."""
+ attributes = {
+ POSITION_ATTRIBUTE: [],
+ NORMAL_ATTRIBUTE: []
+ }
+
+ if use_tangents:
+ attributes[TANGENT_ATTRIBUTE] = []
+
+ result_primitive = {
+ MATERIAL_ID: a[MATERIAL_ID],
+ INDICES_ID: [],
+ ATTRIBUTES_ID: attributes
+ }
+
+ source_attributes = a[ATTRIBUTES_ID]
+
+ #
+
+ tex_coord_index = 0
+ process_tex_coord = True
+ while process_tex_coord:
+ tex_coord_id = TEXCOORD_PREFIX + str(tex_coord_index)
+
+ if source_attributes.get(tex_coord_id) is not None:
+ attributes[tex_coord_id] = []
+ tex_coord_index += 1
+ else:
+ process_tex_coord = False
+
+ tex_coord_max = tex_coord_index
+
+ #
+
+ color_index = 0
+ process_color = True
+ while process_color:
+ color_id = COLOR_PREFIX + str(color_index)
+
+ if source_attributes.get(color_id) is not None:
+ attributes[color_id] = []
+ color_index += 1
+ else:
+ process_color = False
+
+ color_max = color_index
+
+ #
+
+ bone_index = 0
+ process_bone = True
+ while process_bone:
+ joint_id = JOINTS_PREFIX + str(bone_index)
+ weight_id = WEIGHTS_PREFIX + str(bone_index)
+
+ if source_attributes.get(joint_id) is not None:
+ attributes[joint_id] = []
+ attributes[weight_id] = []
+ bone_index += 1
+ else:
+ process_bone = False
+
+ bone_max = bone_index
+
+ #
+
+ morph_index = 0
+ process_morph = True
+ while process_morph:
+ morph_position_id = MORPH_POSITION_PREFIX + str(morph_index)
+ morph_normal_id = MORPH_NORMAL_PREFIX + str(morph_index)
+ morph_tangent_id = MORPH_TANGENT_PREFIX + str(morph_index)
+
+ if source_attributes.get(morph_position_id) is not None:
+ attributes[morph_position_id] = []
+ attributes[morph_normal_id] = []
+ if use_tangents:
+ attributes[morph_tangent_id] = []
+ morph_index += 1
+ else:
+ process_morph = False
+
+ morph_max = morph_index
+
+ #
+
+ min_index = min(indices)
+ max_index = max(indices)
+
+ for old_index in indices:
+ result_primitive[INDICES_ID].append(old_index - min_index)
+
+ for old_index in range(min_index, max_index + 1):
+ for vi in range(0, 3):
+ attributes[POSITION_ATTRIBUTE].append(source_attributes[POSITION_ATTRIBUTE][old_index * 3 + vi])
+ attributes[NORMAL_ATTRIBUTE].append(source_attributes[NORMAL_ATTRIBUTE][old_index * 3 + vi])
+
+ if use_tangents:
+ for vi in range(0, 4):
+ attributes[TANGENT_ATTRIBUTE].append(source_attributes[TANGENT_ATTRIBUTE][old_index * 4 + vi])
+
+ for tex_coord_index in range(0, tex_coord_max):
+ tex_coord_id = TEXCOORD_PREFIX + str(tex_coord_index)
+ for vi in range(0, 2):
+ attributes[tex_coord_id].append(source_attributes[tex_coord_id][old_index * 2 + vi])
+
+ for color_index in range(0, color_max):
+ color_id = COLOR_PREFIX + str(color_index)
+ for vi in range(0, 4):
+ attributes[color_id].append(source_attributes[color_id][old_index * 4 + vi])
+
+ for bone_index in range(0, bone_max):
+ joint_id = JOINTS_PREFIX + str(bone_index)
+ weight_id = WEIGHTS_PREFIX + str(bone_index)
+ for vi in range(0, 4):
+ attributes[joint_id].append(source_attributes[joint_id][old_index * 4 + vi])
+ attributes[weight_id].append(source_attributes[weight_id][old_index * 4 + vi])
+
+ for morph_index in range(0, morph_max):
+ morph_position_id = MORPH_POSITION_PREFIX + str(morph_index)
+ morph_normal_id = MORPH_NORMAL_PREFIX + str(morph_index)
+ morph_tangent_id = MORPH_TANGENT_PREFIX + str(morph_index)
+ for vi in range(0, 3):
+ attributes[morph_position_id].append(source_attributes[morph_position_id][old_index * 3 + vi])
+ attributes[morph_normal_id].append(source_attributes[morph_normal_id][old_index * 3 + vi])
+ if use_tangents:
+ for vi in range(0, 4):
+ attributes[morph_tangent_id].append(source_attributes[morph_tangent_id][old_index * 4 + vi])
+
+ return result_primitive
+
+
+def extract_primitive_pack(a, indices, use_tangents):
+ """Pack indices, that the first one starts with 0. Current indices can have gaps."""
+ attributes = {
+ POSITION_ATTRIBUTE: [],
+ NORMAL_ATTRIBUTE: []
+ }
+
+ if use_tangents:
+ attributes[TANGENT_ATTRIBUTE] = []
+
+ result_primitive = {
+ MATERIAL_ID: a[MATERIAL_ID],
+ INDICES_ID: [],
+ ATTRIBUTES_ID: attributes
+ }
+
+ source_attributes = a[ATTRIBUTES_ID]
+
+ #
+
+ tex_coord_index = 0
+ process_tex_coord = True
+ while process_tex_coord:
+ tex_coord_id = TEXCOORD_PREFIX + str(tex_coord_index)
+
+ if source_attributes.get(tex_coord_id) is not None:
+ attributes[tex_coord_id] = []
+ tex_coord_index += 1
+ else:
+ process_tex_coord = False
+
+ tex_coord_max = tex_coord_index
+
+ #
+
+ color_index = 0
+ process_color = True
+ while process_color:
+ color_id = COLOR_PREFIX + str(color_index)
+
+ if source_attributes.get(color_id) is not None:
+ attributes[color_id] = []
+ color_index += 1
+ else:
+ process_color = False
+
+ color_max = color_index
+
+ #
+
+ bone_index = 0
+ process_bone = True
+ while process_bone:
+ joint_id = JOINTS_PREFIX + str(bone_index)
+ weight_id = WEIGHTS_PREFIX + str(bone_index)
+
+ if source_attributes.get(joint_id) is not None:
+ attributes[joint_id] = []
+ attributes[weight_id] = []
+ bone_index += 1
+ else:
+ process_bone = False
+
+ bone_max = bone_index
+
+ #
+
+ morph_index = 0
+ process_morph = True
+ while process_morph:
+ morph_position_id = MORPH_POSITION_PREFIX + str(morph_index)
+ morph_normal_id = MORPH_NORMAL_PREFIX + str(morph_index)
+ morph_tangent_id = MORPH_TANGENT_PREFIX + str(morph_index)
+
+ if source_attributes.get(morph_position_id) is not None:
+ attributes[morph_position_id] = []
+ attributes[morph_normal_id] = []
+ if use_tangents:
+ attributes[morph_tangent_id] = []
+ morph_index += 1
+ else:
+ process_morph = False
+
+ morph_max = morph_index
+
+ #
+
+ old_to_new_indices = {}
+ new_to_old_indices = {}
+
+ new_index = 0
+ for old_index in indices:
+ if old_to_new_indices.get(old_index) is None:
+ old_to_new_indices[old_index] = new_index
+ new_to_old_indices[new_index] = old_index
+ new_index += 1
+
+ result_primitive[INDICES_ID].append(old_to_new_indices[old_index])
+
+ end_new_index = new_index
+
+ for new_index in range(0, end_new_index):
+ old_index = new_to_old_indices[new_index]
+
+ for vi in range(0, 3):
+ attributes[POSITION_ATTRIBUTE].append(source_attributes[POSITION_ATTRIBUTE][old_index * 3 + vi])
+ attributes[NORMAL_ATTRIBUTE].append(source_attributes[NORMAL_ATTRIBUTE][old_index * 3 + vi])
+
+ if use_tangents:
+ for vi in range(0, 4):
+ attributes[TANGENT_ATTRIBUTE].append(source_attributes[TANGENT_ATTRIBUTE][old_index * 4 + vi])
+
+ for tex_coord_index in range(0, tex_coord_max):
+ tex_coord_id = TEXCOORD_PREFIX + str(tex_coord_index)
+ for vi in range(0, 2):
+ attributes[tex_coord_id].append(source_attributes[tex_coord_id][old_index * 2 + vi])
+
+ for color_index in range(0, color_max):
+ color_id = COLOR_PREFIX + str(color_index)
+ for vi in range(0, 4):
+ attributes[color_id].append(source_attributes[color_id][old_index * 4 + vi])
+
+ for bone_index in range(0, bone_max):
+ joint_id = JOINTS_PREFIX + str(bone_index)
+ weight_id = WEIGHTS_PREFIX + str(bone_index)
+ for vi in range(0, 4):
+ attributes[joint_id].append(source_attributes[joint_id][old_index * 4 + vi])
+ attributes[weight_id].append(source_attributes[weight_id][old_index * 4 + vi])
+
+ for morph_index in range(0, morph_max):
+ morph_position_id = MORPH_POSITION_PREFIX + str(morph_index)
+ morph_normal_id = MORPH_NORMAL_PREFIX + str(morph_index)
+ morph_tangent_id = MORPH_TANGENT_PREFIX + str(morph_index)
+ for vi in range(0, 3):
+ attributes[morph_position_id].append(source_attributes[morph_position_id][old_index * 3 + vi])
+ attributes[morph_normal_id].append(source_attributes[morph_normal_id][old_index * 3 + vi])
+ if use_tangents:
+ for vi in range(0, 4):
+ attributes[morph_tangent_id].append(source_attributes[morph_tangent_id][old_index * 4 + vi])
+
+ return result_primitive
+
+
+def extract_primitives(glTF, blender_mesh, blender_vertex_groups, modifiers, export_settings):
+ """
+ Extract primitives from a mesh. Polygons are triangulated and sorted by material.
+
+ Furthermore, primitives are split up, if the indices range is exceeded.
+ Finally, triangles are also split up/duplicated, if face normals are used instead of vertex normals.
+ """
+ print_console('INFO', 'Extracting primitive')
+
+ use_tangents = False
+ if blender_mesh.uv_layers.active and len(blender_mesh.uv_layers) > 0:
+ try:
+ blender_mesh.calc_tangents()
+ use_tangents = True
+ except Exception:
+ print_console('WARNING', 'Could not calculate tangents. Please try to triangulate the mesh first.')
+
+ #
+
+ material_map = {}
+
+ #
+ # Gathering position, normal and tex_coords.
+ #
+ no_material_attributes = {
+ POSITION_ATTRIBUTE: [],
+ NORMAL_ATTRIBUTE: []
+ }
+
+ if use_tangents:
+ no_material_attributes[TANGENT_ATTRIBUTE] = []
+
+ #
+ # Directory of materials with its primitive.
+ #
+ no_material_primitives = {
+ MATERIAL_ID: '',
+ INDICES_ID: [],
+ ATTRIBUTES_ID: no_material_attributes
+ }
+
+ material_name_to_primitives = {'': no_material_primitives}
+
+ #
+
+ vertex_index_to_new_indices = {}
+
+ material_map[''] = vertex_index_to_new_indices
+
+ #
+ # Create primitive for each material.
+ #
+ for blender_material in blender_mesh.materials:
+ if blender_material is None:
+ continue
+
+ attributes = {
+ POSITION_ATTRIBUTE: [],
+ NORMAL_ATTRIBUTE: []
+ }
+
+ if use_tangents:
+ attributes[TANGENT_ATTRIBUTE] = []
+
+ primitive = {
+ MATERIAL_ID: blender_material.name,
+ INDICES_ID: [],
+ ATTRIBUTES_ID: attributes
+ }
+
+ material_name_to_primitives[blender_material.name] = primitive
+
+ #
+
+ vertex_index_to_new_indices = {}
+
+ material_map[blender_material.name] = vertex_index_to_new_indices
+
+ tex_coord_max = 0
+ if blender_mesh.uv_layers.active:
+ tex_coord_max = len(blender_mesh.uv_layers)
+
+ #
+
+ vertex_colors = {}
+
+ color_index = 0
+ for vertex_color in blender_mesh.vertex_colors:
+ vertex_color_name = COLOR_PREFIX + str(color_index)
+ vertex_colors[vertex_color_name] = vertex_color
+
+ color_index += 1
+ if color_index >= GLTF_MAX_COLORS:
+ break
+ color_max = color_index
+
+ #
+
+ bone_max = 0
+ for blender_polygon in blender_mesh.polygons:
+ for loop_index in blender_polygon.loop_indices:
+ vertex_index = blender_mesh.loops[loop_index].vertex_index
+ bones_count = len(blender_mesh.vertices[vertex_index].groups)
+ if bones_count > 0:
+ if bones_count % 4 == 0:
+ bones_count -= 1
+ bone_max = max(bone_max, bones_count // 4 + 1)
+
+ #
+
+ morph_max = 0
+
+ blender_shape_keys = []
+
+ if blender_mesh.shape_keys is not None:
+ morph_max = len(blender_mesh.shape_keys.key_blocks) - 1
+
+ for blender_shape_key in blender_mesh.shape_keys.key_blocks:
+ if blender_shape_key != blender_shape_key.relative_key:
+ blender_shape_keys.append(ShapeKey(
+ blender_shape_key,
+ blender_shape_key.normals_vertex_get(), # calculate vertex normals for this shape key
+ blender_shape_key.normals_polygon_get())) # calculate polygon normals for this shape key
+
+ #
+ # Convert polygon to primitive indices and eliminate invalid ones. Assign to material.
+ #
+ for blender_polygon in blender_mesh.polygons:
+ export_color = True
+
+ #
+
+ if blender_polygon.material_index < 0 or blender_polygon.material_index >= len(blender_mesh.materials) or \
+ blender_mesh.materials[blender_polygon.material_index] is None:
+ primitive = material_name_to_primitives['']
+ vertex_index_to_new_indices = material_map['']
+ else:
+ primitive = material_name_to_primitives[blender_mesh.materials[blender_polygon.material_index].name]
+ vertex_index_to_new_indices = material_map[blender_mesh.materials[blender_polygon.material_index].name]
+ #
+
+ attributes = primitive[ATTRIBUTES_ID]
+
+ face_normal = blender_polygon.normal
+ face_tangent = Vector((0.0, 0.0, 0.0))
+ face_bitangent = Vector((0.0, 0.0, 0.0))
+ if use_tangents:
+ for loop_index in blender_polygon.loop_indices:
+ temp_vertex = blender_mesh.loops[loop_index]
+ face_tangent += temp_vertex.tangent
+ face_bitangent += temp_vertex.bitangent
+
+ face_tangent.normalize()
+ face_bitangent.normalize()
+
+ #
+
+ indices = primitive[INDICES_ID]
+
+ loop_index_list = []
+
+ if len(blender_polygon.loop_indices) == 3:
+ loop_index_list.extend(blender_polygon.loop_indices)
+ elif len(blender_polygon.loop_indices) > 3:
+ # Triangulation of polygon. Using internal function, as non-convex polygons could exist.
+ polyline = []
+
+ for loop_index in blender_polygon.loop_indices:
+ vertex_index = blender_mesh.loops[loop_index].vertex_index
+ v = blender_mesh.vertices[vertex_index].co
+ polyline.append(Vector((v[0], v[1], v[2])))
+
+ triangles = tessellate_polygon((polyline,))
+
+ for triangle in triangles:
+ loop_index_list.append(blender_polygon.loop_indices[triangle[0]])
+ loop_index_list.append(blender_polygon.loop_indices[triangle[2]])
+ loop_index_list.append(blender_polygon.loop_indices[triangle[1]])
+ else:
+ continue
+
+ for loop_index in loop_index_list:
+ vertex_index = blender_mesh.loops[loop_index].vertex_index
+
+ if vertex_index_to_new_indices.get(vertex_index) is None:
+ vertex_index_to_new_indices[vertex_index] = []
+
+ #
+
+ v = None
+ n = None
+ t = None
+ b = None
+ uvs = []
+ colors = []
+ joints = []
+ weights = []
+
+ target_positions = []
+ target_normals = []
+ target_tangents = []
+
+ vertex = blender_mesh.vertices[vertex_index]
+
+ v = convert_swizzle_location(vertex.co, export_settings)
+ if blender_polygon.use_smooth:
+ n = convert_swizzle_location(vertex.normal, export_settings)
+ if use_tangents:
+ t = convert_swizzle_tangent(blender_mesh.loops[loop_index].tangent, export_settings)
+ b = convert_swizzle_location(blender_mesh.loops[loop_index].bitangent, export_settings)
+ else:
+ n = convert_swizzle_location(face_normal, export_settings)
+ if use_tangents:
+ t = convert_swizzle_tangent(face_tangent, export_settings)
+ b = convert_swizzle_location(face_bitangent, export_settings)
+
+ if use_tangents:
+ tv = Vector((t[0], t[1], t[2]))
+ bv = Vector((b[0], b[1], b[2]))
+ nv = Vector((n[0], n[1], n[2]))
+
+ if (nv.cross(tv)).dot(bv) < 0.0:
+ t[3] = -1.0
+
+ if blender_mesh.uv_layers.active:
+ for tex_coord_index in range(0, tex_coord_max):
+ uv = blender_mesh.uv_layers[tex_coord_index].data[loop_index].uv
+ uvs.append([uv.x, 1.0 - uv.y])
+
+ #
+
+ if color_max > 0 and export_color:
+ for color_index in range(0, color_max):
+ color_name = COLOR_PREFIX + str(color_index)
+ color = vertex_colors[color_name].data[loop_index].color
+ colors.append([
+ color_srgb_to_scene_linear(color[0]),
+ color_srgb_to_scene_linear(color[1]),
+ color_srgb_to_scene_linear(color[2]),
+ 1.0
+ ])
+
+ #
+
+ bone_count = 0
+
+ if blender_vertex_groups is not None and vertex.groups is not None and len(vertex.groups) > 0 and export_settings[gltf2_blender_export_keys.SKINS]:
+ joint = []
+ weight = []
+ for group_element in vertex.groups:
+
+ if len(joint) == 4:
+ bone_count += 1
+ joints.append(joint)
+ weights.append(weight)
+ joint = []
+ weight = []
+
+ #
+
+ vertex_group_index = group_element.group
+ vertex_group_name = blender_vertex_groups[vertex_group_index].name
+
+ #
+
+ joint_index = 0
+
+ if modifiers is not None:
+ modifiers_dict = {m.type: m for m in modifiers}
+ if "ARMATURE" in modifiers_dict:
+ armature = modifiers_dict["ARMATURE"].object
+ skin = gltf2_blender_gather_skins.gather_skin(armature, export_settings)
+ for index, j in enumerate(skin.joints):
+ if j.name == vertex_group_name:
+ joint_index = index
+
+ joint_weight = group_element.weight
+
+ #
+ joint.append(joint_index)
+ weight.append(joint_weight)
+
+ if len(joint) > 0:
+ bone_count += 1
+
+ for fill in range(0, 4 - len(joint)):
+ joint.append(0)
+ weight.append(0.0)
+
+ joints.append(joint)
+ weights.append(weight)
+
+ for fill in range(0, bone_max - bone_count):
+ joints.append([0, 0, 0, 0])
+ weights.append([0.0, 0.0, 0.0, 0.0])
+
+ #
+
+ if morph_max > 0 and export_settings[gltf2_blender_export_keys.MORPH]:
+ for morph_index in range(0, morph_max):
+ blender_shape_key = blender_shape_keys[morph_index]
+
+ v_morph = convert_swizzle_location(blender_shape_key.shape_key.data[vertex_index].co,
+ export_settings)
+
+ # Store delta.
+ v_morph -= v
+
+ target_positions.append(v_morph)
+
+ #
+
+ n_morph = None
+
+ if blender_polygon.use_smooth:
+ temp_normals = blender_shape_key.vertex_normals
+ n_morph = (temp_normals[vertex_index * 3 + 0], temp_normals[vertex_index * 3 + 1],
+ temp_normals[vertex_index * 3 + 2])
+ else:
+ temp_normals = blender_shape_key.polygon_normals
+ n_morph = (
+ temp_normals[blender_polygon.index * 3 + 0], temp_normals[blender_polygon.index * 3 + 1],
+ temp_normals[blender_polygon.index * 3 + 2])
+
+ n_morph = convert_swizzle_location(n_morph, export_settings)
+
+ # Store delta.
+ n_morph -= n
+
+ target_normals.append(n_morph)
+
+ #
+
+ if use_tangents:
+ rotation = n_morph.rotation_difference(n)
+
+ t_morph = Vector((t[0], t[1], t[2]))
+
+ t_morph.rotate(rotation)
+
+ target_tangents.append(t_morph)
+
+ #
+ #
+
+ create = True
+
+ for current_new_index in vertex_index_to_new_indices[vertex_index]:
+ found = True
+
+ for i in range(0, 3):
+ if attributes[POSITION_ATTRIBUTE][current_new_index * 3 + i] != v[i]:
+ found = False
+ break
+
+ if attributes[NORMAL_ATTRIBUTE][current_new_index * 3 + i] != n[i]:
+ found = False
+ break
+
+ if use_tangents:
+ for i in range(0, 4):
+ if attributes[TANGENT_ATTRIBUTE][current_new_index * 4 + i] != t[i]:
+ found = False
+ break
+
+ if not found:
+ continue
+
+ for tex_coord_index in range(0, tex_coord_max):
+ uv = uvs[tex_coord_index]
+
+ tex_coord_id = TEXCOORD_PREFIX + str(tex_coord_index)
+ for i in range(0, 2):
+ if attributes[tex_coord_id][current_new_index * 2 + i] != uv[i]:
+ found = False
+ break
+
+ if export_color:
+ for color_index in range(0, color_max):
+ color = colors[color_index]
+
+ color_id = COLOR_PREFIX + str(color_index)
+ for i in range(0, 3):
+ # Alpha is always 1.0 - see above.
+ current_color = attributes[color_id][current_new_index * 4 + i]
+ if color_srgb_to_scene_linear(current_color) != color[i]:
+ found = False
+ break
+
+ if export_settings[gltf2_blender_export_keys.SKINS]:
+ for bone_index in range(0, bone_max):
+ joint = joints[bone_index]
+ weight = weights[bone_index]
+
+ joint_id = JOINTS_PREFIX + str(bone_index)
+ weight_id = WEIGHTS_PREFIX + str(bone_index)
+ for i in range(0, 4):
+ if attributes[joint_id][current_new_index * 4 + i] != joint[i]:
+ found = False
+ break
+ if attributes[weight_id][current_new_index * 4 + i] != weight[i]:
+ found = False
+ break
+
+ if export_settings[gltf2_blender_export_keys.MORPH]:
+ for morph_index in range(0, morph_max):
+ target_position = target_positions[morph_index]
+ target_normal = target_normals[morph_index]
+ if use_tangents:
+ target_tangent = target_tangents[morph_index]
+
+ target_position_id = MORPH_POSITION_PREFIX + str(morph_index)
+ target_normal_id = MORPH_NORMAL_PREFIX + str(morph_index)
+ target_tangent_id = MORPH_TANGENT_PREFIX + str(morph_index)
+ for i in range(0, 3):
+ if attributes[target_position_id][current_new_index * 3 + i] != target_position[i]:
+ found = False
+ break
+ if attributes[target_normal_id][current_new_index * 3 + i] != target_normal[i]:
+ found = False
+ break
+ if use_tangents:
+ if attributes[target_tangent_id][current_new_index * 3 + i] != target_tangent[i]:
+ found = False
+ break
+
+ if found:
+ indices.append(current_new_index)
+
+ create = False
+ break
+
+ if not create:
+ continue
+
+ new_index = 0
+
+ if primitive.get('max_index') is not None:
+ new_index = primitive['max_index'] + 1
+
+ primitive['max_index'] = new_index
+
+ vertex_index_to_new_indices[vertex_index].append(new_index)
+
+ #
+ #
+
+ indices.append(new_index)
+
+ #
+
+ attributes[POSITION_ATTRIBUTE].extend(v)
+ attributes[NORMAL_ATTRIBUTE].extend(n)
+ if use_tangents:
+ attributes[TANGENT_ATTRIBUTE].extend(t)
+
+ if blender_mesh.uv_layers.active:
+ for tex_coord_index in range(0, tex_coord_max):
+ tex_coord_id = TEXCOORD_PREFIX + str(tex_coord_index)
+
+ if attributes.get(tex_coord_id) is None:
+ attributes[tex_coord_id] = []
+
+ attributes[tex_coord_id].extend(uvs[tex_coord_index])
+
+ if export_color:
+ for color_index in range(0, color_max):
+ color_id = COLOR_PREFIX + str(color_index)
+
+ if attributes.get(color_id) is None:
+ attributes[color_id] = []
+
+ attributes[color_id].extend(colors[color_index])
+
+ if export_settings[gltf2_blender_export_keys.SKINS]:
+ for bone_index in range(0, bone_max):
+ joint_id = JOINTS_PREFIX + str(bone_index)
+
+ if attributes.get(joint_id) is None:
+ attributes[joint_id] = []
+
+ attributes[joint_id].extend(joints[bone_index])
+
+ weight_id = WEIGHTS_PREFIX + str(bone_index)
+
+ if attributes.get(weight_id) is None:
+ attributes[weight_id] = []
+
+ attributes[weight_id].extend(weights[bone_index])
+
+ if export_settings[gltf2_blender_export_keys.MORPH]:
+ for morph_index in range(0, morph_max):
+ target_position_id = MORPH_POSITION_PREFIX + str(morph_index)
+
+ if attributes.get(target_position_id) is None:
+ attributes[target_position_id] = []
+
+ attributes[target_position_id].extend(target_positions[morph_index])
+
+ target_normal_id = MORPH_NORMAL_PREFIX + str(morph_index)
+
+ if attributes.get(target_normal_id) is None:
+ attributes[target_normal_id] = []
+
+ attributes[target_normal_id].extend(target_normals[morph_index])
+
+ if use_tangents:
+ target_tangent_id = MORPH_TANGENT_PREFIX + str(morph_index)
+
+ if attributes.get(target_tangent_id) is None:
+ attributes[target_tangent_id] = []
+
+ attributes[target_tangent_id].extend(target_tangents[morph_index])
+
+ #
+ # Add primitive plus split them if needed.
+ #
+
+ result_primitives = []
+
+ for material_name, primitive in material_name_to_primitives.items():
+ export_color = True
+
+ #
+
+ indices = primitive[INDICES_ID]
+
+ if len(indices) == 0:
+ continue
+
+ position = primitive[ATTRIBUTES_ID][POSITION_ATTRIBUTE]
+ normal = primitive[ATTRIBUTES_ID][NORMAL_ATTRIBUTE]
+ if use_tangents:
+ tangent = primitive[ATTRIBUTES_ID][TANGENT_ATTRIBUTE]
+ tex_coords = []
+ for tex_coord_index in range(0, tex_coord_max):
+ tex_coords.append(primitive[ATTRIBUTES_ID][TEXCOORD_PREFIX + str(tex_coord_index)])
+ colors = []
+ if export_color:
+ for color_index in range(0, color_max):
+ tex_coords.append(primitive[ATTRIBUTES_ID][COLOR_PREFIX + str(color_index)])
+ joints = []
+ weights = []
+ if export_settings[gltf2_blender_export_keys.SKINS]:
+ for bone_index in range(0, bone_max):
+ joints.append(primitive[ATTRIBUTES_ID][JOINTS_PREFIX + str(bone_index)])
+ weights.append(primitive[ATTRIBUTES_ID][WEIGHTS_PREFIX + str(bone_index)])
+
+ target_positions = []
+ target_normals = []
+ target_tangents = []
+ if export_settings[gltf2_blender_export_keys.MORPH]:
+ for morph_index in range(0, morph_max):
+ target_positions.append(primitive[ATTRIBUTES_ID][MORPH_POSITION_PREFIX + str(morph_index)])
+ target_normals.append(primitive[ATTRIBUTES_ID][MORPH_NORMAL_PREFIX + str(morph_index)])
+ if use_tangents:
+ target_tangents.append(primitive[ATTRIBUTES_ID][MORPH_TANGENT_PREFIX + str(morph_index)])
+
+ #
+
+ count = len(indices)
+
+ if count == 0:
+ continue
+
+ max_index = max(indices)
+
+ #
+
+ range_indices = 65536
+
+ #
+
+ if max_index >= range_indices:
+ #
+ # Splitting result_primitives.
+ #
+
+ # At start, all indices are pending.
+ pending_attributes = {
+ POSITION_ATTRIBUTE: [],
+ NORMAL_ATTRIBUTE: []
+ }
+
+ if use_tangents:
+ pending_attributes[TANGENT_ATTRIBUTE] = []
+
+ pending_primitive = {
+ MATERIAL_ID: material_name,
+ INDICES_ID: [],
+ ATTRIBUTES_ID: pending_attributes
+ }
+
+ pending_primitive[INDICES_ID].extend(indices)
+
+ pending_attributes[POSITION_ATTRIBUTE].extend(position)
+ pending_attributes[NORMAL_ATTRIBUTE].extend(normal)
+ if use_tangents:
+ pending_attributes[TANGENT_ATTRIBUTE].extend(tangent)
+ tex_coord_index = 0
+ for tex_coord in tex_coords:
+ pending_attributes[TEXCOORD_PREFIX + str(tex_coord_index)] = tex_coord
+ tex_coord_index += 1
+ if export_color:
+ color_index = 0
+ for color in colors:
+ pending_attributes[COLOR_PREFIX + str(color_index)] = color
+ color_index += 1
+ if export_settings[gltf2_blender_export_keys.SKINS]:
+ joint_index = 0
+ for joint in joints:
+ pending_attributes[JOINTS_PREFIX + str(joint_index)] = joint
+ joint_index += 1
+ weight_index = 0
+ for weight in weights:
+ pending_attributes[WEIGHTS_PREFIX + str(weight_index)] = weight
+ weight_index += 1
+ if export_settings[gltf2_blender_export_keys.MORPH]:
+ morph_index = 0
+ for target_position in target_positions:
+ pending_attributes[MORPH_POSITION_PREFIX + str(morph_index)] = target_position
+ morph_index += 1
+ morph_index = 0
+ for target_normal in target_normals:
+ pending_attributes[MORPH_NORMAL_PREFIX + str(morph_index)] = target_normal
+ morph_index += 1
+ if use_tangents:
+ morph_index = 0
+ for target_tangent in target_tangents:
+ pending_attributes[MORPH_TANGENT_PREFIX + str(morph_index)] = target_tangent
+ morph_index += 1
+
+ pending_indices = pending_primitive[INDICES_ID]
+
+ # Continue until all are processed.
+ while len(pending_indices) > 0:
+
+ process_indices = pending_primitive[INDICES_ID]
+ max_index = max(process_indices)
+
+ pending_indices = []
+
+ #
+ #
+
+ all_local_indices = []
+
+ for i in range(0, (max_index // range_indices) + 1):
+ all_local_indices.append([])
+
+ #
+ #
+
+ # For all faces ...
+ for face_index in range(0, len(process_indices), 3):
+
+ written = False
+
+ face_min_index = min(process_indices[face_index + 0], process_indices[face_index + 1],
+ process_indices[face_index + 2])
+ face_max_index = max(process_indices[face_index + 0], process_indices[face_index + 1],
+ process_indices[face_index + 2])
+
+ # ... check if it can be but in a range of maximum indices.
+ for i in range(0, (max_index // range_indices) + 1):
+ offset = i * range_indices
+
+ # Yes, so store the primitive with its indices.
+ if face_min_index >= offset and face_max_index < offset + range_indices:
+ all_local_indices[i].extend(
+ [process_indices[face_index + 0], process_indices[face_index + 1],
+ process_indices[face_index + 2]])
+
+ written = True
+ break
+
+ # If not written, the triangle face has indices from different ranges.
+ if not written:
+ pending_indices.extend([process_indices[face_index + 0], process_indices[face_index + 1],
+ process_indices[face_index + 2]])
+
+ # Only add result_primitives, which do have indices in it.
+ for local_indices in all_local_indices:
+ if len(local_indices) > 0:
+ current_primitive = extract_primitive_floor(pending_primitive, local_indices, use_tangents)
+
+ result_primitives.append(current_primitive)
+
+ print_console('DEBUG', 'Adding primitive with splitting. Indices: ' + str(
+ len(current_primitive[INDICES_ID])) + ' Vertices: ' + str(
+ len(current_primitive[ATTRIBUTES_ID][POSITION_ATTRIBUTE]) // 3))
+
+ # Process primitive faces having indices in several ranges.
+ if len(pending_indices) > 0:
+ pending_primitive = extract_primitive_pack(pending_primitive, pending_indices, use_tangents)
+
+ print_console('DEBUG', 'Creating temporary primitive for splitting')
+
+ else:
+ #
+ # No splitting needed.
+ #
+ result_primitives.append(primitive)
+
+ print_console('DEBUG', 'Adding primitive without splitting. Indices: ' + str(
+ len(primitive[INDICES_ID])) + ' Vertices: ' + str(
+ len(primitive[ATTRIBUTES_ID][POSITION_ATTRIBUTE]) // 3))
+
+ print_console('INFO', 'Primitives created: ' + str(len(result_primitives)))
+
+ return result_primitives
+