import bpy from .constants import image_name, image_width, image_height import numpy as np from .libs.PIL import Image import mathutils from timeit import default_timer as timer def apply_color(): start = timer() context = bpy.context paint_buffer = bpy.data.images.get(image_name) normal_buffer = context.scene.normal_texture_settings.texture custom_collection = context.scene.texture_collection_settings normal_color = context.scene.normal_color_global returnValue = -1 if paint_buffer: # apply normal color if normal_buffer and normal_color != mathutils.Vector((1.0, 1.0, 1.0)): if paint_buffer.size[0] == normal_buffer.size[0] and paint_buffer.size[1] == normal_buffer.size[1]: # create arrays paint_mask_pixels = np.empty(len(paint_buffer.pixels), dtype=np.float32) paint_buffer.pixels.foreach_get(paint_mask_pixels) paint_mask_pixels = (paint_mask_pixels * 255).astype(np.uint8) target_pixels = np.empty(len(normal_buffer.pixels), dtype=np.float32) normal_buffer.pixels.foreach_get(target_pixels) target_pixels = (target_pixels * 255).astype(np.uint8) new_pixels = np.tile((np.array([*normal_color, 1.0], dtype=np.float32) * 255), (image_width * image_height, 1)).astype(np.uint8) # Convert arrays to PIL Images paint_mask_image = Image.frombuffer('RGBA', (image_width, image_height), paint_mask_pixels, 'raw', 'RGBA', 0, 1) target_image = Image.frombuffer('RGBA', (image_width, image_height), target_pixels, 'raw', 'RGBA', 0, 1) new_image = Image.frombuffer('RGBA', (image_width, image_height), new_pixels, 'raw', 'RGBA', 0, 1) r_mask, g_mask, b_mask, a_mask = paint_mask_image.split() # separates the channels paint_mask_image = Image.merge("RGBA", (r_mask, g_mask, b_mask, r_mask)) # replace alpha with red # Blend buffers blended_image = Image.composite(new_image, target_image, paint_mask_image) # Convert blended image back to numpy array and normalize blended_pixels = np.array(blended_image, dtype=np.uint8).astype(np.float32) / 255.0 # Save texture normal_buffer.pixels.foreach_set(blended_pixels.ravel()) normal_buffer.update() print("Color applied") returnValue = 0 else: print("Texture sizes don't match") returnValue = -1 else: print("no normal buffer selected") returnValue = -1 # reset paint buffer reset_pixels = np.empty(len(paint_buffer.pixels), dtype=np.float32) reset_pixels[0::4] = 0 # R reset_pixels[1::4] = 0 # G reset_pixels[2::4] = 0 # B reset_pixels[3::4] = 1 # A paint_buffer.pixels.foreach_set(reset_pixels) paint_buffer.update() else: print("Texture 'vPainter_buffer' not found") returnValue = -1 end = timer() print(f"Time taken to apply color: {end - start:.6f} seconds") return returnValue def register(): bpy.utils.register_class(VPAINTER_OT_apply_color) def unregister(): bpy.utils.unregister_class(VPAINTER_OT_apply_color)