shown in other instead.
Vegetation: Authoring Tips
This article describes principles of modeling and configuring plants and ways to achieve the best performance in scenes with dense vegetation in UNIGINE.
Models of plants based on polygon meshes are to be used for close-ups and middle distances for the most realistic representation of real-life greenery. It is crucial to use optimized 3D models of trees in real-time projects.
In this section you will be introduced to some vegetation authoring tips in UNIGINE and third-party Digital Content Creation software.
When preparing a 3D model of a tree with dense foliage, avoid creating topology for all branches and leaves, instead it is much more efficient performance-wise to simulate fine details with textures. The main rule of models optimized for use in real-time is "the less polygons — the better", this is much more critical for rendering a dense forest filled with multiple types of plants and grasses.
Therefore, it is highly recommended to prepare several levels of detail (LODs) for a plant to be used at different distances from the camera.
The overall workflow of modeling a tree is as follows:
- Model several small branches with leaves and bake the models into texture atlases — the obtained textures are going to be your foliage textures. Here are examples of such textures:
Create low-poly meshes that will represent foliage chunks, map UVs for proper texturing. The chunks do not have to be flat, you can experiment with the shape and bend of meshes. It is also important to prepare at least 3 LODs, make sure to optimize the meshes of LODs to the full extent:
Create the trunk with large branches and its levels of detail. Prepare and assign necessary textures and a material.
Also, it is recommended to transfer normals from the trunk to the adjoined vertices of branches to make a more natural look of joints:Adjusted normals of branches at joints provide a more natural look.
Scatter the LODs of foliage chunks over branches of the corresponding trunk LODs forming the tree crown:
The fact that the same number of chunks is used on all LODs may result in a higher polygon count, however, this approach has a number of advantages:
- High diversity of branches makes it possible to create more realistic plants;
- A better, almost seamless transition between LODs. All elements can be adjusted at any time to get rid of any inconsistencies;
- A more permissive art pipeline enabling the artists to collect trees of different size and age out of the same chunks;
- Accurate work of post effects even on the lowest LODs (SSAO, SSGI, etc.).
- It is also recommended to create a separate low detail foliage LOD to simplify shadow casting. You can duplicate the lowest LOD and optimize it even more for this purpose and configure shadow casting in UNIGINE.
For better blending with terrain prepare a separate bottom part of the trunk with a new material assigned. You can merge it to the mesh of the highest LOD for convenience:
Orient the model so it will be imported in UNIGINE appropriately, reset all transformations.
Pay attention to the correct position of the mesh's pivot point (apparently, all the LODs must have the same position). As a rule, the pivot is placed at the bottommost point of the plant for the ease of world design, however, the position of the pivot can be altered if this is needed for stem animation.
As the result, the model has the following content:
For convenience, it is recommended to add postfixes to the names of levels of detail that will be used later during import.
- Consider further adjustment of vertex normals and vertex colors and UVs for leaves animation.
- Export the model to the recommended FBX format.
Configuring the Look of the Plant#
To make all separate objects surfaces of the single Mesh Static, enable Merge Static Meshes in the import settings.
Setting Up LODs#
When dynamic shadow casting is used, all polygons are rendered one more time for each light source with shadows enabled. World light sources can have up to 4 shadow cascades, so the number of polygons rendered into shadow maps can be tremendous leading to a strong performance hit. You can estimate this number by using the Rendering Profiler.
That is why it is a best practice to use a low-poly mesh for foliage shadows. Perform the following steps:
- Disable shadow casting for all foliage LODs except the Shadow LOD. You can do it by one of the following ways:
- Hide the shadow LOD for any camera by toggling off all bits of its Viewport Mask.
See the demonstration of configuring a shadow LOD in the Bit Masking video tutorial.
If the Import Materials flag was enabled in the import options, all necessary materials are already generated and assigned to the surfaces of the tree. Let's consider material parameters that worth being noted:
- Make the leaves material Alpha-Test to cut out texels according to the Alpha channel of the Albedo texture.
If specular highlights are incorrect, it is recommended to set the Specular value to 0.Incorrect lighting on the Reflections Rendering Debug preview (left) and the result image (right).
Consider enabling the Two Sided option for the material to make the foliage densier. Be careful as it may significantly affect performance if there are too many polygons in the scene.
It may be better to switch the Backside Normal mode to the To Front Side option since it usually provides more realistic results for foliage.
If textures make it evident that foliage is made of flat chunks, a great solution to this is the Angle Fade feature that cuts out polygons faced to the camera at extreme angles.
This feature may work incorrectly for meshes that have modified normals.
Adjusting translucency for the foliage material is necessary for a better look. Increase the Translucent value to permit light to pass through the object.
You can also enable the use of the Translucent Map in the States tab to specify a single-channel texture that will define parts of the object that aren't translucent (such as branches).There is no need to paint fibers and small features of leaves on the Translucent texture if the Normal map is used and defines such surface irregularities.Albedo textureTranslucent texture
- Enable the Terrain Lerp flag for the material of the bottom part of the tree to blend your tree with a Terrain in your scene.
Vertex Normals Adjustment#
The fact that foliage is composed of flat chunks results in inaccurate shading. To counteract this and hide the flatness of the mesh, adjust vertex normals and affect the foliage is shaded.
The following solutions are possible:
Enable the Normals Rotated To Camera option so all normals of the surface will be oriented towards the camera ignoring the geometry normals. This feaure checks out as a quick solution, although it makes all polygons shaded the same way.
Edit vertex normals manually in your modeling software. Transfer vertex normals from a boundary cage to make foliage look as a smooth and dense tree crown.
It is recommended to use a dome-like boundary cage with the sides elongated to the ground to avoid shading errors on lower polygons.Transfering normals from a boundary cage.
As a result, the flatness of foliage geometry is less evident (on the right):
MipMapping technique, supported by UNIGINE renderer, implies sampling lower textures for smaller and distant polygons. At that, small features of foliage start wiping away with the distance, in some cases, branches and leaves look thicker when far from the camera than on a close-up view.
This issue can be resolved via these approaches:
- Engage the Mip Bias feature to be able to shift the distance at which the switch between MIP levels is performed. This option significantly affects the performance.
- By default, MIP maps for a texture are generated automatically on import using the Box filtering that may provide too blurred results. Consider switching to the Point filtering type to get sharper MIP maps.
- You can also prepare custom MIP maps in third-party software. For example, here is a comparison between MIP maps generated using the Box filtering and the sharper Kaiser filtering:
To import a texture with custom MIP levels, use the Combine option for the texture with laid out MIP levels or save them to a .dds format and import the texture with the Unchanged option enabled.
Enable the Vegetation state to activate a set of animation-related parameters.
At that, the Field Animation makes the plant be affected by Field Animation volumes enabling you to override animation parameters locally (e.g., simulation of rotor downwash effects in close proximity to a rotorcraft).
Stem animation applies vertex movement based on spatial 3D noise to simulate bending of the plant's trunk or stem caused by wind. The mesh's pivot point is considered fixed and the further the vertex is along the Z axis, the stronger movement is applied to it.
Thus, it is necessary to place the pivot point at the correct position (usually, it is the bottommost point of the stem) and orient the model so the Z axis goes upwards.
The animation is controlled by a set of Parameters.
Make note that all surfaces of the plant must have identical stem animation parameters in order to synchronize their movement.
The Leaves animation is another layer of vertex shader animation that is mainly applied to foliage providing additional detail bending. Using this type of animation requires preliminary adjustment to geometry on the modeling stage.
Several approaches of leaves animation are available out of the box, select the type of animation using the Leaves option.
Geometry Vertex Color Based#
This recommended approach providing the best control over foliage implies that leaves are rendered as polygons and vertex colors are used for animation.
Vegetation movements are defined by RGB channels of vertex colors as follows:
|Red channel is used for animation of smaller or peripheral parts of vegetation (leaves). Bright parts are animated, and dark parts are stiff.|
|Green channel is used to define the movement order for branches in order to desynchronize them. The movement sequence starts from the brightest element to the darkest.|
|Blue channel is used to define which parts of branches can be bent. Brigher parts indicate bendable portions, and darker parts — stiff portions.|
Vertices movement is controlled by the animation parameters:
It is also a normal practice to animate branches using this technique even if they are attached to the trunk:
At that, related surfaces must have the same vertex colors on adjacent vertices and identical animation parameters in order to synchronize their movement:
This is a rather legacy approach when leaves are rendered as standard polygons. It requires the UV Channel 2 to be defined for the mesh.
Geometry UV-based animation.
UV Channel 2: the stiffest vertices are in the top left corner.
Animation uses UV channel 2 of an object as follows: in the UV grid, [0,1] is the pivot point for the object's movements and the stiffest part of the object, and towards [1,0], the object becomes more flexible.
Control the vertices movement via the same Animation Parameters.
This is the most performance-friendly way of animating distant vegetation: all quads are rendered as billboards that always face the camera; the UV Channel 2 defines the size and movement of polygons. Hence, the foliage mesh should contain only quad polygons for leaves.
A billboards-based bush
The mesh of the bush
Animation uses UV channel 2 of an object as follows: in the UV grid, [0,1] is the pivot point for the billboard's movements, and the billboard's size can be changed by scaling the polygon in the UV channel.
UV Channel 1
UV Channel 2
Mesh (above) and the result (below)
Control the polygons movement via the same Animation Parameters.
Global Animation Options#
Stem and leaves animation are also controlled by the global Vegetation Animation Parameters. Via these settings, you can adjust stem and leaves animation intensity, speed and wind effect globally and control the weather conditions per-world.
Note that the global parameters are just multipliers for the per-material animation parameters.
To randomly scatter a great number of identical meshes across the terrain, Mesh Clutter is used. Mesh Clutter scatters objects procedurally, and renders only those objects which are in the viewing frustum. The typical workflow is as follows:
Click Create -> Clutter -> Mesh and specify the .mesh asset to be used as the source mesh for the Mesh Clutter. Click within the viewport to place the new node in the world.
.fbx assets are containers for .mesh assets, right click on the asset and choose Open or double click on it to access its content.
- If you already have a configured tree in your world, you can copy all materials and parameters from surfaces of the configured tree and paste them sequentially or by surface names to the Mesh Clutter.
- Place the node in the scene and set the Size to cover the whole playable area.
The operation of Mesh Clutter objects is float-based, so it is not recommended to use Sizes bigger than 10000 units lengthwise and widthwise. If you need to fill areas beyond this limit, you will need to split the single Mesh Clutter object into a grid of several clutters manually.
- Adjust the parameters of scattering: set the desired Density in meshes per square unit; diversify the appearance of the forest by randomizing the Scale, Offset and Rotation parameters.
Make the clutter object child to the terrain and enable the Intersection flag to make trees follow the surface.
If the Intersection flag is enabled, toggle it off and on to forcefully re-generate the clutter object.
- Adjust the Visibility and Fade distances. Given the number of polygons that might come into play in a dense forest, it is recommended to make Mesh Clutter visible at as short distances as possible and use impostors at further distances.
By default, trees are scattered across the whole area. You can mask areas with vegetation via the following approaches:
Using a single-channel texture. You can prepare a texture in third-party software or create a new one and draw the mask from the scratch. All Mesh Clutter and Grass objects that use that texture are updated on the fly.
Using Landscape Terrain masks. If your world contains a prepared Landscape Terrain with configured masks, you can use the data of any of them to define the density of the vegetation: just select the desired mask in the Mask Terrain parameter:
Landscape TerrainMask preview of Landscape TerrainVegetation is scattered according to the terrain mask
You can also edit the mask by using the Brush Editor and have the Mesh Clutter updated on the fly.All data of a Landscape Terrain including masks is subject to data streaming. If you have unpotimized streaming settings there might be a bottleneck in mask data loading on world startup and changing the camera position, affecting the performance of Mesh Clutter generation.
As an additional feature, masking by a mesh is also available:
Cutout by intersection with objects:
Cutting out trees within a box.
- Create a Mesh Static or a Decal representing a bounding cutout volume. Enable the Clutter Interaction flag for it.
- Choose and enable a bit of the Intersection mask of the object that will be used for the cutout feature.
- Enable the same bit of the Cutout Intersection mask of the clutter object.
- Hide the visual representation of the object from the camera by disabling all bits of its Viewport mask and disable shadow casting for it.
- Using a single-channel texture. You can prepare a texture in third-party software or create a new one and draw the mask from the scratch. All Mesh Clutter and Grass objects that use that texture are updated on the fly.
Keep the optimal Step value for the best performance.
The clutter is rendered as a 2D grid, in each cell of which meshes are randomly scattered depending on the density and probability of appearing. Generation of meshes in the cells is time-sliced starting from the nearest cells to reduce load on CPU.Cell division.
The Step value defines the cell size in units. Thus, this value defines the resulting number of cells along each axis (the size divided by the step), it is highly recommended to choose the values that are divided with no remainder.Each cell requires 1 DIP call, so the higher the number of cells (i.e. the smaller the step), the more reduced the performance is. However, to create a large cell takes longer time. When the camera moves fast enough, small cells are created one by one very fast and smoothly, but large ones can noticeably pop into sight and cause a small rendering lag.
The same way you can scatter bushes and chunks of polygon grass across the terrain.
Finally, by combining several clutters for different types of trees, bushes and grass, you get a diverse look of vegetation.
As a finishing touch, you can place trees as Static Meshes where needed. It is efficient performance-wise to collect a significant number of identical meshes into a Mesh Cluster object in order to treat and render a bunch of meshes as one object.
You can bake identical meshes of their hierarchy or collect all similar meshes in the world. Refer to the dedicated article for more details on the ways of collecting a cluster.
The other convenient approach to quickly scatter clusters of grass, bushes and trees across the scene is using the mesh placement brush tool:
A billboard is a rectangular flat object that always faces the camera. Using billboards instead of fully functional objects that are barely seen from far off significantly simplifies and speeds up rendering.
In terms of UNIGINE, Impostors are billboard-like objects that are capable of mimicing the appearance of polygon meshes by displaying different areas of textures depending on the angle of view. Impostors serve for speeding up geometry rendering by reducing the number of polygons while saving visual fidelity.
It is easy to generate impostors for single meshes and Mesh Clutters by using the built-in Impostor Creator tool.
For a forest based on a Mesh Clutter, a Grass object with the grass_impostor_base material will be used as a low-poly LOD. At that, the clutter and grass parameters must match to make sure the position and orientation of all LODs are the same.
Mesh Clutter and Impostors
Meshes' and Impostors' Wireframes
Grass objects are also rendered as a 2D grid to optimize performance. The Step parameter defines the cell size. Usually, impostors are visible much further than meshes and the Step value is to be chosen respectively. You can use the Subdivision parameter that subdivides large grass cells so that they match smaller cells of a clutter to make positions of randomly scattered objects coincide with positions of grass-based impostors. Therefore, the Clutter Step must match the ratio of Step/Subdivision values of the grass.
To fill empty spots on the terrain and increase the overall density of lower vegetation in the scene, a Grass object with the grass_base material can be used. The grass_base material is intended to represent the basic features of grass and has a lower visual fidelity compared to the mesh_base material, so Grass should be thought of as an additional filling layer of grass.
On the first step, you need to prepare a Diffuse texture with chunks representing small grass tufts:
Chunks are to be placed in the texture as follows:
- Vertical columns represent different grass species, each of which will be distributed according to the corresponding channel of the Mask texture. Therefore, the number of columns must match the number of channels of the Mask texture; otherwise, grass tufts will be sliced incorrectly.
- Horizontal rows represent variations of grass of the particular species (thinner, thicker, tangled, etc.). There can be from 1 to 4 rows and this number must coincide with the Num Textures value.
For a grass texture with 4 columns a mask with 4 channels should be used, refer to the Texture Slots section for more details:
Visually attractive grass, however, may reduce performance if rendered as a whole. To allow rendering at interactive frame rates, all computations are time-sliced and performed per cell of a 2D grid. So choosing the optimal Step for cells is very important for a better performance.
For more details on creating and configuring grass refer to the in-depth tutorial: Adding Grass.