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
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
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
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_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
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
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)
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
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
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)
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
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
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_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
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
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