def gather_image_property(export_settings, blender_object, target, property_name, property_definition, hubs_config): blender_image = getattr(target, property_name) if blender_image: image_data = ExportImage.from_blender_image(blender_image) if image_data.empty(): return None mime_type = gltf2_blender_gather_image.__gather_mime_type((), image_data, export_settings) name = gltf2_blender_gather_image.__gather_name(image_data, export_settings) uri = gltf2_blender_gather_image.__gather_uri(image_data, mime_type, name, export_settings) buffer_view = gltf2_blender_gather_image.__gather_buffer_view(image_data, mime_type, name, export_settings) return gltf2_blender_gather_image.__make_image( buffer_view, None, None, mime_type, name, uri, export_settings ) else: return None
def __get_image_data(sockets_or_slots, export_settings) -> ExportImage: # For shared resources, such as images, we just store the portion of data that is needed in the glTF property # in a helper class. During generation of the glTF in the exporter these will then be combined to actual binary # resources. if __is_socket(sockets_or_slots): results = [ __get_tex_from_socket(socket, export_settings) for socket in sockets_or_slots ] composed_image = ExportImage() for result, socket in zip(results, sockets_or_slots): if result.shader_node.image.channels == 0: gltf2_io_debug.print_console( "WARNING", "Image '{}' has no color channels and cannot be exported.". format(result.shader_node.image)) continue # rudimentarily try follow the node tree to find the correct image data. src_chan = Channel.R for elem in result.path: if isinstance(elem.from_node, bpy.types.ShaderNodeSeparateRGB): src_chan = { 'R': Channel.R, 'G': Channel.G, 'B': Channel.B, }[elem.from_socket.name] dst_chan = None # some sockets need channel rewriting (gltf pbr defines fixed channels for some attributes) if socket.name == 'Metallic': dst_chan = Channel.B elif socket.name == 'Roughness': dst_chan = Channel.G elif socket.name == 'Occlusion' and len( sockets_or_slots) > 1 and sockets_or_slots[1] is not None: dst_chan = Channel.R elif socket.name == 'Alpha' and len( sockets_or_slots) > 1 and sockets_or_slots[1] is not None: dst_chan = Channel.A if dst_chan is not None: composed_image.fill_image(result.shader_node.image, dst_chan, src_chan) # Since metal/roughness are always used together, make sure # the other channel is filled. if socket.name == 'Metallic' and not composed_image.is_filled( Channel.G): composed_image.fill_white(Channel.G) elif socket.name == 'Roughness' and not composed_image.is_filled( Channel.B): composed_image.fill_white(Channel.B) else: # copy full image...eventually following sockets might overwrite things composed_image = ExportImage.from_blender_image( result.shader_node.image) return composed_image elif __is_slot(sockets_or_slots): texture = __get_tex_from_slot(sockets_or_slots[0]) image = ExportImage.from_blender_image(texture.image) return image else: raise NotImplementedError()
def __get_image_data(sockets, export_settings) -> ExportImage: # For shared resources, such as images, we just store the portion of data that is needed in the glTF property # in a helper class. During generation of the glTF in the exporter these will then be combined to actual binary # resources. results = [ __get_tex_from_socket(socket, export_settings) for socket in sockets ] composed_image = ExportImage() for result, socket in zip(results, sockets): if result.shader_node.image.channels == 0: gltf2_io_debug.print_console( "WARNING", "Image '{}' has no color channels and cannot be exported.". format(result.shader_node.image)) continue # Assume that user know what he does, and that channels/images are already combined correctly for pbr # If not, we are going to keep only the first texture found # Example : If user set up 2 or 3 different textures for Metallic / Roughness / Occlusion # Only 1 will be used at export # This Warning is displayed in UI of this option if export_settings['gltf_keep_original_textures']: composed_image = ExportImage.from_original( result.shader_node.image) else: # rudimentarily try follow the node tree to find the correct image data. src_chan = Channel.R for elem in result.path: if isinstance(elem.from_node, bpy.types.ShaderNodeSeparateRGB): src_chan = { 'R': Channel.R, 'G': Channel.G, 'B': Channel.B, }[elem.from_socket.name] if elem.from_socket.name == 'Alpha': src_chan = Channel.A dst_chan = None # some sockets need channel rewriting (gltf pbr defines fixed channels for some attributes) if socket.name == 'Metallic': dst_chan = Channel.B elif socket.name == 'Roughness': dst_chan = Channel.G elif socket.name == 'Occlusion': dst_chan = Channel.R elif socket.name == 'Alpha': dst_chan = Channel.A elif socket.name == 'Clearcoat': dst_chan = Channel.R elif socket.name == 'Clearcoat Roughness': dst_chan = Channel.G if dst_chan is not None: composed_image.fill_image(result.shader_node.image, dst_chan, src_chan) # Since metal/roughness are always used together, make sure # the other channel is filled. if socket.name == 'Metallic' and not composed_image.is_filled( Channel.G): composed_image.fill_white(Channel.G) elif socket.name == 'Roughness' and not composed_image.is_filled( Channel.B): composed_image.fill_white(Channel.B) else: # copy full image...eventually following sockets might overwrite things composed_image = ExportImage.from_blender_image( result.shader_node.image) return composed_image