def gather_image(blender_shader_sockets: typing.Tuple[bpy.types.NodeSocket],
                 export_settings):
    if not __filter_image(blender_shader_sockets, export_settings):
        return None

    image_data = __get_image_data(blender_shader_sockets, export_settings)
    if image_data.empty():
        # The export image has no data
        return None

    mime_type = __gather_mime_type(blender_shader_sockets, image_data,
                                   export_settings)
    name = __gather_name(image_data, export_settings)

    uri = __gather_uri(image_data, mime_type, name, export_settings)
    buffer_view = __gather_buffer_view(image_data, mime_type, name,
                                       export_settings)

    image = __make_image(
        buffer_view,
        __gather_extensions(blender_shader_sockets, export_settings),
        __gather_extras(blender_shader_sockets, export_settings), mime_type,
        name, uri, export_settings)

    export_user_extensions('gather_image_hook', export_settings, image,
                           blender_shader_sockets)

    return image
Exemplo n.º 2
0
def __gather_material_unlit(blender_material, export_settings):
    gltf2_unlit = gltf2_blender_gather_materials_unlit

    info = gltf2_unlit.detect_shadeless_material(blender_material, export_settings)
    if info is None:
        return None

    material = gltf2_io.Material(
        alpha_cutoff=__gather_alpha_cutoff(blender_material, export_settings),
        alpha_mode=__gather_alpha_mode(blender_material, export_settings),
        double_sided=__gather_double_sided(blender_material, export_settings),
        extensions={"KHR_materials_unlit": Extension("KHR_materials_unlit", {}, required=False)},
        extras=__gather_extras(blender_material, export_settings),
        name=__gather_name(blender_material, export_settings),
        emissive_factor=None,
        emissive_texture=None,
        normal_texture=None,
        occlusion_texture=None,

        pbr_metallic_roughness=gltf2_io.MaterialPBRMetallicRoughness(
            base_color_factor=gltf2_unlit.gather_base_color_factor(info, export_settings),
            base_color_texture=gltf2_unlit.gather_base_color_texture(info, export_settings),
            metallic_factor=0.0,
            roughness_factor=0.9,
            metallic_roughness_texture=None,
            extensions=None,
            extras=None,
        )
    )

    export_user_extensions('gather_material_unlit_hook', export_settings, material, blender_material)

    return material
Exemplo n.º 3
0
def gather_texture(blender_shader_sockets: typing.Tuple[bpy.types.NodeSocket],
                   export_settings):
    """
    Gather texture sampling information and image channels from a blender shader texture attached to a shader socket.

    :param blender_shader_sockets: The sockets of the material which should contribute to the texture
    :param export_settings: configuration of the export
    :return: a glTF 2.0 texture with sampler and source embedded (will be converted to references by the exporter)
    """
    if not __filter_texture(blender_shader_sockets, export_settings):
        return None

    texture = gltf2_io.Texture(
        extensions=__gather_extensions(blender_shader_sockets,
                                       export_settings),
        extras=__gather_extras(blender_shader_sockets, export_settings),
        name=__gather_name(blender_shader_sockets, export_settings),
        sampler=__gather_sampler(blender_shader_sockets, export_settings),
        source=__gather_source(blender_shader_sockets, export_settings))

    # although valid, most viewers can't handle missing source properties
    if texture.source is None:
        return None

    export_user_extensions('gather_texture_hook', export_settings, texture,
                           blender_shader_sockets)

    return texture
def gather_mesh(blender_mesh: bpy.types.Mesh,
                library: Optional[str],
                blender_object: Optional[bpy.types.Object],
                vertex_groups: Optional[bpy.types.VertexGroups],
                modifiers: Optional[bpy.types.ObjectModifiers],
                skip_filter: bool,
                material_names: Tuple[str],
                export_settings
                ) -> Optional[gltf2_io.Mesh]:
    if not skip_filter and not __filter_mesh(blender_mesh, library, vertex_groups, modifiers, export_settings):
        return None

    mesh = gltf2_io.Mesh(
        extensions=__gather_extensions(blender_mesh, library, vertex_groups, modifiers, export_settings),
        extras=__gather_extras(blender_mesh, library, vertex_groups, modifiers, export_settings),
        name=__gather_name(blender_mesh, library, vertex_groups, modifiers, export_settings),
        weights=__gather_weights(blender_mesh, library, vertex_groups, modifiers, export_settings),
        primitives=__gather_primitives(blender_mesh, library, blender_object, vertex_groups, modifiers, material_names, export_settings),
    )

    if len(mesh.primitives) == 0:
        print_console("WARNING", "Mesh '{}' has no primitives and will be omitted.".format(mesh.name))
        return None

    export_user_extensions('gather_mesh_hook',
                           export_settings,
                           mesh,
                           blender_mesh,
                           blender_object,
                           vertex_groups,
                           modifiers,
                           skip_filter,
                           material_names)

    return mesh
