├── .gitignore ├── Editor.meta ├── Editor ├── Data.meta ├── Data │ ├── Nodes.meta │ └── Nodes │ │ ├── Input.meta │ │ ├── Input │ │ ├── Scene.meta │ │ └── Scene │ │ │ ├── MainLight.cs │ │ │ ├── MainLight.cs.meta │ │ │ ├── RealtimeShadow.cs │ │ │ └── RealtimeShadow.cs.meta │ │ ├── Procedural.meta │ │ └── Procedural │ │ ├── Noise.meta │ │ └── Noise │ │ ├── SimplexNoise3DNode.cs │ │ └── SimplexNoise3DNode.cs.meta ├── ShaderGraphExtensions.Editor.asmdef └── ShaderGraphExtensions.Editor.asmdef.meta ├── README.md └── README.md.meta /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9c648d800692f40eaaae13765527ada5 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Data.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 755579c7f8199442698616bdfc16e9a4 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Data/Nodes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a101c8b4e00de4befa774edda67639fe 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Data/Nodes/Input.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4aa78313861b46af905d4bf2eeaa3671 3 | timeCreated: 1521534766 -------------------------------------------------------------------------------- /Editor/Data/Nodes/Input/Scene.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 93f2442287df45ff9a582924d447994f 3 | timeCreated: 1521534766 -------------------------------------------------------------------------------- /Editor/Data/Nodes/Input/Scene/MainLight.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor.Graphing; 2 | using UnityEditor.ShaderGraph; 3 | using UnityEngine; 4 | 5 | namespace ShaderGraphExtensions 6 | { 7 | [Title("Input", "Scene", "Main Light")] 8 | public class MainLight : AbstractMaterialNode, IGeneratesBodyCode, IGeneratesFunction, IMayRequirePosition 9 | { 10 | public MainLight() 11 | { 12 | name = "Main Light"; 13 | UpdateNodeAfterDeserialization(); 14 | } 15 | 16 | public override string documentationURL 17 | { 18 | get { return "https://github.com/beinteractive/ShaderGraphExtensions"; } 19 | } 20 | 21 | const int OutputSlotId = 0; 22 | const int OutputSlot1Id = 1; 23 | const int OutputSlot2Id = 2; 24 | const string k_OutputSlotName = "Attenuation"; 25 | const string k_OutputSlot1Name = "Color"; 26 | const string k_OutputSlot2Name = "Direction"; 27 | 28 | public override bool hasPreview 29 | { 30 | get { return false; } 31 | } 32 | 33 | string GetFunctionName() 34 | { 35 | return string.Format("sge_MainLight{0}", precision); 36 | } 37 | 38 | public sealed override void UpdateNodeAfterDeserialization() 39 | { 40 | AddSlot(new Vector1MaterialSlot(OutputSlotId, k_OutputSlotName, k_OutputSlotName, SlotType.Output, 0)); 41 | AddSlot(new Vector3MaterialSlot(OutputSlot1Id, k_OutputSlot1Name, k_OutputSlot1Name, SlotType.Output, Vector3.zero)); 42 | AddSlot(new Vector3MaterialSlot(OutputSlot2Id, k_OutputSlot2Name, k_OutputSlot2Name, SlotType.Output, Vector3.zero)); 43 | RemoveSlotsNameNotMatching(new[] {OutputSlotId, OutputSlot1Id, OutputSlot2Id}); 44 | } 45 | 46 | public void GenerateNodeCode(ShaderGenerator visitor, GenerationMode generationMode) 47 | { 48 | visitor.AddShaderChunk(string.Format("{0} {1};", FindOutputSlot(OutputSlotId).concreteValueType.ToString(precision), GetVariableNameForSlot(OutputSlotId)), false); 49 | visitor.AddShaderChunk(string.Format("{0} {1};", FindOutputSlot(OutputSlot1Id).concreteValueType.ToString(precision), GetVariableNameForSlot(OutputSlot1Id)), false); 50 | visitor.AddShaderChunk(string.Format("{0} {1};", FindOutputSlot(OutputSlot2Id).concreteValueType.ToString(precision), GetVariableNameForSlot(OutputSlot2Id)), false); 51 | visitor.AddShaderChunk(string.Format("{0}(IN.{1}, {2}, {3}, {4});", GetFunctionName(), 52 | CoordinateSpace.World.ToVariableName(InterpolatorType.Position), 53 | GetVariableNameForSlot(OutputSlotId), GetVariableNameForSlot(OutputSlot1Id), GetVariableNameForSlot(OutputSlot2Id)), false); 54 | } 55 | 56 | public void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode) 57 | { 58 | registry.ProvideFunction(GetFunctionName(), s => 59 | { 60 | s.AppendLine("#ifndef LIGHTWEIGHT_LIGHTING_INCLUDED"); 61 | s.Append(@" 62 | // Abstraction over Light input constants 63 | struct LightInput 64 | { 65 | float4 position; 66 | half3 color; 67 | half4 distanceAttenuation; 68 | half4 spotDirection; 69 | half4 spotAttenuation; 70 | }; 71 | 72 | // Abstraction over Light shading data. 73 | struct Light 74 | { 75 | half3 direction; 76 | half3 color; 77 | half attenuation; 78 | half subtractiveModeAttenuation; 79 | }; 80 | 81 | // Matches Unity Vanila attenuation 82 | // Attenuation smoothly decreases to light range. 83 | half DistanceAttenuation(half distanceSqr, half3 distanceAttenuation) 84 | { 85 | // We use a shared distance attenuation for additional directional and puctual lights 86 | // for directional lights attenuation will be 1 87 | half quadFalloff = distanceAttenuation.x; 88 | half denom = distanceSqr * quadFalloff + 1.0; 89 | half lightAtten = 1.0 / denom; 90 | 91 | // We need to smoothly fade attenuation to light range. We start fading linearly at 80% of light range 92 | // Therefore: 93 | // fadeDistance = (0.8 * 0.8 * lightRangeSq) 94 | // smoothFactor = (lightRangeSqr - distanceSqr) / (lightRangeSqr - fadeDistance) 95 | // We can rewrite that to fit a MAD by doing 96 | // distanceSqr * (1.0 / (fadeDistanceSqr - lightRangeSqr)) + (-lightRangeSqr / (fadeDistanceSqr - lightRangeSqr) 97 | // distanceSqr * distanceAttenuation.y + distanceAttenuation.z 98 | half smoothFactor = saturate(distanceSqr * distanceAttenuation.y + distanceAttenuation.z); 99 | return lightAtten * smoothFactor; 100 | } 101 | 102 | half SpotAttenuation(half3 spotDirection, half3 lightDirection, half4 spotAttenuation) 103 | { 104 | // Spot Attenuation with a linear falloff can be defined as 105 | // (SdotL - cosOuterAngle) / (cosInnerAngle - cosOuterAngle) 106 | // This can be rewritten as 107 | // invAngleRange = 1.0 / (cosInnerAngle - cosOuterAngle) 108 | // SdotL * invAngleRange + (-cosOuterAngle * invAngleRange) 109 | // SdotL * spotAttenuation.x + spotAttenuation.y 110 | 111 | // If we precompute the terms in a MAD instruction 112 | half SdotL = dot(spotDirection, lightDirection); 113 | half atten = saturate(SdotL * spotAttenuation.x + spotAttenuation.y); 114 | return atten * atten; 115 | } 116 | 117 | half4 GetLightDirectionAndAttenuation(LightInput lightInput, float3 positionWS) 118 | { 119 | half4 directionAndAttenuation; 120 | float3 posToLightVec = lightInput.position.xyz - positionWS * lightInput.position.w; 121 | float distanceSqr = max(dot(posToLightVec, posToLightVec), FLT_MIN); 122 | 123 | directionAndAttenuation.xyz = half3(posToLightVec * rsqrt(distanceSqr)); 124 | directionAndAttenuation.w = DistanceAttenuation(distanceSqr, lightInput.distanceAttenuation.xyz); 125 | directionAndAttenuation.w *= SpotAttenuation(lightInput.spotDirection.xyz, directionAndAttenuation.xyz, lightInput.spotAttenuation); 126 | return directionAndAttenuation; 127 | } 128 | 129 | half4 GetMainLightDirectionAndAttenuation(LightInput lightInput, float3 positionWS) 130 | { 131 | half4 directionAndAttenuation = GetLightDirectionAndAttenuation(lightInput, positionWS); 132 | 133 | // Cookies are only computed for main light 134 | // directionAndAttenuation.w *= CookieAttenuation(positionWS); 135 | 136 | return directionAndAttenuation; 137 | } 138 | 139 | Light GetMainLight(float3 positionWS) 140 | { 141 | LightInput lightInput; 142 | lightInput.position = float4(-0.3213938, 0.7660444, -0.5566704, 0); 143 | lightInput.color = half3(1, 1, 1); 144 | lightInput.distanceAttenuation = half4(0, 1, 0, 0); 145 | lightInput.spotDirection = half4(0, 0, 1, 0); 146 | lightInput.spotAttenuation = half4(0, 1, 0, 1); 147 | 148 | half4 directionAndRealtimeAttenuation = GetMainLightDirectionAndAttenuation(lightInput, positionWS); 149 | 150 | Light light; 151 | light.direction = directionAndRealtimeAttenuation.xyz; 152 | light.attenuation = directionAndRealtimeAttenuation.w; 153 | light.subtractiveModeAttenuation = lightInput.distanceAttenuation.w; 154 | light.color = lightInput.color; 155 | 156 | return light; 157 | } 158 | "); 159 | s.AppendLine("#endif"); 160 | s.AppendLine("void {0}({1}3 WorldSpacePosition, out {2} Attenuation, out {3} Color, out {4} Direction)", 161 | GetFunctionName(), 162 | precision, 163 | FindOutputSlot(OutputSlotId).concreteValueType.ToString(precision), 164 | FindOutputSlot(OutputSlot1Id).concreteValueType.ToString(precision), 165 | FindOutputSlot(OutputSlot2Id).concreteValueType.ToString(precision)); 166 | using (s.BlockScope()) 167 | { 168 | s.AppendLine("Light mainLight = GetMainLight(WorldSpacePosition);"); 169 | s.AppendLine("Attenuation = mainLight.attenuation;"); 170 | s.AppendLine("Color = mainLight.color;"); 171 | s.AppendLine("Direction = mainLight.direction;"); 172 | } 173 | }); 174 | } 175 | 176 | public NeededCoordinateSpace RequiresPosition() 177 | { 178 | return CoordinateSpace.World.ToNeededCoordinateSpace(); 179 | } 180 | } 181 | } -------------------------------------------------------------------------------- /Editor/Data/Nodes/Input/Scene/MainLight.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f11b586d7e5d4c8198e004d844b8f7e2 3 | timeCreated: 1521534788 -------------------------------------------------------------------------------- /Editor/Data/Nodes/Input/Scene/RealtimeShadow.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor.Graphing; 2 | using UnityEditor.ShaderGraph; 3 | 4 | namespace ShaderGraphExtensions 5 | { 6 | [Title("Input", "Scene", "Realtime Shadow")] 7 | public class RealtimeShadow : AbstractMaterialNode, IGeneratesBodyCode, IGeneratesFunction, IMayRequirePosition 8 | { 9 | public RealtimeShadow() 10 | { 11 | name = "Realtime Shadow"; 12 | UpdateNodeAfterDeserialization(); 13 | } 14 | 15 | public override string documentationURL 16 | { 17 | get { return "https://github.com/beinteractive/ShaderGraphExtensions"; } 18 | } 19 | 20 | const int OutputSlotId = 0; 21 | const string k_OutputSlotName = "Out"; 22 | 23 | public override bool hasPreview 24 | { 25 | get { return false; } 26 | } 27 | 28 | string GetFunctionName() 29 | { 30 | return string.Format("sge_RealtimeShadow{0}", precision); 31 | } 32 | 33 | public sealed override void UpdateNodeAfterDeserialization() 34 | { 35 | AddSlot(new Vector1MaterialSlot(OutputSlotId, k_OutputSlotName, k_OutputSlotName, SlotType.Output, 0)); 36 | RemoveSlotsNameNotMatching(new[] {OutputSlotId}); 37 | } 38 | 39 | public void GenerateNodeCode(ShaderGenerator visitor, GenerationMode generationMode) 40 | { 41 | visitor.AddShaderChunk(string.Format("{0} {1};", FindOutputSlot(OutputSlotId).concreteValueType.ToString(precision), GetVariableNameForSlot(OutputSlotId)), false); 42 | visitor.AddShaderChunk(string.Format("{0}(IN.{1}, {2});", GetFunctionName(), 43 | CoordinateSpace.World.ToVariableName(InterpolatorType.Position), 44 | GetVariableNameForSlot(OutputSlotId)), false); 45 | } 46 | 47 | public void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode) 48 | { 49 | registry.ProvideFunction(GetFunctionName(), s => 50 | { 51 | s.AppendLine("#ifndef LIGHTWEIGHT_SHADOWS_INCLUDED"); 52 | s.Append(@" 53 | float4 ComputeShadowCoord(float4 clipPos) 54 | { 55 | return (0.0).xxxx; 56 | } 57 | 58 | half RealtimeShadowAttenuation(float4 shadowCoord) 59 | { 60 | return 1.0h; 61 | } 62 | "); 63 | s.AppendLine("#endif"); 64 | s.AppendLine("void {0}({1}3 WorldSpacePosition, out {2} Out)", 65 | GetFunctionName(), 66 | precision, 67 | FindOutputSlot(OutputSlotId).concreteValueType.ToString(precision)); 68 | using (s.BlockScope()) 69 | { 70 | s.AppendLine("Out = RealtimeShadowAttenuation(ComputeShadowCoord(TransformWorldToHClip(WorldSpacePosition)));"); 71 | } 72 | }); 73 | } 74 | 75 | public NeededCoordinateSpace RequiresPosition() 76 | { 77 | return CoordinateSpace.World.ToNeededCoordinateSpace(); 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /Editor/Data/Nodes/Input/Scene/RealtimeShadow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7d3c6b9944aa44dba3b1703aa6a2d2df 3 | timeCreated: 1521541143 -------------------------------------------------------------------------------- /Editor/Data/Nodes/Procedural.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 02075a7602dec44d7ab066dd3c1fc712 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Data/Nodes/Procedural/Noise.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 231d5b3485828479eb8bb3e38f7a539f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Data/Nodes/Procedural/Noise/SimplexNoise3DNode.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using UnityEditor.ShaderGraph; 3 | using UnityEngine; 4 | 5 | namespace ShaderGraphExtensions 6 | { 7 | [Title("Procedural", "Noise", "Simplex Noise 3D")] 8 | public class SimplexNoise3DNode : CodeFunctionNode 9 | { 10 | public override bool hasPreview { get { return true; } } 11 | 12 | public SimplexNoise3DNode() 13 | { 14 | name = "Simplex Noise 3D"; 15 | } 16 | 17 | public override string documentationURL 18 | { 19 | get { return "https://github.com/beinteractive/ShaderGraphExtensions"; } 20 | } 21 | 22 | protected override MethodInfo GetFunctionToConvert() 23 | { 24 | return GetType().GetMethod("ShaderGraphExtensions_SimplexNoise3D", BindingFlags.Static | BindingFlags.NonPublic); 25 | } 26 | static string ShaderGraphExtensions_SimplexNoise3D( 27 | [Slot(0, Binding.None)] Vector3 Position, 28 | [Slot(1, Binding.None, 2, 2, 2, 2)] Vector1 Scale, 29 | [Slot(2, Binding.None)] out Vector1 Out) 30 | { 31 | return "{ Out = sge_simplexNoise3D(Position * Scale) + 0.5; }"; 32 | } 33 | 34 | public override void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode) 35 | { 36 | registry.ProvideFunction("sge_mod289", s => s.Append(@" 37 | float3 sge_mod289(float3 x) 38 | { 39 | return x - floor(x / 289.0) * 289.0; 40 | } 41 | 42 | float4 sge_mod289(float4 x) 43 | { 44 | return x - floor(x / 289.0) * 289.0; 45 | } 46 | ")); 47 | 48 | registry.ProvideFunction("sge_permute", s => s.Append(@" 49 | float4 sge_permute(float4 x) 50 | { 51 | return sge_mod289((x * 34.0 + 1.0) * x); 52 | } 53 | ")); 54 | 55 | registry.ProvideFunction("sge_simplexNoise3D", s => s.Append(@" 56 | float sge_simplexNoise3D(float3 v) 57 | { 58 | const float2 C = float2(1.0 / 6.0, 1.0 / 3.0); 59 | 60 | // First corner 61 | float3 i = floor(v + dot(v, C.yyy)); 62 | float3 x0 = v - i + dot(i, C.xxx); 63 | 64 | // Other corners 65 | float3 g = step(x0.yzx, x0.xyz); 66 | float3 l = 1.0 - g; 67 | float3 i1 = min(g.xyz, l.zxy); 68 | float3 i2 = max(g.xyz, l.zxy); 69 | 70 | // x1 = x0 - i1 + 1.0 * C.xxx; 71 | // x2 = x0 - i2 + 2.0 * C.xxx; 72 | // x3 = x0 - 1.0 + 3.0 * C.xxx; 73 | float3 x1 = x0 - i1 + C.xxx; 74 | float3 x2 = x0 - i2 + C.yyy; 75 | float3 x3 = x0 - 0.5; 76 | 77 | // Permutations 78 | i = sge_mod289(i); // Avoid truncation effects in permutation 79 | float4 p = 80 | sge_permute(sge_permute(sge_permute(i.z + float4(0.0, i1.z, i2.z, 1.0)) 81 | + i.y + float4(0.0, i1.y, i2.y, 1.0)) 82 | + i.x + float4(0.0, i1.x, i2.x, 1.0)); 83 | 84 | // Gradients: 7x7 points over a square, mapped onto an octahedron. 85 | // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) 86 | float4 j = p - 49.0 * floor(p / 49.0); // mod(p,7*7) 87 | 88 | float4 x_ = floor(j / 7.0); 89 | float4 y_ = floor(j - 7.0 * x_); // mod(j,N) 90 | 91 | float4 x = (x_ * 2.0 + 0.5) / 7.0 - 1.0; 92 | float4 y = (y_ * 2.0 + 0.5) / 7.0 - 1.0; 93 | 94 | float4 h = 1.0 - abs(x) - abs(y); 95 | 96 | float4 b0 = float4(x.xy, y.xy); 97 | float4 b1 = float4(x.zw, y.zw); 98 | 99 | //float4 s0 = float4(lessThan(b0, 0.0)) * 2.0 - 1.0; 100 | //float4 s1 = float4(lessThan(b1, 0.0)) * 2.0 - 1.0; 101 | float4 s0 = floor(b0) * 2.0 + 1.0; 102 | float4 s1 = floor(b1) * 2.0 + 1.0; 103 | float4 sh = -step(h, 0.0); 104 | 105 | float4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; 106 | float4 a1 = b1.xzyw + s1.xzyw * sh.zzww; 107 | 108 | float3 g0 = float3(a0.xy, h.x); 109 | float3 g1 = float3(a0.zw, h.y); 110 | float3 g2 = float3(a1.xy, h.z); 111 | float3 g3 = float3(a1.zw, h.w); 112 | 113 | // Normalise gradients 114 | float4 norm = 1.79284291400159 - (float4(dot(g0, g0), dot(g1, g1), dot(g2, g2), dot(g3, g3))) * 0.85373472095314; 115 | g0 *= norm.x; 116 | g1 *= norm.y; 117 | g2 *= norm.z; 118 | g3 *= norm.w; 119 | 120 | // Mix final noise value 121 | float4 m = max(0.6 - float4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); 122 | m = m * m; 123 | m = m * m; 124 | 125 | float4 px = float4(dot(x0, g0), dot(x1, g1), dot(x2, g2), dot(x3, g3)); 126 | return 42.0 * dot(m, px); 127 | } 128 | ")); 129 | 130 | base.GenerateNodeFunction(registry, generationMode); 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /Editor/Data/Nodes/Procedural/Noise/SimplexNoise3DNode.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7c3dced73724c43a19c0dd1b8057083c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/ShaderGraphExtensions.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ShaderGraphExtensions.Editor", 3 | "references": [ 4 | "Unity.ShaderGraph.Editor" 5 | ], 6 | "optionalUnityReferences": [], 7 | "includePlatforms": [ 8 | "Editor" 9 | ], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": false 12 | } 13 | -------------------------------------------------------------------------------- /Editor/ShaderGraphExtensions.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 398338bbf1e684b93af3fd5ec322b4f0 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shader Graph Extensions 2 | 3 | ## Custom Nodes 4 | 5 | ### Procedural / Noise / Simplex Noise 3D 6 | 7 | 2018-03-12 12 21 40 8 | 9 | ## Input / Scene / Main Light 10 | 11 | **Experimental** 12 | 13 | Output main light's parameters. 14 | 15 | 2018-03-22 10 36 48 16 | 17 | ## Input / Scene / Realtime Shadow 18 | 19 | **Experimental / Not for production use** 20 | 21 | Output shadowmap value 22 | 23 | 2018-03-22 10 37 05 24 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3164c8e69027e4e8ab8fe5cf4927fb8b 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------