yum/3ner

A toon shader for Unity's BIRP.

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

yumFold: move operations into separate filec09509e

master
6.1 KiB137 linesraw
1using System;
2using System.Collections.Generic;
3using UnityEditor;
4using UnityEngine;
5
6public class FoldSlot
7{
8    public int opcode;
9    public float float0, float1, float2, float3;
10    public Vector4 vec0, vec1, vec2, vec3;
11
12    static string Prefix(int i) => $"_Vertex_Deformation_Slot_{i}_";
13
14    void ApplyToTarget(string pfx, Action<string, float> sf, Action<string, int> si, Action<string, Vector4> sv)
15    {
16        sf(pfx + "Enabled", 1f);
17        si(pfx + "Opcode",   opcode);
18        sf(pfx + "Float_0",  float0);
19        sf(pfx + "Float_1",  float1);
20        sf(pfx + "Float_2",  float2);
21        sf(pfx + "Float_3",  float3);
22        sv(pfx + "Vector_0", vec0);
23        sv(pfx + "Vector_1", vec1);
24        sv(pfx + "Vector_2", vec2);
25        sv(pfx + "Vector_3", vec3);
26    }
27
28    static void ClearTarget(string pfx, Action<string, float> sf, Action<string, int> si, Action<string, Vector4> sv)
29    {
30        sf(pfx + "Enabled", 0f);
31        si(pfx + "Opcode",   0);
32        sf(pfx + "Float_0",  0f);
33        sf(pfx + "Float_1",  0f);
34        sf(pfx + "Float_2",  0f);
35        sf(pfx + "Float_3",  0f);
36        sv(pfx + "Vector_0", Vector4.zero);
37        sv(pfx + "Vector_1", Vector4.zero);
38        sv(pfx + "Vector_2", Vector4.zero);
39        sv(pfx + "Vector_3", Vector4.zero);
40    }
41
42    public void ApplyToMaterial(Material mat, int i) =>
43        ApplyToTarget(Prefix(i), mat.SetFloat, mat.SetInteger, (k, v) => mat.SetVector(k, v));
44
45    public void ApplyToPropertyBlock(MaterialPropertyBlock mpb, int i) =>
46        ApplyToTarget(Prefix(i), mpb.SetFloat, mpb.SetInteger, (k, v) => mpb.SetVector(k, v));
47
48    public static void ClearSlot(Material mat, int i) =>
49        ClearTarget(Prefix(i), mat.SetFloat, mat.SetInteger, (k, v) => mat.SetVector(k, v));
50
51    public static void ClearInPropertyBlock(MaterialPropertyBlock mpb, int i) =>
52        ClearTarget(Prefix(i), mpb.SetFloat, mpb.SetInteger, (k, v) => mpb.SetVector(k, v));
53}
54
55public class FoldPipelineBuilder
56{
57    readonly List<FoldSlot> slots = new();
58    Material targetMaterial;
59
60    FoldPipelineBuilder() { }
61
62    public static FoldPipelineBuilder Create() => new();
63
64    public FoldPipelineBuilder For(Material material) { targetMaterial = material; return this; }
65
66    FoldPipelineBuilder AddSlot(FoldSlot slot) { slots.Add(slot); return this; }
67
68    FoldPipelineBuilder Prs(int opcode, Vector3 p, Vector3 r, Vector3 s, float t) =>
69        AddSlot(new FoldSlot { opcode = opcode, vec0 = p, vec1 = r, vec2 = s, float0 = t });
70
71    FoldPipelineBuilder Vec1t(int opcode, Vector3 v, float t) =>
72        AddSlot(new FoldSlot { opcode = opcode, vec0 = v, float0 = t });
73
74    public FoldPipelineBuilder TubeToPlane(Vector3 p, Vector3 r, Vector3 s, float t)           => Prs(TubeToPlaneOp.Opcode, p, r, s, t);
75    public FoldPipelineBuilder PlaneToTube(Vector3 p, Vector3 r, Vector3 s, float t)           => Prs(PlaneToTubeOp.Opcode, p, r, s, t);
76    public FoldPipelineBuilder PlaneToHemiOctahedron(Vector3 p, Vector3 r, Vector3 s, float t) => Prs(PlaneToHemiOctahedronOp.Opcode, p, r, s, t);
77    public FoldPipelineBuilder HemiOctahedronToPlane(Vector3 p, Vector3 r, Vector3 s, float t) => Prs(HemiOctahedronToPlaneOp.Opcode, p, r, s, t);
78    public FoldPipelineBuilder PlaneToOctahedron(Vector3 p, Vector3 r, Vector3 s, float t)     => Prs(PlaneToOctahedronOp.Opcode, p, r, s, t);
79    public FoldPipelineBuilder OctahedronToPlane(Vector3 p, Vector3 r, Vector3 s, float t)     => Prs(OctahedronToPlaneOp.Opcode, p, r, s, t);
80    public FoldPipelineBuilder PointAlign(Vector3 po, Vector3 pp, Vector3 r, float t)          => Prs(PointAlignOp.Opcode, po, pp, r, t);
81    public FoldPipelineBuilder AxisAlign(Vector3 po, Vector3 pp, Vector3 r, float t)           => Prs(AxisAlignOp.Opcode, po, pp, r, t);
82    public FoldPipelineBuilder Scale(Vector3 k, float t)                                       => Vec1t(ScaleOp.Opcode, k, t);
83    public FoldPipelineBuilder Translate(Vector3 offset, float t)                              => Vec1t(TranslateOp.Opcode, offset, t);
84
85    public FoldPipelineBuilder Rotate(Vector3 center, Vector3 axis, float angle, float t) =>
86        AddSlot(new FoldSlot { opcode = RotateOp.Opcode, vec0 = center, vec1 = axis, float0 = angle, float1 = t });
87
88    public FoldPipelineBuilder NormConversion(float inputK, float outputK, float t) =>
89        AddSlot(new FoldSlot { opcode = NormConversionOp.Opcode, float0 = inputK, float1 = outputK, float2 = t });
90
91    public FoldPipelineBuilder Seal(float A, float k, float st, float t) =>
92        AddSlot(new FoldSlot { opcode = SealOp.Opcode, float0 = A, float1 = k, float2 = st, float3 = t });
93
94    public FoldPipelineBuilder SineWaves() => AddSlot(new FoldSlot { opcode = SineWavesOp.Opcode });
95    public FoldPipelineBuilder FBM()       => AddSlot(new FoldSlot { opcode = FBMOp.Opcode });
96
97    public FoldPipelineBuilder Custom(int opcode,
98        float f0 = 0, float f1 = 0, float f2 = 0, float f3 = 0,
99        Vector4? v0 = null, Vector4? v1 = null, Vector4? v2 = null, Vector4? v3 = null) =>
100        AddSlot(new FoldSlot
101        {
102            opcode = opcode,
103            float0 = f0, float1 = f1, float2 = f2, float3 = f3,
104            vec0 = v0 ?? Vector4.zero,
105            vec1 = v1 ?? Vector4.zero,
106            vec2 = v2 ?? Vector4.zero,
107            vec3 = v3 ?? Vector4.zero
108        });
109
110    public void Apply()
111    {
112        if (targetMaterial == null)
113        {
114            Debug.LogError("No target material set. Use .For(material) before .Apply()");
115            return;
116        }
117
118        if (slots.Count > 16)
119            Debug.LogWarning($"Too many operations ({slots.Count}). Only the first 16 will be applied.");
120
121        Undo.RecordObject(targetMaterial, "Apply Vertex Deformation");
122
123        targetMaterial.SetFloat("_Vertex_Deformation_Enabled", 1f);
124
125        for (int i = 0; i < 16; i++)
126            FoldSlot.ClearSlot(targetMaterial, i);
127
128        for (int i = 0; i < slots.Count && i < 16; i++)
129            slots[i].ApplyToMaterial(targetMaterial, i);
130
131        EditorUtility.SetDirty(targetMaterial);
132    }
133
134    public void Clear() => slots.Clear();
135    public int Count => slots.Count;
136    public FoldSlot GetSlot(int index) => index < slots.Count ? slots[index] : null;
137}