Hi, friends!
I’m having trouble creating grass.
I’ve found that no matter if I make a grass mesh with Blender or generate a mesh using C# script, the final result has a rendering order issue.
Just like this picture below, I’ve tried many ways to solve it but failed.
Could you please help me?
Thank you!
Welcome to the wonderful world of transparency sorting weirdness!
Fast, efficient, and accurate real time sorting of transparent surfaces is an unsolved problem in real time rendering. What you’re seeing is when a single mesh is rendered, the order the triangles are rendered in is the order they exist in the mesh. If this order happens to be back to front (furthest surface to closest surface) then everything will look correct. If this isn’t the order they render in, then it’ll look wrong as surfaces that are further away will end up rendering “on top” of those closer to the camera.
The most common solution to this problem is to use an alpha test (aka alpha cutout) material instead of an alpha blended one. The reason why this fixes the problem is because opaque surface write to the depth buffer which ensures correct sorting of opaque pixels regardless of the order they’re rendered. When using alpha test each pixel is still fully opaque, so they can still be sorted properly. This doesn’t work for transparent surfaces because the color and depth buffers can only hold one color and depth value at a time per pixel. For opaque surfaces if a pixel is closer than the one last rendered to the depth buffer, it can replace the color and depth values, and if it’s further that pixel can be skipped. For transparencies if objects render out of order it’d need to be able to know the color of the surfaces further and closer to the camera and insert itself between them, which isn’t possible without keeping a record of every surface rendered to every pixel.
The other common option is to pre-sort the meshes every frame. This is actually how Unity’s own grass systems work, with each quad or foliage mesh instance being sorted back to front before being rendered. When using quad grass this works pretty well, but if you’re using custom meshes for foliage there can still be sorting issues within a single mesh, which is something you’re also seeing with your mesh as you have 3 intersecting quads per grass tuft. This is an unsolvable problem for even per-triangle sorting (again, see the above link to Painter’s Algorithm).
Other alternatives are OIT (Order Independent Transparency) or approximate OIT. That “keep a list of every surface at every pixel” is one of those OIT options. But doing that means the render target can use an unbound amount of memory, which can be very difficult to deal with. Approximate OIT techniques use various different options for limiting the amount of data required, to different levels of approximate-ness, cost, and appearance. Unfortunately the “best” approximate OIT methods all either fail at handling the transition to surfaces that are near or fully opaque, like the center of your grass stalks are, or fail at handling multiple overlapping thin surfaces, which grass also is. Grass render is literally the worst case for all of the OIT methods out there. Hence why almost everyone just ends up using alpha testing instead.