Skip to content

Commit

Permalink
glTF exporter: performance: using numpy
Browse files Browse the repository at this point in the history
Thanks scurest!
  • Loading branch information
julienduroure committed Jul 21, 2020
1 parent 2b4bf94 commit 3ea1673
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 228 deletions.
2 changes: 1 addition & 1 deletion io_scene_gltf2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
185 changes: 76 additions & 109 deletions io_scene_gltf2/blender/exp/gltf2_blender_gather_primitive_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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):
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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

Expand All @@ -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

Expand Down
58 changes: 7 additions & 51 deletions io_scene_gltf2/blender/exp/gltf2_blender_gather_primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
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
Expand Down Expand Up @@ -160,75 +159,32 @@ 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] \
and export_settings[MORPH_NORMAL] \
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
Expand Down
Loading

0 comments on commit 3ea1673

Please sign in to comment.