yum/3ner
A toon shader for Unity's BIRP.
git clone https://git.yummers.dev/yum/3ner
b3a533b
master
1using System ; 2using System . Collections . Generic ; 3using System . Reflection ; 4using UnityEngine ; 5 6namespace Yum . Fold 7{ 8[ AttributeUsage ( AttributeTargets . Field )] 9public abstract class JumpbackAttribute : Attribute 10{ 11public abstract object Apply ( object authored ); 12} 13public sealed class CopyAttribute : JumpbackAttribute 14{ 15public override object Apply ( object authored ) => authored ; 16} 17public sealed class ZeroAttribute : JumpbackAttribute 18{ 19public override object Apply ( object authored ) => authored is Vector4 v 20? ( object ) new Vector4 ( 0 , 0 , 0 , v . w ) : 0f ; 21} 22public sealed class OneAttribute : JumpbackAttribute 23{ 24public override object Apply ( object authored ) => authored is Vector4 v 25? ( object ) new Vector4 ( 1 , 1 , 1 , v . w ) : 1f ; 26} 27 28// Slot maps a named field to its scalar or vector slot in the shader ABI. 29[ AttributeUsage ( AttributeTargets . Field )] 30sealed class SlotAttribute : Attribute 31{ 32public readonly int index ; 33public SlotAttribute ( int index ) { this . index = index ; } 34} 35[ AttributeUsage ( AttributeTargets . Class )] 36sealed class OpcodeAttribute : Attribute 37{ 38public readonly int value ; 39public OpcodeAttribute ( int value ) { this . value = value ; } 40} 41 42public static class FoldOperators 43{ 44[ Opcode ( 0 )] public sealed class None { } 45 46[ Opcode ( 1 )] public sealed class TubeToPlane 47{ 48[ Copy , Slot ( 0 )] public Vector3 Origin = Vector3 . zero ; 49[ Copy , Slot ( 1 )] public Vector3 RAxis = Vector3 . right ; 50[ Copy , Slot ( 2 )] public Vector3 SAxis = Vector3 . forward ; 51[ Zero , Slot ( 0 )] public float T = 1 ; 52} 53 54[ Opcode ( 2 )] public sealed class PlaneToTube 55{ 56[ Copy , Slot ( 0 )] public Vector3 Origin = Vector3 . zero ; 57[ Copy , Slot ( 1 )] public Vector3 RAxis = Vector3 . right ; 58[ Copy , Slot ( 2 )] public Vector3 SAxis = Vector3 . forward ; 59[ Zero , Slot ( 0 )] public float T = 1 ; 60} 61 62[ Opcode ( 3 )] public sealed class PointAlign 63{ 64[ Copy , Slot ( 0 )] public Vector3 Origin = Vector3 . zero ; 65[ Copy , Slot ( 1 )] public Vector3 Target = Vector3 . up ; 66[ Copy , Slot ( 2 )] public Vector3 RAxis = Vector3 . right ; 67[ Zero , Slot ( 0 )] public float T = 1 ; 68} 69 70[ Opcode ( 4 )] public sealed class AxisAlign 71{ 72[ Copy , Slot ( 0 )] public Vector3 Origin = Vector3 . zero ; 73[ Copy , Slot ( 1 )] public Vector3 Target = Vector3 . up ; 74[ Copy , Slot ( 2 )] public Vector3 RAxis = Vector3 . right ; 75[ Zero , Slot ( 0 )] public float T = 1 ; 76} 77 78[ Opcode ( 5 )] public sealed class NormConversion 79{ 80[ Copy , Slot ( 0 )] public float InputNorm = 2 ; 81[ Copy , Slot ( 1 )] public float OutputNorm = 1 ; 82[ Zero , Slot ( 2 )] public float T = 1 ; 83} 84 85[ Opcode ( 6 )] public sealed class Seal 86{ 87[ Copy , Slot ( 0 )] public float Amplitude = .1f ; 88[ Copy , Slot ( 1 )] public float Frequency = 2 ; 89[ Copy , Slot ( 2 )] public float TimeMultiplier = .8f ; 90[ Zero , Slot ( 3 )] public float T = 1 ; 91} 92 93[ Opcode ( 7 )] public sealed class SineWaves 94{ 95[ Zero , Slot ( 0 )] public Vector3 Amplitude = new Vector3 ( 0 , .1f , 0 ); 96[ Copy , Slot ( 1 )] public Vector3 Direction = Vector3 . right ; 97[ Copy , Slot ( 2 )] public Vector3 WaveNumber = Vector3 . one ; 98[ Copy , Slot ( 3 )] public Vector3 AngularVelocity = Vector3 . one ; 99} 100 101[ Opcode ( 8 )] public sealed class FBM 102{ 103[ Zero , Slot ( 0 )] public Vector3 Amplitude = Vector3 . one * .1f ; 104[ Copy , Slot ( 1 )] public Vector3 Velocity = Vector3 . zero ; 105[ Copy , Slot ( 2 )] public Vector3 Period = Vector3 . one ; 106[ Copy , Slot ( 0 )] public float Gain = .5f ; 107[ Copy , Slot ( 1 )] public float Lacunarity = 2 ; 108[ Copy , Slot ( 2 )] public float Octaves = 4 ; 109[ Copy , Slot ( 3 )] public float Scale = 1 ; 110} 111 112[ Opcode ( 9 )] public sealed class PlaneToHemiOctahedron 113{ 114[ Copy , Slot ( 0 )] public Vector3 Origin = Vector3 . zero ; 115[ Copy , Slot ( 1 )] public Vector3 RAxis = Vector3 . right ; 116[ Copy , Slot ( 2 )] public Vector3 SAxis = Vector3 . forward ; 117[ Zero , Slot ( 0 )] public float T = 1 ; 118} 119 120[ Opcode ( 10 )] public sealed class HemiOctahedronToPlane 121{ 122[ Copy , Slot ( 0 )] public Vector3 Origin = Vector3 . zero ; 123[ Copy , Slot ( 1 )] public Vector3 RAxis = Vector3 . right ; 124[ Copy , Slot ( 2 )] public Vector3 SAxis = Vector3 . forward ; 125[ Zero , Slot ( 0 )] public float T = 1 ; 126} 127 128[ Opcode ( 11 )] public sealed class Scale 129{ 130[ One , Slot ( 0 )] public Vector3 Factors = Vector3 . one ; 131[ Zero , Slot ( 0 )] public float T = 1 ; 132} 133 134[ Opcode ( 12 )] public sealed class Translate 135{ 136[ Zero , Slot ( 0 )] public Vector3 Offset = Vector3 . zero ; 137[ Zero , Slot ( 0 )] public float T = 1 ; 138} 139 140[ Opcode ( 13 )] public sealed class PlaneToOctahedron 141{ 142[ Copy , Slot ( 0 )] public Vector3 Origin = Vector3 . zero ; 143[ Copy , Slot ( 1 )] public Vector3 RAxis = Vector3 . right ; 144[ Copy , Slot ( 2 )] public Vector3 SAxis = Vector3 . forward ; 145[ Zero , Slot ( 0 )] public float T = 1 ; 146} 147 148[ Opcode ( 14 )] public sealed class OctahedronToPlane 149{ 150[ Copy , Slot ( 0 )] public Vector3 Origin = Vector3 . zero ; 151[ Copy , Slot ( 1 )] public Vector3 RAxis = Vector3 . right ; 152[ Copy , Slot ( 2 )] public Vector3 SAxis = Vector3 . forward ; 153[ Zero , Slot ( 0 )] public float T = 1 ; 154} 155 156[ Opcode ( 15 )] public sealed class Rotate 157{ 158[ Copy , Slot ( 0 )] public Vector3 Center = Vector3 . zero ; 159[ Copy , Slot ( 1 )] public Vector3 Axis = Vector3 . up ; 160[ Copy , Slot ( 0 )] public float Angle = Mathf . PI / 2 ; // Radians. 161[ Zero , Slot ( 1 )] public float T = 1 ; 162} 163 164sealed class Definition 165{ 166public FoldOperator defaults ; 167public readonly Dictionary < FieldInfo , JumpbackAttribute > policies = new Dictionary < FieldInfo , JumpbackAttribute > (); 168} 169 170// Cache mappings once. Serialized slots and animation property names stay stable. 171static readonly Dictionary < int , Definition > Definitions = BuildDefinitions (); 172static Dictionary < int , Definition > BuildDefinitions () 173{ 174var definitions = new Dictionary < int , Definition > (); 175foreach ( var type in typeof ( FoldOperators ). GetNestedTypes ( BindingFlags . Public )) 176{ 177var opcode = type . GetCustomAttribute < OpcodeAttribute > (); 178if ( opcode == null ) continue ; 179var source = Activator . CreateInstance ( type ); 180var definition = new Definition { defaults = new FoldOperator { enabled = true , opcode = opcode . value } }; 181foreach ( var field in type . GetFields ( BindingFlags . Public | BindingFlags . Instance )) 182{ 183var slot = field . GetCustomAttribute < SlotAttribute > (); 184var policy = field . GetCustomAttribute < JumpbackAttribute > (); 185bool vector = field . FieldType == typeof ( Vector3 ); 186if ( slot == null || policy == null || slot . index < 0 || slot . index > 3 || 187( ! vector && field . FieldType != typeof ( float ))) 188throw new InvalidOperationException ( $"Invalid Fold field definition: { type . Name } . { field . Name } " ); 189var packed = typeof ( FoldOperator ). GetField (( vector ? "vector" : "float" ) + slot . index ); 190object value = field . GetValue ( source ); 191packed . SetValue ( definition . defaults , vector ? ( object )( Vector4 )( Vector3 ) value : value ); 192definition . policies . Add ( packed , policy ); 193} 194definitions . Add ( opcode . value , definition ); 195} 196return definitions ; 197} 198 199public static FoldOperator Defaults ( int opcode ) => Definitions . TryGetValue ( opcode , out var definition ) 200? definition . defaults . Copy () : new FoldOperator { enabled = true , opcode = opcode }; 201 202public static FoldOperator Jumpback ( FoldOperator authored ) 203{ 204// Opcode, enabled, unused fields and vector w components retain their authored values. 205var result = authored . Copy (); 206if ( Definitions . TryGetValue ( authored . opcode , out var definition )) 207foreach ( var entry in definition . policies ) 208entry . Key . SetValue ( result , entry . Value . Apply ( entry . Key . GetValue ( authored ))); 209return result ; 210} 211} 212}