Exemplo n.º 5
0
def gather_material(blender_material, export_settings):
    """
    Gather the material used by the blender primitive.

    :param blender_material: the blender material used in the glTF primitive
    :param export_settings:
    :return: a glTF material
    """
    if not __filter_material(blender_material, export_settings):
        return None

    mat_unlit = __gather_material_unlit(blender_material, export_settings)
    if mat_unlit is not None:
        return mat_unlit

    orm_texture = __gather_orm_texture(blender_material, export_settings)

    material = gltf2_io.Material(
        alpha_cutoff=__gather_alpha_cutoff(blender_material, export_settings),
        alpha_mode=__gather_alpha_mode(blender_material, export_settings),
        double_sided=__gather_double_sided(blender_material, export_settings),
        emissive_factor=__gather_emissive_factor(blender_material, export_settings),
        emissive_texture=__gather_emissive_texture(blender_material, export_settings),
        extensions=__gather_extensions(blender_material, export_settings),
        extras=__gather_extras(blender_material, export_settings),
        name=__gather_name(blender_material, export_settings),
        normal_texture=__gather_normal_texture(blender_material, export_settings),
        occlusion_texture=__gather_occlusion_texture(blender_material, orm_texture, export_settings),
        pbr_metallic_roughness=__gather_pbr_metallic_roughness(blender_material, orm_texture, export_settings)
    )

    export_user_extensions('gather_material_hook', export_settings, material, blender_material)

    return material
Exemplo n.º 6
0
def __gather_animation(blender_action: bpy.types.Action,
                       blender_object: bpy.types.Object,
                       export_settings) -> typing.Optional[gltf2_io.Animation]:
    if not __filter_animation(blender_action, blender_object, export_settings):
        return None

    name = __gather_name(blender_action, blender_object, export_settings)
    try:
        animation = gltf2_io.Animation(
            channels=__gather_channels(blender_action, blender_object,
                                       export_settings),
            extensions=__gather_extensions(blender_action, blender_object,
                                           export_settings),
            extras=__gather_extras(blender_action, blender_object,
                                   export_settings),
            name=name,
            samplers=__gather_samplers(blender_action, blender_object,
                                       export_settings))
    except RuntimeError as error:
        print_console(
            "WARNING",
            "Animation '{}' could not be exported. Cause: {}".format(
                name, error))
        return None

    # To allow reuse of samplers in one animation,
    __link_samplers(animation, export_settings)

    if not animation.channels:
        return None

    export_user_extensions('gather_animation_hook', export_settings, animation,
                           blender_action, blender_object)

    return animation
def gather_sampler(blender_shader_node: bpy.types.Node, export_settings):
    wrap_s, wrap_t = __gather_wrap(blender_shader_node, export_settings)

    sampler = gltf2_io.Sampler(
        extensions=__gather_extensions(blender_shader_node, export_settings),
        extras=__gather_extras(blender_shader_node, export_settings),
        mag_filter=__gather_mag_filter(blender_shader_node, export_settings),
        min_filter=__gather_min_filter(blender_shader_node, export_settings),
        name=__gather_name(blender_shader_node, export_settings),
        wrap_s=wrap_s,
        wrap_t=wrap_t,
    )

    export_user_extensions('gather_sampler_hook', export_settings, sampler, blender_shader_node)

    if not sampler.extensions and not sampler.extras and not sampler.name:
        return __sampler_by_value(
            sampler.mag_filter,
            sampler.min_filter,
            sampler.wrap_s,
            sampler.wrap_t,
            export_settings,
        )

    return sampler
