yum/3ner

A toon shader for Unity's BIRP.

git clone https://git.yummers.dev/yum/3ner

yumRemove locking thingy from fourier water compute shader3c03db9

master
1 folder4 files

files

Editor/
FoldMaterialAnimator.cs27.0 KiB
FoldOperators.cs8.6 KiB
FoldStack.cs4.6 KiB
README.md12.8 KiB

FoldEditor

Open Tools → yum_food → FoldEditor in Unity 2022.3.22f1.

  1. Drag a scene mesh object, model/prefab, or renderer into Mesh / Object. A model/prefab can be instantiated from the window. A bare Mesh asset is resolved to an existing scene renderer because materials belong to renderers, not meshes.
  2. Select a renderer and material slot. The editor checks for the unlocked yum_food/3ner shader, the complete 16-slot layout, and both the deformation toggle and keyword. Enable deformation if prompted. Stacks initialize automatically.
  3. Add operators, choose opcodes, adjust parameters and 0–1 interpolators. Use arrows to reorder and × to remove. Disabled slots are skipped, matching the shader; later slots remain active. Changes support Undo.
  4. Choose the Animator/Animation root and click Create animation at the bottom of the Animation section (switching from an existing clip requires confirmation), or open an existing writable clip in Unity's Animation window. New clips and controllers go under Assets/yum_food/FoldEditor/Generated/Animations/.
  5. Keyframe at the starting frame. Advance moves the Animation playhead after every keyframe-button click (default: 60 frames; negative values move backward, stopping at frame 0; 0 keeps the current frame). Advance cursor moves by that amount; Retreat cursor moves by its negative. Neither creates or deletes keys, and both stop at frame 0. Adjust the stack and keyframe again, or move the playhead manually. All fields of each changed operator are keyed together. The initial pose also keys unused slots so adding/removing operators later plays back correctly. The button covers all compatible material stacks on the selected renderer.

Each operator header has a ⋮ menu with Copy Settings and Paste Settings. Copy includes the operator type, enabled state, and all numeric parameters; paste replaces those settings in the destination slot and supports Undo. Paste is disabled unless the clipboard contains copied Fold operator settings. Per-window Advanced options stay with the destination slot.

Clear keyframe deletes all keys at the current cursor frame across every track of the active clip, including object-reference tracks. It supports Undo and does not advance the cursor.

Ease linear spans converts existing linear Fold parameter spans across the active clip to ease in/out (zero endpoint slopes). Key times and values stay fixed. Stepped reorder handoffs, constant holds, opcode/enabled tracks, custom curves, and non-Fold tracks are preserved. Each side of a handoff key is handled independently, so a stepped arrival can still ease into the next pose. The conversion supports one-step Undo and does not advance the cursor. Newly recorded spans still default to linear; run the conversion again after further authoring if needed.

When an existing operator changes, its last known state is also keyed at the preceding Fold appearance keyframe, before writing the new pose. Missing prior fields use zero. For example, adding a change for operator 1 at t2 holds its previous state through t1, instead of starting its interpolation at t0. Existing keys at t1 are preserved, and both edits share one Undo step.

When a new operator is first keyed with inputs different from its jumpback pose, FoldEditor inserts the pose defined by the named-field attributes on each operator definition in FoldOperators.cs ([Zero], [One], [Copy]) at current frame - Advance, then keys the user's settings at the current frame. Each operator has its own typed definition with defaults and [Zero], [One], or [Copy] on each field. [Slot] maps that field to shader storage. Copy preserves the authored value; opcode, enabled state, and unused fields are also preserved. Interpolation parameters start at zero, Scale starts at one, Translate and Sine Waves/FBM amplitudes start at zero, and shape controls such as axes and periods are copied. Vector policies affect xyz and preserve w. Seal copies its amplitude, frequency and time multiplier, and starts its interpolation at zero. Numeric fields interpolate between the two poses. A new operator already matching its jumpback pose gets only the current key, with no earlier key or empty-slot history changes. The check is independent of the previous slot inputs and ignores the opcode and enabled flag. Identity Scale (1,1,1) and Translate (0,0,0) are neutral regardless of t; Scale (0,0,0) is not neutral and does trigger an earlier key. Reorder handoffs still apply where an existing operator must move out of the slot. Only that operator's slot changes. Empty-slot keys inside the new span are removed so they cannot interrupt the interpolation. Negative Advance places the default key later in time; the position is clamped at frame 0, and Advance 0 creates only the current key. If the slot was previously occupied, its existing history is protected: insertion during a reorder starts at the handoff, and reuse starts no earlier than the preceding empty pose. Both keys and any removed empty-slot keys share one Undo step.

Re-keying an existing endpoint reuses its earlier jumpback key instead of treating that generated key as a new authored pose. The jumpback values are overwritten according to the edited operator's field policies, including copied shape controls. Existing stepped handoffs retain their original time; repeated edits do not advance them one frame at a time. Detection uses the saved curve values and tangents, so it survives reopening the editor and Undo/Redo.

