parent
2b4bf943d0
commit
3ea1673580
|
@ -15,7 +15,7 @@
|
|||
bl_info = {
|
||||
'name': 'glTF 2.0 format',
|
||||
'author': 'Julien Duroure, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
|
||||
"version": (1, 3, 33),
|
||||
"version": (1, 3, 34),
|
||||
'blender': (2, 90, 0),
|
||||
'location': 'File > Import-Export',
|
||||
'description': 'Import-Export as glTF 2.0',
|
||||
|
|
|
@ -12,12 +12,13 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import numpy as np
|
||||
|
||||
from . import gltf2_blender_export_keys
|
||||
from io_scene_gltf2.io.com import gltf2_io
|
||||
from io_scene_gltf2.io.com import gltf2_io_constants
|
||||
from io_scene_gltf2.io.com import gltf2_io_debug
|
||||
from io_scene_gltf2.io.exp import gltf2_io_binary_data
|
||||
from io_scene_gltf2.blender.exp import gltf2_blender_utils
|
||||
|
||||
|
||||
def gather_primitive_attributes(blender_primitive, export_settings):
|
||||
|
@ -36,72 +37,79 @@ def gather_primitive_attributes(blender_primitive, export_settings):
|
|||
return attributes
|
||||
|
||||
|
||||
def array_to_accessor(array, component_type, data_type, include_max_and_min=False):
|
||||
dtype = gltf2_io_constants.ComponentType.to_numpy_dtype(component_type)
|
||||
num_elems = gltf2_io_constants.DataType.num_elements(data_type)
|
||||
|
||||
if type(array) is not np.ndarray:
|
||||
array = np.array(array, dtype=dtype)
|
||||
array = array.reshape(len(array) // num_elems, num_elems)
|
||||
|
||||
assert array.dtype == dtype
|
||||
assert array.shape[1] == num_elems
|
||||
|
||||
amax = None
|
||||
amin = None
|
||||
if include_max_and_min:
|
||||
amax = np.amax(array, axis=0).tolist()
|
||||
amin = np.amin(array, axis=0).tolist()
|
||||
|
||||
return gltf2_io.Accessor(
|
||||
buffer_view=gltf2_io_binary_data.BinaryData(array.tobytes()),
|
||||
byte_offset=None,
|
||||
component_type=component_type,
|
||||
count=len(array),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=amax,
|
||||
min=amin,
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=data_type,
|
||||
)
|
||||
|
||||
|
||||
def __gather_position(blender_primitive, export_settings):
|
||||
position = blender_primitive["attributes"]["POSITION"]
|
||||
componentType = gltf2_io_constants.ComponentType.Float
|
||||
return {
|
||||
"POSITION": gltf2_io.Accessor(
|
||||
buffer_view=gltf2_io_binary_data.BinaryData.from_list(position, componentType),
|
||||
byte_offset=None,
|
||||
component_type=componentType,
|
||||
count=len(position) // gltf2_io_constants.DataType.num_elements(gltf2_io_constants.DataType.Vec3),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=gltf2_blender_utils.max_components(position, gltf2_io_constants.DataType.Vec3),
|
||||
min=gltf2_blender_utils.min_components(position, gltf2_io_constants.DataType.Vec3),
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=gltf2_io_constants.DataType.Vec3
|
||||
"POSITION": array_to_accessor(
|
||||
position,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
data_type=gltf2_io_constants.DataType.Vec3,
|
||||
include_max_and_min=True
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def __gather_normal(blender_primitive, export_settings):
|
||||
if export_settings[gltf2_blender_export_keys.NORMALS]:
|
||||
normal = blender_primitive["attributes"]['NORMAL']
|
||||
return {
|
||||
"NORMAL": gltf2_io.Accessor(
|
||||
buffer_view=gltf2_io_binary_data.BinaryData.from_list(normal, gltf2_io_constants.ComponentType.Float),
|
||||
byte_offset=None,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
count=len(normal) // gltf2_io_constants.DataType.num_elements(gltf2_io_constants.DataType.Vec3),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=None,
|
||||
min=None,
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=gltf2_io_constants.DataType.Vec3
|
||||
)
|
||||
}
|
||||
return {}
|
||||
if not export_settings[gltf2_blender_export_keys.NORMALS]:
|
||||
return {}
|
||||
normal = blender_primitive["attributes"].get('NORMAL')
|
||||
if not normal:
|
||||
return {}
|
||||
return {
|
||||
"NORMAL": array_to_accessor(
|
||||
normal,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
data_type=gltf2_io_constants.DataType.Vec3,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def __gather_tangent(blender_primitive, export_settings):
|
||||
if export_settings[gltf2_blender_export_keys.TANGENTS]:
|
||||
if blender_primitive["attributes"].get('TANGENT') is not None:
|
||||
tangent = blender_primitive["attributes"]['TANGENT']
|
||||
return {
|
||||
"TANGENT": gltf2_io.Accessor(
|
||||
buffer_view=gltf2_io_binary_data.BinaryData.from_list(
|
||||
tangent, gltf2_io_constants.ComponentType.Float),
|
||||
byte_offset=None,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
count=len(tangent) // gltf2_io_constants.DataType.num_elements(gltf2_io_constants.DataType.Vec4),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=None,
|
||||
min=None,
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=gltf2_io_constants.DataType.Vec4
|
||||
)
|
||||
}
|
||||
|
||||
return {}
|
||||
if not export_settings[gltf2_blender_export_keys.TANGENTS]:
|
||||
return {}
|
||||
tangent = blender_primitive["attributes"].get('TANGENT')
|
||||
if not tangent:
|
||||
return {}
|
||||
return {
|
||||
"TANGENT": array_to_accessor(
|
||||
tangent,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
data_type=gltf2_io_constants.DataType.Vec4,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def __gather_texcoord(blender_primitive, export_settings):
|
||||
|
@ -111,20 +119,10 @@ def __gather_texcoord(blender_primitive, export_settings):
|
|||
tex_coord_id = 'TEXCOORD_' + str(tex_coord_index)
|
||||
while blender_primitive["attributes"].get(tex_coord_id) is not None:
|
||||
tex_coord = blender_primitive["attributes"][tex_coord_id]
|
||||
attributes[tex_coord_id] = gltf2_io.Accessor(
|
||||
buffer_view=gltf2_io_binary_data.BinaryData.from_list(
|
||||
tex_coord, gltf2_io_constants.ComponentType.Float),
|
||||
byte_offset=None,
|
||||
attributes[tex_coord_id] = array_to_accessor(
|
||||
tex_coord,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
count=len(tex_coord) // gltf2_io_constants.DataType.num_elements(gltf2_io_constants.DataType.Vec2),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=None,
|
||||
min=None,
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=gltf2_io_constants.DataType.Vec2
|
||||
data_type=gltf2_io_constants.DataType.Vec2,
|
||||
)
|
||||
tex_coord_index += 1
|
||||
tex_coord_id = 'TEXCOORD_' + str(tex_coord_index)
|
||||
|
@ -138,20 +136,10 @@ def __gather_colors(blender_primitive, export_settings):
|
|||
color_id = 'COLOR_' + str(color_index)
|
||||
while blender_primitive["attributes"].get(color_id) is not None:
|
||||
internal_color = blender_primitive["attributes"][color_id]
|
||||
attributes[color_id] = gltf2_io.Accessor(
|
||||
buffer_view=gltf2_io_binary_data.BinaryData.from_list(
|
||||
internal_color, gltf2_io_constants.ComponentType.Float),
|
||||
byte_offset=None,
|
||||
attributes[color_id] = array_to_accessor(
|
||||
internal_color,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
count=len(internal_color) // gltf2_io_constants.DataType.num_elements(gltf2_io_constants.DataType.Vec4),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=None,
|
||||
min=None,
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=gltf2_io_constants.DataType.Vec4
|
||||
data_type=gltf2_io_constants.DataType.Vec4,
|
||||
)
|
||||
color_index += 1
|
||||
color_id = 'COLOR_' + str(color_index)
|
||||
|
@ -173,20 +161,10 @@ def __gather_skins(blender_primitive, export_settings):
|
|||
|
||||
# joints
|
||||
internal_joint = blender_primitive["attributes"][joint_id]
|
||||
joint = gltf2_io.Accessor(
|
||||
buffer_view=gltf2_io_binary_data.BinaryData.from_list(
|
||||
internal_joint, gltf2_io_constants.ComponentType.UnsignedShort),
|
||||
byte_offset=None,
|
||||
joint = array_to_accessor(
|
||||
internal_joint,
|
||||
component_type=gltf2_io_constants.ComponentType.UnsignedShort,
|
||||
count=len(internal_joint) // gltf2_io_constants.DataType.num_elements(gltf2_io_constants.DataType.Vec4),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=None,
|
||||
min=None,
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=gltf2_io_constants.DataType.Vec4
|
||||
data_type=gltf2_io_constants.DataType.Vec4,
|
||||
)
|
||||
attributes[joint_id] = joint
|
||||
|
||||
|
@ -201,21 +179,10 @@ def __gather_skins(blender_primitive, export_settings):
|
|||
factor = 1.0 / total
|
||||
internal_weight[idx:idx + 4] = [w * factor for w in weight_slice]
|
||||
|
||||
weight = gltf2_io.Accessor(
|
||||
buffer_view=gltf2_io_binary_data.BinaryData.from_list(
|
||||
internal_weight, gltf2_io_constants.ComponentType.Float),
|
||||
byte_offset=None,
|
||||
weight = array_to_accessor(
|
||||
internal_weight,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
count=len(internal_weight) // gltf2_io_constants.DataType.num_elements(
|
||||
gltf2_io_constants.DataType.Vec4),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=None,
|
||||
min=None,
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=gltf2_io_constants.DataType.Vec4
|
||||
data_type=gltf2_io_constants.DataType.Vec4,
|
||||
)
|
||||
attributes[weight_id] = weight
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ from io_scene_gltf2.blender.exp.gltf2_blender_gather_cache import cached
|
|||
from io_scene_gltf2.blender.exp import gltf2_blender_extract
|
||||
from io_scene_gltf2.blender.exp import gltf2_blender_gather_accessors
|
||||
from io_scene_gltf2.blender.exp import gltf2_blender_gather_primitive_attributes
|
||||
from io_scene_gltf2.blender.exp import gltf2_blender_utils
|
||||
from io_scene_gltf2.blender.exp import gltf2_blender_gather_materials
|
||||
|
||||
from io_scene_gltf2.io.com import gltf2_io
|
||||
|
@ -160,26 +159,11 @@ def __gather_targets(blender_primitive, blender_mesh, modifiers, export_settings
|
|||
if blender_primitive["attributes"].get(target_position_id):
|
||||
target = {}
|
||||
internal_target_position = blender_primitive["attributes"][target_position_id]
|
||||
binary_data = gltf2_io_binary_data.BinaryData.from_list(
|
||||
target["POSITION"] = gltf2_blender_gather_primitive_attributes.array_to_accessor(
|
||||
internal_target_position,
|
||||
gltf2_io_constants.ComponentType.Float
|
||||
)
|
||||
target["POSITION"] = gltf2_io.Accessor(
|
||||
buffer_view=binary_data,
|
||||
byte_offset=None,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
count=len(internal_target_position) // gltf2_io_constants.DataType.num_elements(
|
||||
gltf2_io_constants.DataType.Vec3),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=gltf2_blender_utils.max_components(
|
||||
internal_target_position, gltf2_io_constants.DataType.Vec3),
|
||||
min=gltf2_blender_utils.min_components(
|
||||
internal_target_position, gltf2_io_constants.DataType.Vec3),
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=gltf2_io_constants.DataType.Vec3
|
||||
data_type=gltf2_io_constants.DataType.Vec3,
|
||||
include_max_and_min=True,
|
||||
)
|
||||
|
||||
if export_settings[NORMALS] \
|
||||
|
@ -187,48 +171,20 @@ def __gather_targets(blender_primitive, blender_mesh, modifiers, export_settings
|
|||
and blender_primitive["attributes"].get(target_normal_id):
|
||||
|
||||
internal_target_normal = blender_primitive["attributes"][target_normal_id]
|
||||
binary_data = gltf2_io_binary_data.BinaryData.from_list(
|
||||
target['NORMAL'] = gltf2_blender_gather_primitive_attributes.array_to_accessor(
|
||||
internal_target_normal,
|
||||
gltf2_io_constants.ComponentType.Float,
|
||||
)
|
||||
target['NORMAL'] = gltf2_io.Accessor(
|
||||
buffer_view=binary_data,
|
||||
byte_offset=None,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
count=len(internal_target_normal) // gltf2_io_constants.DataType.num_elements(
|
||||
gltf2_io_constants.DataType.Vec3),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=None,
|
||||
min=None,
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=gltf2_io_constants.DataType.Vec3
|
||||
data_type=gltf2_io_constants.DataType.Vec3,
|
||||
)
|
||||
|
||||
if export_settings[TANGENTS] \
|
||||
and export_settings[MORPH_TANGENT] \
|
||||
and blender_primitive["attributes"].get(target_tangent_id):
|
||||
internal_target_tangent = blender_primitive["attributes"][target_tangent_id]
|
||||
binary_data = gltf2_io_binary_data.BinaryData.from_list(
|
||||
target['TANGENT'] = gltf2_blender_gather_primitive_attributes.array_to_accessor(
|
||||
internal_target_tangent,
|
||||
gltf2_io_constants.ComponentType.Float,
|
||||
)
|
||||
target['TANGENT'] = gltf2_io.Accessor(
|
||||
buffer_view=binary_data,
|
||||
byte_offset=None,
|
||||
component_type=gltf2_io_constants.ComponentType.Float,
|
||||
count=len(internal_target_tangent) // gltf2_io_constants.DataType.num_elements(
|
||||
gltf2_io_constants.DataType.Vec3),
|
||||
extensions=None,
|
||||
extras=None,
|
||||
max=None,
|
||||
min=None,
|
||||
name=None,
|
||||
normalized=None,
|
||||
sparse=None,
|
||||
type=gltf2_io_constants.DataType.Vec3
|
||||
data_type=gltf2_io_constants.DataType.Vec3,
|
||||
)
|
||||
targets.append(target)
|
||||
morph_index += 1
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import math
|
||||
from io_scene_gltf2.io.com import gltf2_io_constants
|
||||
|
||||
|
||||
# TODO: we could apply functional programming to these problems (currently we only have a single use case)
|
||||
|
||||
def split_list_by_data_type(l: list, data_type: gltf2_io_constants.DataType):
|
||||
"""
|
||||
Split a flat list of components by their data type.
|
||||
|
||||
E.g.: A list [0,1,2,3,4,5] of data type Vec3 would be split to [[0,1,2], [3,4,5]]
|
||||
:param l: the flat list
|
||||
:param data_type: the data type of the list
|
||||
:return: a list of lists, where each element list contains the components of the data type
|
||||
"""
|
||||
if not (len(l) % gltf2_io_constants.DataType.num_elements(data_type) == 0):
|
||||
raise ValueError("List length does not match specified data type")
|
||||
num_elements = gltf2_io_constants.DataType.num_elements(data_type)
|
||||
return [l[i:i + num_elements] for i in range(0, len(l), num_elements)]
|
||||
|
||||
|
||||
def max_components(l: list, data_type: gltf2_io_constants.DataType) -> list:
|
||||
"""
|
||||
Find the maximum components in a flat list.
|
||||
|
||||
This is required, for example, for the glTF2.0 accessor min and max properties
|
||||
:param l: the flat list of components
|
||||
:param data_type: the data type of the list (determines the length of the result)
|
||||
:return: a list with length num_elements(data_type) containing the maximum per component along the list
|
||||
"""
|
||||
components_lists = split_list_by_data_type(l, data_type)
|
||||
result = [-math.inf] * gltf2_io_constants.DataType.num_elements(data_type)
|
||||
for components in components_lists:
|
||||
for i, c in enumerate(components):
|
||||
result[i] = max(result[i], c)
|
||||
return result
|
||||
|
||||
|
||||
def min_components(l: list, data_type: gltf2_io_constants.DataType) -> list:
|
||||
"""
|
||||
Find the minimum components in a flat list.
|
||||
|
||||
This is required, for example, for the glTF2.0 accessor min and max properties
|
||||
:param l: the flat list of components
|
||||
:param data_type: the data type of the list (determines the length of the result)
|
||||
:return: a list with length num_elements(data_type) containing the minimum per component along the list
|
||||
"""
|
||||
components_lists = split_list_by_data_type(l, data_type)
|
||||
result = [math.inf] * gltf2_io_constants.DataType.num_elements(data_type)
|
||||
for components in components_lists:
|
||||
for i, c in enumerate(components):
|
||||
result[i] = min(result[i], c)
|
||||
return result
|
|
@ -34,6 +34,18 @@ class ComponentType(IntEnum):
|
|||
ComponentType.Float: 'f'
|
||||
}[component_type]
|
||||
|
||||
@classmethod
|
||||
def to_numpy_dtype(cls, component_type):
|
||||
import numpy as np
|
||||
return {
|
||||
ComponentType.Byte: np.int8,
|
||||
ComponentType.UnsignedByte: np.uint8,
|
||||
ComponentType.Short: np.int16,
|
||||
ComponentType.UnsignedShort: np.uint16,
|
||||
ComponentType.UnsignedInt: np.uint32,
|
||||
ComponentType.Float: np.float32,
|
||||
}[component_type]
|
||||
|
||||
@classmethod
|
||||
def from_legacy_define(cls, type_define):
|
||||
return {
|
||||
|
|
Loading…
Reference in New Issue