Example #1
0
def __gather_indices(blender_primitive, blender_mesh, modifiers,
                     export_settings):
    indices = blender_primitive.get('indices')
    if indices is None:
        return None

    # NOTE: Values used by some graphics APIs as "primitive restart" values are disallowed.
    # Specifically, the values 65535 (in UINT16) and 4294967295 (in UINT32) cannot be used as indices.
    # https://github.com/KhronosGroup/glTF/issues/1142
    # https://github.com/KhronosGroup/glTF/pull/1476/files
    # Also, UINT8 mode is not supported:
    # https://github.com/KhronosGroup/glTF/issues/1471
    max_index = indices.max()
    if max_index < 65535:
        component_type = gltf2_io_constants.ComponentType.UnsignedShort
        indices = indices.astype(np.uint16, copy=False)
    elif max_index < 4294967295:
        component_type = gltf2_io_constants.ComponentType.UnsignedInt
        indices = indices.astype(np.uint32, copy=False)
    else:
        print_console(
            'ERROR', 'A mesh contains too many vertices (' + str(max_index) +
            ') and needs to be split before export.')
        return None

    element_type = gltf2_io_constants.DataType.Scalar
    binary_data = gltf2_io_binary_data.BinaryData(indices.tobytes())
    return gltf2_blender_gather_accessors.gather_accessor(
        binary_data, component_type, len(indices), None, None, element_type,
        export_settings)
Example #2
0
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]

            if type(colors) is not np.ndarray:
                colors = np.array(colors, dtype=np.float32)
                colors = colors.reshape(len(colors) // 4, 4)

            # Convert to normalized ushorts
            colors *= 65535
            colors += 0.5  # bias for rounding
            colors = colors.astype(np.uint16)

            attributes[color_id] = gltf2_io.Accessor(
                buffer_view=gltf2_io_binary_data.BinaryData(colors.tobytes()),
                byte_offset=None,
                component_type=gltf2_io_constants.ComponentType.UnsignedShort,
                count=len(colors),
                extensions=None,
                extras=None,
                max=None,
                min=None,
                name=None,
                normalized=True,
                sparse=None,
                type=gltf2_io_constants.DataType.Vec4,
            )

            color_index += 1
            color_id = 'COLOR_' + str(color_index)
    return attributes
Example #3
0
def __gather_buffer_view(sockets_or_slots, export_settings):
    if export_settings['gltf_format'] != 'ASCII':

        image = __get_image_data(sockets_or_slots)
        return gltf2_io_binary_data.BinaryData(
            data=image.to_image_data(__gather_mime_type(sockets_or_slots, export_settings)))
    return None
Example #4
0
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,
    )
Example #5
0
def __gather_targets(blender_primitive, blender_object, export_settings):
    if export_settings['gltf_morph']:
        targets = []
        blender_mesh = blender_object.data
        if blender_mesh.shape_keys is not None:
            morph_index = 0
            for blender_shape_key in blender_mesh.shape_keys.key_blocks:
                if blender_shape_key != blender_shape_key.relative_key:

                    target_position_id = 'MORPH_POSITION_' + str(morph_index)
                    target_normal_id = 'MORPH_NORMAL_' + str(morph_index)
                    target_tangent_id = 'MORPH_TANGENT_' + str(morph_index)

                    if blender_primitive["attributes"].get(target_position_id):
                        target = {}
                        internal_target_position = blender_primitive[
                            "attributes"][target_position_id]
                        target["POSITION"] = gltf2_io_binary_data.BinaryData(
                            internal_target_position,
                            gltf2_io_constants.GLTF_COMPONENT_TYPE_FLOAT,
                            gltf2_io_constants.GLTF_DATA_TYPE_VEC3,
                            group_label="primitives_targets")
                        if export_settings['gltf_normals'] \
                                and export_settings['gltf_morph_normal'] \
                                and blender_primitive["attributes"].get(target_normal_id):

                            internal_target_normal = blender_primitive[
                                "attributes"][target_normal_id]
                            target['NORMAL'] = gltf2_io_binary_data.BinaryData(
                                internal_target_normal,
                                gltf2_io_constants.GLTF_COMPONENT_TYPE_FLOAT,
                                gltf2_io_constants.GLTF_DATA_TYPE_VEC3,
                                group_label="primitives_targets")
                        if export_settings['gltf_tangents'] \
                                and export_settings['gltf_morph_tangent'] \
                                and blender_primitive["attributes"].get(target_tangent_id):
                            internal_target_tangent = blender_primitive[
                                "attributes"][target_tangent_id]
                            target['TANGENT'] = gltf2_io_binary_data.BinaryData(
                                internal_target_tangent,
                                gltf2_io_constants.GLTF_COMPONENT_TYPE_FLOAT,
                                gltf2_io_constants.GLTF_DATA_TYPE_VEC3,
                                group_label="primitives_targets")
                        targets.append(target)
                        morph_index += 1
        return targets
    return None