The keyframe comparison uses keys at or before the playhead, not interpolated values or an in-memory snapshot. This works after reopening the window, switching clips, and undoing edits. Partial keys made with Animation's Record mode are completed by the button. Opcode and enabled keys are stepped; scalar/vector keys default to linear interpolation. Reordering first preserves the longest unchanged operator sequence within each material, then matches remaining unchanged states, including repeated opcodes such as two Plane to Tube folds. This prevents a newly inserted operator with identical settings from taking the history of an existing operator farther down the stack; the inserted operator gets the neutral jumpback while the existing sequence keeps its pose. Each previous state can be used only once. Remaining edited operators are matched by their original slot or an unambiguous opcode. Only the source and destination slots of a moved operator get a stepped transition: their old layout is held up to the intermediate key, where their previous parameter values are placed in the new order, followed by normal interpolation to the current pose. Unchanged slots and other materials receive no reorder keys or tangent changes. With Advance 60, the intermediate key is 59 frames before the cursor. The key is clamped between the preceding pose and the current pose; adjacent poses use a direct step. Negative Advance uses its magnitude, and Advance 0 places the transition one frame after the preceding pose. Existing stepped tangents are preserved by subsequent keyframes, and the entire edit shares one Undo step. Identical duplicate states are interchangeable. Distinct duplicates retain their matching values when shifted by an insertion; ambiguous edited duplicates are not guessed between.

Replacing an occupied slot with a different opcode uses the same stepped handoff as reordering, even when no old operators survive. At current frame - abs(Advance) + 1 (clamped after the preceding pose and at or before the cursor), replacements start at their attribute-defined jumpback pose, and removed operators become empty. The old pose holds until that boundary; numeric fields then interpolate from the new defaults to the current pose. Earlier animation into rest is preserved. Operator identity is still inferred from opcode IDs, so edits retaining the same opcode are treated as parameter changes.

Under each operator's A (Advanced) toggle button, Disable jump-back keyframing records that operator only at the cursor. It skips automatic default, previous-state hold, and handoff keys, leaving earlier key values and tangent modes intact. Other operators retain their normal behavior, and the cursor still advances after keyframing. This option defaults off, belongs only to the current editor window, and follows operators when reordered; it is not stored in materials or animation tracks.

Each renderer receives a FoldStack component and one Fold Material N child with a FoldMaterialAnimator per supported material. These children provide stable native animation bindings: Unity 2022.3 does not expose the nested custom classes/arrays used by the editing model as animation properties. Integer opcode keys use Unity's discrete bit encoding. Keep the components and child names for playback. No runtime reflection or editor APIs are used by the animation drivers.

Outside Animation preview, editing updates the selected shared material's slots as well as this renderer's overrides. Other renderers sharing that material therefore see the material changes. During Animation preview, only the renderer overrides change. Closing FoldEditor leaves the saved stack active; disabling FoldStack restores the original indexed property blocks. Material slots are independently driven even when they share a material asset. Keep shader features enabled on materials before playback; keywords cannot be animated through a property block.

Seal, Sine Waves and FBM use getTime() in vertex.cginc; Sine Waves and FBM have no local interpolation parameter. Seal uses Float 3 for interpolation (default 1): zero preserves the input mesh and one applies the full deformation. Existing Seal slots with Float 3 saved as zero need it set to 1 to retain the full deformation. Their controls expose amplitude, frequency, velocity, period, gain, lacunarity and octave parameters as applicable. FBM exposes a scalar Scale (default 1) in Float 3 that multiplies noise frequency and is copied into jumpback poses. Existing FBM slots with Float 3 set to zero need Scale set to 1 to retain their previous frequency. Keyframing these parameters does not freeze shader time. Rotate displays degrees and stores radians. Norm exponents must be positive and finite, FBM periods nonzero, and fold bases nonzero and orthogonal. Deformation does not expand renderer bounds; configure bounds separately for large displacements.

Tools → yum_food → FoldEditor Validation runs temporary-object integration checks for grouped keys, actual AnimationClip sampling, independent material slots, discrete opcodes, and property-block restoration. Stop Animation preview first. It cleans up its temporary objects and Undo group. The same checks were run in an isolated Unity 2022.3.22f1 batch project. They validate the editor/animation bridge, not rendered output or the numerical behavior of the shader's deformation functions.

Bake for VRChat

Bake sits beside Create animation. Choose the source clip and its Animation root, set Bake speed (0–10; 1 is original speed, 2 is twice as fast, 0 holds the starting pose), then click Bake. The clip is saved beside the source as <source>_Baked.anim without a dialog. Baking again updates that asset while keeping its GUID, so existing Animator references remain valid. The original clip and scene are unchanged.

Assign the baked clip to the Animator state's Motion slot and disable FoldStack on the affected renderers. Keep the Animator on the same root. To edit again, restore the source clip and re-enable FoldStack. Animator state speed still multiplies the baked playback speed.

The export translates existing Fold keys directly into renderer material-property curves. It preserves curve/key counts, values, tangents and interpolation; there is no sampling, no per-frame key generation and no material snapshots. Bake speed retimes keys and tangents (0 holds the initial pose). Opcode keys are decoded from Unity's integer bit representation into stepped numeric curves targeting the shader's float-backed AnimatedOpcode override. A default of -1 retains the original integer opcode on existing materials. Other animation tracks, clip settings and events are retained and retimed (events are omitted at speed 0). Shader-driven time effects keep running at speed 0.

Native material-property curves apply to the renderer, not an individual material slot. Baking therefore requires one material per renderer; split multi-material meshes into separate renderers first. Existing conflicting material-property or material-swap tracks are rejected. A failed conversion leaves the previous baked asset intact. Rebaking a former snapshot export removes its material subassets.

Tools → yum_food → Fold Bake Validation checks exact key counts/tangents, script-free float/vector/opcode playback, absence of material snapshots, loop settings, preserved source/non-Fold tracks, speed 0/2, rebake GUID preservation, and multi-material rejection.