This grass effect is a compute shader in Unity (URP) that spawns planes along an existing surface that slightly curves naturally and can move with the wind to create a hatching-like brush effect on the ground. Using a compute shader took advantage of parallel computing to create the grass in a more performant way when compared to other solutions.
Each blade has full texture customizability with a custom color for the base and the tip. Further customization has been added to implement custom spawning, allowing for a mask to be passed to the shader, taking the original UVs of the spawning mesh, and spawning grass within certain bounds.
Finally, another shader material was added underneath the grass within our scene dressing to make the grass look more "full" and transition into the painted environment better with a swirl and watercolor-like effect.
Hand-drawn textures and full customization were an important part of the game's style, so adding particular customizability to the shader was very important.
Above are some texture tests created to experiment with different grass styles to see what would look the best for each stylized area in the game. We found that the grass blades with more alpha variances and a rough brush stroke feel looked the best to our playtesters.
To save development time, our team of 3 needed a quick way to "paint" on grass into the environment and reuse these grass layouts for other island scene dressing. My solution was to use a flat UV projection over a mesh that comprised the top part of our islands. Then, we would use that as a mask to see where to spawn the compute shader grass.
This saved many hours of development time while opening up new ways for our team to show information to the player as we discovered we could use existing textures such as UI Arrows to spawn informational grass.
As mentioned previously, a base grass material was added to give the grass a "full" look and better transition to the textured environment.
On the left you can see how noise within the UVs distorted the edges of a straight mask texture, allowing for a less harsh transition into non-grassy areas. There are slight color variances within the texture as well using Voronoi noise cells to emulate some of the color jitter seen in the hand-textured environment assets.
When originally making the grass shader, I created a geometry shader with the help of the following video tutorial. This was the first time learning HLSL, so it was a daunting task, yet with many comments, trial and error, and reading forums, I was able to implement the grass and test in the game.
I loved the main blade customization of the grass with a texture, and the custom shadow colors, however, it didn't provide a way to do custom grass spawning other than recommending painting with vertex colors. This is where I first introduced my custom texture-spawning mask feature.
However, we learned quickly that this implementation didn't work for MAC computers and we had been taking a performance hit, so I realized I needed to make a shift to another solution. Since this prototype, I've tried to do more prior research on compatibility to avoid re-doing work.
NedMakesGames' video is ultimately the tutorial used as the base of the grass within our game. I loved the implementation of the compute shader as it had better performance and implemented some LOD adjustments that the previous tutorial did not. However, it was stylistically very different, creating triangle planes and adjusting colors rather than passing texture. It also didn't have any spawning customization, yet that was similar to the previous tutorial.
Ultimately, I was able to continue learning HLSL while learning about how computer shaders work differently than geometry shaders. Eventually, I was able to add the texture customization for each blade of grass and use the spawning mesh UVs to mask grass spawning as well!
During this exploration of grass, I was able to development a base understanding of grass in games, geometry shaders, compute shaders, and the importance of research and stylization in the prototyping phase. There are still areas of improvement, that I believe can bring the shader to the next level.
Physical Interactions: While the implemented shader blows in the wind, there are no physical player or attack interactions. Due to time limitations, this was a polish element that had been cut, however, it would provide another level of engagement and immersion that we would like to implement.
Shadow Color Customization: Currently, when a shadow is cast on the compute shader grass, it is cast as a black shadow. This was different in the geometry shader that used a custom color. I hope to improve the shadow color by either connecting it to the ambient color of the scene or manually passing a shadow color.
Tesselation and Plane Adjustments: The planes that spawn the grass scale with the side of the islands. With variable island sizes, the grass can look very different. Having a form of tesselation adjustment to the plane would allow for there to be less or more grass spawned without creating a custom mesh for each instance.
Grass Base Material Fusion: In the current implementation, there are two parts, the main grass and the grass base. I would like to fuse the two into one shader material allowing for easier creation of grass in the future and fewer existing objects in the world that need to be rendered on different game objects.
Copyright © 2024 Nathan Lacsamana - All Rights Reserved.