def __gather_buffer_view(sockets_or_slots, export_settings):
    if export_settings[gltf2_blender_export_keys.FORMAT] != 'GLTF_SEPARATE':
        image = __get_image_data(sockets_or_slots, export_settings)
        if image is None:
            return None
        return gltf2_io_binary_data.BinaryData(
            data=image.to_image_data(__gather_mime_type()))
    return None
Example #7
0
def __gather_position(blender_primitive, export_settings):
    position = blender_primitive["attributes"]["POSITION"]
    componentType = gltf2_io_constants.GLTF_COMPONENT_TYPE_FLOAT
    return {
        "POSITION": gltf2_io_binary_data.BinaryData(
            position,
            componentType,
            gltf2_io_constants.GLTF_DATA_TYPE_VEC3,
            group_label="primitives_attributes"
        )
    }
Example #8
0
def __gather_normal(blender_primitive, export_settings):
    if export_settings['gltf_normals']:
        normal = blender_primitive["attributes"]['NORMAL']
        return {
            "NORMAL": gltf2_io_binary_data.BinaryData(
                normal,
                gltf2_io_constants.GLTF_COMPONENT_TYPE_FLOAT,
                gltf2_io_constants.GLTF_DATA_TYPE_VEC3,
                group_label="primitives_attributes"
            )
        }
    return {}
Example #9
0
def __gather_tangent(blender_primitive, export_settings):
    if export_settings['gltf_tangents']:
        if blender_primitive["attributes"].get('TANGENT') is not None:
            tangent = blender_primitive["attributes"]['TANGENT']
            return {
                "TANGENT": gltf2_io_binary_data.BinaryData(
                    tangent,
                    gltf2_io_constants.GLTF_COMPONENT_TYPE_FLOAT,
                    gltf2_io_constants.GLTF_DATA_TYPE_VEC3,
                    group_label="primitives_attributes"
                )
            }
    return {}
Example #10
0
def __gather_skins(blender_primitive, export_settings):
    attributes = {}
    if export_settings['gltf_skins']:
        bone_index = 0
        joint_id = 'JOINTS_' + str(bone_index)
        weight_id = 'WEIGHTS_' + str(bone_index)
        while blender_primitive["attributes"].get(joint_id) and blender_primitive["attributes"].get(weight_id):

            # joints
            internal_joint = blender_primitive["attributes"][joint_id]
            joint = gltf2_io_binary_data.BinaryData(
                internal_joint,
                gltf2_io_constants.GLTF_COMPONENT_TYPE_UNSIGNED_SHORT,
                gltf2_io_constants.GLTF_DATA_TYPE_VEC4,
                group_label="primitives_attributes"
            ),
            if joint < 0:
                # gltf2_io_debug('ERROR', 'Could not create accessor for ' + joint_id)
                break
            attributes[joint_id] = joint

            # weights
            internal_weight = blender_primitive["attributes"][weight_id]
            weight = gltf2_io_binary_data.BinaryData(
                internal_weight,
                gltf2_io_constants.GLTF_COMPONENT_TYPE_FLOAT,
                gltf2_io_constants.GLTF_DATA_TYPE_VEC4,
                group_label="primitives_attributes"
            )
            if weight < 0:
                # print_console('ERROR', 'Could not create accessor for ' + weight_id)
                break
            attributes[weight_id] = weight

            bone_index += 1
            joint_id = 'JOINTS_' + str(bone_index)
            weight_id = 'WEIGHTS_' + str(bone_index)
    return attributes