def gather_animation_sampler(channels: typing.Tuple[bpy.types.FCurve],
                             blender_object: bpy.types.Object,
                             bake_bone: typing.Union[str, None],
                             bake_channel: typing.Union[str, None],
                             bake_range_start, bake_range_end,
                             action_name: str, driver_obj,
                             export_settings) -> gltf2_io.AnimationSampler:

    blender_object_if_armature = blender_object if blender_object.type == "ARMATURE" else None
    if blender_object_if_armature is not None and driver_obj is None:
        if bake_bone is None:
            pose_bone_if_armature = gltf2_blender_get.get_object_from_datapath(
                blender_object_if_armature, channels[0].data_path)
        else:
            pose_bone_if_armature = blender_object.pose.bones[bake_bone]
    else:
        pose_bone_if_armature = None
    non_keyed_values = __gather_non_keyed_values(channels, blender_object,
                                                 blender_object_if_armature,
                                                 pose_bone_if_armature,
                                                 bake_channel, driver_obj,
                                                 export_settings)

    sampler = gltf2_io.AnimationSampler(
        extensions=__gather_extensions(channels, blender_object_if_armature,
                                       export_settings, bake_bone,
                                       bake_channel),
        extras=__gather_extras(channels, blender_object_if_armature,
                               export_settings, bake_bone, bake_channel),
        input=__gather_input(channels, blender_object_if_armature,
                             non_keyed_values, bake_bone, bake_channel,
                             bake_range_start, bake_range_end, action_name,
                             driver_obj, export_settings),
        interpolation=__gather_interpolation(channels,
                                             blender_object_if_armature,
                                             export_settings, bake_bone,
                                             bake_channel),
        output=__gather_output(
            channels,
            blender_object.matrix_parent_inverse.copy().freeze(),
            blender_object_if_armature, non_keyed_values, bake_bone,
            bake_channel, bake_range_start, bake_range_end, action_name,
            driver_obj, export_settings))

    export_user_extensions('gather_animation_sampler_hook', export_settings,
                           sampler, channels, blender_object, bake_bone,
                           bake_channel, bake_range_start, bake_range_end,
                           action_name)

    return sampler
def gather_camera(blender_camera, export_settings):
    if not __filter_camera(blender_camera, export_settings):
        return None

    camera = gltf2_io.Camera(
        extensions=__gather_extensions(blender_camera, export_settings),
        extras=__gather_extras(blender_camera, export_settings),
        name=__gather_name(blender_camera, export_settings),
        orthographic=__gather_orthographic(blender_camera, export_settings),
        perspective=__gather_perspective(blender_camera, export_settings),
        type=__gather_type(blender_camera, export_settings))

    export_user_extensions('gather_camera_hook', export_settings, camera,
                           blender_camera)

    return camera
def __gather_scene(blender_scene, export_settings):
    scene = gltf2_io.Scene(
        extensions=None,
        extras=__gather_extras(blender_scene, export_settings),
        name=blender_scene.name,
        nodes=[]
    )

    for _blender_object in [obj for obj in blender_scene.objects if obj.proxy is None]:
        if _blender_object.parent is None:
            blender_object = _blender_object.proxy if _blender_object.proxy else _blender_object
            node = gltf2_blender_gather_nodes.gather_node(
                blender_object,
                blender_object.library.name if blender_object.library else None,
                blender_scene, None, export_settings)
            if node is not None:
                scene.nodes.append(node)

    export_user_extensions('gather_scene_hook', export_settings, scene, blender_scene)

    return scene
def gather_animation_channel_target(
        channels: typing.Tuple[bpy.types.FCurve],
        blender_object: bpy.types.Object, bake_bone: typing.Union[str, None],
        bake_channel: typing.Union[str, None], driver_obj,
        export_settings) -> gltf2_io.AnimationChannelTarget:

    animation_channel_target = gltf2_io.AnimationChannelTarget(
        extensions=__gather_extensions(channels, blender_object,
                                       export_settings, bake_bone),
        extras=__gather_extras(channels, blender_object, export_settings,
                               bake_bone),
        node=__gather_node(channels, blender_object, export_settings,
                           bake_bone, driver_obj),
        path=__gather_path(channels, blender_object, export_settings,
                           bake_bone, bake_channel))

    export_user_extensions('gather_animation_channel_target_hook',
                           export_settings, animation_channel_target, channels,
                           blender_object, bake_bone, bake_channel)

    return animation_channel_target
