Skip to content

Commit 8ef84a1

Browse files
+CPU per cell frustum culling, can render 10M grass on adreno612 now
1 parent 01e3adb commit 8ef84a1

File tree

6 files changed

+248
-80
lines changed

6 files changed

+248
-80
lines changed

Assets/URPMobileGrassInstancedIndirectDemo/InstancedIndirectGrass/Core/CullingCompute.compute

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
//cullingComputeShader.SetMatrix("_VPMatrix", p * v); //set from C#
66
float4x4 _VPMatrix;
77
float _MaxDrawDistance;
8-
StructuredBuffer<float3> _AllInstancesTransformBuffer; //will not change until instance count change
9-
AppendStructuredBuffer<uint> _VisibleInstanceOnlyTransformIDBuffer; //will set counter to 0 per frame, then fill in by this compute shader
8+
uint _StartOffset;
9+
StructuredBuffer<float3> _AllInstancesPosWSBuffer; //will not change until instance count change
10+
AppendStructuredBuffer<uint> _VisibleInstancesOnlyPosWSIDBuffer; //will set counter to 0 per frame, then fill in by this compute shader
1011

11-
[numthreads(1024,1,1)]
12+
[numthreads(64,1,1)]
1213
void CSMain (uint3 id : SV_DispatchThreadID)
1314
{
1415
//posWS -> posCS
15-
float4 absPosCS = abs(mul(_VPMatrix,float4(_AllInstancesTransformBuffer[id.x],1.0)));
16+
float4 absPosCS = abs(mul(_VPMatrix,float4(_AllInstancesPosWSBuffer[id.x + _StartOffset],1.0)));
1617

1718
//do culling test in clip space, result is the same as doing test in NDC space.
1819
//prefer clip space here because doing culling test in clip space is faster than doing culling test in NDC, because we can skip 1 division.
@@ -21,5 +22,5 @@ void CSMain (uint3 id : SV_DispatchThreadID)
2122
//y test allow 50% more threshold (hardcode for grass)
2223
//x test allow 10% more threshold (hardcode for grass)
2324
if (absPosCS.z <= absPosCS.w && absPosCS.y <= absPosCS.w*1.5 && absPosCS.x <= absPosCS.w*1.1 && absPosCS.w <= _MaxDrawDistance)
24-
_VisibleInstanceOnlyTransformIDBuffer.Append(id.x);
25+
_VisibleInstancesOnlyPosWSIDBuffer.Append(id.x + _StartOffset);
2526
}

Assets/URPMobileGrassInstancedIndirectDemo/InstancedIndirectGrass/Core/InstancedIndirectGrass.mat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ Material:
9292
- _ZWrite: 1
9393
m_Colors:
9494
- _BaseColor: {r: 0.41936636, g: 0.7169812, b: 0.29423285, a: 1}
95-
- _BoundSize: {r: 55.9017, g: 55.9017, b: 0, a: 0}
95+
- _BoundSize: {r: 661.4378, g: 661.4378, b: 0, a: 0}
9696
- _Color: {r: 1, g: 1, b: 1, a: 1}
9797
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
9898
- _GroundColor: {r: 0.2195755, g: 0.46226418, b: 0.2581851, a: 1}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
5+
public class InstancedIndirectGrassPosDefine : MonoBehaviour
6+
{
7+
[Range(1, 40000000)]
8+
public int instanceCount = 1000000;
9+
public float drawDistance = 125;
10+
11+
int cacheCount = -1;
12+
13+
// Start is called before the first frame update
14+
void Start()
15+
{
16+
UpdatePosIfNeeded();
17+
}
18+
19+
private void UpdatePosIfNeeded()
20+
{
21+
if (instanceCount == cacheCount)
22+
return;
23+
24+
Debug.Log("UpdatePos (Slow)");
25+
26+
//same seed to keep grass visual the same
27+
UnityEngine.Random.InitState(123);
28+
29+
//auto keep density the same
30+
float scale = Mathf.Sqrt((instanceCount / 4)) / 2f;
31+
transform.localScale = new Vector3(scale, transform.localScale.y, scale);
32+
33+
//////////////////////////////////////////////////////////////////////////
34+
//can define any posWS in this section, random is just an example
35+
//////////////////////////////////////////////////////////////////////////
36+
List<Vector3> positions = new List<Vector3>(instanceCount);
37+
for (int i = 0; i < instanceCount; i++)
38+
{
39+
Vector3 pos = Vector3.zero;
40+
41+
pos.x = UnityEngine.Random.Range(-1f, 1f) * transform.lossyScale.x;
42+
pos.z = UnityEngine.Random.Range(-1f, 1f) * transform.lossyScale.z;
43+
44+
//transform to posWS in C#
45+
pos += transform.position;
46+
47+
positions.Add(new Vector3(pos.x, pos.y, pos.z));
48+
}
49+
50+
//send all posWS to renderer
51+
InstancedIndirectGrassRenderer.instance.allGrassPos = positions;
52+
cacheCount = positions.Count;
53+
}
54+
private void Update()
55+
{
56+
UpdatePosIfNeeded();
57+
}
58+
private void OnGUI()
59+
{
60+
GUI.Label(new Rect(300, 50, 200, 30), "Instance Count: " + instanceCount/1000000 + "Million");
61+
instanceCount = Mathf.Max(1, (int)(GUI.HorizontalSlider(new Rect(300, 100, 200, 30), instanceCount / 1000000f, 1, 10)) * 1000000);
62+
63+
GUI.Label(new Rect(300, 150, 200, 30), "Draw Distance: " + drawDistance);
64+
drawDistance = Mathf.Max(1, (int)(GUI.HorizontalSlider(new Rect(300, 200, 200, 30), drawDistance / 25f, 1, 8)) * 25);
65+
InstancedIndirectGrassRenderer.instance.drawDistance = drawDistance;
66+
}
67+
}

Assets/URPMobileGrassInstancedIndirectDemo/InstancedIndirectGrass/Core/InstancedIndirectGrassPosDefine.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)