Example #11
0
def __gather_colors(blender_primitive, export_settings):
    attributes = {}
    if export_settings['gltf_colors']:
        color_index = 0
        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_binary_data.BinaryData(
                internal_color,
                gltf2_io_constants.GLTF_COMPONENT_TYPE_FLOAT,
                gltf2_io_constants.GLTF_DATA_TYPE_VEC4,
                group_label="primitives_attributes"
            )
            color_index += 1
            color_id = 'COLOR_' + str(color_index)
    return attributes
Example #12
0
def __gather_texcoord(blender_primitive, export_settings):
    attributes = {}
    if export_settings['gltf_texcoords']:
        texcoord_index = 0
        texcoord_id = 'TEXCOORD_' + str(texcoord_index)
        while blender_primitive["attributes"].get(texcoord_id) is not None:
            texcoord = blender_primitive["attributes"][texcoord_id]
            attributes[texcoord_id] = gltf2_io_binary_data.BinaryData(
                texcoord,
                gltf2_io_constants.GLTF_COMPONENT_TYPE_FLOAT,
                gltf2_io_constants.GLTF_DATA_TYPE_VEC2,
                group_label="primitives_attributes"
            )
            texcoord_index += 1
            texcoord_id = 'TEXCOORD_' + str(texcoord_index)
    return attributes
def __get_keyframe_accessor(frame_start, frame_end, frame_step):
    # Gets an accessor for a range of keyframes. Used for sampler.input.
    fps = bpy.context.scene.render.fps
    keyframes = [
        frame / fps for frame in range(frame_start, frame_end, frame_step)
    ]
    keyframe_data = array.array('f', keyframes).tobytes()
    return gltf2_io.Accessor(
        buffer_view=gltf2_io_binary_data.BinaryData(keyframe_data),
        component_type=gltf2_io_constants.ComponentType.Float,
        type=gltf2_io_constants.DataType.Scalar,
        count=len(keyframes),
        min=[keyframes[0]],
        max=[keyframes[-1]],
        byte_offset=None,
        extensions=None,
        extras=None,
        name='accessorAnimationInput',
        normalized=None,
        sparse=None,
    )
Example #14
0
def __gather_inverse_bind_matrices(blender_object, export_settings):
    inverse_matrices = []

    axis_basis_change = mathutils.Matrix.Identity(4)
    if export_settings['gltf_yup']:
        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)))

    for blender_bone in blender_object.pose.bones:
        inverse_bind_matrix = axis_basis_change * blender_bone.bone.matrix_local
        bind_shape_matrix = axis_basis_change * blender_object.matrix_world.inverted() * axis_basis_change.inverted()

        inverse_bind_matrix = inverse_bind_matrix.inverted() * bind_shape_matrix
        for column in range(0, 4):
            for row in range(0, 4):
                inverse_matrices.append(inverse_bind_matrix[row][column])

    return gltf2_io_binary_data.BinaryData(
        data=inverse_matrices,
        component_type=gltf2_io_constants.GLTF_COMPONENT_TYPE_FLOAT,
        element_type=gltf2_io_constants.GLTF_DATA_TYPE_MAT4,
        group_label='inverse_bind_matrices'
    )
Example #15
0
def __gather_indices(blender_primitive, export_settings):
    indices = blender_primitive['indices']

    max_index = max(indices)
    if max_index < 256:
        component_type = gltf2_io_constants.GLTF_COMPONENT_TYPE_UNSIGNED_BYTE
    elif max_index < 65536:
        component_type = gltf2_io_constants.GLTF_COMPONENT_TYPE_UNSIGNED_SHORT
    elif max_index < 4294967296:
        component_type = gltf2_io_constants.GLTF_COMPONENT_TYPE_UNSIGNED_INT
    else:
        gltf2_io_debug.print_console('ERROR',
                                     'Invalid max_index: ' + str(max_index))
        return None

    if export_settings['gltf_force_indices']:
        component_type = export_settings['gltf_indices']

    element_type = gltf2_io_constants.GLTF_DATA_TYPE_SCALAR
    return gltf2_io_binary_data.BinaryData(indices,
                                           component_type,
                                           element_type,
                                           group_label="primitive_indices")
