azkavyro's picture
Added all files including vyro_workflows
6fecfbe
from numba import jit
import numpy as np
import torch
def perlin_power_fractal_batch(batch_size, width, height, X, Y, Z, frame, evolution_factor=0.1, octaves=4, persistence=1.0, lacunarity=2.0, exponent=4.0, scale=100, brightness=0.0, contrast=0.0, seed=None):
"""
Generate a batch of images with a Perlin power fractal effect.
Parameters:
batch_size (int): Number of noisy tensors to generate in the batch.
width (int): Width of each tensor in pixels.
height (int): Height of each image in pixels.
X (float): X-coordinate offset for noise sampling.
Y (float): Y-coordinate offset for noise sampling.
Z (float): Z-coordinate offset for noise sampling.
frame (int): The current frame number for time evolution.
evolution_factor (float): Factor controlling time evolution. Determines how much the noise evolves over time based on the batch index.
octaves (int): Number of octaves for fractal generation. Controls the level of detail and complexity in the output.
Lower values (0-3) create smoother patterns, while higher values (6-8) create more intricate and rough patterns.
persistence (float): Persistence parameter for fractal generation. Determines the amplitude decrease of each octave.
Higher values (0.5-0.9) result in more defined and contrasted patterns, while lower values create smoother patterns.
lacunarity (float): Lacunarity parameter for fractal generation. Controls the increase in frequency from one octave to the next.
Higher values (2.0-3.0) create more detailed and finer patterns, while lower values create coarser patterns.
exponent (int): Exponent applied to the noise values. Adjusting this parameter controls the overall intensity and contrast of the output.
Higher values (>1) emphasize the differences between noisy elements, resulting in more distinct features.
scale (int): Scaling factor for frequency of noise. Larger values produce smaller, more detailed patterns, while smaller values create larger patterns.
brightness (float): Adjusts the overall brightness of the generated noise.
- -1.0 makes the noise completely black.
- 0.0 has no effect on brightness.
- 1.0 makes the noise completely white.
contrast (float): Adjusts the contrast of the generated noise.
- -1.0 reduces contrast, enhancing the difference between dark and light areas.
- 0.0 has no effect on contrast.
- 1.0 increases contrast, enhancing the difference between dark and light areas.
seed (int, optional): Seed for random number generation. If None, uses random seeds for each batch.
Returns:
torch.Tensor: A tensor containing the generated images in the shape (batch_size, 4, height, width).
"""
@jit(nopython=True)
def fade(t):
return 6 * t**5 - 15 * t**4 + 10 * t**3
@jit(nopython=True)
def lerp(t, a, b):
return a + t * (b - a)
@jit(nopython=True)
def grad(hash, x, y, z):
h = hash & 15
u = x if h < 8 else y
v = y if h < 4 else (x if h == 12 or h == 14 else z)
return (u if (h & 1) == 0 else -u) + (v if (h & 2) == 0 else -v)
@jit(nopython=True)
def noise(x, y, z, p):
X = np.int32(np.floor(x)) & 255
Y = np.int32(np.floor(y)) & 255
Z = np.int32(np.floor(z)) & 255
x -= np.floor(x)
y -= np.floor(y)
z -= np.floor(z)
u = fade(x)
v = fade(y)
w = fade(z)
A = p[X] + Y
AA = p[A] + Z
AB = p[A + 1] + Z
B = p[X + 1] + Y
BA = p[B] + Z
BB = p[B + 1] + Z
return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), grad(p[BA], x - 1, y, z)),
lerp(u, grad(p[AB], x, y - 1, z), grad(p[BB], x - 1, y - 1, z))),
lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), grad(p[BA + 1], x - 1, y, z - 1)),
lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1))))
noise_maps = []
for i in range(batch_size):
unique_seed = seed + i if seed is not None else None
np.random.seed(unique_seed)
p = np.arange(256, dtype=np.int32)
np.random.shuffle(p)
p = np.concatenate((p, p))
noise_map_r = np.zeros((height, width))
noise_map_g = np.zeros((height, width))
noise_map_b = np.zeros((height, width))
noise_map_a = np.zeros((height, width))
amplitude = 1.0
total_amplitude = 0.0
for octave in range(octaves):
frequency = lacunarity ** octave
amplitude *= persistence
total_amplitude += amplitude
for y in range(height):
for x in range(width):
nx = x / scale * frequency
ny = y / scale * frequency
nz = evolution_factor * i + frame
noise_value_r = noise(nx + X, ny + Y, nz + Z, p) * amplitude ** exponent
noise_value_g = noise(nx + X + 1000, ny + Y + 1000, nz + Z + 1000, p) * amplitude ** exponent
noise_value_b = noise(nx + X + 2000, ny + Y + 2000, nz + Z + 2000, p) * amplitude ** exponent
noise_value_a = noise(nx + X + 3000, ny + Y + 3000, nz + Z + 3000, p) * amplitude ** exponent
current_value_r = noise_map_r[y, x]
current_value_g = noise_map_g[y, x]
current_value_b = noise_map_b[y, x]
current_value_a = noise_map_a[y, x]
noise_map_r[y, x] = current_value_r + noise_value_r
noise_map_g[y, x] = current_value_g + noise_value_g
noise_map_b[y, x] = current_value_b + noise_value_b
noise_map_a[y, x] = current_value_a + noise_value_a
min_value_r = np.min(noise_map_r)
max_value_r = np.max(noise_map_r)
min_value_g = np.min(noise_map_g)
max_value_g = np.max(noise_map_g)
min_value_b = np.min(noise_map_b)
max_value_b = np.max(noise_map_b)
min_value_a = np.min(noise_map_a)
max_value_a = np.max(noise_map_a)
noise_map_r = np.interp(noise_map_r, (min_value_r, max_value_r), (0.0, 1.0))
noise_map_g = np.interp(noise_map_g, (min_value_g, max_value_g), (0.0, 1.0))
noise_map_b = np.interp(noise_map_b, (min_value_b, max_value_b), (0.0, 1.0))
noise_map_a = np.interp(noise_map_a, (min_value_a, max_value_a), (0.0, 1.0))
noise_map = np.stack((noise_map_r, noise_map_g, noise_map_b, noise_map_a), axis=-1)
noise_maps.append(noise_map)
noise_maps_array = np.array(noise_maps, dtype=np.float32)
image_tensor_batch = torch.tensor(noise_maps_array, dtype=torch.float32).permute(0, 3, 1, 2)
image_tensor_batch = (image_tensor_batch + brightness) * (1.0 + contrast)
image_tensor_batch = torch.clamp(image_tensor_batch, 0.0, 1.0)
latents = image_tensor_batch.view(batch_size, 4, height, width)
tensors = image_tensor_batch.reshape(batch_size, height, width, 4)
return (latents, tensors)
# COMFYUI NODES
class Vyro_PFN_Latent:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"batch_size": ("INT", {"default": 1, "max": 64, "min": 1, "step": 1}),
"width": ("INT", {"default": 512, "max": 8192, "min": 64, "step": 1}),
"height": ("INT", {"default": 512, "max": 8192, "min": 64, "step": 1}),
"X": ("INT", {"default": 0, "max": 99999999, "min": -99999999, "step": 1}),
"Y": ("INT", {"default": 0, "max": 99999999, "min": -99999999, "step": 1}),
"Z": ("INT", {"default": 0, "max": 99999999, "min": -99999999, "step": 1}),
"evolution": ("FLOAT", {"default": 0.0, "max": 1.0, "min": 0.0, "step": 0.01}),
"frame": ("INT", {"default": 0, "max": 99999999, "min": 0, "step": 1}),
"scale": ("INT", {"default": 100, "max": 2048, "min": 2, "step": 1}),
"octaves": ("INT", {"default": 8, "max": 8, "min": 0, "step": 1}),
"persistence": ("FLOAT", {"default": 1.0, "max": 10.0, "min": 0.01, "step": 0.01}),
"lacunarity": ("FLOAT", {"default": 2.0, "max": 1000.0, "min": 0.01, "step": 0.01}),
"exponent": ("FLOAT", {"default": 4.0, "max": 38.0, "min": 0.01, "step": 0.01}),
"brightness": ("FLOAT", {"default": 0.0, "max": 1.0, "min": -1.0, "step": 0.01}),
"contrast": ("FLOAT", {"default": 0.0, "max": 1.0, "min": -1.0, "step": 0.01}),
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
},
}
RETURN_TYPES = ("LATENT","IMAGE")
RETURN_NAMES = ("latents","previews")
FUNCTION = "power_fractal_latent"
CATEGORY = "latent/noise"
def power_fractal_latent(self, batch_size, width, height, X, Y, Z, evolution, frame, scale, octaves, persistence, lacunarity, exponent, brightness, contrast, seed):
width = width // 8
height = height // 8
seed = int(str(seed)[:8])
latents, tensors = perlin_power_fractal_batch(batch_size, width, height, X, Y, Z, frame, evolution, octaves, persistence, lacunarity, exponent, scale, brightness, contrast, seed)
return ({'samples': latents}, tensors)
NODE_CLASS_MAPPINGS = {
"Vyro_PFN_Latent": Vyro_PFN_Latent
}
NODE_DISPLAY_NAME_MAPPINGS = {
"Vyro_PFN_Latent": "Perlin Power Fractal Noise"
}