January 3, 2017

The Best Grass Ever: Circular Temporal Displacement

Rendering grass by itself is fairly easy: texture, mesh, masked material, grass tool, done. Unfortunately more complex features like vertex displacement on grass cards can get very expensive and unwieldy if you don't have a solid plan to tackle the motion and normals. Some novices may be tempted to use the included Simple Grass Wind function in the engine, but the motion from Simple Grass Wind is very repetitive, unnatural, and faltering. Also, the node does not include proper normal output. I have spent years trying to find a good solution for grass, and through texture-based vertex displacement I believe I have found it.



I call this technique Circular Temporal Displacement. Grass movement is based off of a circular motion though the use of sine and cosine waves. These waves are displaced by a panning texture not affecting the vertex displacement directly, but by bending the inputs to the sine waves generating the circular motion. That motion feeds the grass normals and vertex displacement. This technique involves a combination of world-aligned panning grayscale texture maps, time, sine and cosine (circular) waves, and UV distortion to provide the movement. The colors of the grass can be enhanced through fresnel shading and hue-shifting textures per instance. The quality and performance of this grass is remarkable, with large landscapes receiving plenty of 3D grass coverage with fully featured normals, lighting, UV splines, and vertex displacement (allowing for correct full scene shadows) for not even 1ms difference, mostly from pixel overdraw of translucency. The technique is incredibly well optimized for mid-spec PC and can be scaled to greater heights.

Benefits of this technique:
  • Beautiful swirling motion with real vertex displacement
  • Smooth spline-like waving along plane
  • Relatively easy setup
  • Beautiful normals facing the top of the blade
  • Normals from vertex displacement (retrieved for free with little hassle)
  • Great artistic control (from the motion texture to parameters)
  • Parameters can match stiff, dry grass in a field or flowing underwater grass
Limitations:
  • Vertex movement is locked to a simplified rotate around the Z axis in world space: no vertical displacement, and can be odd for grass planes placed at an angle
  • Normals are not physically accurate



The reason I do not use a texture to directly control the position of the grass is because textures have an immediate "lock" on their position which results in stiff motion. The results never seem to look natural with textures. It was much easier to control the grass by creating a generic circular motion that always runs and then changing the temporal distance along that motion. It gave me the constant natural smooth motion I was looking for with the added benefit of complex wind behavior.

This perfectly uniform vertex motion is then combined with vertex normals from the grass card (facing directly up from the base of the mesh). I was looking for beautiful grass and achieves good performance in 4K. The movement is very inexpensive.

While the quickest and easiest way to mask from base to height is through the use of a single masked channel of a texture coordinate, there is a higher per-pixel cost in using this method as opposed to taking advantage of the vertex color. Since a basic grass card only has 4 vertices, the vertex method is extremely simple and easy to setup and very cheap as well. To make the effect more interesting, try different patterns on the panning grayscale motion texture, or blending two textures at once.

It is highly recommended for grass cards to use contact shadows (from the directional light) and screen space ambient occlusion (from post process) to get the best looking results. One thing I know for sure, this grass looks stunning in motion.

2 comments:

  1. The Dropbox link appears to be broken!

    ReplyDelete
    Replies
    1. Sorry! I've actually made an improved version of the grass shader. Try now!: https://www.dropbox.com/s/8r53yuod9ehe8ke/GrassShaderCopyPaste.txt?dl=0

      Delete