diff options
Diffstat (limited to 'Scripts')
| -rw-r--r-- | Scripts/GrassGridBlit.shader | 77 | ||||
| -rwxr-xr-x | Scripts/InstanceGrass.asset | 1265 | ||||
| -rwxr-xr-x | Scripts/InstanceGrass.cs | 343 | ||||
| -rwxr-xr-x | Scripts/InstanceGrass.cs.meta | 11 |
4 files changed, 1696 insertions, 0 deletions
diff --git a/Scripts/GrassGridBlit.shader b/Scripts/GrassGridBlit.shader new file mode 100644 index 0000000..f4dc872 --- /dev/null +++ b/Scripts/GrassGridBlit.shader @@ -0,0 +1,77 @@ +Shader "yum_food/GrassGridBlit" +{ + Properties + { + } + SubShader + { + Tags { "RenderType"="Opaque" } + LOD 100 + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + // Grid parameters + float3 _PlayerGridPos; // Player's grid cell position (x, y, z) + int3 _GridCount; // Number of instances along each axis + int3 _GridHalf; // Half dimensions for centering around player + int2 _TexDimensions; // Texture width and height + + v2f vert (appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = v.uv; + return o; + } + + float4 frag (v2f i) : SV_Target + { + // Convert UV to pixel coordinates + int2 pixelCoord = int2(i.uv.x * _TexDimensions.x, i.uv.y * _TexDimensions.y); + + // Convert pixel coordinate to instance index + int instanceID = pixelCoord.x + pixelCoord.y * _TexDimensions.x; + + // Calculate total valid instances + int totalInstances = _GridCount.x * _GridCount.y * _GridCount.z; + + // If this pixel is beyond valid instances, output invalid marker + if (instanceID >= totalInstances) { + return float4(0, 0, 0, -1); // Alpha = -1 marks invalid + } + + // Convert instance index to local grid coordinates (0 to GridCount-1) + int localX = instanceID % _GridCount.x; + int localY = (instanceID / _GridCount.x) % _GridCount.y; + int localZ = instanceID / (_GridCount.x * _GridCount.y); + + // Convert to world grid coordinates centered around player + int worldX = _PlayerGridPos.x - _GridHalf.x + localX; + int worldY = _PlayerGridPos.y - _GridHalf.y + localY; + int worldZ = _PlayerGridPos.z - _GridHalf.z + localZ; + + // Store world grid coordinates in RGB channels, alpha = 0 marks valid + return float4(worldX, worldY, worldZ, 0); + } + ENDCG + } + } +} diff --git a/Scripts/InstanceGrass.asset b/Scripts/InstanceGrass.asset new file mode 100755 index 0000000..3dd3bc4 --- /dev/null +++ b/Scripts/InstanceGrass.asset @@ -0,0 +1,1265 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c333ccfdd0cbdbc4ca30cef2dd6e6b9b, type: 3} + m_Name: InstanceGrass + m_EditorClassIdentifier: + serializedUdonProgramAsset: {fileID: 11400000, guid: db135bbe94c59ac45866d438c8479426, + type: 2} + udonAssembly: + assemblyError: + sourceCsScript: {fileID: 11500000, guid: 8dd03d28500e21640aad6c2650091d4c, type: 3} + scriptVersion: 2 + compiledVersion: 2 + behaviourSyncMode: 0 + hasInteractEvent: 0 + scriptID: -6812178109815128089 + serializationData: + SerializedFormat: 2 + SerializedBytes: + ReferencedUnityObjects: [] + SerializedBytesString: + Prefab: {fileID: 0} + PrefabModificationsReferencedUnityObjects: [] + PrefabModifications: [] + SerializationNodes: + - Name: fieldDefinitions + Entry: 7 + Data: 0|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[UdonSharp.Compiler.FieldDefinition, + UdonSharp.Editor]], mscorlib + - Name: comparer + Entry: 7 + Data: 1|System.Collections.Generic.GenericEqualityComparer`1[[System.String, + mscorlib]], mscorlib + - Name: + Entry: 8 + Data: + - Name: + Entry: 12 + Data: 23 + - Name: + Entry: 7 + Data: + - Name: $k + Entry: 1 + Data: prefab_ + - Name: $v + Entry: 7 + Data: 2|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: prefab_ + - Name: <UserType>k__BackingField + Entry: 7 + Data: 3|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: UnityEngine.GameObject, UnityEngine.CoreModule + - Name: + Entry: 8 + Data: + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 3 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: true + - Name: _fieldAttributes + Entry: 7 + Data: 4|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 1 + - Name: + Entry: 7 + Data: 5|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: density_ + - Name: $v + Entry: 7 + Data: 6|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: density_ + - Name: <UserType>k__BackingField + Entry: 7 + Data: 7|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: System.Single, mscorlib + - Name: + Entry: 8 + Data: + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 7 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: true + - Name: _fieldAttributes + Entry: 7 + Data: 8|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 1 + - Name: + Entry: 7 + Data: 9|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: extent_meters_ + - Name: $v + Entry: 7 + Data: 10|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: extent_meters_ + - Name: <UserType>k__BackingField + Entry: 7 + Data: 11|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: UnityEngine.Vector3, UnityEngine.CoreModule + - Name: + Entry: 8 + Data: + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 11 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: true + - Name: _fieldAttributes + Entry: 7 + Data: 12|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 1 + - Name: + Entry: 7 + Data: 13|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: 14|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: angle_randomization_ + - Name: <UserType>k__BackingField + Entry: 9 + Data: 11 + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 11 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>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: scale_randomization_ + - Name: $v + Entry: 7 + Data: 17|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: scale_randomization_ + - Name: <UserType>k__BackingField + Entry: 9 + Data: 7 + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 7 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: true + - Name: _fieldAttributes + Entry: 7 + Data: 18|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 1 + - Name: + Entry: 7 + Data: 19|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: max_grid_size_ + - Name: $v + Entry: 7 + Data: 20|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: max_grid_size_ + - Name: <UserType>k__BackingField + Entry: 7 + Data: 21|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: UnityEngine.Vector3Int, UnityEngine.CoreModule + - Name: + Entry: 8 + Data: + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 21 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: true + - Name: _fieldAttributes + Entry: 7 + Data: 22|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 1 + - Name: + Entry: 7 + Data: 23|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: blit_material_ + - Name: $v + Entry: 7 + Data: 24|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: blit_material_ + - Name: <UserType>k__BackingField + Entry: 7 + Data: 25|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: UnityEngine.Material, UnityEngine.CoreModule + - Name: + Entry: 8 + Data: + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 25 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: true + - Name: _fieldAttributes + Entry: 7 + Data: 26|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 1 + - Name: + Entry: 7 + Data: 27|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: mesh_ + - Name: $v + Entry: 7 + Data: 28|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: mesh_ + - Name: <UserType>k__BackingField + Entry: 7 + Data: 29|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: UnityEngine.Mesh, UnityEngine.CoreModule + - Name: + Entry: 8 + Data: + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 29 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 30|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_material_ + - Name: $v + Entry: 7 + Data: 31|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: instance_material_ + - Name: <UserType>k__BackingField + Entry: 9 + Data: 25 + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 25 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 32|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: base_transform_ + - Name: $v + Entry: 7 + Data: 33|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: base_transform_ + - Name: <UserType>k__BackingField + Entry: 7 + Data: 34|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: UnityEngine.Transform, UnityEngine.CoreModule + - Name: + Entry: 8 + Data: + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 34 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 35|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: cell_dim_ + - Name: $v + Entry: 7 + Data: 36|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: cell_dim_ + - Name: <UserType>k__BackingField + Entry: 9 + Data: 11 + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 11 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 37|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: inv_cell_dim_ + - Name: $v + Entry: 7 + Data: 38|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: inv_cell_dim_ + - Name: <UserType>k__BackingField + Entry: 9 + Data: 11 + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 11 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 39|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: count_ + - Name: $v + Entry: 7 + Data: 40|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: count_ + - Name: <UserType>k__BackingField + Entry: 9 + Data: 21 + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 21 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 41|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: total_instances_ + - Name: $v + Entry: 7 + Data: 42|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: total_instances_ + - Name: <UserType>k__BackingField + Entry: 7 + Data: 43|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: System.Int32, mscorlib + - Name: + Entry: 8 + Data: + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 43 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 44|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: initialized_ + - Name: $v + Entry: 7 + Data: 45|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: initialized_ + - Name: <UserType>k__BackingField + Entry: 7 + Data: 46|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: System.Boolean, mscorlib + - Name: + Entry: 8 + Data: + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 46 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 47|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: density_live_ + - Name: $v + Entry: 7 + Data: 48|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: density_live_ + - Name: <UserType>k__BackingField + Entry: 9 + Data: 7 + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 7 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 49|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: extent_meters_live_ + - Name: $v + Entry: 7 + Data: 50|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: extent_meters_live_ + - Name: <UserType>k__BackingField + Entry: 9 + Data: 11 + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 11 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 51|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: angle_randomization_live_ + - Name: $v + Entry: 7 + Data: 52|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: angle_randomization_live_ + - Name: <UserType>k__BackingField + Entry: 9 + Data: 11 + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 11 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 53|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: scale_randomization_live_ + - Name: $v + Entry: 7 + Data: 54|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: scale_randomization_live_ + - Name: <UserType>k__BackingField + Entry: 9 + Data: 7 + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 7 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 55|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_data_tex_ + - Name: $v + Entry: 7 + Data: 56|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: instance_data_tex_ + - Name: <UserType>k__BackingField + Entry: 7 + Data: 57|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: UnityEngine.RenderTexture, UnityEngine.CoreModule + - Name: + Entry: 8 + Data: + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 57 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 58|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: identity_transforms_ + - Name: $v + Entry: 7 + Data: 59|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: identity_transforms_ + - Name: <UserType>k__BackingField + Entry: 7 + Data: 60|System.RuntimeType, mscorlib + - Name: + Entry: 1 + Data: UnityEngine.Matrix4x4[], UnityEngine.CoreModule + - Name: + Entry: 8 + Data: + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 60 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 61|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: tex_width_ + - Name: $v + Entry: 7 + Data: 62|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: tex_width_ + - Name: <UserType>k__BackingField + Entry: 9 + Data: 43 + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 43 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 63|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: tex_height_ + - Name: $v + Entry: 7 + Data: 64|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor + - Name: <Name>k__BackingField + Entry: 1 + Data: tex_height_ + - Name: <UserType>k__BackingField + Entry: 9 + Data: 43 + - Name: <SystemType>k__BackingField + Entry: 9 + Data: 43 + - Name: <SyncMode>k__BackingField + Entry: 7 + Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib + - Name: + Entry: 6 + Data: + - Name: + Entry: 8 + Data: + - Name: <IsSerialized>k__BackingField + Entry: 5 + Data: false + - Name: _fieldAttributes + Entry: 7 + Data: 65|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: 13 + Data: + - Name: + Entry: 8 + Data: diff --git a/Scripts/InstanceGrass.cs b/Scripts/InstanceGrass.cs new file mode 100755 index 0000000..3c0d8f6 --- /dev/null +++ b/Scripts/InstanceGrass.cs @@ -0,0 +1,343 @@ +using UdonSharp; +using UnityEngine; +using VRC.SDKBase; + +#if UNITY_EDITOR && !COMPILER_UDONSHARP +using UnityEditor; +using System.IO; +#endif + +public class InstanceGrass : UdonSharpBehaviour +{ + [SerializeField] public GameObject prefab_; + // The density of instances, in instances per meter. + [SerializeField] public float density_; + // 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 Vector3 angle_randomization_; + [SerializeField] public float scale_randomization_; + + // GPU mode settings + [SerializeField] public Vector3Int max_grid_size_ = new Vector3Int(512, 1, 512); // Maximum grid dimensions for GPU mode + [SerializeField] public Material blit_material_; // Auto-generated in editor, set by custom editor + + private Mesh mesh_; + private Material instance_material_; // Extracted from prefab + private Transform base_transform_; + private Vector3 cell_dim_; + private Vector3 inv_cell_dim_; + private Vector3Int count_; + private int total_instances_; + private bool initialized_; + + // Track fields to detect runtime changes. + private float density_live_; + private Vector3 extent_meters_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 int tex_width_; + private int tex_height_; + + private void Init() { + // Extract components from prefab. + if (prefab_ != null) { + MeshFilter mesh_filter = prefab_.GetComponent<MeshFilter>(); + if (mesh_filter == null && prefab_.transform.childCount > 0) { + mesh_filter = prefab_.GetComponentInChildren<MeshFilter>(); + } + if (mesh_filter != null) { + mesh_ = mesh_filter.sharedMesh; + if (mesh_ == null) { + mesh_ = mesh_filter.mesh; + } + } else { + Debug.LogError("[Grass::Debug] Could not find MeshFilter on prefab or children."); + } + + MeshRenderer mesh_renderer = prefab_.GetComponent<MeshRenderer>(); + if (mesh_renderer == null && prefab_.transform.childCount > 0) { + mesh_renderer = prefab_.GetComponentInChildren<MeshRenderer>(); + } + if (mesh_renderer != null) { + Material[] materials = mesh_renderer.sharedMaterials; + if (materials != null && materials.Length > 0) { + instance_material_ = materials[0]; + } else { + Debug.LogError("[Grass::Debug] MeshRenderer has no materials."); + } + } else { + Debug.LogError("[Grass::Debug] Could not find MeshRenderer on prefab."); + } + + base_transform_ = prefab_.transform; + Debug.Log($"[Grass::Debug] Prefab transform - pos:{base_transform_.position}, rot:{base_transform_.rotation.eulerAngles}, scale:{base_transform_.localScale}"); + } else { + Debug.LogError("[Grass::Debug] prefab is null in Init()."); + } + + density_ = Mathf.Max(1e-6f, density_); + extent_meters_ = Vector3.Max(Vector3.one * 1e-6f, extent_meters_); + angle_randomization_ = new Vector3( + Mathf.Clamp(angle_randomization_.x, 0f, 180f), + Mathf.Clamp(angle_randomization_.y, 0f, 180f), + Mathf.Clamp(angle_randomization_.z, 0f, 180f)); + + // Use max_grid_size_ directly for GPU mode + count_ = Vector3Int.Min(max_grid_size_, new Vector3Int( + Mathf.Max(1, Mathf.RoundToInt(density_ * extent_meters_.x)), + Mathf.Max(1, Mathf.RoundToInt(density_ * extent_meters_.y)), + Mathf.Max(1, Mathf.RoundToInt(density_ * extent_meters_.z)))); + + cell_dim_ = new Vector3( + extent_meters_.x / count_.x, + extent_meters_.y / count_.y, + extent_meters_.z / count_.z); + inv_cell_dim_ = new Vector3( + 1f / cell_dim_.x, + 1f / cell_dim_.y, + 1f / cell_dim_.z); + + total_instances_ = count_.x * count_.y * count_.z; + + // Calculate texture dimensions (power of 2, minimum 256x256) + int min_tex_size = Mathf.CeilToInt(Mathf.Sqrt(total_instances_)); + tex_width_ = Mathf.Max(256, Mathf.NextPowerOfTwo(min_tex_size)); + tex_height_ = tex_width_; + + // Create instance data texture + if (instance_data_tex_ != null) { + instance_data_tex_.Release(); + } + instance_data_tex_ = new RenderTexture(tex_width_, tex_height_, 0, RenderTextureFormat.ARGBFloat); + 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; + } + } + + if (mesh_ != null) { + // Set huge bounds so culling doesn't interfere + mesh_.bounds = new Bounds(Vector3.zero, Vector3.one * 10000f); + } + + density_live_ = density_; + extent_meters_live_ = extent_meters_; + angle_randomization_live_ = angle_randomization_; + scale_randomization_live_ = scale_randomization_; + + Debug.Log($"[Grass::Debug] Init: density={density_}, extent={extent_meters_}, count={count_}, cell_dim={cell_dim_}, instances={total_instances_}, tex={tex_width_}x{tex_height_}, scale={base_transform_.localScale}, rot={base_transform_.localRotation.eulerAngles}"); + Debug.Log($"[Grass::Debug] Init details: count_.x={count_.x}, count_.y={count_.y}, count_.z={count_.z}, extent.x={extent_meters_.x}, extent.z={extent_meters_.z}"); + } + + private bool Valid() { + if (prefab_ == null) { + Debug.LogError("[Grass::Debug] prefab is null."); + return false; + } + if (mesh_ == null) { + Debug.LogError("[Grass::Debug] mesh is null."); + return false; + } + if (instance_material_ == null) { + Debug.LogError("[Grass::Debug] instance_material is null."); + return false; + } + if (blit_material_ == null) { + Debug.LogError("[Grass::Debug] blit_material is null (failed to generate)."); + return false; + } + if (instance_data_tex_ == null) { + Debug.LogError("[Grass::Debug] instance_data_tex is null."); + return false; + } + return true; + } + + void Start() { + Init(); + if (!Valid()) { + return; + } + + initialized_ = true; + Debug.Log($"[Grass::Debug] GPU mode initialized"); + } + + void Update() { + // Reinitialize if any config changed at runtime. + if (density_ != density_live_ || + extent_meters_ != extent_meters_live_ || + angle_randomization_ != angle_randomization_live_ || + scale_randomization_ != scale_randomization_live_) { + Init(); + initialized_ = false; + } + + if (!Valid()) { + return; + } + + 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); + + int half_x = count_.x / 2; + int half_y = count_.y / 2; + int half_z = count_.z / 2; + + // Update blit material properties + blit_material_.SetVector("_PlayerGridPos", new Vector3(grid_x, grid_y, grid_z)); + blit_material_.SetVector("_GridCount", new Vector3(count_.x, count_.y, count_.z)); + blit_material_.SetVector("_GridHalf", new Vector3(half_x, half_y, half_z)); + blit_material_.SetVector("_TexDimensions", new Vector2(tex_width_, tex_height_)); + + // Blit to generate instance data texture + VRCGraphics.Blit(null, instance_data_tex_, blit_material_); + + // Update instance material properties + instance_material_.SetTexture("_Instance_Texture_Offset_Data_Tex", instance_data_tex_); + instance_material_.SetVector("_Instance_Texture_Offset_Cell_Dimensions", cell_dim_); + instance_material_.SetVector("_Instance_Texture_Offset_Angle_Randomization", angle_randomization_); + instance_material_.SetFloat("_Instance_Texture_Offset_Scale_Randomization", scale_randomization_); + instance_material_.SetVector("_Instance_Texture_Offset_Base_Scale", base_transform_.localScale); + + // Pass rotation as quaternion (x, y, z, w) + Quaternion rot = base_transform_.localRotation; + instance_material_.SetVector("_Instance_Texture_Offset_Base_Rotation", new Vector4(rot.x, rot.y, rot.z, rot.w)); + + 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, + UnityEngine.Rendering.ShadowCastingMode.Off, + true, + 0, + null, + UnityEngine.Rendering.LightProbeUsage.Off, + null); + + initialized_ = true; + } + + void OnDestroy() { + if (instance_data_tex_ != null) { + instance_data_tex_.Release(); + } + } +} + +#if UNITY_EDITOR && !COMPILER_UDONSHARP +[CustomEditor(typeof(InstanceGrass))] +public class InstanceGrassEditor : Editor +{ + public override void OnInspectorGUI() + { + DrawDefaultInspector(); + + InstanceGrass script = (InstanceGrass)target; + + // Auto-generate blit material if missing + if (script.blit_material_ == null) + { + if (GUILayout.Button("Generate Blit Material")) + { + GenerateBlitMaterial(script); + } + + EditorGUILayout.HelpBox("Blit material is missing. Click the button above to auto-generate it.", MessageType.Warning); + } + else + { + EditorGUILayout.HelpBox("Blit material is set. GPU instancing ready.", MessageType.Info); + } + } + + private void GenerateBlitMaterial(InstanceGrass script) + { + Shader blitShader = Shader.Find("yum_food/GrassGridBlit"); + if (blitShader == null) + { + EditorUtility.DisplayDialog("Error", "Could not find shader 'yum_food/GrassGridBlit'. Make sure GrassGridBlit.shader is imported.", "OK"); + return; + } + + string assetPath = "Assets/yum_food/3ner/Grass_Generated/Grass_generated.mat"; + + // Create or load existing material + Material blitMat = AssetDatabase.LoadAssetAtPath<Material>(assetPath); + if (blitMat == null) + { + // Create new material + blitMat = new Material(blitShader); + blitMat.name = "Grass_generated"; + + // Ensure directory exists + string directory = Path.GetDirectoryName(assetPath); + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + AssetDatabase.CreateAsset(blitMat, assetPath); + Debug.Log($"[Grass::Editor] Created blit material at {assetPath}"); + } + else + { + // Update existing material shader + blitMat.shader = blitShader; + EditorUtility.SetDirty(blitMat); + Debug.Log($"[Grass::Editor] Updated existing blit material at {assetPath}"); + } + + script.blit_material_ = blitMat; + EditorUtility.SetDirty(script); + AssetDatabase.SaveAssets(); + } + + [UnityEditor.Callbacks.DidReloadScripts] + private static void OnScriptsReloaded() + { + // Auto-generate blit material for all InstanceGrass components when scripts reload + InstanceGrass[] allGrass = FindObjectsOfType<InstanceGrass>(); + foreach (var grass in allGrass) + { + if (grass.blit_material_ == null) + { + var editor = CreateEditor(grass) as InstanceGrassEditor; + if (editor != null) + { + editor.GenerateBlitMaterial(grass); + DestroyImmediate(editor); + } + } + } + } +} +#endif diff --git a/Scripts/InstanceGrass.cs.meta b/Scripts/InstanceGrass.cs.meta new file mode 100755 index 0000000..58e03e6 --- /dev/null +++ b/Scripts/InstanceGrass.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8dd03d28500e21640aad6c2650091d4c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: |
