Пример #1
0
def gather_mesh(blender_mesh: bpy.types.Mesh,
                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, vertex_groups,
                                             modifiers, export_settings):
        return None

    mesh = gltf2_io.Mesh(
        extensions=__gather_extensions(blender_mesh, vertex_groups, modifiers,
                                       export_settings),
        extras=__gather_extras(blender_mesh, vertex_groups, modifiers,
                               export_settings),
        name=__gather_name(blender_mesh, vertex_groups, modifiers,
                           export_settings),
        primitives=__gather_primitives(blender_mesh, blender_object,
                                       vertex_groups, modifiers,
                                       material_names, export_settings),
        weights=__gather_weights(blender_mesh, vertex_groups, modifiers,
                                 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
Пример #2
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_animation_channel(channels: typing.Tuple[bpy.types.FCurve],
                               blender_object: bpy.types.Object,
                               export_settings,
                               bake_bone: typing.Union[str, None],
                               bake_channel: typing.Union[str, None],
                               bake_range_start,
                               bake_range_end,
                               action_name: str,
                               driver_obj
                               ) -> typing.Union[gltf2_io.AnimationChannel, None]:
    if not __filter_animation_channel(channels, blender_object, export_settings):
        return None

    animation_channel = gltf2_io.AnimationChannel(
        extensions=__gather_extensions(channels, blender_object, export_settings, bake_bone),
        extras=__gather_extras(channels, blender_object, export_settings, bake_bone),
        sampler=__gather_sampler(channels, blender_object, export_settings, bake_bone, bake_channel, bake_range_start, bake_range_end, action_name, driver_obj),
        target=__gather_target(channels, blender_object, export_settings, bake_bone, bake_channel, driver_obj)
    )

    export_user_extensions('gather_animation_channel_hook',
                           export_settings,
                           animation_channel,
                           channels,
                           blender_object,
                           bake_bone,
                           bake_channel,
                           bake_range_start,
                           bake_range_end,
                           action_name)

    return animation_channel
Пример #4
0
def gather_node(vnode, export_settings):
    blender_object = vnode.blender_object

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

    # 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(vnode, export_settings)


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

    vnode.node = node

    if node.skin is not None:
        vnode.skin = skin

    return node
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
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
    """
    modifiers = {m.type: m for m in blender_object.modifiers}

    if not __filter_skin(modifiers, export_settings):
        return None

    armature = modifiers["ARMATURE"].object
    joints = __gather_joints(blender_object, export_settings)
    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=joints,
        name=__gather_name(blender_object, armature, export_settings),
        skeleton=__gather_skeleton(armature, joints, export_settings))

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

    return skin
def gather_texture(
        blender_shader_sockets_or_texture_slots: typing.Union[
            typing.Tuple[bpy.types.NodeSocket], typing.Tuple[typing.Any]],
        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)
    """
    # TODO: extend to texture slots
    if not __filter_texture(blender_shader_sockets_or_texture_slots, export_settings):
        return None

    texture = gltf2_io.Texture(
        extensions=__gather_extensions(blender_shader_sockets_or_texture_slots, export_settings),
        extras=__gather_extras(blender_shader_sockets_or_texture_slots, export_settings),
        name=__gather_name(blender_shader_sockets_or_texture_slots, export_settings),
        sampler=__gather_sampler(blender_shader_sockets_or_texture_slots, export_settings),
        source=__gather_source(blender_shader_sockets_or_texture_slots, 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_or_texture_slots)

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

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

    mime_type = __gather_mime_type(blender_shader_sockets_or_texture_slots,
                                   export_settings)
    name = __gather_name(blender_shader_sockets_or_texture_slots,
                         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_or_texture_slots,
                            export_settings),
        __gather_extras(blender_shader_sockets_or_texture_slots,
                        export_settings), mime_type, name, uri,
        export_settings)

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

    return image
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_joint_vnode(vnode, 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)
    """
    vtree = export_settings['vtree']
    blender_object = vtree.nodes[vnode].blender_object
    blender_bone = vtree.nodes[vnode].blender_bone

    mat = vtree.nodes[
        vtree.nodes[vnode].parent_uuid].matrix_world.inverted_safe(
        ) @ vtree.nodes[vnode].matrix_world

    trans, rot, sca = mat.decompose()

    trans = __convert_swizzle_location(trans, export_settings)
    rot = __convert_swizzle_rotation(rot, export_settings)
    sca = __convert_swizzle_scale(sca, export_settings)

    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 = []

    for bone_uuid in [
            c for c in vtree.nodes[vnode].children
            if vtree.nodes[c].blender_type ==
            gltf2_blender_gather_tree.VExportNode.BONE
    ]:
        children.append(gather_joint_vnode(bone_uuid, 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)

    vtree.nodes[vnode].node = node

    return node
Пример #11
0
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
Пример #12
0
def gather_skin(armature_uuid, 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
    """

    blender_armature_object = export_settings['vtree'].nodes[
        armature_uuid].blender_object

    if not __filter_skin(blender_armature_object, export_settings):
        return None

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

    # If armature is not exported, joints will be empty.
    # Do not construct skin in that case
    if len(skin.joints) == 0:
        return None

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

    return skin
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)

    if image_data.original is None:
        uri = __gather_uri(image_data, mime_type, name, export_settings)
    else:
        # Retrieve URI relative to exported glTF files
        uri = __gather_original_uri(image_data.original.filepath,
                                    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
def gather_material_pbr_metallic_roughness(blender_material, orm_texture, export_settings):
    if not __filter_pbr_material(blender_material, export_settings):
        return None, None

    base_color_texture, use_active_uvmap_base_color_texture = __gather_base_color_texture(blender_material, export_settings)
    metallic_roughness_texture, use_active_uvmap_metallic_roughness_texture = __gather_metallic_roughness_texture(blender_material, orm_texture, export_settings)

    material = gltf2_io.MaterialPBRMetallicRoughness(
        base_color_factor=__gather_base_color_factor(blender_material, export_settings),
        base_color_texture=base_color_texture,
        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=metallic_roughness_texture,
        roughness_factor=__gather_roughness_factor(blender_material, export_settings)
    )

    # merge all use_active_uvmap infos
    uvmap_actives = []
    if use_active_uvmap_base_color_texture is True:
        uvmap_actives.append("baseColorTexture")
    if use_active_uvmap_metallic_roughness_texture is True:
        uvmap_actives.append("metallicRoughnessTexture")

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

    return material, uvmap_actives
def gather_material_occlusion_texture_info_class(
        blender_shader_sockets_or_texture_slots: typing.Union[
            typing.Tuple[bpy.types.NodeSocket],
            typing.Tuple[bpy.types.Texture]], export_settings):
    if not __filter_texture_info(blender_shader_sockets_or_texture_slots,
                                 export_settings):
        return None

    texture_info = gltf2_io.MaterialOcclusionTextureInfoClass(
        extensions=__gather_extensions(blender_shader_sockets_or_texture_slots,
                                       export_settings),
        extras=__gather_extras(blender_shader_sockets_or_texture_slots,
                               export_settings),
        strength=__gather_scale(blender_shader_sockets_or_texture_slots,
                                export_settings),
        index=__gather_index(blender_shader_sockets_or_texture_slots,
                             export_settings),
        tex_coord=__gather_tex_coord(blender_shader_sockets_or_texture_slots,
                                     export_settings))

    if texture_info.index is None:
        return None

    export_user_extensions('gather_material_occlusion_texture_info_class_hook',
                           export_settings, texture_info,
                           blender_shader_sockets_or_texture_slots)

    return texture_info
Пример #16
0
def gather_material(blender_material, mesh_double_sided, 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

    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, mesh_double_sided, 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
Пример #17
0
def __get_blender_actions(blender_object: bpy.types.Object,
                            export_settings
                          ) -> typing.List[typing.Tuple[bpy.types.Action, str, str]]:
    blender_actions = []
    blender_tracks = {}
    action_on_type = {}

    export_user_extensions('pre_gather_actions_hook', export_settings, blender_object)

    if blender_object.animation_data is not None:
        # Collect active action.
        if blender_object.animation_data.action is not None:
            blender_actions.append(blender_object.animation_data.action)
            blender_tracks[blender_object.animation_data.action.name] = None
            action_on_type[blender_object.animation_data.action.name] = "OBJECT"

        # Collect associated strips from NLA tracks.
        if export_settings['gltf_nla_strips'] is True:
            for track in blender_object.animation_data.nla_tracks:
                # Multi-strip tracks do not export correctly yet (they need to be baked),
                # so skip them for now and only write single-strip tracks.
                non_muted_strips = [strip for strip in track.strips if strip.action is not None and strip.mute is False]
                if track.strips is None or len(non_muted_strips) != 1:
                    continue
                for strip in non_muted_strips:
                    blender_actions.append(strip.action)
                    blender_tracks[strip.action.name] = track.name # Always set after possible active action -> None will be overwrite
                    action_on_type[strip.action.name] = "OBJECT"

    if blender_object.type == "MESH" \
            and blender_object.data is not None \
            and blender_object.data.shape_keys is not None \
            and blender_object.data.shape_keys.animation_data is not None:

            if blender_object.data.shape_keys.animation_data.action is not None:
                blender_actions.append(blender_object.data.shape_keys.animation_data.action)
                blender_tracks[blender_object.data.shape_keys.animation_data.action.name] = None
                action_on_type[blender_object.data.shape_keys.animation_data.action.name] = "SHAPEKEY"

            if export_settings['gltf_nla_strips'] is True:
                for track in blender_object.data.shape_keys.animation_data.nla_tracks:
                    # Multi-strip tracks do not export correctly yet (they need to be baked),
                    # so skip them for now and only write single-strip tracks.
                    non_muted_strips = [strip for strip in track.strips if strip.action is not None and strip.mute is False]
                    if track.strips is None or len(non_muted_strips) != 1:
                        continue
                    for strip in non_muted_strips:
                        blender_actions.append(strip.action)
                        blender_tracks[strip.action.name] = track.name # Always set after possible active action -> None will be overwrite
                        action_on_type[strip.action.name] = "SHAPEKEY"

    export_user_extensions('gather_actions_hook', export_settings, blender_object, blender_actions, blender_tracks, action_on_type)

    # Remove duplicate actions.
    blender_actions = list(set(blender_actions))
    # sort animations alphabetically (case insensitive) so they have a defined order and match Blender's Action list
    blender_actions.sort(key = lambda a: a.name.lower())

    return [(blender_action, blender_tracks[blender_action.name], action_on_type[blender_action.name]) for blender_action in blender_actions]
def __gather_gltf(exporter, export_settings):
    export_settings['bounding_box_max_x'] = 0
    export_settings['bounding_box_max_y'] = 0
    export_settings['bounding_box_max_z'] = 0
    export_settings['bounding_box_min_x'] = 0
    export_settings['bounding_box_min_y'] = 0
    export_settings['bounding_box_min_z'] = 0

    active_scene_idx, scenes, animations = gltf2_blender_gather.gather_gltf2(
        export_settings)

    print(f'gather_gltf2 complete')

    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.compress_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)

    exporter.add_original_extensions(bpy.context.scene['extensionsRequired'],
                                     bpy.context.scene['extensionsUsed'])

    bounding_box_max = [
        export_settings['bounding_box_max_x'],
        export_settings['bounding_box_max_y'],
        export_settings['bounding_box_max_z'],
    ]
    bounding_box_min = [
        export_settings['bounding_box_min_x'],
        export_settings['bounding_box_min_y'],
        export_settings['bounding_box_min_z'],
    ]

    extensions = {
        "ASOBO_asset_optimized": {
            "BoundingBoxMax": bounding_box_max,
            "BoundingBoxMin": bounding_box_min,
            "MajorVersion": 4,
            "MinorVersion": 2
        },
        "ASOBO_normal_map_convention": {
            "tangent_space_convention": "DirectX"
        }
    }

    exporter.add_asobo_bounding_box(extensions)
Пример #19
0
def __gather_node(blender_object, library, blender_scene, dupli_object_parent,
                  export_settings):
    children = __gather_children(blender_object, blender_scene,
                                 export_settings)

    # 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:
            pass
        else:
            return None

    node = gltf2_io.Node(
        camera=__gather_camera(blender_object, export_settings),
        children=children,
        extensions=__gather_extensions(blender_object, export_settings),
        extras=__gather_extras(blender_object, export_settings),
        matrix=__gather_matrix(blender_object, export_settings),
        mesh=__gather_mesh(blender_object, library, export_settings),
        name=__gather_name(blender_object, export_settings),
        rotation=None,
        scale=None,
        skin=__gather_skin(blender_object, export_settings),
        translation=None,
        weights=__gather_weights(blender_object, export_settings))
    node.__blender_data = ('OBJECT', blender_object)

    # If node mesh is skined, transforms should be ignored at import, so no need to set them here
    # if node.skin is None:
    # While its not needed by the gltf2 spec, MSFS might still want to see it
    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
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_material_unlit(blender_material, active_uvmap_index,
                            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

    base_color_texture, use_active_uvmap = gltf2_unlit.gather_base_color_texture(
        info, export_settings)

    base_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=base_color_texture,
            metallic_factor=0.0,
            roughness_factor=0.9,
            metallic_roughness_texture=None,
            extensions=None,
            extras=None,
        ))

    if use_active_uvmap is not None:
        # Because some part of material are shared (eg pbr_metallic_roughness), we must copy the material
        # Texture must be shared, but not TextureInfo
        material = deepcopy(base_material)
        __get_new_material_texture_shared(base_material, material)
        material.pbr_metallic_roughness.base_color_texture.tex_coord = active_uvmap_index
    elif use_active_uvmap is None and active_uvmap_index != -1:
        # If material is not using active UVMap, we need to return the same material,
        # Even if multiples meshes are using different active UVMap
        material = gather_material(blender_material, -1, export_settings)
    else:
        material = base_material

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

    return material
Пример #22
0
def __export(export_settings):
    exporter = GlTF2Exporter(export_settings)
    __gather_gltf(exporter, export_settings)
    buffer = __create_buffer(exporter, export_settings)
    exporter.finalize_images()
    json = __fix_json(exporter.glTF.to_dict())

    export_user_extensions('gather_gltf_hook', export_settings, exporter.glTF)
    exporter.traverse_extensions()

    return json, buffer
Пример #23
0
def __gather_gltf(exporter, export_settings):
    active_scene_idx, scenes, animations = gltf2_blender_gather.gather_gltf2(export_settings)

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

    export_user_extensions('gather_gltf_hook', export_settings, active_scene_idx, scenes, animations)

    for idx, scene in enumerate(scenes):
        exporter.add_scene(scene, idx==active_scene_idx)
    for animation in animations:
        exporter.add_animation(animation)
Пример #24
0
def __export(export_settings):
    exporter = GlTF2Exporter(export_settings)
    __gather_gltf(exporter, export_settings)
    buffer = __create_buffer(exporter, export_settings)
    exporter.finalize_images()

    export_user_extensions('gather_gltf_hook', export_settings, exporter.glTF)
    exporter.traverse_extensions()

    # now that addons possibly add some fields in json, we can fix in needed
    json = __fix_json(exporter.glTF.to_dict())

    return json, buffer
Пример #25
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))

    # If emissive is set, from an emissive node (not PBR)
    # We need to set manually default values for
    # pbr_metallic_roughness.baseColor
    if material.emissive_factor is not None and gltf2_blender_get.get_node_socket(
            blender_material, bpy.types.ShaderNodeBsdfPrincipled,
            "Base Color") is None:
        material.pbr_metallic_roughness = gltf2_blender_gather_materials_pbr_metallic_roughness.get_default_pbr_for_emissive_node(
        )

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

    return material
Пример #26
0
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
Пример #27
0
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)
    """
    translation, rotation, scale = __gather_trans_rot_scale(
        blender_object, blender_bone, export_settings)

    # 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)
    node.__blender_data = ('BONE', blender_object, blender_bone.name)

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

    return node
Пример #28
0
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_sampler(blender_shader_node: bpy.types.Node, export_settings):
    if not __filter_sampler(blender_shader_node, export_settings):
        return None

    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=__gather_wrap_s(blender_shader_node, export_settings),
        wrap_t=__gather_wrap_t(blender_shader_node, export_settings))

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

    return sampler
Пример #30
0
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 blender_scene.objects:
        if blender_object.parent is None:
            node = gltf2_blender_gather_nodes.gather_node(
                blender_object, blender_scene, export_settings)
            if node is not None:
                scene.nodes.append(node)

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

    return scene