def convert_png_to_jpg_rgb(self, tex_path): tex_basename = os.path.splitext(tex_path)[0] img = PNMImage() self.load_img_with_retry(img, tex_path) jpg_path = tex_basename + '.jpg' x_size = img.get_x_size() y_size = img.get_y_size() output_img = PNMImage(x_size, y_size, 3) output_img.copy_sub_image(img, 0, 0, 0, 0, x_size, y_size) jpg_path = tex_basename + '.jpg' print(f'Writing JPG {jpg_path}...') output_img.write(Filename.from_os_specific(jpg_path)) if img.num_channels == 4: alpha_image = PNMImage(x_size, y_size, 1) alpha_image.set_type(RGB_TYPE) # Copy alpha channel from source image for i in range(x_size): for j in range(y_size): alpha_image.set_gray(i, j, img.get_alpha(i, j)) rgb_path = tex_basename + '_a.rgb' print(f'Writing RGB {rgb_path}...') alpha_image.write(Filename.from_os_specific(rgb_path))
def filter_cubemap(orig_pth): if not os.path.isdir("Filtered/"): os.makedirs("Filtered/") # Copy original cubemap for i in range(6): shutil.copyfile(orig_pth.replace("#", str(i)), "Filtered/0-" + str(i) + ".png") mip = 0 while True: print("Filtering mipmap", mip) mip += 1 pth = "Filtered/" + str(mip - 1) + "-#.png" dst_pth = "Filtered/" + str(mip) + "-#.png" first_img = load_nth_face(pth, 0) size = first_img.get_x_size() // 2 if size < 1: break blur_size = size * 0.002 blur_size += mip * 0.85 blur_size = int(blur_size) effective_size = size + 2 * blur_size faces = [load_nth_face(pth, i) for i in range(6)] cubemap = loader.loadCubeMap(pth) node = NodePath("") node.set_shader(compute_shader) node.set_shader_input("SourceCubemap", cubemap) node.set_shader_input("size", size) node.set_shader_input("blurSize", blur_size) node.set_shader_input("effectiveSize", effective_size) final_img = PNMImage(size, size, 3) for i in range(6): face_dest = dst_pth.replace("#", str(i)) dst = Texture("Face-" + str(i)) dst.setup_2d_texture(effective_size, effective_size, Texture.T_float, Texture.F_rgba16) # Execute compute shader node.set_shader_input("faceIndex", i) node.set_shader_input("DestTex", dst) attr = node.get_attrib(ShaderAttrib) base.graphicsEngine.dispatch_compute(( (effective_size+15) // 16, (effective_size+15) // 16, 1), attr, base.win.get_gsg()) base.graphicsEngine.extract_texture_data(dst, base.win.get_gsg()) img = PNMImage(effective_size, effective_size, 3) dst.store(img) img.gaussian_filter(blur_size) final_img.copy_sub_image(img, 0, 0, blur_size, blur_size, size, size) final_img.write(face_dest)
def generate_atlas(files, dest_dat, dest_png): entries = [] virtual_atlas_size = 32 all_entries_matched = False print("Loading", len(files), "entries ..") for verbose_name, source in files: entries.append(AtlasEntry(verbose_name, source)) entries = sorted(entries, key=lambda a: -a.area) while not all_entries_matched: print("Trying to pack into a", virtual_atlas_size, "x", virtual_atlas_size, "atlas ..") packer = LUIAtlasPacker(virtual_atlas_size) all_entries_matched = True for entry in entries: print("Finding position for", entry.w, entry.h) uv = packer.find_position(entry.w, entry.h) if uv.get_x() < 0: # print " Not all images matched, trying next power of 2" all_entries_matched = False virtual_atlas_size *= 2 break entry.assigned_pos = uv print("Matched entries, writing atlas ..") atlas_description_content = "" dest = PNMImage(virtual_atlas_size, virtual_atlas_size, 4) for entry in entries: if not entry.tex.has_alpha(): entry.tex.add_alpha() entry.tex.alpha_fill(1.0) dest.copy_sub_image( entry.tex, int(entry.assigned_pos.get_x()), int(entry.assigned_pos.get_y())) atlas_description_content += "{0} {1} {2} {3} {4}\n".format( entry.name.replace(" ", "_"), int(entry.assigned_pos.get_x()), int(entry.assigned_pos.get_y()), entry.w, entry.h) print("Writing", entry.name,"with dimensions", entry.w, entry.h) dest.write(dest_png) with open(dest_dat, "w") as handle: handle.write(atlas_description_content)
def load_3d_texture(cls, fname, tile_size_x, tile_size_y=None, num_tiles=None): """ Loads a texture from the given filename and dimensions. If only one dimensions is specified, the other dimensions are assumed to be equal. This internally loads the texture into ram, splits it into smaller sub-images, and then calls the load_3d_texture from the Panda loader """ # Generate a unique name to prevent caching tempfile_name = "$$SliceLoaderTemp-" + str(time.time()) + "/" # For quaddratic textures tile_size_y = tile_size_x if tile_size_y is None else tile_size_y num_tiles = tile_size_x if num_tiles is None else num_tiles # Load sliced image from disk source = PNMImage(fname) width = source.get_x_size() # Find slice properties num_cols = width // tile_size_x temp = PNMImage( tile_size_x, tile_size_y, source.get_num_channels(), source.get_maxval()) # Construct a ramdisk to write the files to vfs = VirtualFileSystem.get_global_ptr() ramdisk = VirtualFileMountRamdisk() vfs.mount(ramdisk, tempfile_name, 0) # Extract all slices and write them to the virtual disk for z_slice in range(num_tiles): slice_x = (z_slice % num_cols) * tile_size_x slice_y = (z_slice // num_cols) * tile_size_y temp.copy_sub_image(source, 0, 0, slice_x, slice_y, tile_size_x, tile_size_y) temp.write(tempfile_name + str(z_slice) + ".png") # Load the de-sliced texture from the ramdisk texture_handle = Globals.loader.load3DTexture(tempfile_name + "/#.png") # This should never trigger, but can't hurt to have assert texture_handle.get_x_size() == tile_size_x assert texture_handle.get_y_size() == tile_size_y assert texture_handle.get_z_size() == num_tiles # Finally unmount the ramdisk vfs.unmount(ramdisk) return texture_handle
def load_sliced_3d_texture(cls, fname, tile_size_x, tile_size_y=None, num_tiles=None): """ Loads a texture from the given filename and dimensions. If only one dimensions is specified, the other dimensions are assumed to be equal. This internally loads the texture into ram, splits it into smaller sub-images, and then calls the load_3d_texture from the Panda loader """ tempfile_name = "/$$slice_loader_temp-" + str(time.time()) + "/" tile_size_y = tile_size_x if tile_size_y is None else tile_size_y num_tiles = tile_size_x if num_tiles is None else num_tiles # Load sliced image from disk tex_handle = cls.load_texture(fname) source = PNMImage() tex_handle.store(source) width = source.get_x_size() # Find slice properties num_cols = width // tile_size_x temp_img = PNMImage(tile_size_x, tile_size_y, source.get_num_channels(), source.get_maxval()) # Construct a ramdisk to write the files to vfs = VirtualFileSystem.get_global_ptr() ramdisk = VirtualFileMountRamdisk() vfs.mount(ramdisk, tempfile_name, 0) # Extract all slices and write them to the virtual disk for z_slice in range(num_tiles): slice_x = (z_slice % num_cols) * tile_size_x slice_y = (z_slice // num_cols) * tile_size_y temp_img.copy_sub_image(source, 0, 0, slice_x, slice_y, tile_size_x, tile_size_y) temp_img.write(tempfile_name + str(z_slice) + ".png") # Load the de-sliced texture from the ramdisk texture_handle = cls.load_3d_texture(tempfile_name + "/#.png") vfs.unmount(ramdisk) return texture_handle
def load_sliced_3d_texture(cls, fname, tile_size_x, tile_size_y=None, num_tiles=None): """ Loads a texture from the given filename and dimensions. If only one dimensions is specified, the other dimensions are assumed to be equal. This internally loads the texture into ram, splits it into smaller sub-images, and then calls the load_3d_texture from the Panda loader """ tempfile_name = "/$$slice_loader_temp-" + str(time.time()) + "/" tile_size_y = tile_size_x if tile_size_y is None else tile_size_y num_tiles = tile_size_x if num_tiles is None else num_tiles # Load sliced image from disk source = PNMImage(fname) width = source.get_x_size() # Find slice properties num_cols = width // tile_size_x temp_img = PNMImage( tile_size_x, tile_size_y, source.get_num_channels(), source.get_maxval()) # Construct a ramdisk to write the files to vfs = VirtualFileSystem.get_global_ptr() ramdisk = VirtualFileMountRamdisk() vfs.mount(ramdisk, tempfile_name, 0) # Extract all slices and write them to the virtual disk for z_slice in range(num_tiles): slice_x = (z_slice % num_cols) * tile_size_x slice_y = (z_slice // num_cols) * tile_size_y temp_img.copy_sub_image(source, 0, 0, slice_x, slice_y, tile_size_x, tile_size_y) temp_img.write(tempfile_name + str(z_slice) + ".png") # Load the de-sliced texture from the ramdisk texture_handle = cls.load_3d_texture(tempfile_name + "/#.png") vfs.unmount(ramdisk) return texture_handle
def convert_texture(self, texture, model_path=None): if not self.model_path: self.print_exc('ERROR: No model path specified in ImageConverter.') return tex_path = texture[0] tex_basename = os.path.splitext(os.path.basename(tex_path))[0] if not os.path.isabs(tex_path): if '../' in tex_path and model_path: # This texture path is using relative paths. # We assume that the working directory is the model's directory tex_path = os.path.join(os.path.dirname(model_path), tex_path) else: tex_path = os.path.join(self.model_path, tex_path) tex_path = tex_path.replace('\\', os.sep).replace('/', os.sep) if not os.path.exists(tex_path): self.print_exc('ERROR: Could not convert {}: Missing RGB texture!'.format(tex_path)) return png_tex_path = os.path.join(os.path.dirname(tex_path), tex_basename + '.png') png_tex_path = png_tex_path.replace('\\', os.sep).replace('/', os.sep) print('Converting to PNG...', png_tex_path) if len(texture) == 1: # Only one texture, we can save this immediately if tex_path.lower().endswith('.rgb'): output_img = PNMImage() output_img.read(Filename.from_os_specific(tex_path)) if output_img.num_channels in (1, 2) and 'golf_ball' not in tex_path and 'roll-o-dex' not in tex_path: # HACK: Toontown output_img.set_color_type(4) for i in range(output_img.get_x_size()): for j in range(output_img.get_y_size()): output_img.set_alpha(i, j, output_img.get_gray(i, j)) else: output_img = self.read_texture(tex_path, alpha=False) elif len(texture) == 2: img = self.read_texture(tex_path, alpha=True) # Two textures: the second one should be a RGB file alpha_path = texture[1] if not os.path.isabs(alpha_path): if '../' in alpha_path and model_path: # This texture path is using relative paths. # We assume that the working directory is the model's directory alpha_path = os.path.join(os.path.dirname(model_path), alpha_path) else: alpha_path = os.path.join(self.model_path, alpha_path) alpha_path = alpha_path.replace('\\', os.sep).replace('/', os.sep) if not os.path.exists(alpha_path): self.print_exc('ERROR: Could not convert {} with alpha {}: Missing alpha texture!'.format(tex_path, alpha_path)) return alpha_img = PNMImage() alpha_img.read(Filename.from_os_specific(alpha_path)) alpha_img = self.resize_image(alpha_img, img.get_x_size(), img.get_y_size()) output_img = PNMImage(img.get_x_size(), img.get_y_size(), 4) output_img.alpha_fill(1) output_img.copy_sub_image(img, 0, 0, 0, 0, img.get_x_size(), img.get_y_size()) for i in range(img.get_x_size()): for j in range(img.get_y_size()): output_img.set_alpha(i, j, alpha_img.get_gray(i, j)) output_img.write(Filename.from_os_specific(png_tex_path))
content = content.replace("%ENDIF_" + def_name + "%", "") else: content = content.replace("%IF_" + def_name + "%", "<!--") content = content.replace("%ENDIF_" + def_name + "%", "-->") content = content.replace("%ALPHA%", str(material["roughness"] * material["roughness"])) content = content.replace("%IOR%", str(material.get("ior", 1.51))) content = content.replace("%BASECOLOR%", str(material["basecolor"]).strip("()")) content = content.replace("%MATERIAL_SRC%", material.get("material_src", "").strip("()")) with open("res/scene.xml", "w") as handle: handle.write(content) os.system("run_mitsuba.bat > nul") print(" Writing result ..") img = PNMImage("scene-rp.png") img_ref = PNMImage("scene.png") img.copy_sub_image(img_ref, 256, 0, 256, 0, 256, 512) img.mult_sub_image(overlay, 0, 0) img.write("batch_compare/" + material["name"] + ".png") try: os.remove("_tmp_material.py") except: pass print("Done!")