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 Handling a List of a Million structs containing 2 Vectors each

Discussion in 'Scripting' started by Reid_Taylor, Jul 4, 2023.

  1. Reid_Taylor

    Reid_Taylor

    Joined:
    Oct 9, 2019
    Posts:
    57
    Ok... So... First and foremost I want to say that I am by no means an expert on the topic of this thread; however, in the last few days, I have figured out how to use Compute Shaders and Compute Buffers to render around 2 million blades of grass on my m2 MacBook Air at around 60fps.

    Here is a picture for basic reference:
    Screenshot 2023-07-04 at 12.33.23 PM.png

    As you can see, a C# script currently gathers all the vertices from a source mesh (currently a plane) and passes them to the compute shader as an array of BladeSource (a struct containing a position and normal).

    This system currently needs to be used in a large world and obviously, I don't want grass inside objects like a well, a house, an NPC, etc... Now, I could model a mesh that fits the world and has vertices where each blade of grass should be but that would be inconvenient, tedious, and hard to work with involving any change. At least from what I have tried, Unity's serializable object severely struggles to save a List of millions of a struct, so I can't just create a public List that is edited by a brush drawing SceneGUI. The easy part is generating the points, but what is the smartest way to generate them so that they can be saved (and not take 5 hours)?

    Thanks,
    Let me know if any further clarification is required.
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    4,048
    You don't have to use [SerializeField] to serialize data. You could use a BinaryWriter or Unity's serialization package.

    You can also use GPU Instancing to draw many copies of the same mesh.
     
  3. Reid_Taylor

    Reid_Taylor

    Joined:
    Oct 9, 2019
    Posts:
    57
    I will look into BinaryWriters and how they might be of some use. Will I be able to massively improve save speeds with them? Even with a list with more than 1 million items?

    I am currently using a mix of Compute Shaders, HLSL Shaders, and C# to use

    Graphics.DrawProceduralIndirect(instantiatedMat, bounds, MeshTopology.Triangles, argsBuffer, 0, null, null, ShadowCastingMode.Off, true, gameObject.layer);


    And since I am using Metal and it needs to be performant for mobile devices, this is an extremely efficient (the most I have found) way to draw a huge amount of grass with little to no bottleneck.

    Thanks for the quick response!
     
  4. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    4,048
    Well, a million times two Vector3 equals about 23 Megabytes uncompressed. That will always take some time, and definitely not something you want to do in the middle of gameplay, especially not on mobile.

    I would question why you need to save this many vectors. You could simply draw polygon areas within which grass appears, rather than trying to serialize every individual grass mesh. That is definitely overkill.
     
  5. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,128
    Have you looked into using volumes to indicate where the grass should and shouldn't spawn? I'd think they would work well with compute shaders since you're just passing in data representing the shapes of the volumes, and the shader just turns on/off the grass if it's inside it.
     
  6. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    11,002
    Or use a texture as a density map, which opens up more styling possibilities?
     
    zulo3d likes this.
  7. Reid_Taylor

    Reid_Taylor

    Joined:
    Oct 9, 2019
    Posts:
    57
    @CodeSmile
    Yeah, I totally agree about that being overkill. I am not needing any of this to be done in gameplay. I just want to be able to edit where the grass is in the editor and I need to save that data for initialization at the start of the game. I like the polygon idea.

    @Ryiah
    Is there a specific Component, Function, or Class that you are referring to which makes using volumes convenient or are you just suggesting a different route? I like the idea even though I am still not sure how I would go about implementing it... In terms of performance, I definitely would not want to be calculating any blades that are not rendered on screen, so I need to be cautious of any solution which would do that. Maybe I could do something mixed with volumes and what CodeSmile was saying about having areas in which the grass will be generated at the beginning of the game.

    @AcidArrow
    This was initially my favorite solution, but I dislike the idea of having to edit a texture in the editor (partially cause I know I would run into other performance issues in the editor) and being limited by resolution. Thoughts on execution?
     
  8. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    11,002
    If you edit it as a rendertexture and then have a save button so it is actually written to a file (or a CPU texture) manually every once in a while it should be pretty fast.

    Although this would not be trivial to implement, especially if you want it to be user friendly.

    I think I wouldn't bother and would just replicate the significant parts of my world / scene in Modo (it's my 3d software of choice, but it could be any), and then load the texture there and do the editing there so I don't have to code my own custom solution inside Unity. But this quickly falls apart if you use things that aren't exported easily from Unity (like terrain?) or if your game world is super complex and big?

    If the underlying geo has enough vertices you could also just paint a vertex map and use that? Which solves the resolution problem. (Although I hate Polybrush with passion)

    I don't know, I feel there are too many unknowns and the solutions I am coming up with are mostly based on what I would do in my games, which have small maybe up to medium scenes.
     
  9. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,128
    I'm referring to volumes in a loose sense. Basically you would pass through data that represents spheres or cubes and the compute shader would scan through them any time it went to render grass skipping any if they fall within the boundaries of the volume.
     
    Bunny83 likes this.
  10. Reid_Taylor

    Reid_Taylor

    Joined:
    Oct 9, 2019
    Posts:
    57
    I like this idea, but unless I’m not thinking clearly (which is highly probable), then I would have to check the distance between every blade and every volume, every frame. And that would be absolutely disgusting ??