def __get_image_data(sockets_or_slots): # For shared ressources, 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 # ressources. def split_pixels_by_channels( image: bpy.types.Image) -> typing.List[typing.List[float]]: pixels = np.array(image.pixels) pixels = pixels.reshape( (pixels.shape[0] // image.channels, image.channels)) channels = np.split(pixels, pixels.shape[1], axis=1) return channels if __is_socket(sockets_or_slots): results = [ __get_tex_from_socket(socket) for socket in sockets_or_slots ] image = None for result, socket in zip(results, sockets_or_slots): # rudimentarily try follow the node tree to find the correct image data. channel = None for elem in result.path: if isinstance(elem.from_node, bpy.types.ShaderNodeSeparateRGB): channel = {'R': 0, 'G': 1, 'B': 2}[elem.from_socket.name] if channel is not None: pixels = [ split_pixels_by_channels(result.shader_node.image)[channel] ] else: pixels = split_pixels_by_channels(result.shader_node.image) channel = 0 file_name = os.path.splitext(result.shader_node.image.name)[0] image_data = gltf2_io_image_data.ImageData( file_name, result.shader_node.image.size[0], result.shader_node.image.size[1], channel, pixels) if image is None: image = image_data else: image.add_to_image(channel, image_data) return image elif __is_slot(sockets_or_slots): texture = __get_tex_from_slot(sockets_or_slots[0]) pixels = split_pixels_by_channels(texture.image) image_data = gltf2_io_image_data.ImageData(texture.name, texture.image.size[0], texture.image.size[1], 0, pixels) return image_data else: # Texture slots raise NotImplementedError()
def __gather_uri(image_data, mime_type, name, export_settings): if export_settings[gltf2_blender_export_keys.FORMAT] == 'GLTF_SEPARATE': # as usual we just store the data in place instead of already resolving the references return gltf2_io_image_data.ImageData( data=image_data.encode(mime_type=mime_type), mime_type=mime_type, name=name) return None
def __gather_uri(image_data: bytes, image_name: str, mime_type: str, export_settings): if export_settings[gltf2_blender_export_keys.FORMAT] == 'GLTF_SEPARATE': return gltf2_io_image_data.ImageData( data=image_data, mime_type=mime_type, name=image_name, ) return None
def __gather_uri(sockets_or_slots, export_settings): if export_settings[gltf2_blender_export_keys.FORMAT] == 'GLTF_SEPARATE': # as usual we just store the data in place instead of already resolving the references mime_type = __gather_mime_type(sockets_or_slots, export_settings) return gltf2_io_image_data.ImageData( data=__get_image_data(sockets_or_slots, export_settings).encode(mime_type=mime_type), mime_type=mime_type, name=__gather_name(sockets_or_slots, export_settings)) return None
def __get_image_data(sockets_or_slots, export_settings): # For shared ressources, 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 # ressources. def split_pixels_by_channels( image: bpy.types.Image, export_settings ) -> typing.Optional[typing.List[typing.List[float]]]: channelcache = export_settings['gltf_channelcache'] if image.name in channelcache: return channelcache[image.name] pixels = np.array(image.pixels) pixels = pixels.reshape( (pixels.shape[0] // image.channels, image.channels)) channels = np.split(pixels, pixels.shape[1], axis=1) channelcache[image.name] = channels return channels if __is_socket(sockets_or_slots): results = [ __get_tex_from_socket(socket) for socket in sockets_or_slots ] image = None 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. source_channel = None target_channel = None source_channels_length = None for elem in result.path: if isinstance(elem.from_node, bpy.types.ShaderNodeSeparateRGB): source_channel = { 'R': 0, 'G': 1, 'B': 2 }[elem.from_socket.name] if source_channel is not None: pixels = [ split_pixels_by_channels(result.shader_node.image, export_settings)[source_channel] ] target_channel = source_channel source_channel = 0 source_channels_length = 1 else: pixels = split_pixels_by_channels(result.shader_node.image, export_settings) target_channel = 0 source_channel = 0 source_channels_length = len(pixels) # Change target channel for metallic and roughness. if elem.to_socket.name == 'Metallic': target_channel = 2 source_channels_length = 1 elif elem.to_socket.name == 'Roughness': target_channel = 1 source_channels_length = 1 file_name = os.path.splitext(result.shader_node.image.name)[0] if result.shader_node.image.packed_file is None: file_path = result.shader_node.image.filepath else: # empty path for packed textures, because they are converted to png anyway file_path = "" image_data = gltf2_io_image_data.ImageData( file_name, file_path, result.shader_node.image.size[0], result.shader_node.image.size[1], source_channel, target_channel, source_channels_length, pixels) if image is None: image = image_data else: image.add_to_image(target_channel, image_data) return image elif __is_slot(sockets_or_slots): texture = __get_tex_from_slot(sockets_or_slots[0]) pixels = split_pixels_by_channels(texture.image, export_settings) image_data = gltf2_io_image_data.ImageData(texture.name, texture.image.filepath, texture.image.size[0], texture.image.size[1], 0, 0, len(pixels), pixels) return image_data else: # Texture slots raise NotImplementedError()