From 864c2ba12dc864d9cb55cb797ba8919bee5b5913 Mon Sep 17 00:00:00 2001 From: yum Date: Mon, 16 Feb 2026 16:32:00 -0800 Subject: Add instancing distance culling, scale deformation * GPU instance distance culling now takes a min/max range * Fold recovers ops from material, allowing state to persist across editor restarts * Add scale node to vertex deformation framework * Remove fold presets - dumb LLM idea, unused * Drop more "undeform" code; unused, was for ray marching, which does not work well * Fix reflection energy compensation; was using cloth math, which makes things too bright --- 3ner.cginc | 38 +++- 3ner.shader | 4 +- Scripts/DataDecoder.asset | 0 Scripts/Fold/Editor/FoldEditorWindow.cs | 180 +++++++-------- Scripts/Fold/Editor/FoldPipelineBuilder.cs | 58 +---- Scripts/GrassGridBlit.shader | 0 Scripts/InstanceGrass.asset | 348 +++++++++++++++++++++++------ Scripts/InstanceGrass.cs | 70 ++++-- brdf.cginc | 23 +- globals.cginc | 11 +- impostor.cginc | 108 ++++++--- instancing.cginc | 109 +++++---- interpolators.cginc | 4 +- pbr.cginc | 3 - vertex.cginc | 20 ++ vertex_deformation.slang | 103 +-------- 16 files changed, 667 insertions(+), 412 deletions(-) mode change 100755 => 100644 Scripts/DataDecoder.asset mode change 100644 => 100755 Scripts/GrassGridBlit.shader mode change 100755 => 100644 Scripts/InstanceGrass.asset diff --git a/3ner.cginc b/3ner.cginc index e675bc2..cf03caf 100755 --- a/3ner.cginc +++ b/3ner.cginc @@ -31,11 +31,32 @@ v2f vert(appdata v) { UNITY_TRANSFER_INSTANCE_ID(v, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); - // Apply instance texture offset transformation if enabled + impostor_vert(v.vertex.xyz); + +#if defined(_VERTEX_DEFORMATION) && ( \ + defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS) || \ + defined(_VERTEX_DEFORMATION_TESSELLATION)) || \ + (defined(_IMPOSTORS) && defined(_INSTANCE_TEXTURE_OFFSET)) + o.objPos_orig = v.vertex; +#endif + + + [branch] if (instance_distance_culling()) { + return (v2f) asfloat(-1); + } instancing_vert(v); -#if defined(_IMPOSTORS) - impostor_vert(v.vertex.xyz); +#if defined(_INSTANCE_TEXTURE_OFFSET) && defined(UNITY_INSTANCING_ENABLED) + // Early exit custom frustum culling. + float3 instanceCenter; + if (get_instance_center(instanceCenter)) { + float4 instanceClipPos = UnityObjectToClipPos(instanceCenter); + instanceClipPos /= instanceClipPos.w; + float k = 1.05; + if (any(instanceClipPos.xy < -k) || any(instanceClipPos.xy > k)) { + return (v2f) asfloat(-1); + } + } #endif #if defined(_TESSELLATION) @@ -47,9 +68,6 @@ v2f vert(appdata v) { o.uv23.zw = v.uv3; float3 obj_space_camera_pos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0)); o.objPos = v.vertex; -#if defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS) || defined(_VERTEX_DEFORMATION_TESSELLATION) - o.objPos_orig = v.vertex; -#endif #if defined(_RAY_MARCHING_BAKED_ORIGINS) o.color = v.color; #endif @@ -190,7 +208,10 @@ v2f domain( o.objPos = DOMAIN_INTERP(objPos); #endif -#if defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS) || defined(_VERTEX_DEFORMATION_TESSELLATION) +#if defined(_VERTEX_DEFORMATION) && ( \ + defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS) || \ + defined(_VERTEX_DEFORMATION_TESSELLATION)) || \ + defined(_IMPOSTORS) && defined(_INSTANCE_TEXTURE_OFFSET) o.objPos_orig = DOMAIN_INTERP(objPos_orig); o.objPos = o.objPos_orig; deform(o.objPos); @@ -266,9 +287,6 @@ float4 frag(v2f i, uint facing : SV_IsFrontFace return 0; #endif - // Apply instancing effects (e.g., distance culling) - instancing_frag(i); - #if defined(_RAY_MARCHING) const bool is_fragment = true; ray_march(i, is_fragment); diff --git a/3ner.shader b/3ner.shader index e411ada..926f408 100755 --- a/3ner.shader +++ b/3ner.shader @@ -429,12 +429,14 @@ Shader "yum_food/3ner" //ifex _Instance_Distance_Culling_Enabled==0 [HideInInspector] m_start_Instance_Distance_Culling("Distance Culling", Float) = 0 [ThryToggle(_INSTANCE_DISTANCE_CULLING)] _Instance_Distance_Culling_Enabled("Enable", Float) = 0 - _Instance_Distance_Culling_Distance("Distance (m)", Float) = 10 + _Instance_Distance_Culling_Min_Distance("Min distance (m)", Float) = 0 + _Instance_Distance_Culling_Max_Distance("Max distance (m)", Float) = 10 [HideInInspector] m_end_Instance_Distance_Culling("Instance Distance Culling", Float) = 0 //endex //ifex _Instance_Texture_Offset_Enabled==0 [HideInInspector] m_start_Instance_Texture_Offset("Texture Offset", Float) = 0 [ThryToggle(_INSTANCE_TEXTURE_OFFSET)] _Instance_Texture_Offset_Enabled("Enable", Float) = 0 + [DoNotLock] [HideInInspector] _Instance_ID("Instance ID", Float) = 0 _Instance_Texture_Offset_Data_Tex("Instance Data Texture", 2D) = "black" {} _Instance_Texture_Offset_Cell_Dimensions("Cell Dimensions", Vector) = (1, 1, 1, 0) _Instance_Texture_Offset_Angle_Randomization("Angle Randomization", Vector) = (0, 0, 0, 0) diff --git a/Scripts/DataDecoder.asset b/Scripts/DataDecoder.asset old mode 100755 new mode 100644 diff --git a/Scripts/Fold/Editor/FoldEditorWindow.cs b/Scripts/Fold/Editor/FoldEditorWindow.cs index ab02781..b174b54 100755 --- a/Scripts/Fold/Editor/FoldEditorWindow.cs +++ b/Scripts/Fold/Editor/FoldEditorWindow.cs @@ -18,11 +18,6 @@ public class FoldEditorWindow : EditorWindow window.minSize = new Vector2(400, 300); } - void OnEnable() - { - // Operations list is restored via SerializeReference - } - void OnGUI() { EditorGUILayout.Space(5); @@ -86,9 +81,6 @@ public class FoldEditorWindow : EditorWindow liveUpdate = GUILayout.Toggle(liveUpdate, "Live", EditorStyles.toolbarButton, GUILayout.Width(40)); - if (GUILayout.Button("Load Presets", EditorStyles.toolbarDropDown, GUILayout.Width(100))) - ShowPresetsMenu(); - EditorGUILayout.EndHorizontal(); } @@ -217,6 +209,7 @@ public class FoldEditorWindow : EditorWindow menu.AddItem(new GUIContent("Point Align"), false, () => AddOperation(new PointAlignOp())); menu.AddItem(new GUIContent("Axis Align"), false, () => AddOperation(new AxisAlignOp())); menu.AddSeparator(""); + menu.AddItem(new GUIContent("Scale"), false, () => AddOperation(new ScaleOp())); menu.AddItem(new GUIContent("Norm Conversion"), false, () => AddOperation(new NormConversionOp())); menu.AddItem(new GUIContent("Seal"), false, () => AddOperation(new SealOp())); menu.AddSeparator(""); @@ -226,23 +219,6 @@ public class FoldEditorWindow : EditorWindow menu.ShowAsContext(); } - void ShowPresetsMenu() - { - var menu = new GenericMenu(); - - menu.AddItem(new GUIContent("Tube to Plane"), false, () => LoadPreset_TubeToPlane()); - menu.AddItem(new GUIContent("Plane to Tube"), false, () => LoadPreset_PlaneToTube()); - menu.AddItem(new GUIContent("Plane to Hemi-Octahedron"), false, () => LoadPreset_PlaneToHemiOct()); - menu.AddSeparator(""); - menu.AddItem(new GUIContent("Norm: L1→L2 (Diamond→Sphere)"), false, () => LoadPreset_NormL1L2()); - menu.AddItem(new GUIContent("Norm: L2→L1 (Sphere→Diamond)"), false, () => LoadPreset_NormL2L1()); - menu.AddItem(new GUIContent("Norm: L2→L∞ (Sphere→Cube)"), false, () => LoadPreset_NormL2Linf()); - menu.AddSeparator(""); - menu.AddItem(new GUIContent("Complex/Tube→Plane + Norm Conv"), false, () => LoadPreset_TubePlaneNorm()); - - menu.ShowAsContext(); - } - void AddOperation(DeformOperation op) { if (operations.Count >= 16) @@ -251,68 +227,6 @@ public class FoldEditorWindow : EditorWindow expandedOps.Add(operations.Count - 1); } - void LoadPreset_TubeToPlane() - { - operations.Clear(); - expandedOps.Clear(); - AddOperation(new TubeToPlaneOp()); - } - - void LoadPreset_PlaneToTube() - { - operations.Clear(); - expandedOps.Clear(); - AddOperation(new PlaneToTubeOp()); - } - - void LoadPreset_PlaneToHemiOct() - { - operations.Clear(); - expandedOps.Clear(); - AddOperation(new PlaneToHemiOctahedronOp()); - } - - void LoadPreset_NormL1L2() - { - operations.Clear(); - expandedOps.Clear(); - var op = new NormConversionOp(); - op.inputK = 1f; - op.outputK = 2f; - AddOperation(op); - } - - void LoadPreset_NormL2L1() - { - operations.Clear(); - expandedOps.Clear(); - var op = new NormConversionOp(); - op.inputK = 2f; - op.outputK = 1f; - AddOperation(op); - } - - void LoadPreset_NormL2Linf() - { - operations.Clear(); - expandedOps.Clear(); - var op = new NormConversionOp(); - op.inputK = 2f; - op.outputK = float.PositiveInfinity; - AddOperation(op); - } - - void LoadPreset_TubePlaneNorm() - { - operations.Clear(); - expandedOps.Clear(); - AddOperation(new TubeToPlaneOp()); - var norm = new NormConversionOp(); - norm.inputK = 2f; - norm.outputK = 1f; - AddOperation(norm); - } - void ApplyToMaterial() { var builder = FoldPipelineBuilder.Create().For(targetMaterial); @@ -325,10 +239,53 @@ public class FoldEditorWindow : EditorWindow void LoadFromMaterial() { - // Could potentially read back from material properties here - // For now, just clear the list operations.Clear(); expandedOps.Clear(); + + for (int i = 0; i < 16; i++) + { + var prefix = $"_Vertex_Deformation_Slot_{i}_"; + if (targetMaterial.GetFloat(prefix + "Enabled") < 0.5f) + break; + + int opcode = targetMaterial.GetInteger(prefix + "Opcode"); + if (opcode == FoldPipelineBuilder.Opcodes.None) + break; + + var slot = new FoldSlot + { + opcode = opcode, + float0 = targetMaterial.GetFloat(prefix + "Float_0"), + float1 = targetMaterial.GetFloat(prefix + "Float_1"), + float2 = targetMaterial.GetFloat(prefix + "Float_2"), + float3 = targetMaterial.GetFloat(prefix + "Float_3"), + vec0 = targetMaterial.GetVector(prefix + "Vector_0"), + vec1 = targetMaterial.GetVector(prefix + "Vector_1"), + vec2 = targetMaterial.GetVector(prefix + "Vector_2"), + vec3 = targetMaterial.GetVector(prefix + "Vector_3"), + }; + + DeformOperation op = opcode switch + { + FoldPipelineBuilder.Opcodes.TubeToPlane => new TubeToPlaneOp(slot), + FoldPipelineBuilder.Opcodes.PlaneToTube => new PlaneToTubeOp(slot), + FoldPipelineBuilder.Opcodes.PlaneToHemiOctahedron => new PlaneToHemiOctahedronOp(slot), + FoldPipelineBuilder.Opcodes.HemiOctahedronToPlane => new HemiOctahedronToPlaneOp(slot), + FoldPipelineBuilder.Opcodes.Scale => new ScaleOp(slot), + FoldPipelineBuilder.Opcodes.PointAlign => new PointAlignOp(slot), + FoldPipelineBuilder.Opcodes.AxisAlign => new AxisAlignOp(slot), + FoldPipelineBuilder.Opcodes.NormConversion => new NormConversionOp(slot), + FoldPipelineBuilder.Opcodes.Seal => new SealOp(slot), + FoldPipelineBuilder.Opcodes.SineWaves => new SineWavesOp(), + FoldPipelineBuilder.Opcodes.FBM => new FBMOp(), + _ => null + }; + + if (op == null) + break; + + operations.Add(op); + } } } @@ -349,6 +306,9 @@ public class TubeToPlaneOp : DeformOperation public Vector3 s = Vector3.forward; public float t = 1f; + public TubeToPlaneOp() { } + public TubeToPlaneOp(FoldSlot slot) { p = slot.vec0; r = slot.vec1; s = slot.vec2; t = slot.float0; } + public override string GetDisplayName() => "Tube to Plane"; public override void DrawParameters() @@ -371,6 +331,9 @@ public class PlaneToTubeOp : DeformOperation public Vector3 s = Vector3.forward; public float t = 1f; + public PlaneToTubeOp() { } + public PlaneToTubeOp(FoldSlot slot) { p = slot.vec0; r = slot.vec1; s = slot.vec2; t = slot.float0; } + public override string GetDisplayName() => "Plane to Tube"; public override void DrawParameters() @@ -393,6 +356,9 @@ public class PlaneToHemiOctahedronOp : DeformOperation public Vector3 s = Vector3.forward; public float t = 1f; + public PlaneToHemiOctahedronOp() { } + public PlaneToHemiOctahedronOp(FoldSlot slot) { p = slot.vec0; r = slot.vec1; s = slot.vec2; t = slot.float0; } + public override string GetDisplayName() => "Plane to Hemi-Octahedron"; public override void DrawParameters() @@ -407,6 +373,27 @@ public class PlaneToHemiOctahedronOp : DeformOperation builder.PlaneToHemiOctahedron(p, r, s, t); } +[System.Serializable] +public class ScaleOp : DeformOperation +{ + public Vector3 k = Vector3.one; + public float t = 1f; + + public ScaleOp() { } + public ScaleOp(FoldSlot slot) { k = slot.vec0; t = slot.float0; } + + public override string GetDisplayName() => "Scale"; + + public override void DrawParameters() + { + k = EditorGUILayout.Vector3Field("Scale", k); + t = EditorGUILayout.Slider("Interpolation (t)", t, 0f, 1f); + } + + public override void ApplyTo(FoldPipelineBuilder builder) => + builder.Scale(k, t); +} + [System.Serializable] public class HemiOctahedronToPlaneOp : DeformOperation { @@ -415,6 +402,9 @@ public class HemiOctahedronToPlaneOp : DeformOperation public Vector3 s = Vector3.forward; public float t = 1f; + public HemiOctahedronToPlaneOp() { } + public HemiOctahedronToPlaneOp(FoldSlot slot) { p = slot.vec0; r = slot.vec1; s = slot.vec2; t = slot.float0; } + public override string GetDisplayName() => "Hemi-Octahedron to Plane"; public override void DrawParameters() @@ -437,6 +427,9 @@ public class PointAlignOp : DeformOperation public Vector3 r = Vector3.right; public float t = 1f; + public PointAlignOp() { } + public PointAlignOp(FoldSlot slot) { po = slot.vec0; pp = slot.vec1; r = slot.vec2; t = slot.float0; } + public override string GetDisplayName() => "Point Align"; public override void DrawParameters() @@ -459,6 +452,9 @@ public class AxisAlignOp : DeformOperation public Vector3 r = Vector3.right; public float t = 1f; + public AxisAlignOp() { } + public AxisAlignOp(FoldSlot slot) { po = slot.vec0; pp = slot.vec1; r = slot.vec2; t = slot.float0; } + public override string GetDisplayName() => "Axis Align"; public override void DrawParameters() @@ -480,6 +476,9 @@ public class NormConversionOp : DeformOperation public float outputK = 1f; public float t = 1f; + public NormConversionOp() { } + public NormConversionOp(FoldSlot slot) { inputK = slot.float0; outputK = slot.float1; t = slot.float2; } + public override string GetDisplayName() => $"Norm Conversion (L{FormatNorm(inputK)}→L{FormatNorm(outputK)})"; string FormatNorm(float k) @@ -521,6 +520,9 @@ public class SealOp : DeformOperation public float st = 0.8f; public float t = 1f; + public SealOp() { } + public SealOp(FoldSlot slot) { A = slot.float0; k = slot.float1; st = slot.float2; t = slot.float3; } + public override string GetDisplayName() => "Seal"; public override void DrawParameters() diff --git a/Scripts/Fold/Editor/FoldPipelineBuilder.cs b/Scripts/Fold/Editor/FoldPipelineBuilder.cs index 3731cf8..85a7a4f 100755 --- a/Scripts/Fold/Editor/FoldPipelineBuilder.cs +++ b/Scripts/Fold/Editor/FoldPipelineBuilder.cs @@ -58,6 +58,7 @@ public class FoldPipelineBuilder public const int FBM = 8; public const int PlaneToHemiOctahedron = 9; public const int HemiOctahedronToPlane = 10; + public const int Scale = 11; } FoldPipelineBuilder() { } @@ -109,6 +110,17 @@ public class FoldPipelineBuilder return this; } + public FoldPipelineBuilder Scale(Vector3 k, float t) + { + slots.Add(new FoldSlot + { + opcode = Opcodes.Scale, + vec0 = k, + float0 = t + }); + return this; + } + public FoldPipelineBuilder HemiOctahedronToPlane(Vector3 p, Vector3 r, Vector3 s, float t) { slots.Add(new FoldSlot @@ -236,49 +248,3 @@ public class FoldPipelineBuilder public int Count => slots.Count; } - -public static class FoldPresets -{ - public static void TubeToPlaneFull(Material mat) => - FoldPipelineBuilder.Create() - .For(mat) - .TubeToPlane(Vector3.zero, Vector3.right, Vector3.forward, 1f) - .Apply(); - - public static void PlaneToTubeFull(Material mat) => - FoldPipelineBuilder.Create() - .For(mat) - .PlaneToTube(Vector3.zero, Vector3.right, Vector3.forward, 1f) - .Apply(); - - public static void PlaneToHemiOctahedronFull(Material mat) => - FoldPipelineBuilder.Create() - .For(mat) - .PlaneToHemiOctahedron(Vector3.zero, Vector3.right, Vector3.forward, 1f) - .Apply(); - - public static void TubeToPlaneThenNormConv(Material mat) => - FoldPipelineBuilder.Create() - .For(mat) - .TubeToPlane(Vector3.zero, Vector3.right, Vector3.forward, 1f) - .NormConversion(2f, 1f, 1f) - .Apply(); - - public static void NormConvL1ToL2(Material mat) => - FoldPipelineBuilder.Create() - .For(mat) - .NormConversion(1f, 2f, 1f) - .Apply(); - - public static void NormConvL2ToL1(Material mat) => - FoldPipelineBuilder.Create() - .For(mat) - .NormConversion(2f, 1f, 1f) - .Apply(); - - public static void NormConvL2ToLinf(Material mat) => - FoldPipelineBuilder.Create() - .For(mat) - .NormConversion(2f, float.PositiveInfinity, 1f) - .Apply(); -} diff --git a/Scripts/GrassGridBlit.shader b/Scripts/GrassGridBlit.shader old mode 100644 new mode 100755 diff --git a/Scripts/InstanceGrass.asset b/Scripts/InstanceGrass.asset old mode 100755 new mode 100644 index 3dd3bc4..8d50781 --- a/Scripts/InstanceGrass.asset +++ b/Scripts/InstanceGrass.asset @@ -44,7 +44,7 @@ MonoBehaviour: Data: - Name: Entry: 12 - Data: 23 + Data: 27 - Name: Entry: 7 Data: @@ -230,10 +230,64 @@ MonoBehaviour: Data: - Name: $k Entry: 1 - Data: angle_randomization_ + Data: min_distance_ - Name: $v Entry: 7 Data: 14|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: min_distance_ + - Name: k__BackingField + Entry: 9 + Data: 7 + - Name: k__BackingField + Entry: 9 + Data: 7 + - Name: k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 5 + Data: true + - Name: _fieldAttributes + Entry: 7 + Data: 15|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 1 + - Name: + Entry: 7 + Data: 16|UnityEngine.SerializeField, UnityEngine.CoreModule + - Name: + Entry: 8 + Data: + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 7 + Data: + - Name: $k + Entry: 1 + Data: angle_randomization_ + - Name: $v + Entry: 7 + Data: 17|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: angle_randomization_ @@ -257,13 +311,13 @@ MonoBehaviour: Data: true - Name: _fieldAttributes Entry: 7 - Data: 15|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 18|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 1 - Name: Entry: 7 - Data: 16|UnityEngine.SerializeField, UnityEngine.CoreModule + Data: 19|UnityEngine.SerializeField, UnityEngine.CoreModule - Name: Entry: 8 Data: @@ -287,7 +341,7 @@ MonoBehaviour: Data: scale_randomization_ - Name: $v Entry: 7 - Data: 17|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 20|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: scale_randomization_ @@ -311,13 +365,13 @@ MonoBehaviour: Data: true - Name: _fieldAttributes Entry: 7 - Data: 18|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 21|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 1 - Name: Entry: 7 - Data: 19|UnityEngine.SerializeField, UnityEngine.CoreModule + Data: 22|UnityEngine.SerializeField, UnityEngine.CoreModule - Name: Entry: 8 Data: @@ -341,13 +395,13 @@ MonoBehaviour: Data: max_grid_size_ - Name: $v Entry: 7 - Data: 20|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 23|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: max_grid_size_ - Name: k__BackingField Entry: 7 - Data: 21|System.RuntimeType, mscorlib + Data: 24|System.RuntimeType, mscorlib - Name: Entry: 1 Data: UnityEngine.Vector3Int, UnityEngine.CoreModule @@ -356,7 +410,7 @@ MonoBehaviour: Data: - Name: k__BackingField Entry: 9 - Data: 21 + Data: 24 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -371,13 +425,13 @@ MonoBehaviour: Data: true - Name: _fieldAttributes Entry: 7 - Data: 22|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 25|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 1 - Name: Entry: 7 - Data: 23|UnityEngine.SerializeField, UnityEngine.CoreModule + Data: 26|UnityEngine.SerializeField, UnityEngine.CoreModule - Name: Entry: 8 Data: @@ -401,13 +455,13 @@ MonoBehaviour: Data: blit_material_ - Name: $v Entry: 7 - Data: 24|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 27|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: blit_material_ - Name: k__BackingField Entry: 7 - Data: 25|System.RuntimeType, mscorlib + Data: 28|System.RuntimeType, mscorlib - Name: Entry: 1 Data: UnityEngine.Material, UnityEngine.CoreModule @@ -416,7 +470,7 @@ MonoBehaviour: Data: - Name: k__BackingField Entry: 9 - Data: 25 + Data: 28 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -431,13 +485,13 @@ MonoBehaviour: Data: true - Name: _fieldAttributes Entry: 7 - Data: 26|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 29|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 1 - Name: Entry: 7 - Data: 27|UnityEngine.SerializeField, UnityEngine.CoreModule + Data: 30|UnityEngine.SerializeField, UnityEngine.CoreModule - Name: Entry: 8 Data: @@ -461,13 +515,13 @@ MonoBehaviour: Data: mesh_ - Name: $v Entry: 7 - Data: 28|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 31|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: mesh_ - Name: k__BackingField Entry: 7 - Data: 29|System.RuntimeType, mscorlib + Data: 32|System.RuntimeType, mscorlib - Name: Entry: 1 Data: UnityEngine.Mesh, UnityEngine.CoreModule @@ -476,7 +530,7 @@ MonoBehaviour: Data: - Name: k__BackingField Entry: 9 - Data: 29 + Data: 32 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -491,7 +545,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 30|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 33|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -515,16 +569,16 @@ MonoBehaviour: Data: instance_material_ - Name: $v Entry: 7 - Data: 31|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 34|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: instance_material_ - Name: k__BackingField Entry: 9 - Data: 25 + Data: 28 - Name: k__BackingField Entry: 9 - Data: 25 + Data: 28 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -539,7 +593,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 32|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 35|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -563,13 +617,13 @@ MonoBehaviour: Data: base_transform_ - Name: $v Entry: 7 - Data: 33|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 36|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: base_transform_ - Name: k__BackingField Entry: 7 - Data: 34|System.RuntimeType, mscorlib + Data: 37|System.RuntimeType, mscorlib - Name: Entry: 1 Data: UnityEngine.Transform, UnityEngine.CoreModule @@ -578,7 +632,7 @@ MonoBehaviour: Data: - Name: k__BackingField Entry: 9 - Data: 34 + Data: 37 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -593,7 +647,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 35|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 38|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -617,7 +671,7 @@ MonoBehaviour: Data: cell_dim_ - Name: $v Entry: 7 - Data: 36|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 39|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: cell_dim_ @@ -641,7 +695,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 37|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 40|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -665,7 +719,7 @@ MonoBehaviour: Data: inv_cell_dim_ - Name: $v Entry: 7 - Data: 38|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 41|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: inv_cell_dim_ @@ -689,7 +743,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 39|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 42|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -713,16 +767,16 @@ MonoBehaviour: Data: count_ - Name: $v Entry: 7 - Data: 40|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 43|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: count_ - Name: k__BackingField Entry: 9 - Data: 21 + Data: 24 - Name: k__BackingField Entry: 9 - Data: 21 + Data: 24 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -737,7 +791,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 41|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 44|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -761,13 +815,13 @@ MonoBehaviour: Data: total_instances_ - Name: $v Entry: 7 - Data: 42|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 45|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: total_instances_ - Name: k__BackingField Entry: 7 - Data: 43|System.RuntimeType, mscorlib + Data: 46|System.RuntimeType, mscorlib - Name: Entry: 1 Data: System.Int32, mscorlib @@ -776,7 +830,7 @@ MonoBehaviour: Data: - Name: k__BackingField Entry: 9 - Data: 43 + Data: 46 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -791,7 +845,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 44|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 47|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -815,13 +869,13 @@ MonoBehaviour: Data: initialized_ - Name: $v Entry: 7 - Data: 45|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 48|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: initialized_ - Name: k__BackingField Entry: 7 - Data: 46|System.RuntimeType, mscorlib + Data: 49|System.RuntimeType, mscorlib - Name: Entry: 1 Data: System.Boolean, mscorlib @@ -830,7 +884,7 @@ MonoBehaviour: Data: - Name: k__BackingField Entry: 9 - Data: 46 + Data: 49 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -845,7 +899,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 47|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 50|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -869,7 +923,7 @@ MonoBehaviour: Data: density_live_ - Name: $v Entry: 7 - Data: 48|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 51|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: density_live_ @@ -893,7 +947,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 49|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 52|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -917,7 +971,7 @@ MonoBehaviour: Data: extent_meters_live_ - Name: $v Entry: 7 - Data: 50|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 53|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: extent_meters_live_ @@ -941,7 +995,55 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 51|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 54|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 7 + Data: + - Name: $k + Entry: 1 + Data: min_distance_live_ + - Name: $v + Entry: 7 + Data: 55|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: min_distance_live_ + - Name: k__BackingField + Entry: 9 + Data: 7 + - Name: k__BackingField + Entry: 9 + Data: 7 + - Name: k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 56|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -965,7 +1067,7 @@ MonoBehaviour: Data: angle_randomization_live_ - Name: $v Entry: 7 - Data: 52|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 57|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: angle_randomization_live_ @@ -989,7 +1091,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 53|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 58|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -1013,7 +1115,7 @@ MonoBehaviour: Data: scale_randomization_live_ - Name: $v Entry: 7 - Data: 54|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 59|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: scale_randomization_live_ @@ -1037,7 +1139,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 55|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 60|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -1061,13 +1163,13 @@ MonoBehaviour: Data: instance_data_tex_ - Name: $v Entry: 7 - Data: 56|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 61|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: instance_data_tex_ - Name: k__BackingField Entry: 7 - Data: 57|System.RuntimeType, mscorlib + Data: 62|System.RuntimeType, mscorlib - Name: Entry: 1 Data: UnityEngine.RenderTexture, UnityEngine.CoreModule @@ -1076,7 +1178,7 @@ MonoBehaviour: Data: - Name: k__BackingField Entry: 9 - Data: 57 + Data: 62 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -1091,7 +1193,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 58|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 63|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -1115,13 +1217,13 @@ MonoBehaviour: Data: identity_transforms_ - Name: $v Entry: 7 - Data: 59|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 64|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: identity_transforms_ - Name: k__BackingField Entry: 7 - Data: 60|System.RuntimeType, mscorlib + Data: 65|System.RuntimeType, mscorlib - Name: Entry: 1 Data: UnityEngine.Matrix4x4[], UnityEngine.CoreModule @@ -1130,7 +1232,7 @@ MonoBehaviour: Data: - Name: k__BackingField Entry: 9 - Data: 60 + Data: 65 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -1145,7 +1247,115 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 61|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 66|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 7 + Data: + - Name: $k + Entry: 1 + Data: instance_ids_ + - Name: $v + Entry: 7 + Data: 67|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: instance_ids_ + - Name: k__BackingField + Entry: 7 + Data: 68|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: System.Single[], mscorlib + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 9 + Data: 68 + - Name: k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 69|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 7 + Data: + - Name: $k + Entry: 1 + Data: instance_properties_ + - Name: $v + Entry: 7 + Data: 70|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: k__BackingField + Entry: 1 + Data: instance_properties_ + - Name: k__BackingField + Entry: 7 + Data: 71|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: UnityEngine.MaterialPropertyBlock, UnityEngine.CoreModule + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 9 + Data: 71 + - Name: k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 72|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -1169,16 +1379,16 @@ MonoBehaviour: Data: tex_width_ - Name: $v Entry: 7 - Data: 62|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 73|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: tex_width_ - Name: k__BackingField Entry: 9 - Data: 43 + Data: 46 - Name: k__BackingField Entry: 9 - Data: 43 + Data: 46 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -1193,7 +1403,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 63|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 74|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 @@ -1217,16 +1427,16 @@ MonoBehaviour: Data: tex_height_ - Name: $v Entry: 7 - Data: 64|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + Data: 75|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor - Name: k__BackingField Entry: 1 Data: tex_height_ - Name: k__BackingField Entry: 9 - Data: 43 + Data: 46 - Name: k__BackingField Entry: 9 - Data: 43 + Data: 46 - Name: k__BackingField Entry: 7 Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib @@ -1241,7 +1451,7 @@ MonoBehaviour: Data: false - Name: _fieldAttributes Entry: 7 - Data: 65|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + Data: 76|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib - Name: Entry: 12 Data: 0 diff --git a/Scripts/InstanceGrass.cs b/Scripts/InstanceGrass.cs index 3c0d8f6..d6a1eab 100755 --- a/Scripts/InstanceGrass.cs +++ b/Scripts/InstanceGrass.cs @@ -15,6 +15,7 @@ public class InstanceGrass : UdonSharpBehaviour // The extent along each cardinal axis where instances will be rendered, in // meters. I.e. render inside a cube with edges this long. [SerializeField] public Vector3 extent_meters_; + [SerializeField] public float min_distance_; [SerializeField] public Vector3 angle_randomization_; [SerializeField] public float scale_randomization_; @@ -34,12 +35,15 @@ public class InstanceGrass : UdonSharpBehaviour // Track fields to detect runtime changes. private float density_live_; private Vector3 extent_meters_live_; + private float min_distance_live_; private Vector3 angle_randomization_live_; private float scale_randomization_live_; // GPU-specific resources private RenderTexture instance_data_tex_; private Matrix4x4[] identity_transforms_; // All identity matrices + private float[] instance_ids_; + private MaterialPropertyBlock instance_properties_; private int tex_width_; private int tex_height_; @@ -67,6 +71,7 @@ public class InstanceGrass : UdonSharpBehaviour Material[] materials = mesh_renderer.sharedMaterials; if (materials != null && materials.Length > 0) { instance_material_ = materials[0]; + instance_material_.enableInstancing = true; } else { Debug.LogError("[Grass::Debug] MeshRenderer has no materials."); } @@ -117,26 +122,29 @@ public class InstanceGrass : UdonSharpBehaviour instance_data_tex_.filterMode = FilterMode.Point; instance_data_tex_.Create(); - // Create transform array with encoded instance IDs - must match actual draw count - int actual_draw_count = tex_width_ * tex_height_; - if (identity_transforms_ == null || identity_transforms_.Length != actual_draw_count) { - identity_transforms_ = new Matrix4x4[actual_draw_count]; - for (int i = 0; i < actual_draw_count; i++) { - // Encode instance ID in the matrix translation component - // We'll put the ID in the X component, which the shader will read - Matrix4x4 m = Matrix4x4.identity; - m.m03 = i; // Store instance ID in translation.x - identity_transforms_[i] = m; + // Create transform array and per-instance IDs. + if (identity_transforms_ == null || identity_transforms_.Length != total_instances_) { + identity_transforms_ = new Matrix4x4[total_instances_]; + for (int i = 0; i < total_instances_; i++) { + identity_transforms_[i] = Matrix4x4.identity; + } + } + + if (instance_ids_ == null || instance_ids_.Length != total_instances_) { + instance_ids_ = new float[total_instances_]; + for (int i = 0; i < total_instances_; i++) { + instance_ids_[i] = i; } } if (mesh_ != null) { - // Set huge bounds so culling doesn't interfere - mesh_.bounds = new Bounds(Vector3.zero, Vector3.one * 10000f); + // Prevent frustum culling from clipping instanced draws that move in-shader. + mesh_.bounds = new Bounds(Vector3.zero, Vector3.one * 100000f); } density_live_ = density_; extent_meters_live_ = extent_meters_; + min_distance_live_ = min_distance_; angle_randomization_live_ = angle_randomization_; scale_randomization_live_ = scale_randomization_; @@ -182,6 +190,7 @@ public class InstanceGrass : UdonSharpBehaviour // Reinitialize if any config changed at runtime. if (density_ != density_live_ || extent_meters_ != extent_meters_live_ || + min_distance_ != min_distance_live_ || angle_randomization_ != angle_randomization_live_ || scale_randomization_ != scale_randomization_live_) { Init(); @@ -194,9 +203,12 @@ public class InstanceGrass : UdonSharpBehaviour VRCPlayerApi lcl_player = Networking.LocalPlayer; Vector3 player_pos = lcl_player.GetPosition(); - int grid_x = Mathf.FloorToInt(player_pos.x * inv_cell_dim_.x); - int grid_y = Mathf.FloorToInt(player_pos.y * inv_cell_dim_.y); - int grid_z = Mathf.FloorToInt(player_pos.z * inv_cell_dim_.z); + + // Only update grid position on axes with extent >= 1cm + // For axes with smaller extent, keep grid at 0 (don't move with player) + int grid_x = extent_meters_.x >= 0.01f ? Mathf.FloorToInt(player_pos.x * inv_cell_dim_.x) : 0; + int grid_y = extent_meters_.y >= 0.01f ? Mathf.FloorToInt(player_pos.y * inv_cell_dim_.y) : 0; + int grid_z = extent_meters_.z >= 0.01f ? Mathf.FloorToInt(player_pos.z * inv_cell_dim_.z) : 0; int half_x = count_.x / 2; int half_y = count_.y / 2; @@ -222,20 +234,24 @@ public class InstanceGrass : UdonSharpBehaviour Quaternion rot = base_transform_.localRotation; instance_material_.SetVector("_Instance_Texture_Offset_Base_Rotation", new Vector4(rot.x, rot.y, rot.z, rot.w)); + // Distance culling parameters + instance_material_.SetFloat("_Instance_Distance_Culling_Min_Distance", min_distance_); + float max_distance = Mathf.Max(extent_meters_.x, Mathf.Max(extent_meters_.y, extent_meters_.z)); + instance_material_.SetFloat("_Instance_Distance_Culling_Max_Distance", max_distance * 0.5f); + if (Time.frameCount % 300 == 0) { Debug.Log($"[Grass::Debug] Drawing {total_instances_} GPU instances"); Debug.Log($"[Grass::Debug] GridCount={count_}, TexDim={tex_width_}x{tex_height_}, CellDim={cell_dim_}"); } // Draw instances with identity transforms - GPU handles everything - // Must draw tex_width * tex_height instances to match texture VRCGraphics.DrawMeshInstanced( mesh_, 0, instance_material_, identity_transforms_, total_instances_, - null, + GetInstanceProperties(), UnityEngine.Rendering.ShadowCastingMode.Off, true, 0, @@ -246,6 +262,15 @@ public class InstanceGrass : UdonSharpBehaviour initialized_ = true; } + private MaterialPropertyBlock GetInstanceProperties() { + if (instance_properties_ == null) { + instance_properties_ = new MaterialPropertyBlock(); + } + + instance_properties_.SetFloatArray("_Instance_ID", instance_ids_); + return instance_properties_; + } + void OnDestroy() { if (instance_data_tex_ != null) { instance_data_tex_.Release(); @@ -288,7 +313,16 @@ public class InstanceGrassEditor : Editor return; } - string assetPath = "Assets/yum_food/3ner/Grass_Generated/Grass_generated.mat"; + // Get hierarchy path + Transform current = script.transform; + string hierarchyPath = current.name; + while (current.parent != null) + { + current = current.parent; + hierarchyPath = current.name + "/" + hierarchyPath; + } + + string assetPath = $"Assets/yum_food/3ner/Grass_Generated/{hierarchyPath}/Grass_generated.mat"; // Create or load existing material Material blitMat = AssetDatabase.LoadAssetAtPath(assetPath); diff --git a/brdf.cginc b/brdf.cginc index 682f6a0..d44ce14 100755 --- a/brdf.cginc +++ b/brdf.cginc @@ -167,12 +167,13 @@ float4 brdf(Pbr pbr, LightData data) { cc_dfg = float3(1, 1, 1); } float cc_Ess = max(cc_dfg.y, 1e-4f); - float cc_energy_comp = 1.0f + cc_f0 * (rcp(cc_Ess) - 1.0f); + //float cc_energy_comp = 1.0f + cc_f0 * (rcp(cc_Ess) - 1.0f); + float cc_energy_comp = 1; #endif float3 f0_color = lerp(f0, pbr.albedo.xyz, pbr.metallic); - float Ess = max(dfg.y, 1e-4f); - float3 energy_comp = 1.0f + f0_color * (rcp(Ess) - 1.0f); + //float3 energy_comp = 1.0f + f0_color * (rcp(dfg.yyy) - 1.0f); + float3 energy_comp = 1.0f; // Direct { @@ -247,18 +248,18 @@ float4 brdf(Pbr pbr, LightData data) { remainder -= Fcl * pbr.cl_strength; #endif - // Standard PBR IBL using split-sum approximation - // Specular lobe + // Standard split-sum IBL float3 f0_spec = lerp(f0, pbr.albedo.xyz, pbr.metallic); + //float3 ibl_specular_reflectance = f0_spec * dfg.x + dfg.y; float3 ibl_specular_reflectance = lerp(dfg.xxx, dfg.yyy, f0_spec); - float3 indirect_specular = data.indirect.specular * ibl_specular_reflectance * energy_comp; - const float3 F = F_Schlick(data.indirect.NoL, f0_spec, f90); - const float3 is_conserved = indirect_specular * F; + //float3 ibl_specular_reflectance = f0_spec * dfg.x; + float3 indirect_specular = data.indirect.specular * ibl_specular_reflectance; + + //return float4(data.indirect.specular, 1); - specular += is_conserved; - remainder = saturate(remainder - is_conserved); + specular += indirect_specular; + remainder = saturate(remainder - indirect_specular); - // Diffuse is Lambertian, which is pre-integrated into the SH diffuse probe float3 indirect_diffuse = pbr.albedo.xyz * data.indirect.diffuse * remainder * (1.0 - pbr.metallic); diffuse += indirect_diffuse; } diff --git a/globals.cginc b/globals.cginc index 9bc4330..d3a4b8e 100755 --- a/globals.cginc +++ b/globals.cginc @@ -167,7 +167,8 @@ float _Ray_Marching_Hexagon_Height; #endif // _RAY_MARCHING_HEXAGON #if defined(_INSTANCE_DISTANCE_CULLING) -float _Instance_Distance_Culling_Distance; +float _Instance_Distance_Culling_Min_Distance; +float _Instance_Distance_Culling_Max_Distance; #endif // _INSTANCE_DISTANCE_CULLING #if defined(_INSTANCE_TEXTURE_OFFSET) @@ -180,6 +181,14 @@ float3 _Instance_Texture_Offset_Base_Scale; float4 _Instance_Texture_Offset_Base_Rotation; #endif // _INSTANCE_TEXTURE_OFFSET +// Instancing buffer must be declared at global scope for D3D11 compatibility +#if defined(_INSTANCE_TEXTURE_OFFSET) && defined(UNITY_INSTANCING_ENABLED) +UNITY_INSTANCING_BUFFER_START(InstanceProps) + UNITY_DEFINE_INSTANCED_PROP(float, _Instance_ID) +#define _Instance_ID_arr InstanceProps +UNITY_INSTANCING_BUFFER_END(InstanceProps) +#endif // _INSTANCE_TEXTURE_OFFSET && UNITY_INSTANCING_ENABLED + #if defined(_PARALLAX_HEIGHTMAP) texture2D _Parallax_Heightmap; float4 _Parallax_Heightmap_ST; diff --git a/impostor.cginc b/impostor.cginc index 14fee5b..5674c02 100755 --- a/impostor.cginc +++ b/impostor.cginc @@ -5,6 +5,15 @@ #include "globals.cginc" #include "vertex_deformation.hlsl" +struct ImpostorResult { + float4 albedo; + float3 normal; + float metallic; + float smoothness; + float3 objPos; +}; + +#if defined(_IMPOSTORS) float2 HemiOctEncode(float3 N) { N.y = max(N.y, 1e-4); float3 p = hemi_octahedron_to_plane(normalize(N), 0, float3(1,0,0), float3(0,1,0), 1); @@ -54,8 +63,6 @@ float2 VirtualPlaneUV(float3 planeX, float3 planeY, float3 planeN, float3 pivotT return 0.5 - float2(dot(planeX, offset), dot(planeY, offset)); } -#if defined(_IMPOSTORS) - float2 ClampUvInCell(float2 uv, float2 halfTexelInCell) { return clamp(saturate(uv), halfTexelInCell, 1.0 - halfTexelInCell); } @@ -67,14 +74,6 @@ struct ImpostorSample { float depth; }; -struct ImpostorResult { - float4 albedo; - float3 normal; - float metallic; - float smoothness; - float3 objPos; -}; - ImpostorSample SampleImpostorCell(float2 cell, float2 uvInCell, float invGridRes) { float2 atlasUv = (cell + uvInCell) * invGridRes; float2 gradX = ddx(uvInCell) * invGridRes; @@ -89,22 +88,24 @@ ImpostorSample SampleImpostorCell(float2 cell, float2 uvInCell, float invGridRes return s; } -float2 ImpostorParallaxOffset(float3 planeX, float3 planeY, float3 planeN, float3 pivotToCamOS, float encodedDepth) { +float2 ImpostorParallaxOffset(float3 planeX, float3 planeY, float3 planeN, float3 pivotToCamOS, float encodedDepth, + float impostorNear, float impostorFar, float impostorRadius) { float2 camXY = float2(dot(pivotToCamOS, planeX), dot(pivotToCamOS, planeY)); float camZ = dot(pivotToCamOS, planeN); camZ = (abs(camZ) < 1e-4) ? (camZ < 0 ? -1e-4 : 1e-4) : camZ; - float worldSpaceDepth = lerp(_Impostors_Near_Clip, _Impostors_Far_Clip, encodedDepth); - float depth01 = (worldSpaceDepth - _Impostors_Near_Clip) / (2.0 * _Impostors_Sphere_Radius); + float worldSpaceDepth = lerp(impostorNear, impostorFar, encodedDepth); + float depth01 = (worldSpaceDepth - impostorNear) / (2.0 * impostorRadius); float height = 0.5 - depth01; return (camXY / camZ) * height; } -float3 ReconstructObjectOffset(float3 planeX, float3 planeY, float3 planeN, float2 uv, float encodedDepth) { - float2 offsetXY = (0.5 - uv) * (2.0 * _Impostors_Sphere_Radius); - float worldSpaceDepth = lerp(_Impostors_Near_Clip, _Impostors_Far_Clip, encodedDepth); - float offsetZ = (_Impostors_Sphere_Radius + _Impostors_Near_Clip) - worldSpaceDepth; +float3 ReconstructObjectOffset(float3 planeX, float3 planeY, float3 planeN, float2 uv, float encodedDepth, + float impostorNear, float impostorFar, float impostorRadius) { + float2 offsetXY = (0.5 - uv) * (2.0 * impostorRadius); + float worldSpaceDepth = lerp(impostorNear, impostorFar, encodedDepth); + float offsetZ = (impostorRadius + impostorNear) - worldSpaceDepth; return offsetXY.x * planeX + offsetXY.y * planeY + offsetZ * planeN; } @@ -120,15 +121,26 @@ ImpostorSample BlendImpostorSamples(ImpostorSample s0, ImpostorSample s1, Impost result.metallicGloss = s0.metallicGloss * alphaBw.x + s1.metallicGloss * alphaBw.y + s2.metallicGloss * alphaBw.z; return result; } +#endif // _IMPOSTORS void impostor_vert(inout float3 vertexOS) { +#if defined(_IMPOSTORS) float3 center = mul(unity_ObjectToWorld, float4(0,0,0,1)).xyz; +#if defined(_INSTANCE_TEXTURE_OFFSET) && defined(UNITY_INSTANCING_ENABLED) + float3 instanceCenter; + float4 instanceRotation; + float3 instanceScale; + if (get_instance_transform(instanceCenter, instanceRotation, instanceScale)) { + center = mul(unity_ObjectToWorld, float4(instanceCenter, 1.0)).xyz; + } +#endif // _INSTANCE_TEXTURE_OFFSET && UNITY_INSTANCING_ENABLED + #ifdef SHADOW_CASTER_PASS float3 camPos = _Impostors_Main_Camera_Pos; #else float3 camPos = _WorldSpaceCameraPos; -#endif +#endif // SHADOW_CASTER_PASS float3 viewWS = normalize(camPos - center); float3 right, up; @@ -136,12 +148,27 @@ void impostor_vert(inout float3 vertexOS) { float radiusScale = _Impostors_Sphere_Radius * 2.0; float3 worldPos = center + (vertexOS.x * right + vertexOS.y * up) * radiusScale; vertexOS = mul(unity_WorldToObject, float4(worldPos, 1.0)).xyz; +#endif // _IMPOSTORS } ImpostorResult impostor_frag(float3 worldPos) { ImpostorResult result = (ImpostorResult)0; +#if defined(_IMPOSTORS) float3 center = mul(unity_ObjectToWorld, float4(0,0,0,1)).xyz; + float4 instanceRotation = float4(0, 0, 0, 1); + float instanceScale = 1.0; + bool hasInstanceTransform = false; + +#if defined(_INSTANCE_TEXTURE_OFFSET) && defined(UNITY_INSTANCING_ENABLED) + float3 instanceCenter; + float3 instanceScale3; + if (get_instance_transform(instanceCenter, instanceRotation, instanceScale3)) { + center = mul(unity_ObjectToWorld, float4(instanceCenter, 1.0)).xyz; + instanceScale = max(instanceScale3.x, max(instanceScale3.y, instanceScale3.z)); + hasInstanceTransform = true; + } +#endif // _INSTANCE_TEXTURE_OFFSET && UNITY_INSTANCING_ENABLED #ifdef SHADOW_CASTER_PASS float3 camPos = _Impostors_Main_Camera_Pos; @@ -151,13 +178,28 @@ ImpostorResult impostor_frag(float3 worldPos) { float3 camToCenter = camPos - center; float3 viewDir = normalize(worldPos - camPos); + float impostorRadius = _Impostors_Sphere_Radius * instanceScale; + float impostorNear = _Impostors_Near_Clip * instanceScale; + float impostorFar = _Impostors_Far_Clip * instanceScale; + float b = dot(camToCenter, viewDir); - float c = dot(camToCenter, camToCenter) - _Impostors_Sphere_Radius * _Impostors_Sphere_Radius; + float c = dot(camToCenter, camToCenter) - impostorRadius * impostorRadius; clip(b * b - c); float3x3 worldToObject = (float3x3)unity_WorldToObject; float3 viewOS = mul(worldToObject, normalize(camToCenter)); + float3 pivotToCamOS = mul(worldToObject, camToCenter); + float3 vertexPosOS = mul(worldToObject, worldPos - center); + + if (hasInstanceTransform) { + float4 instanceRotationInv = qconj(instanceRotation); + viewOS = qrotate(instanceRotationInv, viewOS); + pivotToCamOS = qrotate(instanceRotationInv, pivotToCamOS); + vertexPosOS = qrotate(instanceRotationInv, vertexPosOS); + } + float3 vertexToCamOS = pivotToCamOS - vertexPosOS; + float gridRes = (float)_Impostors_Grid_Resolution; float invGridRes = rcp(gridRes); float2 halfTexelInCell = 0.5 * _Impostors_Atlas_TexelSize.xy * gridRes; @@ -173,10 +215,6 @@ ImpostorResult impostor_frag(float3 worldPos) { float2 cell1 = clamp(gridFloor + (isBottomRight ? float2(1,0) : float2(0,1)), 0, gridRes - 1); float2 cell2 = clamp(gridFloor + float2(1,1), 0, gridRes - 1); - float3 pivotToCamOS = mul(worldToObject, camToCenter); - float3 vertexPosOS = mul(worldToObject, worldPos - center); - float3 vertexToCamOS = pivotToCamOS - vertexPosOS; - float3 frameDir0 = DirFromCell(cell0, gridRes); float3 frameDir1 = DirFromCell(cell1, gridRes); float3 frameDir2 = DirFromCell(cell2, gridRes); @@ -215,9 +253,12 @@ ImpostorResult impostor_frag(float3 worldPos) { [branch] if (parallaxStrength > 0.001) { - parallaxOffset0 = ImpostorParallaxOffset(planeX0, planeY0, planeN0, pivotToCamOS, depthBlended) * parallaxStrength; - parallaxOffset1 = ImpostorParallaxOffset(planeX1, planeY1, planeN1, pivotToCamOS, depthBlended) * parallaxStrength; - parallaxOffset2 = ImpostorParallaxOffset(planeX2, planeY2, planeN2, pivotToCamOS, depthBlended) * parallaxStrength; + parallaxOffset0 = ImpostorParallaxOffset(planeX0, planeY0, planeN0, pivotToCamOS, depthBlended, + impostorNear, impostorFar, impostorRadius) * parallaxStrength; + parallaxOffset1 = ImpostorParallaxOffset(planeX1, planeY1, planeN1, pivotToCamOS, depthBlended, + impostorNear, impostorFar, impostorRadius) * parallaxStrength; + parallaxOffset2 = ImpostorParallaxOffset(planeX2, planeY2, planeN2, pivotToCamOS, depthBlended, + impostorNear, impostorFar, impostorRadius) * parallaxStrength; float maxOffsetSq = max(max(dot(parallaxOffset0, parallaxOffset0), dot(parallaxOffset1, parallaxOffset1)), dot(parallaxOffset2, parallaxOffset2)); needsParallaxResample = maxOffsetSq > 0.00005; @@ -261,20 +302,25 @@ ImpostorResult impostor_frag(float3 worldPos) { result.albedo = blended.albedo; float3 normalOS = blended.normal.xyz * 2.0 - 1.0; + if (hasInstanceTransform) { + normalOS = qrotate(instanceRotation, normalOS); + } result.normal = normalize(mul((float3x3)unity_ObjectToWorld, normalOS)); result.metallic = blended.metallicGloss.r; result.smoothness = blended.metallicGloss.g; #if defined(_IMPOSTORS_DEPTH) - float3 offset0 = ReconstructObjectOffset(planeX0, planeY0, planeN0, finalUv0, depth0); - float3 offset1 = ReconstructObjectOffset(planeX1, planeY1, planeN1, finalUv1, depth1); - float3 offset2 = ReconstructObjectOffset(planeX2, planeY2, planeN2, finalUv2, depth2); + float3 offset0 = ReconstructObjectOffset(planeX0, planeY0, planeN0, finalUv0, depth0, + impostorNear, impostorFar, impostorRadius); + float3 offset1 = ReconstructObjectOffset(planeX1, planeY1, planeN1, finalUv1, depth1, + impostorNear, impostorFar, impostorRadius); + float3 offset2 = ReconstructObjectOffset(planeX2, planeY2, planeN2, finalUv2, depth2, + impostorNear, impostorFar, impostorRadius); result.objPos = offset0 * bw.x + offset1 * bw.y + offset2 * bw.z; #endif return result; -} - #endif // _IMPOSTORS +} #endif // __IMPOSTOR_INC diff --git a/instancing.cginc b/instancing.cginc index 6672db4..5ad3b23 100755 --- a/instancing.cginc +++ b/instancing.cginc @@ -48,6 +48,11 @@ float3 qrotate(float4 q, float3 v) { return v + q.w * t + cross(q.xyz, t); } +// Quaternion conjugate (inverse for unit quaternions) +float4 qconj(float4 q) { + return float4(-q.xyz, q.w); +} + // Create quaternion from Euler angles (in degrees) float4 euler_to_quat(float3 euler) { float3 rad = euler * 0.0174533; // deg to rad @@ -83,90 +88,114 @@ float4 compute_rotation(int x, int z) { return euler_to_quat(euler); } -#endif // _INSTANCE_TEXTURE_OFFSET +bool get_instance_transform(out float3 center, out float4 rotation, out float3 scale); -void instance_distance_culling(inout v2f i) { -#if defined(_INSTANCE_DISTANCE_CULLING) - // We want to measure the distance from the instance's transform to the camera. - float3 instance_pos = mul(unity_ObjectToWorld, float4(0, 0, 0, 1)).xyz; - float distance = length(_WorldSpaceCameraPos - instance_pos); - if (distance > _Instance_Distance_Culling_Distance) { - discard; - } -#endif // _INSTANCE_DISTANCE_CULLING +bool get_instance_center(out float3 center) { +#if defined(_INSTANCE_TEXTURE_OFFSET) && defined(UNITY_INSTANCING_ENABLED) + float4 rotation; + float3 scale; + return get_instance_transform(center, rotation, scale); +#else + center = 0; + return false; +#endif // _INSTANCE_TEXTURE_OFFSET && UNITY_INSTANCING_ENABLED } -void instancing_vert(inout appdata v) { +bool get_instance_transform(out float3 center, out float4 rotation, out float3 scale) { #if defined(_INSTANCE_TEXTURE_OFFSET) && defined(UNITY_INSTANCING_ENABLED) - // Extract instance ID from the matrix translation component - // We encoded it in the X translation (m03) on the CPU side - float encodedID = unity_ObjectToWorld[0][3]; - uint instanceID = (uint)encodedID; + uint instanceID = (uint)UNITY_ACCESS_INSTANCED_PROP(InstanceProps, _Instance_ID); - // Read grid coordinates from instance data texture - // _TexelSize.zw contains (width, height) float2 texDimensions = _Instance_Texture_Offset_Data_Tex_TexelSize.zw; int2 texCoord = int2(instanceID % (uint)texDimensions.x, instanceID / (uint)texDimensions.x); float2 uv = (float2(texCoord) + 0.5) / texDimensions; float4 instanceData = _Instance_Texture_Offset_Data_Tex.SampleLevel(point_repeat_s, uv, 0); - // Check if this is a valid instance (alpha >= 0) if (instanceData.w < 0) { - // Invalid instance - collapse to degenerate triangle far away - v.vertex.xyz = float3(0, -100000, 0); - return; + center = 0; + rotation = float4(0, 0, 0, 1); + scale = 1.0; + return false; } int3 gridCoord = int3(instanceData.xyz); - - // Compute hash values for randomization float h0, h1, h2, h3, h4; Hash5(gridCoord.x, gridCoord.z, h0, h1, h2, h3, h4); - // Base grid position float3 basePosition = float3( gridCoord.x * _Instance_Texture_Offset_Cell_Dimensions.x, gridCoord.y * _Instance_Texture_Offset_Cell_Dimensions.y, gridCoord.z * _Instance_Texture_Offset_Cell_Dimensions.z ); - // Add randomized offset within cell float3 positionOffset = float3( _Instance_Texture_Offset_Cell_Dimensions.x * h0, _Instance_Texture_Offset_Cell_Dimensions.y * h1, _Instance_Texture_Offset_Cell_Dimensions.z * h2 ); - // Compute random rotation from hash (in world space) + center = basePosition + positionOffset; + float4 randomRotation = compute_rotation(gridCoord.x, gridCoord.z); + rotation = qmul(randomRotation, _Instance_Texture_Offset_Base_Rotation); + + scale = _Instance_Texture_Offset_Base_Scale * (1.0 + h4 * _Instance_Texture_Offset_Scale_Randomization); + return true; +#else + center = 0; + rotation = float4(0, 0, 0, 1); + scale = 1.0; + return false; +#endif // _INSTANCE_TEXTURE_OFFSET && UNITY_INSTANCING_ENABLED +} - // Combine with base rotation: apply base rotation first, then world-space randomization - float4 finalRotation = qmul(randomRotation, _Instance_Texture_Offset_Base_Rotation); +#endif // _INSTANCE_TEXTURE_OFFSET - // Compute scale - float3 scale = _Instance_Texture_Offset_Base_Scale * (1.0 + h4 * _Instance_Texture_Offset_Scale_Randomization); +bool instance_distance_culling() { +#if defined(_INSTANCE_DISTANCE_CULLING) + float3 instance_pos; + +#if defined(_INSTANCE_TEXTURE_OFFSET) && defined(UNITY_INSTANCING_ENABLED) + if (!get_instance_center(instance_pos)) { + // Invalid instance, discard + return true; + } +#else + instance_pos = mul(unity_ObjectToWorld, float4(0, 0, 0, 1)).xyz; +#endif + + float distance = length(_WorldSpaceCameraPos - instance_pos); + if (distance < _Instance_Distance_Culling_Min_Distance || + distance > _Instance_Distance_Culling_Max_Distance) { + return true; + } +#endif // _INSTANCE_DISTANCE_CULLING + return false; +} + +void instancing_vert(inout appdata v) { +#if defined(_INSTANCE_TEXTURE_OFFSET) && defined(UNITY_INSTANCING_ENABLED) + float3 center; + float4 finalRotation; + float3 scale; + if (!get_instance_transform(center, finalRotation, scale)) { + // Invalid instance - collapse to degenerate triangle far away + v.vertex.xyz = float3(0, -100000, 0); + return; + } // Apply transform to vertex in object space float3 scaledVertex = v.vertex.xyz * scale; float3 rotatedVertex = qrotate(finalRotation, scaledVertex); - float3 transformedVertex = rotatedVertex + basePosition + positionOffset; - - // Compensate for the encoded offset that Unity will apply via the matrix - // Unity will add encodedID to X, so we subtract it here - transformedVertex.x -= encodedID; + float3 transformedVertex = rotatedVertex + center; // Update vertex position v.vertex.xyz = transformedVertex; - // Transform normal and tangent (only rotation, no scale - they're direction vectors) + // Transform normal and tangent v.normal = qrotate(finalRotation, v.normal); v.tangent.xyz = qrotate(finalRotation, v.tangent.xyz); #endif // _INSTANCE_TEXTURE_OFFSET } -void instancing_frag(v2f i) { - instance_distance_culling(i); -} - #endif // __INSTANCING_INC diff --git a/interpolators.cginc b/interpolators.cginc index 6611039..88a4649 100755 --- a/interpolators.cginc +++ b/interpolators.cginc @@ -32,7 +32,9 @@ struct v2f { float4 tangent : TEXCOORD6; UNITY_LIGHTING_COORDS(7,8) // TODO figure out some metaprogramming or preprocessor to better allocate optional texcoords :( -#if defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS) || defined(_VERTEX_DEFORMATION_TESSELLATION) +#if defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS) || \ + defined(_VERTEX_DEFORMATION_TESSELLATION) || \ + defined(_IMPOSTORS) && defined(_INSTANCE_TEXTURE_OFFSET) float3 objPos_orig : TEXCOORD9; #endif #if defined(_RAY_MARCHING_BAKED_ORIGINS) diff --git a/pbr.cginc b/pbr.cginc index b7392f7..c8e58c8 100755 --- a/pbr.cginc +++ b/pbr.cginc @@ -146,8 +146,6 @@ void apply_marble(float3 world_pos, inout float3 albedo) { Pbr getPbr(v2f i) { Pbr pbr = (Pbr) 0; - instancing_frag(i); - float3 n = normalize(i.normal); float3 t = normalize(i.tangent.xyz); t = normalize(t - n * dot(n, t)); // Gram-Schmidt to avoid skew @@ -172,7 +170,6 @@ Pbr getPbr(v2f i) { pbr.metallic = imp.metallic; #if defined(_IMPOSTORS_DEPTH) pbr.objPos = imp.objPos; - pbr.debug = imp.debug; #endif #else pbr.albedo = _MainTex.Sample(aniso16_trilinear_repeat_s, uv_parallax * _MainTex_ST.xy + _MainTex_ST.zw); diff --git a/vertex.cginc b/vertex.cginc index 77412a9..2e0c1dd 100755 --- a/vertex.cginc +++ b/vertex.cginc @@ -15,6 +15,7 @@ #define OPCODE_FBM 8 #define OPCODE_PLANE_TO_HEMI_OCTAHEDRON 9 #define OPCODE_HEMI_OCTAHEDRON_TO_PLANE 10 +#define OPCODE_SCALE 11 #if defined(_VERTEX_DEFORMATION) @@ -182,6 +183,19 @@ void apply_hemi_octahedron_to_plane_normal(inout float3 objPos, inout float3 obj hemi_octahedron_to_plane_normal(objPos, objNorm, objTan, p, r, s, t); } +void apply_scale(inout float3 objPos, float4 v0, float f0) { + float3 k = v0.xyz; + float t = f0; + objPos = scale(objPos, k, t); +} + +void apply_scale_normal(inout float3 objPos, inout float3 objNorm, + inout float3 objTan, float4 v0, float f0) { + float3 k = v0.xyz; + float t = f0; + scale_normal(objPos, objNorm, objTan, k, t); +} + void deform(inout float3 objPos) { const float t = getTime(); @@ -420,6 +434,9 @@ void deform(inout float3 objPos) { case OPCODE_HEMI_OCTAHEDRON_TO_PLANE: apply_hemi_octahedron_to_plane(objPos, v0, v1, v2, f0); break; + case OPCODE_SCALE: + apply_scale(objPos, v0, f0); + break; } } } @@ -665,6 +682,9 @@ void deform_normal(inout float3 objPos, inout float3 objNorm, inout float3 objTa case OPCODE_HEMI_OCTAHEDRON_TO_PLANE: apply_hemi_octahedron_to_plane_normal(objPos, objNorm, objTan, v0, v1, v2, f0); break; + case OPCODE_SCALE: + apply_scale_normal(objPos, objNorm, objTan, v0, f0); + break; } } } diff --git a/vertex_deformation.slang b/vertex_deformation.slang index 1cb002f..0c25d76 100755 --- a/vertex_deformation.slang +++ b/vertex_deformation.slang @@ -53,18 +53,6 @@ normal = mul(itjac, normal) * jac_det; \ tangent = mul(jacobian, tangent) * jac_det -#define R3R3_UNDEFORM_NORMAL_AND_TANGENT(normal, tangent) \ - float3x3 jacobian = float3x3( \ - float3(dp_x_out.d.x, dp_y_out.d.x, dp_z_out.d.x), \ - float3(dp_x_out.d.y, dp_y_out.d.y, dp_z_out.d.y), \ - float3(dp_x_out.d.z, dp_y_out.d.z, dp_z_out.d.z) \ - ); \ - float jac_det = determinant(jacobian); \ - float3x3 inv_jac = inverse(jacobian, jac_det); \ - float3x3 trans_jac = transpose(jacobian); \ - normal = mul(trans_jac, normal) * jac_det; \ - tangent = mul(inv_jac, tangent) * jac_det - // Syntactic sugar - wraps the previous three macros. #define R3R3_NORMALS(xyz, normal, tangent, fun, ...) \ R3R3_DECLARE_BASIS_VECTORS(xyz); \ @@ -111,7 +99,7 @@ public float3 plane_to_tube(float3 xyz, s_cart = normalize(s_cart); float3 rxs_cart = cross(s_cart, r_cart); float3x3 to_rsrxs = float3x3(r_cart, s_cart, rxs_cart); - // Ivnerse of orthonormal matrix is just the transpose. + // Inverse of orthonormal matrix is just the transpose. float3x3 to_cart = transpose(to_rsrxs); // Translate origin to `p` then change into (r, s, r x s) basis. @@ -154,13 +142,6 @@ public void plane_to_tube_normal(inout float3 xyz, inout float3 normal, R3R3_NORMALS(xyz, normal, tangent, plane_to_tube, p, r, s, t); } -public void plane_to_tube_undeform_normal(float3 xyz, inout float3 normal, - inout float3 tangent, float3 p, float3 r, float3 s, float t) { - R3R3_DECLARE_BASIS_VECTORS(xyz); - R3R3_AUTODIFF_BASIS_VECTORS(plane_to_tube, p, r, s, t); - R3R3_UNDEFORM_NORMAL_AND_TANGENT(normal, tangent); -} - [Differentiable] public float3 axis_align(float3 xyz, no_diff float3 po, no_diff float3 pp, no_diff float3 r, no_diff float t) { const float3 xyz0 = xyz; @@ -206,13 +187,6 @@ public void axis_align_normal(inout float3 xyz, inout float3 normal, R3R3_NORMALS(xyz, normal, tangent, axis_align, po, pp, r, t); } -public void axis_align_undeform_normal(float3 xyz, inout float3 normal, - inout float3 tangent, float3 po, float3 pp, float3 r, float t) { - R3R3_DECLARE_BASIS_VECTORS(xyz); - R3R3_AUTODIFF_BASIS_VECTORS(axis_align, po, pp, r, t); - R3R3_UNDEFORM_NORMAL_AND_TANGENT(normal, tangent); -} - // Maps a tube with circular cross section on the xz plane to a quad on the xy // plane. [Differentiable] @@ -274,14 +248,6 @@ public void tube_to_plane_normal(inout float3 xyz, inout float3 normal, R3R3_NORMALS(xyz, normal, tangent, tube_to_plane, p, r, s, t); } -public void tube_to_plane_undeform_normal( - float3 xyz, inout float3 normal, inout float3 tangent, - float3 p, float3 r, float3 s, float t) { - R3R3_DECLARE_BASIS_VECTORS(xyz); - R3R3_AUTODIFF_BASIS_VECTORS(tube_to_plane, p, r, s, t); - R3R3_UNDEFORM_NORMAL_AND_TANGENT(normal, tangent); -} - [Differentiable] public float3 point_align(float3 xyz, no_diff float3 po, no_diff float3 pp, no_diff float3 r, no_diff float t) { const float3 xyz0 = xyz; @@ -320,12 +286,6 @@ public void point_align_normal(inout float3 xyz, inout float3 normal, inout floa R3R3_NORMALS(xyz, normal, tangent, point_align, po, pp, r, t); } -public void point_align_undeform_normal(float3 xyz, inout float3 normal, inout float3 tangent, float3 po, float3 pp, float3 r, float t) { - R3R3_DECLARE_BASIS_VECTORS(xyz); - R3R3_AUTODIFF_BASIS_VECTORS(point_align, po, pp, r, t); - R3R3_UNDEFORM_NORMAL_AND_TANGENT(normal, tangent); -} - [Differentiable] public float3 seal(float3 xyz, no_diff float A, no_diff float k, no_diff float t) { float x = xyz.x; @@ -352,13 +312,6 @@ public void seal_normal(inout float3 xyz, inout float3 normal, R3R3_NORMALS(xyz, normal, tangent, seal, A, k, t); } -public void seal_undeform_normal(float3 xyz, inout float3 normal, - inout float3 tangent, float A, float k, float t) { - R3R3_DECLARE_BASIS_VECTORS(xyz); - R3R3_AUTODIFF_BASIS_VECTORS(seal, A, k, t); - R3R3_UNDEFORM_NORMAL_AND_TANGENT(normal, tangent); -} - [Differentiable] public float3 sine_wave(float3 xyz, no_diff float3 amplitude, @@ -375,14 +328,6 @@ public void sine_wave_normal(inout float3 xyz, inout float3 normal, inout float3 R3R3_NORMALS(xyz, normal, tangent, sine_wave, amplitude, direction, k, omega, t); } -public void sine_wave_undeform_normal(float3 xyz, inout float3 normal, - inout float3 tangent, float3 amplitude, float3 direction, float3 k, - float3 omega, float t) { - R3R3_DECLARE_BASIS_VECTORS(xyz); - R3R3_AUTODIFF_BASIS_VECTORS(sine_wave, amplitude, direction, k, omega, t); - R3R3_UNDEFORM_NORMAL_AND_TANGENT(normal, tangent); -} - [Differentiable] public float3 norm_conversion(float3 xyz, no_diff float input_k, no_diff float output_k, no_diff float t) { float3 xyz_abs = abs(xyz)+1e-4f; @@ -396,12 +341,6 @@ public void norm_conversion_normal(inout float3 xyz, inout float3 normal, inout R3R3_NORMALS(xyz, normal, tangent, norm_conversion, input_k, output_k, t); } -public void norm_conversion_undeform_normal(float3 xyz, inout float3 normal, inout float3 tangent, float input_k, float output_k, float t) { - R3R3_DECLARE_BASIS_VECTORS(xyz); - R3R3_AUTODIFF_BASIS_VECTORS(norm_conversion, input_k, output_k, t); - R3R3_UNDEFORM_NORMAL_AND_TANGENT(normal, tangent); -} - [Differentiable] float3 rand3_hash3(float3 p) { @@ -544,24 +483,6 @@ public void fbm_normal(inout float3 xyz, inout float3 normal, inout float3 tange tangent = mul(jac, tangent); } -public void fbm_undeform_normal(float3 xyz, float t, - float3 amplitude, float gain, float lacunarity, - float3 period, float octaves, float3 velocity, - inout float3 normal, inout float3 tangent) { - float3 dx, dy, dz; - fbm_with_derivatives(xyz, t, amplitude, gain, lacunarity, period, octaves, - velocity, dx, dy, dz); - float3x3 jac = float3x3( - dx.x, dy.x, dz.x, - dx.y, dy.y, dz.y, - dx.z, dy.z, dz.z); - float jac_det = determinant(jac); - float3x3 inv_jac = inverse(jac, jac_det); - float3x3 trans_jac = transpose(jac); - normal = mul(trans_jac, normal) * jac_det; - tangent = mul(inv_jac, tangent); -} - // Maps a plane to a hemi-octahedron (half octahedron). // Uses octahedral parameterization consistent with pbrt's OctahedralVector. // Input: plane on [-1,1]² in the (r, rxs) plane @@ -618,13 +539,6 @@ public void plane_to_hemi_octahedron_normal(inout float3 xyz, inout float3 norma R3R3_NORMALS(xyz, normal, tangent, plane_to_hemi_octahedron, p, r, s, t); } -public void plane_to_hemi_octahedron_undeform_normal(float3 xyz, inout float3 normal, - inout float3 tangent, float3 p, float3 r, float3 s, float t) { - R3R3_DECLARE_BASIS_VECTORS(xyz); - R3R3_AUTODIFF_BASIS_VECTORS(plane_to_hemi_octahedron, p, r, s, t); - R3R3_UNDEFORM_NORMAL_AND_TANGENT(normal, tangent); -} - // Maps a hemi-octahedron to a plane (inverse of plane_to_hemi_octahedron). // Input: unit hemisphere with pole at +s direction // Output: plane on [-1,1]² in the (r, rxs) plane @@ -676,11 +590,16 @@ public void hemi_octahedron_to_plane_normal(inout float3 xyz, inout float3 norma R3R3_NORMALS(xyz, normal, tangent, hemi_octahedron_to_plane, p, r, s, t); } -public void hemi_octahedron_to_plane_undeform_normal(float3 xyz, inout float3 normal, - inout float3 tangent, float3 p, float3 r, float3 s, float t) { - R3R3_DECLARE_BASIS_VECTORS(xyz); - R3R3_AUTODIFF_BASIS_VECTORS(hemi_octahedron_to_plane, p, r, s, t); - R3R3_UNDEFORM_NORMAL_AND_TANGENT(normal, tangent); +[Differentiable] +public float3 scale(float3 xyz, + no_diff float3 k, no_diff float t) { + return dlerp(xyz, xyz * k, t); +} + +public void scale_normal(inout float3 xyz, inout float3 normal, + inout float3 tangent, float3 k, float t) { + R3R3_NORMALS(xyz, normal, tangent, scale, k, t); } #endif // __CUSTOM31_INC + -- cgit v1.2.3