Exemplo n.º 12
0
def __gather_gltf(exporter, export_settings):
    active_scene_idx, scenes, animations = gltf2_blender_gather.gather_gltf2(
        export_settings)

    plan = {
        'active_scene_idx': active_scene_idx,
        'scenes': scenes,
        'animations': animations
    }
    export_user_extensions('gather_gltf_hook', export_settings, plan)
    active_scene_idx, scenes, animations = plan['active_scene_idx'], plan[
        'scenes'], plan['animations']

    if export_settings['gltf_draco_mesh_compression']:
        gltf2_io_draco_compression_extension.encode_scene_primitives(
            scenes, export_settings)
        exporter.add_draco_extension()

    for idx, scene in enumerate(scenes):
        exporter.add_scene(scene, idx == active_scene_idx)
    for animation in animations:
        exporter.add_animation(animation)
def __gather_texture_info_helper(
        primary_socket: bpy.types.NodeSocket,
        blender_shader_sockets: typing.Tuple[bpy.types.NodeSocket], kind: str,
        export_settings):
    if not __filter_texture_info(primary_socket, blender_shader_sockets,
                                 export_settings):
        return None

    tex_transform, tex_coord = __gather_texture_transform_and_tex_coord(
        primary_socket, export_settings)

    fields = {
        'extensions': __gather_extensions(tex_transform, export_settings),
        'extras': __gather_extras(blender_shader_sockets, export_settings),
        'index': __gather_index(blender_shader_sockets, export_settings),
        'tex_coord': tex_coord,
    }

    if kind == 'DEFAULT':
        texture_info = gltf2_io.TextureInfo(**fields)

    elif kind == 'NORMAL':
        fields['scale'] = __gather_normal_scale(primary_socket,
                                                export_settings)
        texture_info = gltf2_io.MaterialNormalTextureInfoClass(**fields)

    elif kind == 'OCCLUSION':
        fields['strength'] = __gather_occlusion_strength(
            primary_socket, export_settings)
        texture_info = gltf2_io.MaterialOcclusionTextureInfoClass(**fields)

    if texture_info.index is None:
        return None

    export_user_extensions('gather_texture_info_hook', export_settings,
                           texture_info, blender_shader_sockets)

    return texture_info
def gather_material_pbr_metallic_roughness(blender_material, orm_texture,
                                           export_settings):
    if not __filter_pbr_material(blender_material, export_settings):
        return None

    material = gltf2_io.MaterialPBRMetallicRoughness(
        base_color_factor=__gather_base_color_factor(blender_material,
                                                     export_settings),
        base_color_texture=__gather_base_color_texture(blender_material,
                                                       export_settings),
        extensions=__gather_extensions(blender_material, export_settings),
        extras=__gather_extras(blender_material, export_settings),
        metallic_factor=__gather_metallic_factor(blender_material,
                                                 export_settings),
        metallic_roughness_texture=__gather_metallic_roughness_texture(
            blender_material, orm_texture, export_settings),
        roughness_factor=__gather_roughness_factor(blender_material,
                                                   export_settings))

    export_user_extensions('gather_material_pbr_metallic_roughness_hook',
                           export_settings, material, blender_material,
                           orm_texture)

    return material
