Perlin Tremor Scheduler¶
Documentation¶
- Class name:
SaltOPAC
- Category:
SALT/AudioViz/Scheduling
- Output node:
False
The SaltOPAC node is designed for orchestrating complex scheduling tasks within audio-visual projects, specifically focusing on applying Perlin noise configurations to enhance the dynamic visual effects. It integrates various scheduling parameters such as zoom, angle, and translations along different axes, to create intricate motion and transformation effects in synchronization with audio or other triggers.
Input types¶
Required¶
use_wiggle
- Determines whether wiggle effects, based on Perlin noise, are applied to the visual elements, adding a dynamic, naturalistic motion.
- Comfy dtype:
BOOLEAN
- Python dtype:
bool
frame_count
- Specifies the number of frames for which the scheduling and effects are calculated, defining the duration of the visual sequence.
- Comfy dtype:
INT
- Python dtype:
int
zoom_range
- Defines the range of zoom values to be applied across frames, influencing the scale of visual elements over time.
- Comfy dtype:
STRING
- Python dtype:
tuple(float, float)
zoom_tremor_scale
- Adjusts the intensity of the zoom tremor effect, allowing for finer control over the zoom dynamics.
- Comfy dtype:
FLOAT
- Python dtype:
float
angle_range
- Sets the range of angles for rotational effects, adding to the complexity of motion.
- Comfy dtype:
STRING
- Python dtype:
tuple(float, float)
angle_tremor_scale
- Controls the scale of angle tremors, affecting the subtlety or intensity of rotational movements.
- Comfy dtype:
FLOAT
- Python dtype:
float
trx_range
- Determines the horizontal translation range, enabling lateral movement across frames.
- Comfy dtype:
STRING
- Python dtype:
tuple(float, float)
trx_tremor_scale
- Modifies the scale of horizontal translation tremors, impacting the smoothness or jitteriness of movement.
- Comfy dtype:
FLOAT
- Python dtype:
float
try_range
- Specifies the vertical translation range, allowing for vertical movement adjustments.
- Comfy dtype:
STRING
- Python dtype:
tuple(float, float)
try_tremor_scale
- Adjusts the intensity of vertical translation tremors, affecting the vertical motion dynamics.
- Comfy dtype:
FLOAT
- Python dtype:
float
trz_range
- Defines the depth translation range, influencing the perception of depth in the visual sequence.
- Comfy dtype:
STRING
- Python dtype:
tuple(float, float)
trz_tremor_scale
- Controls the scale of depth translation tremors, enhancing the depth dynamics.
- Comfy dtype:
FLOAT
- Python dtype:
float
rotx_range
- Sets the range for rotation around the x-axis, contributing to the 3D rotation effects.
- Comfy dtype:
STRING
- Python dtype:
tuple(float, float)
rotx_tremor_scale
- Adjusts the intensity of x-axis rotation tremors, affecting the complexity of 3D rotational movements.
- Comfy dtype:
FLOAT
- Python dtype:
float
roty_range
- Determines the range for rotation around the y-axis, adding another layer of 3D rotation.
- Comfy dtype:
STRING
- Python dtype:
tuple(float, float)
roty_tremor_scale
- Modifies the scale of y-axis rotation tremors, impacting the 3D rotational dynamics.
- Comfy dtype:
FLOAT
- Python dtype:
float
rotz_range
- Specifies the range for rotation around the z-axis, completing the set of 3D rotational dynamics.
- Comfy dtype:
STRING
- Python dtype:
tuple(float, float)
rotz_tremor_scale
- Controls the intensity of z-axis rotation tremors, enhancing the 3D rotation effects.
- Comfy dtype:
FLOAT
- Python dtype:
float
Optional¶
opac_perlin_settings
- This parameter allows for the customization of Perlin noise settings, which are crucial for generating naturalistic variations in the visual effects. By adjusting these settings, users can significantly influence the visual dynamics of the project.
- Comfy dtype:
DICT
- Python dtype:
dict
Output types¶
zoom_schdule_list
- Comfy dtype:
LIST
- unknown
- Python dtype:
unknown
- Comfy dtype:
angle_schdule_list
- Comfy dtype:
LIST
- unknown
- Python dtype:
unknown
- Comfy dtype:
translation_x_schdule_list
- Comfy dtype:
LIST
- unknown
- Python dtype:
unknown
- Comfy dtype:
translation_y_schdule_list
- Comfy dtype:
LIST
- unknown
- Python dtype:
unknown
- Comfy dtype:
translation_z_schdule_list
- Comfy dtype:
LIST
- unknown
- Python dtype:
unknown
- Comfy dtype:
rotation_3d_x_schdule_list
- Comfy dtype:
LIST
- unknown
- Python dtype:
unknown
- Comfy dtype:
rotation_3d_y_schdule_list
- Comfy dtype:
LIST
- unknown
- Python dtype:
unknown
- Comfy dtype:
rotation_3d_z_schdule_list
- Comfy dtype:
LIST
- unknown
- Python dtype:
unknown
- Comfy dtype:
Usage tips¶
- Infra type:
CPU
- Common nodes: unknown
Source code¶
class SaltOPAC:
"""
Generates semi-random keyframes for zoom, spin, and translation based on specified start and end ranges,
with individual tremor scale controls for each parameter, allowing for organic variation using Perlin noise.
"""
def __init__(self):
self.noise_base = random.randint(0, 1000)
self.perlin_noise = PerlinNoise()
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"use_wiggle": ("BOOLEAN", {"default": True}),
"frame_count": ("INT", {"default": 48, "min": 1, "max": 500}),
"zoom_range": ("STRING", {"default": "0.95,1.05"}),
"zoom_tremor_scale": ("FLOAT", {"default": 0.05, "min": 0.01, "max": 1.0}),
"angle_range": ("STRING", {"default": "-5,5"}),
"angle_tremor_scale": ("FLOAT", {"default": 0.05, "min": 0.01, "max": 1.0}),
"trx_range": ("STRING", {"default": "-10,10"}),
"trx_tremor_scale": ("FLOAT", {"default": 0.05, "min": 0.01, "max": 1.0}),
"try_range": ("STRING", {"default": "-10,10"}),
"try_tremor_scale": ("FLOAT", {"default": 0.05, "min": 0.01, "max": 1.0}),
"trz_range": ("STRING", {"default": "-10,10"}),
"trz_tremor_scale": ("FLOAT", {"default": 0.05, "min": 0.01, "max": 1.0}),
"rotx_range": ("STRING", {"default": "-5,5"}),
"rotx_tremor_scale": ("FLOAT", {"default": 0.05, "min": 0.01, "max": 1.0}),
"roty_range": ("STRING", {"default": "-5,5"}),
"roty_tremor_scale": ("FLOAT", {"default": 0.05, "min": 0.01, "max": 1.0}),
"rotz_range": ("STRING", {"default": "-5,5"}),
"rotz_tremor_scale": ("FLOAT", {"default": 0.05, "min": 0.01, "max": 1.0}),
},
"optional": {
"opac_perlin_settings": ("DICT", {})
}
}
RETURN_TYPES = ("LIST", "LIST", "LIST", "LIST", "LIST", "LIST", "LIST", "LIST")
RETURN_NAMES = ("zoom_schdule_list", "angle_schdule_list", "translation_x_schdule_list", "translation_y_schdule_list", "translation_z_schdule_list", "rotation_3d_x_schdule_list", "rotation_3d_y_schdule_list", "rotation_3d_z_schdule_list")
FUNCTION = "execute"
CATEGORY = f"{MENU_NAME}/{SUB_MENU_NAME}/Scheduling"
def process_kwargs(self, **kwargs):
self.use_wiggle = kwargs.get('use_wiggle', True)
self.frame_count = kwargs.get('frame_count', 48)
self.zoom_range = tuple(map(float, kwargs.get('zoom_range', "0.95,1.05").split(',')))
self.zoom_tremor_scale = kwargs.get('zoom_tremor_scale', 0.05)
self.angle_range = tuple(map(float, kwargs.get('angle_range', "-5,5").split(',')))
self.angle_tremor_scale = kwargs.get('angle_tremor_scale', 0.05)
self.trx_range = tuple(map(float, kwargs.get('trx_range', "-10,10").split(',')))
self.trx_tremor_scale = kwargs.get('trx_tremor_scale', 0.05)
self.try_range = tuple(map(float, kwargs.get('try_range', "-10,10").split(',')))
self.try_tremor_scale = kwargs.get('try_tremor_scale', 0.05)
self.trz_range = tuple(map(float, kwargs.get('trz_range', "-10,10").split(',')))
self.trz_tremor_scale = kwargs.get('trz_tremor_scale', 0.05)
self.rotx_range = tuple(map(float, kwargs.get('rotx_range', "-5,5").split(',')))
self.rotx_tremor_scale = kwargs.get('rotx_tremor_scale', 0.05)
self.roty_range = tuple(map(float, kwargs.get('roty_range', "-5,5").split(',')))
self.roty_tremor_scale = kwargs.get('roty_tremor_scale', 0.05)
self.rotz_range = tuple(map(float, kwargs.get('rotz_range', "-5,5").split(',')))
self.rotz_tremor_scale = kwargs.get('rotz_tremor_scale', 0.05)
# Zoom Perlin settings
self.zoom_octaves = kwargs.get('zoom_octaves', 1)
self.zoom_persistence = kwargs.get('zoom_persistence', 0.5)
self.zoom_lacunarity = kwargs.get('zoom_lacunarity', 2.0)
self.zoom_repeat = kwargs.get('zoom_repeat', 1024)
# Angle Perlin settings
self.angle_octaves = kwargs.get('angle_octaves', 1)
self.angle_persistence = kwargs.get('angle_persistence', 0.5)
self.angle_lacunarity = kwargs.get('angle_lacunarity', 2.0)
self.angle_repeat = kwargs.get('angle_repeat', 1024)
# Translation Perlin settings (trx, try, trz)
self.trx_octaves = kwargs.get('trx_octaves', 1)
self.trx_persistence = kwargs.get('trx_persistence', 0.5)
self.trx_lacunarity = kwargs.get('trx_lacunarity', 2.0)
self.trx_repeat = kwargs.get('trx_repeat', 1024)
self.try_octaves = kwargs.get('try_octaves', 1)
self.try_persistence = kwargs.get('try_persistence', 0.5)
self.try_lacunarity = kwargs.get('try_lacunarity', 2.0)
self.try_repeat = kwargs.get('try_repeat', 1024)
self.trz_octaves = kwargs.get('trz_octaves', 1)
self.trz_persistence = kwargs.get('trz_persistence', 0.5)
self.trz_lacunarity = kwargs.get('trz_lacunarity', 2.0)
self.trz_repeat = kwargs.get('trz_repeat', 1024)
# Rotation Perlin settings (rotx, roty, rotz)
self.rotx_octaves = kwargs.get('rotx_octaves', 1)
self.rotx_persistence = kwargs.get('rotx_persistence', 0.5)
self.rotx_lacunarity = kwargs.get('rotx_lacunarity', 2.0)
self.rotx_repeat = kwargs.get('rotx_repeat', 1024)
self.roty_octaves = kwargs.get('roty_octaves', 1)
self.roty_persistence = kwargs.get('roty_persistence', 0.5)
self.roty_lacunarity = kwargs.get('roty_lacunarity', 2.0)
self.roty_repeat = kwargs.get('roty_repeat', 1024)
self.rotz_octaves = kwargs.get('rotz_octaves', 1)
self.rotz_persistence = kwargs.get('rotz_persistence', 0.5)
self.rotz_lacunarity = kwargs.get('rotz_lacunarity', 2.0)
self.rotz_repeat = kwargs.get('rotz_repeat', 1024)
#def sample_perlin(self, base, scale, x, min_val, max_val, octaves=1, persistence=0.5, lacunarity=2.0, repeat=1024):
# noise_val = self.perlin_noise.sample(base + x * scale, scale=1.0, octaves=octaves, persistence=persistence, lacunarity=lacunarity)
# return noise_val * (max_val - min_val) + min_val
def sample_perlin(self, frame_index, range_min, range_max, tremor_scale, octaves, persistence, lacunarity, repeat):
# Prepare noise correctly with normalization
t = frame_index / (self.frame_count - 1 if self.frame_count > 1 else 1)
linear_value = (range_max - range_min) * t + range_min
noise = self.perlin_noise.sample(self.noise_base + frame_index * 0.1, scale=1.0, octaves=octaves, persistence=persistence, lacunarity=lacunarity)
noise_adjustment = 1 + noise * tremor_scale
interpolated_value = linear_value * noise_adjustment
return interpolated_value
def execute(self, **kwargs):
if kwargs.__contains__("opac_perlin_settings"):
perlin_settings = kwargs.pop("opac_perlin_settings")
kwargs.update(perlin_settings)
logger.info("\033[1m\033[94mOPAC Perlin Settings applied!:\033[0m")
# Process the input values
self.process_kwargs(**kwargs)
if not self.use_wiggle:
return ([0] * self.frame_count,) * 8
# More dynamic implementation this time
zoom, angle, translation_x, translation_y, translation_z, rotation_3d_x, rotation_3d_y, rotation_3d_z = (
[self.sample_perlin(i, *param) for i in range(self.frame_count)]
for param in [
(self.zoom_range[0], self.zoom_range[1], self.zoom_tremor_scale, self.zoom_octaves, self.zoom_persistence, self.zoom_lacunarity, self.zoom_repeat),
(self.angle_range[0], self.angle_range[1], self.angle_tremor_scale, self.angle_octaves, self.angle_persistence, self.angle_lacunarity, self.angle_repeat),
(self.trx_range[0], self.trx_range[1], self.trx_tremor_scale, self.trx_octaves, self.trx_persistence, self.trx_lacunarity, self.trx_repeat),
(self.try_range[0], self.try_range[1], self.try_tremor_scale, self.try_octaves, self.try_persistence, self.try_lacunarity, self.try_repeat),
(self.trz_range[0], self.trz_range[1], self.trz_tremor_scale, self.trz_octaves, self.trz_persistence, self.trz_lacunarity, self.trz_repeat),
(self.rotx_range[0], self.rotx_range[1], self.rotx_tremor_scale, self.rotx_octaves, self.rotx_persistence, self.rotx_lacunarity, self.rotx_repeat),
(self.roty_range[0], self.roty_range[1], self.roty_tremor_scale, self.roty_octaves, self.roty_persistence, self.roty_lacunarity, self.roty_repeat),
(self.rotz_range[0], self.rotz_range[1], self.rotz_tremor_scale, self.rotz_octaves, self.rotz_persistence, self.rotz_lacunarity, self.rotz_repeat)
]
)
logger.info("\033[1m\033[94mOPAC Schedule Curves:\033[0m")
log_curve("zoom", zoom)
log_curve("angle", angle)
log_curve("translation_x", translation_x)
log_curve("translation_y", translation_y)
log_curve("translation_z", translation_z)
log_curve("rotation_3d_x", rotation_3d_x)
log_curve("rotation_3d_y", rotation_3d_y)
log_curve("rotation_3d_z", rotation_3d_z)
logger.info("")
return zoom, angle, translation_x, translation_y, translation_z, rotation_3d_x, rotation_3d_y, rotation_3d_z