def __encode_output_accessor(values, path):
    # Encodes a list of T, R, or S (Vector/Quaternion) values to an accessor.
    vals = [x for val in values for x in val]
    vals_data = array.array('f', vals).tobytes()
    name = {
        'translation': 'accessorAnimationPositions',
        'rotation': 'accessorAnimationRotations',
        'scale': 'accessorAnimationScales'
    }.get(path)
    return gltf2_io.Accessor(
        buffer_view=gltf2_io_binary_data.BinaryData(vals_data),
        component_type=gltf2_io_constants.ComponentType.Float,
        type=gltf2_io_constants.DataType.vec_type_from_num(len(values[0])),
        count=len(values),
        min=None,
        max=None,
        byte_offset=None,
        extensions=None,
        extras=None,
        name=name,
        normalized=None,
        sparse=None,
    )
Example #17
0
def custom_data_array_to_accessor(array):
    if type(array) is not np.ndarray:
        array = np.array(array, dtype=np.float32)

    assert array.dtype == np.float32
    assert len(array.shape) == 1

    # Calculate how big a sparse array would be and switch to it if smaller

    indices_nonzero = np.nonzero(array)[0]
    num_nonzero = len(indices_nonzero)

    if num_nonzero == 0:
        return gltf2_io.Accessor(
            count=len(array),
            component_type=gltf2_io_constants.ComponentType.Float,
            type=gltf2_io_constants.DataType.Scalar,
            buffer_view=None,
            byte_offset=None,
            extensions=None,
            extras=None,
            max=None,
            min=None,
            name=None,
            normalized=None,
            sparse=None,
        )

    index_size = (1 if indices_nonzero[-1] < 256 else
                  2 if indices_nonzero[-1] < 65536 else 4)
    value_size = 4  # float32

    dense_bin_size = len(array) * value_size
    sparse_bin_size = num_nonzero * (index_size + value_size)
    bin_size_increase = sparse_bin_size - dense_bin_size
    json_size_increase = 160  # approximate
    net_size_increase = bin_size_increase + json_size_increase

    if net_size_increase >= 0:
        # Dense is better
        return array_to_accessor(
            array,
            component_type=gltf2_io_constants.ComponentType.Float,
            data_type=gltf2_io_constants.DataType.Scalar,
        )

    index_type = (gltf2_io_constants.ComponentType.UnsignedByte
                  if index_size == 1 else
                  gltf2_io_constants.ComponentType.UnsignedShort if index_size
                  == 2 else gltf2_io_constants.ComponentType.UnsignedInt)
    index_dtype = gltf2_io_constants.ComponentType.to_numpy_dtype(index_type)
    indices_nonzero = indices_nonzero.astype(index_dtype)
    values_nonzero = array[indices_nonzero]

    return gltf2_io.Accessor(
        buffer_view=None,
        byte_offset=None,
        component_type=gltf2_io_constants.ComponentType.Float,
        count=len(array),
        extensions=None,
        extras=None,
        max=None,
        min=None,
        name=None,
        normalized=None,
        type=gltf2_io_constants.DataType.Scalar,
        sparse=gltf2_io.AccessorSparse(
            count=num_nonzero,
            indices=gltf2_io.AccessorSparseIndices(
                buffer_view=gltf2_io_binary_data.BinaryData(
                    indices_nonzero.tobytes()),
                component_type=index_type,
                byte_offset=None,
                extensions=None,
                extras=None,
            ),
            values=gltf2_io.AccessorSparseValues(
                buffer_view=gltf2_io_binary_data.BinaryData(
                    values_nonzero.tobytes()),
                byte_offset=None,
                extensions=None,
                extras=None,
            ),
            extensions=None,
            extras=None,
        ),
    )
Example #18
0
def __gather_buffer_view(image_data: bytes, export_settings):
    if export_settings[gltf2_blender_export_keys.FORMAT] != 'GLTF_SEPARATE':
        return gltf2_io_binary_data.BinaryData(data=image_data)
    return None
Example #19
0
def __gather_buffer_view(image_data, mime_type, name, export_settings):
    if export_settings[gltf2_blender_export_keys.FORMAT] != 'GLTF_SEPARATE':
        return gltf2_io_binary_data.BinaryData(data=image_data.encode(mime_type))
    return None