def _load_noise_tex(self): """ Loads the default 4x4 noise tex """ random.seed(42) img = PNMImage(4, 4, 3) for x in range(16): img.set_xel(x%4, x//4, random.random(), random.random(), random.random()) tex = Texture("Random4x4") tex.load(img) self._pipeline.stage_mgr.add_input("Noise4x4", tex)
def create_noise_textures(self): # Always generate the same random textures seed(42) img = PNMImage(4, 4, 3) for x in range(4): for y in range(4): img.set_xel(x, y, random(), random(), random()) tex = Texture("Rand4x4") tex.load(img) self._target.set_shader_input("Noise4x4", tex)
def generate_dataset_texture_into(self, dest_tex, z): resolution_vertical = dest_tex.get_y_size() resolution_horizontal = dest_tex.get_x_size() dest = PNMImage(resolution_vertical, resolution_horizontal, 1, 65535) for vert in range(resolution_vertical): for horiz in range(resolution_horizontal): vert_angle = vert / (resolution_vertical-1.0) vert_angle = math.cos(vert_angle * math.pi) * 90.0 + 90.0 horiz_angle = horiz / (resolution_horizontal-1.0) * 360.0 candela = self.get_candela_value(vert_angle, horiz_angle) dest.set_xel(vert, horiz, candela) dest_tex.load(dest, z, 0)
def generate_dataset_texture_into(self, dest_tex, layer_index): resolution_vertical = dest_tex.get_y_size() resolution_horizontal = dest_tex.get_x_size() dest = PNMImage(resolution_vertical, resolution_horizontal, 1, 65535) for vert in range(resolution_vertical): for horiz in range(resolution_horizontal): vert_angle = vert / (resolution_vertical - 1.0) vert_angle = math.cos(vert_angle * math.pi) * 90.0 + 90.0 horiz_angle = horiz / (resolution_horizontal - 1.0) * 360.0 candela = self.get_candela_value(vert_angle, horiz_angle) dest.set_xel(vert, horiz, candela) dest_tex.load(dest, layer_index, 0)
for i, s_nxv in enumerate(reversed(nxv_values)): if NxV >= s_nxv: index = i break index = len(nxv_values) - index - 1 next_index = index + 1 if index < dest_size - 1 else index curr_nxv = nxv_values[index] next_nxv = nxv_values[next_index] lerp_factor = (NxV - curr_nxv) / max(1e-10, abs(next_nxv - curr_nxv)) lerp_factor = max(0.0, min(1.0, lerp_factor)) indices.append((index, next_index, lerp_factor)) # Generate the final linear lut using the lerp weights for y in xrange(dest_h): for x in xrange(dest_size): curr_i, next_i, lerp = indices[x] curr_v = img.get_xel(curr_i, y) next_v = img.get_xel(next_i, y) dest.set_xel(x, y, curr_v * (1 - lerp) + next_v * lerp) out_name = config["out_name"].replace("{}", str(pass_index)) dest.write(config["out_dir"] + "/" + out_name) try: os.remove("scene.png") except: pass
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from __future__ import division, print_function import math from panda3d.core import PNMImage lut_size = 64 lut_cols = 8 lut_rows = (lut_size + lut_cols - 1) // lut_cols img = PNMImage(lut_size * lut_cols, lut_size * lut_rows, 3, 2**16 - 1) def to_linear(v): return float(v) / float(lut_size-1) def to_linear_inv(v): return 1 - to_linear(v) for r in range(lut_size): for g in range(lut_size): for b in range(lut_size): slice_offset_x = (b % lut_cols) * lut_size slice_offset_y = (b // lut_cols) * lut_size img.set_xel(r + slice_offset_x, g + slice_offset_y, to_linear(r), to_linear_inv(g), to_linear(b)) img.write("DefaultLUT.png")
for k in xrange(3): values[k].append(srgb_to_linear(line[k])) def to_linear(v): return float(v) / float(64 - 1) def to_linear_inv(v): return 1 - to_linear(v) def lookup_value(v, values): return values[int(v * (len(values) - 1))] # Generate lut img = PNMImage(64 * 8, 64 * 8, 3, 2**16 - 1) for r in xrange(64): for g in xrange(64): for b in xrange(64): slice_offset_x = (b % 8) * 64 slice_offset_y = (b // 8) * 64 fr, fg, fb = to_linear(r), to_linear_inv(g), to_linear(b) fr = lookup_value(fr, values[0]) fg = lookup_value(fg, values[1]) fb = lookup_value(fb, values[2]) img.set_xel(r + slice_offset_x, g + slice_offset_y, fr, fg, fb) img.write("film_luts/" + output_name + ".png")
def palettize(self, palette_img, create_rgb=True): """ Runs all palettization procedures on the given PaletteImage. Creates an RGB version of the palette if requested. :palette_img: The PaletteImage you want to palettize. :create_rgb: Would you like to create an RGB variant of the palette? True by default. """ # We need to know the palette's prior size if not palette_img.size_known: raise PalettizerException( "Palette image's size is not known, this is a fatal error!") palette_name = palette_img.basename if self.debug: print( f'[{palette_img.page.group.dirname}] Compiling {palette_name}..' ) # Our max distortion is 1, as we do not want to resize the palette to be smaller accidentally max_distortion = 1 # This array holds all of our PNMImage source textures imgs = [] # We're going to check all of the source textures # so that we can load all of them and determine our palette's final size for placement in palette_img.placements: sources = placement.texture.sources # We need to know the size of all source textures # If a source texture's size is not known, that means that it has been defined but did not exist on the disk when creating textures.boo for source in sources: if not source.size_known: print( f'Warning: Size is not known for source {source.filename}, please consider fixing the texture path and re-running egg-palettize' ) # Source (original) full resolution texture size source = sources[0] x_size = source.x_size y_size = source.y_size # Prior texture position and size tex_position = placement.position tex_x_size = tex_position.x_size tex_y_size = tex_position.y_size # DISTORTER # Fold the points until they scream out # DISTORTER # Change the way it sounds # We need to calculate the maximum distortion for both our X and Y (U/V) coordinates if x_size != tex_x_size: x_distortion = x_size / tex_x_size if x_distortion > max_distortion: max_distortion = x_distortion if y_size != tex_y_size: y_distortion = y_size / tex_y_size if y_distortion > max_distortion: max_distortion = y_distortion # If we have more than one source, that means our texture # has been defined multiple times for the same group... # Panda3D uses the first source texture only, so that's what we'll do. # But we'll make sure to print a warning either way! if len(sources) > 1: source2 = sources[1] if source2.x_size != x_size or source2.y_size != y_size: print( f'Two different source textures are defined for {palette_name}: {source.filename} ({x_size} {y_size}) vs {source2.filename} ({source2.x_size} {source2.y_size})' ) # Time to load the source file from Pandora! img = self.read_texture(source.filename) # Add the source image to our list imgs.append(img) # Well, time to calculate the palette's final size! # We will multiply the current size with the highest distortion. # We do NOT calculate X and Y distortion separately. # Doing so would destroy the aspect ratio of the palette. current_x_size = palette_img.x_size current_y_size = palette_img.y_size new_x_size = round(current_x_size * max_distortion) new_y_size = round(current_y_size * max_distortion) # Power of two time! # It's easier for the game engine to load, as it does not have to scale it automatically. new_x_size, new_y_size = self.scale_power_of_2(new_x_size, new_y_size) # We've changed the palette size. It is necessary to recalculate our texture distortion. x_distortion = new_x_size / current_x_size y_distortion = new_y_size / current_y_size # Create our palette image with four channels. # We will cut down the last channel when necessary. # Having a fourth, empty channel would only increase the file size. new_image = PNMImage(new_x_size, new_y_size, 4) new_image.alpha_fill(1) # Textures with alpha always have four channels set (three for RGB and one for Alpha). has_alpha = palette_img.properties.effective_channels in (2, 4) rgb_only = palette_img.properties.format == TextureGlobals.F_alpha alpha_image = None # If necessary and possible, create an alpha image as well. # Textures with alpha always have four channels set (three for RGB and one for Alpha). if create_rgb and has_alpha and not rgb_only: alpha_image = PNMImage(new_x_size, new_y_size, 1) alpha_image.set_type(PalettizeGlobals.RGB_TYPE) for i, placement in enumerate(palette_img.placements): # Find the loaded source image from before... texture_img = imgs[i] # Calculate the placement of our image! tex_position = placement.placed # Determine the upper left and lower right corners # with some matrix magic. transform = placement.compute_tex_matrix() ul = transform.xform_point(LTexCoordd(0.0, 1.0)) lr = transform.xform_point(LTexCoordd(1.0, 0.0)) # Calculate the top, left, bottom and right corners. top = int(math.floor((1.0 - ul[1]) * new_y_size + 0.5)) left = int(math.floor(ul[0] * new_x_size + 0.5)) bottom = int(math.floor((1.0 - lr[1]) * new_y_size + 0.5)) right = int(math.floor(lr[0] * new_x_size + 0.5)) tex_x_size = right - left tex_y_size = bottom - top org_x_size = round(tex_position.x_size * x_distortion) org_y_size = round(tex_position.y_size * y_distortion) tex_x = round(tex_position.x * x_distortion) tex_y = round(tex_position.y * y_distortion) # Resize our image to the desired size. texture_img = self.resize_image(texture_img, tex_x_size, tex_y_size) for y in range(tex_y, tex_y + org_y_size): sy = y - top # UV wrapping modes - V component (for Y texture coordinate) if placement.placed.wrap_v == TextureGlobals.WM_clamp: sy = max(min(sy, tex_y_size - 1), 0) elif placement.placed.wrap_v == TextureGlobals.WM_mirror: sy = (tex_y_size * 2) - 1 - ( (-sy - 1) % (tex_y_size * 2)) if sy < 0 else sy % (tex_y_size * 2) sy = sy if sy < tex_y_size else 2 * tex_y_size - sy - 1 elif placement.placed.wrap_v == TextureGlobals.WM_mirror_once: sy = sy if sy < tex_y_size else 2 * tex_y_size - sy - 1 # Repeat texture sy = tex_y_size - 1 - ( (-sy - 1) % tex_y_size) if sy < 0 else sy % tex_y_size elif placement.placed.wrap_v == TextureGlobals.WM_border_color: if sy < 0 or sy >= tex_y_size: continue else: # Repeat texture sy = tex_y_size - 1 - ( (-sy - 1) % tex_y_size) if sy < 0 else sy % tex_y_size for x in range(tex_x, tex_x + org_x_size): sx = x - left # UV wrapping modes - U component (for X texture coordinate) if placement.placed.wrap_u == TextureGlobals.WM_clamp: sx = max(min(sx, tex_x_size - 1), 0) elif placement.placed.wrap_u == TextureGlobals.WM_mirror: sx = (tex_x_size * 2) - 1 - ( (-sx - 1) % (tex_x_size * 2)) if sx < 0 else sx % (tex_x_size * 2) sx = sx if sx < tex_x_size else 2 * tex_x_size - sx - 1 elif placement.placed.wrap_u == TextureGlobals.WM_mirror_once: sx = sx if sx >= 0 else ~sx # Repeat texture sx = tex_x_size - 1 - ( (-sx - 1) % tex_x_size) if sx < 0 else sx % tex_x_size elif placement.placed.wrap_u == TextureGlobals.WM_border_color: if sx < 0 or sx >= tex_x_size: continue else: # Repeat texture sx = tex_x_size - 1 - ( (-sx - 1) % tex_x_size) if sx < 0 else sx % tex_x_size new_image.set_xel(x, y, texture_img.get_xel(sx, sy)) new_image.set_alpha(x, y, texture_img.get_alpha(sx, sy)) if alpha_image: alpha_image.set_gray(x, y, texture_img.get_alpha(sx, sy)) return new_image, alpha_image, has_alpha, rgb_only
write_diff_img = False img_a = PNMImage(source_a) img_b = PNMImage(source_b) w, h = img_a.get_x_size(), img_a.get_y_size() img_dest = PNMImage(w, h, 3) error_scale = 10.0 total_diff = 0.0 for x in xrange(w): for y in xrange(h): val_a = img_a.get_xel(x, y) val_b = img_b.get_xel(x, y) abs_diff = (val_a - val_b) * error_scale r, g, b = abs(abs_diff.x), abs(abs_diff.y), abs(abs_diff.z) img_dest.set_xel(x, y, r, g, b) total_diff += r + g + b total_diff /= float(w * h) total_diff /= error_scale print("Average difference: ", total_diff, " in RGB: ", total_diff * 255) img_dest.write("difference.png")
for k in xrange(3): values[k].append(srgb_to_linear(line[k])) def to_linear(v): return float(v) / float(64-1) def to_linear_inv(v): return 1 - to_linear(v) def lookup_value(v, values): return values[int(v * (len(values) - 1) )] # Generate lut img = PNMImage(64 * 8, 64 * 8, 3, 2**16 - 1) for r in xrange(64): for g in xrange(64): for b in xrange(64): slice_offset_x = (b % 8) * 64 slice_offset_y = (b // 8) * 64 fr, fg, fb = to_linear(r), to_linear_inv(g), to_linear(b) fr = lookup_value(fr, values[0]) fg = lookup_value(fg, values[1]) fb = lookup_value(fb, values[2]) img.set_xel(r + slice_offset_x, g + slice_offset_y, fr, fg, fb) img.write("film_luts/" + output_name + ".png")
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from __future__ import division, print_function import math from panda3d.core import PNMImage lut_size = 64 lut_cols = 8 lut_rows = (lut_size + lut_cols - 1) // lut_cols img = PNMImage(lut_size * lut_cols, lut_size * lut_rows, 3, 2**16 - 1) def to_linear(v): return float(v) / float(lut_size-1) def to_linear_inv(v): return 1 - to_linear(v) for r in range(lut_size): for g in range(lut_size): for b in range(lut_size): slice_offset_x = (b % lut_cols) * lut_size slice_offset_y = (b // lut_cols) * lut_size img.set_xel(r + slice_offset_x, g + slice_offset_y, to_linear(r), to_linear_inv(g), to_linear(b)) img.write("default_lut.png")
# Ambient Occlusion, Roughness, Metallicity # R: Ambient Occlusion # G: Roughness, a.k.a. gloss map (if inverted); Gets multiplied with mat.roughness # B: Metallicity; Gets multiplied with mat.metallic metal_rough_pnm = PNMImage(texture_size, texture_size) for x in range(texture_size): x_band = int(float(x) / float(texture_size) * (texture_bands_x)) x_band_base = float(x_band) / float(texture_bands_x - 1) for y in range(texture_size): y_band = int(float(y) / float(texture_size) * (texture_bands_y)) y_band_base = float(y_band) / float(texture_bands_y - 1) ambient_occlusion = 1.0 roughness = x_band_base * 0.18 + 0.12 # 0.12 - 0.3 metallicity = y_band_base * 0.1 + 0.88 # 0.1 - 0.98 metal_rough_pnm.set_xel(x, y, (ambient_occlusion, roughness, metallicity)) metal_rough_tex = Texture("MetalRoughness") metal_rough_tex.load(metal_rough_pnm) ts = TextureStage('MetalRoughness') # a.k.a. Selector ts.set_mode(TextureStage.M_selector) card_np.set_texture(ts, metal_rough_tex) # Normals # RGB is the normalized normal vector (z is perpendicular to # the surface) * 0.5 + 0.5 normal_pnm = PNMImage(texture_size, texture_size) for x in range(texture_size): for y in range(texture_size): v = Vec3(gauss(0, 0.2), gauss(0, 0.2), 1) v.normalize()