Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Best Way to Instance Thousands of Grass on a Mesh?

Discussion in 'High Definition Render Pipeline' started by ChiliStudio, May 9, 2021.

  1. ChiliStudio

    ChiliStudio

    Joined:
    Jan 19, 2018
    Posts:
    33
    Hey there!

    My game infinitely generates tiles which the player travels along. I am struggling to solve this problem and would love ideas or a better approach.

    I need a good solution for spawning grass and other vegetation which uses Shader Graph shaders for wind sway.

    I have tried DrawMeshInstanced; the problem with this is that I don't have a good way to control which Matrices to draw.

    My current idea has been to associate grass matrices with the tile beforehand by raycasting and storing a List<Matrix4x4[]> on each tile. Then when the player enter's the tile, they will instance every Matrix4x4 in the tile, as well as in the nearest adjacent tile.

    This would work if I could figure out how to store the Matrices on each tile (Unity prefabs won't do this by default).

    Another problem with this approach is that the tiles can be very large and tank performance. Frustum and occlusion culling are basically out of the picture as far as I know because GPU culling is not supported with shader graphs, and the CPU frustum culling using culling groups and reconstructing the matrices is likely less efficient than just drawing all the matrices. Also, I would have to convert the matrices on each tile from local to world coordinates whenever they spawn in, and I'm not sure if that is efficient or even possible.

    I have also tried creating a moving grid around the player that randomly spawns rows and columns of grass as the player travels, using a noise texture such that the randomness of the grass spawns is persistent, but the problem is the number of raycasts that have to be performed every frame.

    Note: I have to raycast to place the grass because it uses the terrains vertex color as a spawn rule

    Prefabs are terrible for performance too. And I honestly don't want to store thousands of grass prefab transforms in my scene.

    Here is a picture from my scene.



    If I can avoid raycasting at runtime, I'd love to.

    Does anyone know how its done in Rust, for instance?
     
  2. olavrv

    olavrv

    Joined:
    May 26, 2015
    Posts:
    502
    I think the best option is to use Vegetation Studio Pro. with this you can have incredible numbers of vegetation (trees, grass, bushes), and it renders with good performance.
     
  3. Deleted User

    Deleted User

    Guest

  4. BattleAngelAlita

    BattleAngelAlita

    Joined:
    Nov 20, 2016
    Posts:
    400
    BatchRendererGroup
     
  5. ChiliStudio

    ChiliStudio

    Joined:
    Jan 19, 2018
    Posts:
    33
    Update: The solution for me was to purchase GPU Instancer which uses indirect instancing, and supports HDRP shader graph shaders with one extra node they gave. GPU Instancer handles occlusion culling and frustum culling. I then store the grass/rocks/flowers position, rotations, and scales on a script on the tiles when I perform the raycasts (before runtime). Then when tiles spawn in, I take this data and form arrays of matrices that take the local position /rotations and convert them to the world, then tell the GPUInstancer to make instances at those matrices with the associated GPUI prefabs. --All along with a custom spawning script I made which uses vertex colors and noise textures for distribution. When the tile needs to delete, I just remove all the instances within the bounds of the tiles mesh! Works perfectly and I don't give up any performance.