Big update
This commit is contained in:
+112
-15
@@ -79,19 +79,30 @@ def _update_knot_material_cb(self, context) -> None:
|
||||
if not self.uid:
|
||||
self.uid = f"knot_{random.randint(100000, 999999)}"
|
||||
|
||||
if self.material_mode == 'PRESET':
|
||||
_ensure_item_preset_material(self)
|
||||
try:
|
||||
scene = getattr(context, "scene", None)
|
||||
if scene is None:
|
||||
return
|
||||
|
||||
# Rebuild blend materials to keep transitions up to date
|
||||
prebuild_playlist_blend_materials(context.scene)
|
||||
if self.material_mode == 'PRESET':
|
||||
_ensure_item_preset_material(self)
|
||||
|
||||
# Force redraw of 3-D viewport
|
||||
for area in context.screen.areas:
|
||||
if area.type == 'VIEW_3D':
|
||||
area.tag_redraw()
|
||||
# Rebuild blend materials to keep transitions up to date
|
||||
prebuild_playlist_blend_materials(scene)
|
||||
|
||||
# Instantly update the active viewport knot's material
|
||||
_update_viewport_knot_material(context.scene)
|
||||
# Instantly update the active viewport knot's material
|
||||
_update_viewport_knot_material(scene)
|
||||
|
||||
# Force redraw of 3-D viewport if screen exists
|
||||
screen = getattr(context, "screen", None)
|
||||
if screen:
|
||||
for area in screen.areas:
|
||||
if area.type == 'VIEW_3D':
|
||||
area.tag_redraw()
|
||||
except Exception:
|
||||
# Safe fallback: if this callback fires during depsgraph evaluation
|
||||
# (e.g., driven by an F-curve), context accesses will throw internal state bugs.
|
||||
pass
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -111,10 +122,14 @@ class KnotGlobalSettings(bpy.types.PropertyGroup):
|
||||
"""Scene-level playback and rendering settings."""
|
||||
frames_per_knot: bpy.props.IntProperty(
|
||||
name="Frames per Knot", default=12, min=1)
|
||||
resolution: bpy.props.IntProperty(
|
||||
name="Curve Resolution", default=128, min=3, max=1024)
|
||||
bevel_resolution: bpy.props.IntProperty(
|
||||
name="Bevel Resolution", default=8, min=0, max=64)
|
||||
preview_resolution: bpy.props.IntProperty(
|
||||
name="Preview Curve Res", default=64, min=3, max=1024)
|
||||
render_resolution: bpy.props.IntProperty(
|
||||
name="Render Curve Res", default=128, min=3, max=2048)
|
||||
preview_bevel_resolution: bpy.props.IntProperty(
|
||||
name="Preview Bevel Res", default=4, min=0, max=64)
|
||||
render_bevel_resolution: bpy.props.IntProperty(
|
||||
name="Render Bevel Res", default=8, min=0, max=64)
|
||||
knot_scale: bpy.props.FloatProperty(
|
||||
name="Global Scale", default=1.0, min=0.01)
|
||||
global_speed: bpy.props.FloatProperty(
|
||||
@@ -127,6 +142,38 @@ class KnotGlobalSettings(bpy.types.PropertyGroup):
|
||||
name="Reactivity", default=1.0, min=0.0, max=10.0,
|
||||
description="Scales all per-knot animation rates. Wire a driver here for audio-reactive animation.")
|
||||
|
||||
# New 8 Global Variables
|
||||
global_turbulence: bpy.props.FloatProperty(
|
||||
name="Turbulence (Noise)", default=0.0, min=0.0,
|
||||
description="Injects 3D noise/displacement into the final curve vertices.")
|
||||
global_emission_multiplier: bpy.props.FloatProperty(
|
||||
name="Emission Multiplier", default=1.0, min=0.0,
|
||||
description="Master scalar for the shader's emission strength.")
|
||||
global_master_thickness: bpy.props.FloatProperty(
|
||||
name="Master Thickness", default=1.0, min=0.0,
|
||||
description="Multiplier for the knot's bevel depth.")
|
||||
global_hue_shift: bpy.props.FloatProperty(
|
||||
name="Hue Shift", default=0.0,
|
||||
description="Offset applied to the material's color hue.")
|
||||
camera_shake_amplitude: bpy.props.FloatProperty(
|
||||
name="Camera Shake Amp", default=0.0, min=0.0,
|
||||
description="Injects X/Y/Z jitter into the active camera's location.")
|
||||
auto_turntable_speed: bpy.props.FloatProperty(
|
||||
name="Turntable Speed", default=0.0,
|
||||
description="Constant Z-axis rotation speed applied to the master knot object.")
|
||||
smooth_shading: bpy.props.BoolProperty(
|
||||
name="Smooth Shading", default=True,
|
||||
description="Enforce Smooth shading on the generated mesh.")
|
||||
viewport_wireframe: bpy.props.BoolProperty(
|
||||
name="Viewport Wireframe", default=False,
|
||||
description="Force the object to display as wireframe in the 3D viewport.")
|
||||
|
||||
# UI expand state
|
||||
ui_show_global: bpy.props.BoolProperty(name="Global Settings", default=True)
|
||||
ui_show_playback: bpy.props.BoolProperty(name="Playback", default=True)
|
||||
ui_show_playlist: bpy.props.BoolProperty(name="Playlist", default=True)
|
||||
ui_show_knot_edit: bpy.props.BoolProperty(name="Selected Knot", default=True)
|
||||
|
||||
|
||||
class KnotItem(bpy.types.PropertyGroup):
|
||||
"""One entry in the knot playlist."""
|
||||
@@ -147,25 +194,37 @@ class KnotItem(bpy.types.PropertyGroup):
|
||||
|
||||
# Topology (Torus Knot)
|
||||
torus_p: bpy.props.IntProperty(name="Revolutions (p)", default=2, min=1)
|
||||
mod_torus_p: bpy.props.FloatProperty(name="Mod p", default=0.0)
|
||||
torus_q: bpy.props.IntProperty(name="Spins (q)", default=3, min=1)
|
||||
mod_torus_q: bpy.props.FloatProperty(name="Mod q", default=0.0)
|
||||
|
||||
# Topology (Mobius)
|
||||
mobius_twists: bpy.props.IntProperty(name="Half Twists", default=1, min=1)
|
||||
mod_mobius_twists: bpy.props.FloatProperty(name="Mod Twists", default=0.0)
|
||||
mobius_width: bpy.props.FloatProperty(name="Width", default=1.0, min=0.1)
|
||||
mod_mobius_width: bpy.props.FloatProperty(name="Mod Width", default=0.0)
|
||||
|
||||
# Topology (Lissajous 3D)
|
||||
liss_kx: bpy.props.IntProperty(name="kx (Freq X)", default=3, min=1)
|
||||
mod_liss_kx: bpy.props.FloatProperty(name="Mod kx", default=0.0)
|
||||
liss_ky: bpy.props.IntProperty(name="ky (Freq Y)", default=2, min=1)
|
||||
mod_liss_ky: bpy.props.FloatProperty(name="Mod ky", default=0.0)
|
||||
liss_kz: bpy.props.IntProperty(name="kz (Freq Z)", default=4, min=1)
|
||||
mod_liss_kz: bpy.props.FloatProperty(name="Mod kz", default=0.0)
|
||||
liss_amp: bpy.props.FloatProperty(name="Amplitude", default=2.0, min=0.1)
|
||||
mod_liss_amp: bpy.props.FloatProperty(name="Mod Amp", default=0.0)
|
||||
|
||||
# Topology (Spherical Spiral)
|
||||
spiral_turns: bpy.props.IntProperty(name="Turns", default=10, min=1)
|
||||
mod_spiral_turns: bpy.props.FloatProperty(name="Mod Turns", default=0.0)
|
||||
spiral_R: bpy.props.FloatProperty(name="Radius", default=2.0, min=0.1)
|
||||
mod_spiral_R: bpy.props.FloatProperty(name="Mod Radius", default=0.0)
|
||||
|
||||
# Radii (Torus Knot)
|
||||
torus_R: bpy.props.FloatProperty(name="Major", default=2.0, min=0.0)
|
||||
mod_torus_R: bpy.props.FloatProperty(name="Mod Major", default=0.0)
|
||||
torus_r: bpy.props.FloatProperty(name="Minor", default=1.0, min=0.0)
|
||||
mod_torus_r: bpy.props.FloatProperty(name="Mod Minor", default=0.0)
|
||||
|
||||
# Colors (legacy TKP path)
|
||||
multiple_links: bpy.props.BoolProperty(name="Multiple Links", default=False)
|
||||
@@ -205,7 +264,8 @@ class KnotItem(bpy.types.PropertyGroup):
|
||||
# Transition
|
||||
transition_frames: bpy.props.IntProperty(
|
||||
name="Transition Frames", default=0, min=0,
|
||||
description="Number of frames to morph into the next knot (0 = instant)")
|
||||
description="Number of frames to morph into the next knot (0 = instant)",
|
||||
update=_update_knot_material_cb)
|
||||
transition_easing: bpy.props.EnumProperty(
|
||||
name="Easing",
|
||||
items=[
|
||||
@@ -217,8 +277,11 @@ class KnotItem(bpy.types.PropertyGroup):
|
||||
|
||||
# Geometry
|
||||
geo_extrude: bpy.props.FloatProperty(name="Extrude", default=0.0, min=0.0)
|
||||
mod_geo_extrude: bpy.props.FloatProperty(name="Mod Extrude", default=0.0)
|
||||
geo_offset: bpy.props.FloatProperty(name="Offset", default=0.0)
|
||||
mod_geo_offset: bpy.props.FloatProperty(name="Mod Offset", default=0.0)
|
||||
geo_bDepth: bpy.props.FloatProperty(name="Bevel Depth", default=0.04, min=0.0)
|
||||
mod_geo_bDepth: bpy.props.FloatProperty(name="Mod BDepth", default=0.0)
|
||||
|
||||
# Dimensions mode
|
||||
mode: bpy.props.EnumProperty(
|
||||
@@ -226,13 +289,25 @@ class KnotItem(bpy.types.PropertyGroup):
|
||||
items=[('MAJOR_MINOR', "Major/Minor", ""), ('EXT_INT', "Exterior/Interior", "")],
|
||||
default='MAJOR_MINOR')
|
||||
torus_eR: bpy.props.FloatProperty(name="Exterior", default=3.0, min=0.0)
|
||||
mod_torus_eR: bpy.props.FloatProperty(name="Mod Ext", default=0.0)
|
||||
torus_iR: bpy.props.FloatProperty(name="Interior", default=1.0, min=0.0)
|
||||
mod_torus_iR: bpy.props.FloatProperty(name="Mod Int", default=0.0)
|
||||
torus_h: bpy.props.FloatProperty(name="Height", default=1.0, min=0.0)
|
||||
mod_torus_h: bpy.props.FloatProperty(name="Mod Height", default=0.0)
|
||||
|
||||
# Direction
|
||||
flip_p: bpy.props.BoolProperty(name="Flip p", default=False)
|
||||
flip_q: bpy.props.BoolProperty(name="Flip q", default=False)
|
||||
|
||||
# UI expand state (display-only, not serialised to animation)
|
||||
ui_show_shape: bpy.props.BoolProperty(name="Shape", default=True)
|
||||
ui_show_geometry: bpy.props.BoolProperty(name="Geometry", default=False)
|
||||
ui_show_links: bpy.props.BoolProperty(name="Links & Phases", default=False)
|
||||
ui_show_anim: bpy.props.BoolProperty(name="Animation Rates", default=True)
|
||||
ui_show_material: bpy.props.BoolProperty(name="Material", default=True)
|
||||
ui_show_colors: bpy.props.BoolProperty(name="Colors", default=False)
|
||||
ui_show_trans: bpy.props.BoolProperty(name="Transition", default=False)
|
||||
|
||||
# Material
|
||||
material_mode: bpy.props.EnumProperty(
|
||||
name="Material Mode",
|
||||
@@ -267,17 +342,29 @@ class KnotItem(bpy.types.PropertyGroup):
|
||||
return {
|
||||
"shape_type": self.shape_type,
|
||||
"torus_p": self.torus_p,
|
||||
"mod_torus_p": self.mod_torus_p,
|
||||
"torus_q": self.torus_q,
|
||||
"mod_torus_q": self.mod_torus_q,
|
||||
"mobius_twists": self.mobius_twists,
|
||||
"mod_mobius_twists": self.mod_mobius_twists,
|
||||
"mobius_width": self.mobius_width,
|
||||
"mod_mobius_width": self.mod_mobius_width,
|
||||
"liss_kx": self.liss_kx,
|
||||
"mod_liss_kx": self.mod_liss_kx,
|
||||
"liss_ky": self.liss_ky,
|
||||
"mod_liss_ky": self.mod_liss_ky,
|
||||
"liss_kz": self.liss_kz,
|
||||
"mod_liss_kz": self.mod_liss_kz,
|
||||
"liss_amp": self.liss_amp,
|
||||
"mod_liss_amp": self.mod_liss_amp,
|
||||
"spiral_turns": self.spiral_turns,
|
||||
"mod_spiral_turns": self.mod_spiral_turns,
|
||||
"spiral_R": self.spiral_R,
|
||||
"mod_spiral_R": self.mod_spiral_R,
|
||||
"torus_R": self.torus_R,
|
||||
"mod_torus_R": self.mod_torus_R,
|
||||
"torus_r": self.torus_r,
|
||||
"mod_torus_r": self.mod_torus_r,
|
||||
"multiple_links": self.multiple_links,
|
||||
"use_colors": self.use_colors,
|
||||
"colorSet": self.colorSet,
|
||||
@@ -325,6 +412,7 @@ class KnotGeneratorSettings(bpy.types.PropertyGroup):
|
||||
|
||||
# Standalone booleans without an associated range or prob
|
||||
r_shape_type: bpy.props.BoolProperty(name="Randomize Shape Type", default=True)
|
||||
r_modulations: bpy.props.BoolProperty(name="Randomize Mods", default=True, description="Add random attenuverter modulations to the generated knots")
|
||||
r_transition_easing: bpy.props.BoolProperty(name="Easing", default=False)
|
||||
r_material: bpy.props.BoolProperty(
|
||||
name="Randomize Material", default=True,
|
||||
@@ -337,6 +425,15 @@ class KnotGeneratorSettings(bpy.types.PropertyGroup):
|
||||
allowed_materials: bpy.props.CollectionProperty(type=KnotAllowedMaterial)
|
||||
allowed_materials_index: bpy.props.IntProperty(name="Index", default=0)
|
||||
|
||||
# UI expand state for generator rand sub-boxes
|
||||
ui_show_rand_shape: bpy.props.BoolProperty(name="Shape", default=True)
|
||||
ui_show_rand_geo: bpy.props.BoolProperty(name="Geometry", default=False)
|
||||
ui_show_rand_anim: bpy.props.BoolProperty(name="Animation", default=True)
|
||||
ui_show_rand_mat: bpy.props.BoolProperty(name="Material", default=True)
|
||||
ui_show_base: bpy.props.BoolProperty(name="Base Knot Defaults", default=False)
|
||||
ui_show_generator: bpy.props.BoolProperty(name="Random Generator", default=True)
|
||||
ui_show_rand_toggles: bpy.props.BoolProperty(name="Randomise Toggles", default=True)
|
||||
|
||||
|
||||
# ── Integer range triplets ────────────────────────────────────────────────────
|
||||
_add_rand_int(KnotGeneratorSettings, "torus_p", "Revolutions (p)", 1, 8, rand_default=True, val_min=1)
|
||||
|
||||
Reference in New Issue
Block a user