def gather_skin(blender_object, export_settings):
    """
    Gather armatures, bones etc into a glTF2 skin object.

    :param blender_object: the object which may contain a skin
    :param export_settings:
    :return: a glTF2 skin object
    """
    if not __filter_skin(blender_object, export_settings):
        return None

    skin = gltf2_io.Skin(
        extensions=__gather_extensions(blender_object, export_settings),
        extras=__gather_extras(blender_object, export_settings),
        inverse_bind_matrices=__gather_inverse_bind_matrices(
            blender_object, export_settings),
        joints=__gather_joints(blender_object, export_settings),
        name=__gather_name(blender_object, export_settings),
        skeleton=__gather_skeleton(blender_object, export_settings))

    export_user_extensions('gather_skin_hook', export_settings, skin,
                           blender_object)

    return skin
    def __init__(self, export_settings):
        self.export_settings = export_settings
        self.__finalized = False

        copyright = export_settings[
            gltf2_blender_export_keys.COPYRIGHT] or None
        asset = gltf2_io.Asset(copyright=copyright,
                               extensions=None,
                               extras=None,
                               generator='Khronos glTF Blender I/O v' +
                               get_version_string(),
                               min_version=None,
                               version='2.0')

        export_user_extensions('gather_asset_hook', export_settings, asset)

        self.__gltf = gltf2_io.Gltf(accessors=[],
                                    animations=[],
                                    asset=asset,
                                    buffers=[],
                                    buffer_views=[],
                                    cameras=[],
                                    extensions={},
                                    extensions_required=[],
                                    extensions_used=[],
                                    extras=None,
                                    images=[],
                                    materials=[],
                                    meshes=[],
                                    nodes=[],
                                    samplers=[],
                                    scene=-1,
                                    scenes=[],
                                    skins=[],
                                    textures=[])

        self.__buffer = gltf2_io_buffer.Buffer()
        self.__images = {}

        # mapping of all glTFChildOfRootProperty types to their corresponding root level arrays
        self.__childOfRootPropertyTypeLookup = {
            gltf2_io.Accessor: self.__gltf.accessors,
            gltf2_io.Animation: self.__gltf.animations,
            gltf2_io.Buffer: self.__gltf.buffers,
            gltf2_io.BufferView: self.__gltf.buffer_views,
            gltf2_io.Camera: self.__gltf.cameras,
            gltf2_io.Image: self.__gltf.images,
            gltf2_io.Material: self.__gltf.materials,
            gltf2_io.Mesh: self.__gltf.meshes,
            gltf2_io.Node: self.__gltf.nodes,
            gltf2_io.Sampler: self.__gltf.samplers,
            gltf2_io.Scene: self.__gltf.scenes,
            gltf2_io.Skin: self.__gltf.skins,
            gltf2_io.Texture: self.__gltf.textures
        }

        self.__propertyTypeLookup = [
            gltf2_io.AccessorSparseIndices, gltf2_io.AccessorSparse,
            gltf2_io.AccessorSparseValues, gltf2_io.AnimationChannel,
            gltf2_io.AnimationChannelTarget, gltf2_io.AnimationSampler,
            gltf2_io.Asset, gltf2_io.CameraOrthographic,
            gltf2_io.CameraPerspective, gltf2_io.MeshPrimitive,
            gltf2_io.TextureInfo, gltf2_io.MaterialPBRMetallicRoughness,
            gltf2_io.MaterialNormalTextureInfoClass,
            gltf2_io.MaterialOcclusionTextureInfoClass
        ]

        self.__traverse(asset)
