rename knot_animation folder
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
"""
|
||||
knot_animation/__init__.py
|
||||
--------------------------
|
||||
Blender add-on entry-point for the Pr3tz procedural animation system.
|
||||
|
||||
What this add-on does
|
||||
---------------------
|
||||
1. Registers a VIEW_3D N-panel ("Pr3tz") with:
|
||||
- A per-scene playlist of KnotItem entries, each specifying topology,
|
||||
geometry, animation rates, transition settings, and a material preset.
|
||||
- Operators for adding, removing, reordering, and randomly generating
|
||||
playlist entries.
|
||||
- Global playback controls (speed, phase, reactivity) that can be
|
||||
keyframed or driven for audio-reactive animation.
|
||||
|
||||
2. On every frame change (frame_change_post handler), procedurally rebuilds
|
||||
a single reused NURBS curve object ("AnimKnot") in-place using the
|
||||
parametric torus-knot equations — no bpy.ops, no edit-mode, no depsgraph
|
||||
races.
|
||||
|
||||
3. Interpolates geometry and cross-fades shader materials between adjacent
|
||||
playlist entries during configurable transition windows.
|
||||
|
||||
4. Provides a catalogue of 20 built-in shader presets (GLOSS_BLUE, NEON_GLOW,
|
||||
METALLIC, GLASS, HOLOGRAM, LAVA, IRIDESCENT, …) plus support for arbitrary
|
||||
project materials.
|
||||
|
||||
Module layout
|
||||
-------------
|
||||
types.py — KnotConfig TypedDict (shared data contract)
|
||||
constants.py — pure-data defaults (KNOT_CONFIGS, camera/light positions, …)
|
||||
compat.py — one-shot compatibility patches (headless align_matrix fix)
|
||||
materials.py — 20 shader builders + material cache + blend system
|
||||
geometry.py — _make_torus_knot() (parametric NURBS, no bpy.context reads)
|
||||
handler.py — @persistent frame-change handler + easing + playlist timing
|
||||
properties.py — Blender PropertyGroups (KnotItem, KnotGlobalSettings, …)
|
||||
operators.py — KNOT_OT_* operators
|
||||
ui.py — KNOT_UL_* lists, draw_knot_properties(), KNOT_PT_Panel
|
||||
scene_setup.py — setup_scene() (camera, light, world, render settings)
|
||||
|
||||
How to use
|
||||
----------
|
||||
Requires Blender 5.0 or later.
|
||||
|
||||
Option A – Blender Text Editor:
|
||||
Open knot_animation/__init__.py, click Run Script (Alt+P).
|
||||
|
||||
Option B – Command line:
|
||||
blender.exe --python knot_animation/__init__.py
|
||||
|
||||
Option C – Persistent add-on:
|
||||
Copy the knot_animation/ folder to Blender's addons directory and enable
|
||||
it from Edit → Preferences → Add-ons. The panel appears under the
|
||||
"Pr3tz" tab in the 3-D viewport N-panel.
|
||||
"""
|
||||
|
||||
if "bpy" in locals():
|
||||
import importlib
|
||||
importlib.reload(compat)
|
||||
importlib.reload(constants)
|
||||
importlib.reload(types)
|
||||
importlib.reload(materials)
|
||||
importlib.reload(geometry)
|
||||
importlib.reload(handler)
|
||||
importlib.reload(properties)
|
||||
importlib.reload(operators)
|
||||
importlib.reload(ui)
|
||||
importlib.reload(scene_setup)
|
||||
# bake_export may not exist from a prior session — import if needed
|
||||
if "bake_export" in locals():
|
||||
importlib.reload(bake_export)
|
||||
else:
|
||||
from . import bake_export
|
||||
else:
|
||||
import bpy
|
||||
from . import compat, constants, types, materials, geometry, handler, properties, operators, ui, scene_setup, bake_export
|
||||
|
||||
from .compat import apply_compat_patches
|
||||
from .properties import (
|
||||
KnotAllowedMaterial,
|
||||
KnotGlobalSettings,
|
||||
KnotItem,
|
||||
KnotGeneratorSettings,
|
||||
)
|
||||
from .operators import (
|
||||
KNOT_OT_Add,
|
||||
KNOT_OT_Remove,
|
||||
KNOT_OT_Move,
|
||||
KNOT_OT_Populate,
|
||||
KNOT_OT_BakePreview,
|
||||
KNOT_OT_SyncGeneratorMaterials,
|
||||
KNOT_OT_FitTimeline,
|
||||
KNOT_OT_FitPlaylist,
|
||||
KNOT_OT_GenerateRandom,
|
||||
)
|
||||
from .bake_export import KNOT_OT_BakeExport
|
||||
from .ui import (
|
||||
KNOT_UL_List,
|
||||
KNOT_UL_AllowedMaterialsList,
|
||||
KNOT_PT_Panel,
|
||||
)
|
||||
from .geometry import _remove_existing_knot
|
||||
from .handler import knot_frame_handler
|
||||
from .scene_setup import setup_scene
|
||||
from .constants import KNOT_MAT_NAME, SHADER_BLEND_MAT_NAME
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Add-on metadata
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
bl_info = {
|
||||
"name": "Pr3tz",
|
||||
"author": "knot_animation project",
|
||||
"version": (2, 0, 0),
|
||||
"blender": (5, 0, 0),
|
||||
"location": "View3D > Sidebar > Pr3tz",
|
||||
"description": "Procedural torus-knot animation with playlist, transitions, and 20 shader presets",
|
||||
"category": "Animation",
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Registered Blender classes (order matters for PropertyGroup dependencies)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
classes = (
|
||||
KnotAllowedMaterial,
|
||||
KnotGlobalSettings,
|
||||
KnotItem,
|
||||
KnotGeneratorSettings,
|
||||
KNOT_UL_List,
|
||||
KNOT_UL_AllowedMaterialsList,
|
||||
KNOT_OT_SyncGeneratorMaterials,
|
||||
KNOT_OT_Add,
|
||||
KNOT_OT_Remove,
|
||||
KNOT_OT_Move,
|
||||
KNOT_OT_Populate,
|
||||
KNOT_OT_BakePreview,
|
||||
KNOT_OT_FitTimeline,
|
||||
KNOT_OT_FitPlaylist,
|
||||
KNOT_OT_GenerateRandom,
|
||||
KNOT_OT_BakeExport,
|
||||
KNOT_PT_Panel,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Lifecycle
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def register() -> None:
|
||||
apply_compat_patches()
|
||||
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
bpy.types.Scene.knot_list = bpy.props.CollectionProperty(type=KnotItem)
|
||||
bpy.types.Scene.knot_list_index = bpy.props.IntProperty(name="Index", default=0)
|
||||
bpy.types.Scene.knot_generator = bpy.props.PointerProperty(type=KnotGeneratorSettings)
|
||||
bpy.types.Scene.knot_globals = bpy.props.PointerProperty(type=KnotGlobalSettings)
|
||||
|
||||
# Register to frame_change_post so the handler fires *after* Blender has
|
||||
# evaluated the new frame, preventing the freshly-built mesh from being
|
||||
# overwritten by the depsgraph update.
|
||||
handlers = bpy.app.handlers.frame_change_post
|
||||
for h in list(handlers):
|
||||
if getattr(h, "__name__", "") == knot_frame_handler.__name__:
|
||||
handlers.remove(h)
|
||||
handlers.append(knot_frame_handler)
|
||||
|
||||
print("[KnotScript] Handler and UI registered.")
|
||||
|
||||
|
||||
def unregister() -> None:
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
del bpy.types.Scene.knot_list
|
||||
del bpy.types.Scene.knot_list_index
|
||||
del bpy.types.Scene.knot_generator
|
||||
del bpy.types.Scene.knot_globals
|
||||
|
||||
handlers = bpy.app.handlers.frame_change_post
|
||||
for h in list(handlers):
|
||||
if getattr(h, "__name__", "") == knot_frame_handler.__name__:
|
||||
handlers.remove(h)
|
||||
|
||||
_remove_existing_knot()
|
||||
|
||||
# Purge all cached shader and blend materials on unregister to avoid
|
||||
# data-block buildup on script reload. Only remove zero-user materials.
|
||||
for mat in list(bpy.data.materials):
|
||||
if (mat.name.startswith("KnotShader_")
|
||||
or mat.name.startswith("KnotBlend_")
|
||||
or mat.name.startswith("KnotItem_Preset_")
|
||||
or mat.name in (KNOT_MAT_NAME, SHADER_BLEND_MAT_NAME)):
|
||||
if mat.users == 0:
|
||||
bpy.data.materials.remove(mat)
|
||||
|
||||
print("[KnotScript] Handler and UI unregistered.")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Entry point (run as script or via --python flag)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
setup_scene()
|
||||
|
||||
# Generate the knot for the current frame immediately so the viewport is
|
||||
# not empty when the script first runs.
|
||||
knot_frame_handler(bpy.context.scene)
|
||||
print("[KnotScript] Ready. Start scrubbing the timeline!")
|
||||
print(" Press Space to play, or render with Ctrl+F12.")
|
||||
Reference in New Issue
Block a user