Grass

On a landscape, you can add foliage using the grass settings. This will scatter a 3D model across a landscape.

3D model limitations

This feature is currently limited to work with models that have a single geometry and material. If your model is for example several planes, ensure to combine them to a single geometry before exporting.

Tutorial

1. Import assets

To create grass using this technique, you need both a 3D model and an alpha map texture which we will use in a material later. Download the files below and drag them into your editor.

grass.glb

sprite_0004.png

2. Create a landscape

In the asset browser, select shapes and find Landscape. Add it to the scene. For the purpose of just learning how to use grass, you can leave the default options.

3. Add a grass mesh

  1. Select your landscape object in the scene

  2. Expand the Grass settings

  3. Click add grass layer

  4. Click add mesh

  5. Right click the imported model and click "Select"

You will now have something that looks like this.

4. Create a grass shader

In the asset browser, click add new and then click Shader class. Give the shader the name GrassShader.

Open the project in your code editor and change the created file called grass-shader.ts. Replace the contents of the file with the code below.



import { NodeShaderMaterial, float, lambertMaterial, mix, rgb, rgba, smoothstep, textureSampler2d, transformed, varyingAttributes, varyingFloat, vec2 } from "@hology/core/shader-nodes";
import { NodeShader, NodeShaderOutput, Parameter } from "@hology/core/shader/shader";
import { Color, Texture } from "three";

export default class GrassShader extends NodeShader {
  @Parameter()
  color: Color

  @Parameter()
  colorBottom: Color

  @Parameter()
  alphaMap: Texture

  output(): NodeShaderOutput {
    const distanceFromCamera = transformed.mvPosition.z.multiply(float(-1))
    const distanceAlpha = varyingFloat(smoothstep(float(100), float(60) , distanceFromCamera))    

    const tipColor = rgb(this.color ?? 0xffffff)
    
    const gradientColor = mix(
      tipColor,
      rgb(this.colorBottom),
      varyingAttributes.uv.y
    )

    const alpha = this.alphaMap != null 
      ? textureSampler2d(this.alphaMap).sample(varyingAttributes.uv.multiply(vec2(1, -1))).r
      : float(1)

    const lambertColor = lambertMaterial({color: gradientColor}).rgb

    return {
      color: rgba(lambertColor, alpha.multiply(distanceAlpha)),
      alphaTest: 0.8
    }
  }
}

5. Create a grass blades material

In the asset browser, click "Add new" and this time select "Material". You can name it "GrassBlades".

  1. Select type Custom shader

  2. Set Side to Double.

  3. Select the shader you created in the previous step "GrassShader"

  4. Select two colors. It looks best if the top color is slightly lighter than the bottom color.

  5. For the alpha map, select the texture you imported previously.

6. Create a landscape material

The key to make the grass mesh blend in nicely is to use a similar color at the bottom of the grass mesh as the material used on the landscape.

Create a new material like you did for the grass blades. This time, instead of using a custom shader, we can use Lambert or Standard. Set the color property to the color you used for the bottom of the grass blades.

Assign this new ground material by finding it in the asset browser, click and drag it onto the landscape in the scene.

7. Adjusting the grass settings

You can now go back to the landscape's grass settings and adjust the options.

  • Increase density. Set the density higher to something like 10. A higher density can look more realistic as you will have more grass models scattered on the landscape. However, this comes with a performance cost as it will be much more triangles for the GPU to render.

  • Enable normals up. This will make it so light calculations on the grass mesh is similiar to the ground below. This can make it look more realistic or your moodel may look very dark on the side that is not facing the light.

  • Adjust min scale, to create some variation.

You should now have a landscape that looks similar to this.

Last updated