diff options
Diffstat (limited to 'io_scene_gltf2/blender/exp/gltf2_blender_gather_primitive_attributes.py')
-rwxr-xr-x | io_scene_gltf2/blender/exp/gltf2_blender_gather_primitive_attributes.py | 186 |
1 files changed, 66 insertions, 120 deletions
diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitive_attributes.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitive_attributes.py index 1af588b9..ce2f9a59 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitive_attributes.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitive_attributes.py @@ -10,32 +10,34 @@ from io_scene_gltf2.io.com import gltf2_io_debug from io_scene_gltf2.io.exp import gltf2_io_binary_data + def gather_primitive_attributes(blender_primitive, export_settings): """ - Gathers the attributes, such as POSITION, NORMAL, TANGENT from a blender primitive. + Gathers the attributes, such as POSITION, NORMAL, TANGENT, and all custom attributes from a blender primitive :return: a dictionary of attributes """ attributes = {} - attributes.update(__gather_position(blender_primitive, export_settings)) - attributes.update(__gather_normal(blender_primitive, export_settings)) - attributes.update(__gather_tangent(blender_primitive, export_settings)) - attributes.update(__gather_texcoord(blender_primitive, export_settings)) - attributes.update(__gather_colors(blender_primitive, export_settings)) - attributes.update(__gather_skins(blender_primitive, export_settings)) - return attributes + # loop on each attribute extracted + # for skinning, all linked attributes (WEIGHTS_ and JOINTS_) need to be calculated + # in one shot (because of normalization), so we need to check that it is called only once. -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) + skin_done = False + + for attribute in blender_primitive["attributes"]: + if (attribute.startswith("JOINTS_") or attribute.startswith("WEIGHTS_")) and skin_done is True: + continue + if attribute.startswith("MORPH_"): + continue # Target for morphs will be managed later + attributes.update(__gather_attribute(blender_primitive, attribute, export_settings)) + if (attribute.startswith("JOINTS_") or attribute.startswith("WEIGHTS_")): + skin_done = True + + return attributes - 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 +def array_to_accessor(array, component_type, data_type, include_max_and_min=False): amax = None amin = None @@ -58,109 +60,6 @@ def array_to_accessor(array, component_type, data_type, include_max_and_min=Fals type=data_type, ) - -def __gather_position(blender_primitive, export_settings): - position = blender_primitive["attributes"]["POSITION"] - return { - "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 not export_settings[gltf2_blender_export_keys.NORMALS]: - return {} - if 'NORMAL' not in blender_primitive["attributes"]: - return {} - normal = blender_primitive["attributes"]['NORMAL'] - 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 not export_settings[gltf2_blender_export_keys.TANGENTS]: - return {} - if 'TANGENT' not in blender_primitive["attributes"]: - return {} - tangent = blender_primitive["attributes"]['TANGENT'] - 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): - attributes = {} - if export_settings[gltf2_blender_export_keys.TEX_COORDS]: - tex_coord_index = 0 - 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] = array_to_accessor( - tex_coord, - component_type=gltf2_io_constants.ComponentType.Float, - data_type=gltf2_io_constants.DataType.Vec2, - ) - tex_coord_index += 1 - tex_coord_id = 'TEXCOORD_' + str(tex_coord_index) - return attributes - - -def __gather_colors(blender_primitive, export_settings): - attributes = {} - if export_settings[gltf2_blender_export_keys.COLORS]: - color_index = 0 - color_id = 'COLOR_' + str(color_index) - while blender_primitive["attributes"].get(color_id) is not None: - colors = blender_primitive["attributes"][color_id]["data"] - - if type(colors) is not np.ndarray: - colors = np.array(colors, dtype=np.float32) - colors = colors.reshape(len(colors) // 4, 4) - - if blender_primitive["attributes"][color_id]["norm"] is True: - comp_type = gltf2_io_constants.ComponentType.UnsignedShort - - # Convert to normalized ushorts - colors *= 65535 - colors += 0.5 # bias for rounding - colors = colors.astype(np.uint16) - - else: - comp_type = gltf2_io_constants.ComponentType.Float - - attributes[color_id] = gltf2_io.Accessor( - buffer_view=gltf2_io_binary_data.BinaryData(colors.tobytes(), gltf2_io_constants.BufferViewTarget.ARRAY_BUFFER), - byte_offset=None, - component_type=comp_type, - count=len(colors), - extensions=None, - extras=None, - max=None, - min=None, - name=None, - normalized=blender_primitive["attributes"][color_id]["norm"], - sparse=None, - type=gltf2_io_constants.DataType.Vec4, - ) - - color_index += 1 - color_id = 'COLOR_' + str(color_index) - return attributes - - def __gather_skins(blender_primitive, export_settings): attributes = {} @@ -208,8 +107,10 @@ def __gather_skins(blender_primitive, export_settings): component_type = gltf2_io_constants.ComponentType.UnsignedShort if max(internal_joint) < 256: component_type = gltf2_io_constants.ComponentType.UnsignedByte + joints = np.array(internal_joint, dtype= gltf2_io_constants.ComponentType.to_numpy_dtype(component_type)) + joints = joints.reshape(-1, 4) joint = array_to_accessor( - internal_joint, + joints, component_type, data_type=gltf2_io_constants.DataType.Vec4, ) @@ -236,3 +137,48 @@ def __gather_skins(blender_primitive, export_settings): attributes[weight_id] = weight return attributes + + +def __gather_attribute(blender_primitive, attribute, export_settings): + data = blender_primitive["attributes"][attribute] + + + include_max_and_mins = { + "POSITION": True + } + + if (attribute.startswith("_COLOR") or attribute.startswith("COLOR_")) and blender_primitive["attributes"][attribute]['component_type'] == gltf2_io_constants.ComponentType.UnsignedShort: + # Byte Color vertex color, need to normalize + + data['data'] *= 65535 + data['data'] += 0.5 # bias for rounding + data['data'] = data['data'].astype(np.uint16) + + return { attribute : gltf2_io.Accessor( + buffer_view=gltf2_io_binary_data.BinaryData(data['data'].tobytes(), gltf2_io_constants.BufferViewTarget.ARRAY_BUFFER), + byte_offset=None, + component_type=data['component_type'], + count=len(data['data']), + extensions=None, + extras=None, + max=None, + min=None, + name=None, + normalized=True, + sparse=None, + type=data['data_type'], + ) + } + + elif attribute.startswith("JOINTS_") or attribute.startswith("WEIGHTS_"): + return __gather_skins(blender_primitive, export_settings) + + else: + return { + attribute: array_to_accessor( + data['data'], + component_type=data['component_type'], + data_type=data['data_type'], + include_max_and_min=include_max_and_mins.get(attribute, False) + ) + } |