Grass Shaders
Shell texturing, tessellation, and interactivity.
I made shell texturing and tessellation based shaders in HLSL and Unity Shadergraph.
Tessellation and Geometry
A basic approach for rendering grass naturally is through tessellation and geometry shaders. The geometry shader can produce new geometry per-vertex, so we can use that to produce triangles which will make up the shape of our individual blades of grass. Geometry shaders are limited in the amount of vertices they can output though based on API specifications, so for shapes with very few vertices to begin with, we'll use tessellation to sub-divide it, allowing more vertices to be passed into the geometry shader and thus, more blades of grass.
While a typical shader program goes from Vertex straight to Fragment, Tessellation and Geometry shaders actually fit right in between.
-
The tessellation shader subdivides a shape into more shapes (or different shapes i.e. tris->quads), and is comprised of a Tessellation Control Shader (Hull Shader) and a Tessellation Evaluation Shader (Domain Shader).
-
The geometry shader runs per-vertex, and can output new vertices and displace them.
Grass Vertices
In the geometry shader, we simply need to define the shape of our grass with extra vertices. To make our grass stick up out of a surface, we multiply some height by the surfaces normal, and displace that in any tangential direction. Then add another vertex opposite to that tangent to create our first triangle. Repeat as desired. Lastly place a vertex at the top of all that and centered (so simply Normal * Height) to complete a blade.
Shell Texturing
An alternative technique for generating a grass-like effect is shell texturing, or "shells & fins". The premise of this technique is to render the mesh repeatedly, slightly farther along the surface's normal each time and with the same transparency pattern each time. For each mesh (shell) this creates a flat cross-section of would-be grass-blades . By stacking a large number of these cross-sections, the illusion of grass is created. See below. Because this technique is based on a shell mesh instead of vertices for each individual blade of grass, it can potentially improve performance by rendering far fewer triangles (albeit with transparency).
Since this technique is texture-driven, the style can change drastically.
Compute Shaders
There are a number of ways to create the shells in Unity, each with their own pros and cons. Entirely separate objects, objects with multiple materials (Unity renders each one), geometry shaders, and compute shaders, to name a few.
I experimented with many of these techniques, but ultimately decided to utilize compute shaders, since I wanted to offload work to the GPU, and geometry shaders are falling out of the popular sphere in API specifications. Also, compute shaders work on mobile, where geometry shaders may not.
Performance
Performance is a tricky thing - most optimizations (that aren't automatic at this point) come with draw backs.
Shell texturing, for example, has the clear drawback of blurring and distortions when observed from the side - since the "slices" are just quads.
I'll look at testing these shaders with various adjustments and optimizations in the near future.