Friday, February 23, 2024

GPU Instanced Grass in Unity - Part 4

 

GPU Instanced Grass in Unity


For the original post, please go to https://www.yuque.com/qwerasdwww/dfy5xd


Part 4: Optimization Grass with Frustum Culling




Now, the grass will be rendered in the whole plane, but we only need to render it inside the camera.

Since we are working on GPU, we can do the culling in the compute shader.


In the C# script, we declare a new boolean to determine whether to use furstum culling and two Vector3 values for the grass bounding box.




In previous part, we initialize our clumpsBuffer inside InitMaterialParameters().

We need to create another coumput buffer to store the unculled data, and let the previous compute buffer be the buffer that store the instance data after culling.

Now, we are having two compute buffers, so we can take that part out and create a new function called InitDefaultBuffer() to initialize it.

We use a macro "UseFrustumCulling" and disable it when not using frustum culling.



Now we create a function to initialize buffers we need to store the data after culling. The buffer type is AppendBuffer.

We write the grass bounding box data into the compute shader and enable the macro "UseFrustumCulling".




So in the Start() function, if we are not using fustum culling, then we initalize the clumpsBuffer as usual.

If we are using frustum culling, the we use clumpsRawBuffer to store the unculled data, and use clumpsBuffer to store the data after culling.




Now we finish the prepare work in C# script, we shall move on to the compute shader.

First we define the macro at the very beginning. 



Add we need to write the buffer and corresponding data into the shader.




If we are using furstum culling, then the buffer we use to do the calculation is clumpsRawBuffer, and use append to add clump instance into the buffer.

The count is to make sure the index is less than the size of the compute buffer.




Now the prepare work is done. Let's start the frustum culling.

We can do the culling in the world space or the clip space

Method 1: In the world space, for each grass instance, determine whether the vertices of grass bounding box is inside the frustum.

Let's first define the function for plane. There are two ways to define a plane. A point and a normal vector or three points.



Now let's get the four vertices of the camera far clipping plane. With camera FOV and aspect of ratio, it is easy to calcualte the position of the four vertices.



 

Every two adjenct vertices on the far clipping plane and the camera position will form a plane.

We then use point on the far plane and near plane and the camera forward to create the far and near plane.



Now we have the six planes of the frustum, we write them into the compute shader and declare the array inside the compute shader.



In the compute shader, we also create a method to determine whether a point is outside a plane.



Now for every grass instance, we determine whether its bounding box is inside each frustum plane.



Since this appendbuffer is dynamically changed, we need to update the buffer every frame inside the C# script.



Finally we need to release the buffer.






Method 2:

We do the frustum culling in clipping space.

For a point, after applying projection transformation into clip coordinates, if  -w <= (x,y,z) <= w

then the point is inside the screen. We only need to compare the homogeneous coordinate of each vertex of the grass AABB to its own w component.






No comments:

Post a Comment

GPU Instanced Grass in Unity - Part 7

  GPU Instanced Grass in Unity For the original post, please go to  https://www.yuque.com/qwerasdwww/dfy5xd Part 7: Add Shadow Now the grass...