def gather_joint(blender_object, blender_bone, export_settings):
    """
    Generate a glTF2 node from a blender bone, as joints in glTF2 are simply nodes.

    :param blender_bone: a blender PoseBone
    :param export_settings: the settings for this export
    :return: a glTF2 node (acting as a joint)
    """
    axis_basis_change = mathutils.Matrix.Identity(4)
    if export_settings[gltf2_blender_export_keys.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)))

    # extract bone transform
    if blender_bone.parent is None:
        correction_matrix_local = axis_basis_change @ blender_bone.bone.matrix_local
    else:
        correction_matrix_local = (
            blender_bone.parent.bone.matrix_local.inverted()
            @ blender_bone.bone.matrix_local)

    if (blender_bone.bone.use_inherit_rotation == False
            or blender_bone.bone.inherit_scale != "FULL"
        ) and blender_bone.parent != None:
        rest_mat = (blender_bone.parent.bone.matrix_local.inverted_safe()
                    @ blender_bone.bone.matrix_local)
        matrix_basis = (
            rest_mat.inverted_safe()
            @ blender_bone.parent.matrix.inverted_safe() @ blender_bone.matrix)
    else:
        matrix_basis = blender_bone.matrix
        matrix_basis = blender_object.convert_space(pose_bone=blender_bone,
                                                    matrix=matrix_basis,
                                                    from_space='POSE',
                                                    to_space='LOCAL')

    trans, rot, sca = (correction_matrix_local @ matrix_basis).decompose()
    translation, rotation, scale = (None, None, None)
    if trans[0] != 0.0 or trans[1] != 0.0 or trans[2] != 0.0:
        translation = [trans[0], trans[1], trans[2]]
    if rot[0] != 1.0 or rot[1] != 0.0 or rot[2] != 0.0 or rot[3] != 0.0:
        rotation = [rot[1], rot[2], rot[3], rot[0]]
    if sca[0] != 1.0 or sca[1] != 1.0 or sca[2] != 1.0:
        scale = [sca[0], sca[1], sca[2]]

    # traverse into children
    children = []

    if export_settings["gltf_def_bones"] is False:
        for bone in blender_bone.children:
            children.append(gather_joint(blender_object, bone,
                                         export_settings))
    else:
        _, children_, _ = gltf2_blender_gather_skins.get_bone_tree(
            None, blender_bone.id_data)
        if blender_bone.name in children_.keys():
            for bone in children_[blender_bone.name]:
                children.append(
                    gather_joint(blender_object,
                                 blender_bone.id_data.pose.bones[bone],
                                 export_settings))

    # finally add to the joints array containing all the joints in the hierarchy
    node = gltf2_io.Node(camera=None,
                         children=children,
                         extensions=None,
                         extras=__gather_extras(blender_bone, export_settings),
                         matrix=None,
                         mesh=None,
                         name=blender_bone.name,
                         rotation=rotation,
                         scale=scale,
                         skin=None,
                         translation=translation,
                         weights=None)

    export_user_extensions('gather_joint_hook', export_settings, node,
                           blender_bone)

    return node
def __gather_node(blender_object, library, blender_scene, dupli_object_parent,
                  export_settings):
    children = __gather_children(blender_object, blender_scene,
                                 export_settings)

    camera = None
    mesh = None
    skin = None
    weights = None

    # If blender_scene is None, we are coming from animation export
    # Check to know if object is exported is already done, so we don't check
    # again if object is instanced in scene : this check was already done when exporting object itself
    if not __filter_node(blender_object, blender_scene, export_settings):
        if children:
            # This node should be filtered out, but has un-filtered children present.
            # So, export this node, excluding its camera, mesh, skin, and weights.
            # The transformations and animations on this node will have visible effects on children.
            pass
        else:
            # This node is filtered out, and has no un-filtered children or descendants.
            return None
    else:
        # This node is being fully exported.
        camera = __gather_camera(blender_object, export_settings)
        mesh = __gather_mesh(blender_object, library, export_settings)
        skin = __gather_skin(blender_object, export_settings)
        weights = __gather_weights(blender_object, export_settings)

    node = gltf2_io.Node(
        camera=camera,
        children=children,
        extensions=__gather_extensions(blender_object, export_settings),
        extras=__gather_extras(blender_object, export_settings),
        matrix=__gather_matrix(blender_object, export_settings),
        mesh=mesh,
        name=__gather_name(blender_object, export_settings),
        rotation=None,
        scale=None,
        skin=skin,
        translation=None,
        weights=weights)

    # If node mesh is skined, transforms should be ignored at import, so no need to set them here
    if node.skin is None:
        node.translation, node.rotation, node.scale = __gather_trans_rot_scale(
            blender_object, export_settings)

    if export_settings[gltf2_blender_export_keys.YUP]:
        # Checking node.extensions is making sure that the type of lamp is managed, and will be exported
        if blender_object.type == 'LIGHT' and export_settings[
                gltf2_blender_export_keys.LIGHTS] and node.extensions:
            correction_node = __get_correction_node(blender_object,
                                                    export_settings)
            correction_node.extensions = {
                "KHR_lights_punctual": node.extensions["KHR_lights_punctual"]
            }
            del node.extensions["KHR_lights_punctual"]
            node.children.append(correction_node)
        if blender_object.type == 'CAMERA' and export_settings[
                gltf2_blender_export_keys.CAMERAS]:
            correction_node = __get_correction_node(blender_object,
                                                    export_settings)
            correction_node.camera = node.camera
            node.children.append(correction_node)
        node.camera = None

    export_user_extensions('gather_node_hook', export_settings, node,
                           blender_object)

    return node