float4x4 _VPMatrix; float _MaxDrawDistance; uint _StartOffset; StructuredBuffer<float3> _AllInstancesPosWSBuffer; //will not change until instance count change AppendStructuredBuffer<uint> _VisibleInstancesOnlyPosWSIDBuffer; //will set counter to 0 per frame, then fill in by this compute shader
//do culling test in clip space, result is the same as doing test in NDC space. //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. //the test is using OpenGL standard projection matrix, because all matrix from unity C# is OpenGL standard //if instance is inside camera frustum, and is within draw distance, we append it to _VisibleInstanceOnlyTransformBuffer //y test allow 50% more threshold (hardcode for grass) //x test allow 10% more threshold (hardcode for grass) if (absPosCS.z <= absPosCS.w && absPosCS.y <= absPosCS.w*1.5 && absPosCS.x <= absPosCS.w*1.1 && absPosCS.w <= _MaxDrawDistance) _VisibleInstancesOnlyPosWSIDBuffer.Append(id.x + _StartOffset); }
// A buffer containing the generated mesh StructuredBuffer<DrawTriangle> _DrawTriangles;
// -- retrieve data generated from compute shader v2f vert(uint vertexID : SV_VertexID) { // Initialize the output struct v2f output = (v2f)0; // Get the vertex from the buffer // Since the buffer is structured in triangles, we need to divide the vertexID by three // to get the triangle, and then modulo by 3 to get the vertex on the triangle DrawTriangle tri = _DrawTriangles[vertexID / 3]; DrawVertex input = tri.vertices[vertexID % 3]; output.positionCS = TransformWorldToHClip(input.positionWS); output.positionWS = input.positionWS; float3 faceNormal = GetMainLight().direction * tri.normalOS; output.normalWS = TransformObjectToWorldNormal(faceNormal, true); float fogFactor = ComputeFogFactor(output.positionCS.z); output.fogFactor = fogFactor; output.uv = input.uv; output.diffuseColor = input.diffuseColor; return output; }