# DirectX 11 Grass Shader

This documentation is a collection of information and tutorials for the various areas of the DirectX 11 Grass Shader.

{% hint style="warning" %}
This documentation is meant as a general overview of the concepts used in the shader, if you want to know what a specific setting does, look at its tooltip for more information.
{% endhint %}

{% embed url="<https://youtu.be/kiMk--uVFFI>" %}
A general introduction for the DirectX 11 Grass Shader
{% endembed %}

For feature requests, documentation problems, bugs, or other reasons you can contact me via my [support email](mailto:support@stixgames.com), or the [contact form](https://stixgames.com/contact).

Also don't forget to [join my Discord](https://discord.gg/jvBFhQA) to get support even faster and to show off your creations!

I hope you enjoy using my grass shader!


# Quick Start

{% embed url="<https://youtu.be/kiMk--uVFFI>" %}
A general introduction for the DirectX 11 Grass Shader
{% endembed %}

## Create a grass material

1. In the project window, navigate to the folder where you want to create your grass material.
2. Right click > Create > Material
3. Select the shader: `Stix Games / Grass` or `Stix Games / Grass Forward Only`

## Render the grass on your custom mesh of Unity terrain

1. Select your floor object. This can be a custom mesh or a Unity terrain, the process is the same. Make sure you have selected the object with the `Mesh Filter` or `Terrain` component.
2. Add Component: `Stix Games > General > Nature Mesh Filter`
3. Add Component: `Stix Games > General > Grass Renderer`
4. Select your grass material in the Grass Renderers Material Field
5. Configure all settings to your liking

## Customize you material

Now it's all about what you want to create. Check the [Material Settings](/general/material-settings) page, read tooltips, and try playing around with the material. The various settings can drastically change the looks and performance impact of your grass.&#x20;

If you ever get stuck, come back to this documentation, check the [Performance Optimization](/guides/performance-optimization) guide, or contact me via my [support email](mailto:support@stixgames.com), the [contact form](https://stixgames.com/contact), or [Discord](https://discord.gg/jvBFhQA)!


# Grass Renderer Components

The get grass in your scene you only need two components and a material:

* [Nature Mesh Filter](/general/grass-renderer-components/nature-mesh-filter)
* [Grass Renderer](/general/grass-renderer-components/grass-renderer)

You can also check out the [Quick Start](/general/quick-start) guide for a step by step explanation.


# Nature Mesh Filter

The Nature Mesh Filter is the bridge between the regular Mesh Filter or Unity Terrain, the Grass Renderer, and the Grass Fallback Renderer. It also supports preprocessing the mesh, so deformed meshes with irregular polygon sizes can automatically be processed, so the blades of grass appear smooth and without artifacts.

The mesh normalization should only be enabled when necessary and you should try to use as little polygons as possible, to improve performance.

{% hint style="info" %}
The Nature Mesh Filter works with regular meshes and Unity terrain, you can treat them the same and the filter will take care of the conversion.
{% endhint %}


# Grass Renderer

The grass renderer takes the processed mesh from the Nature Mesh Filter and renders your grass material.

It can also be used to automatically set the floor color and texture for your material, you should be careful not to use the same material with multiple renderers in this case, or they might interfere with each other.

{% hint style="info" %}
The grass material could also be used like a regular material, however, you need to duplicate the floor object for this. This way you lose the ability of mesh normalization and grass fallback, so it is recommended that you always use the Nature Mesh Filter and Grass Renderer components. If your project was made with pre 2.0 versions of the shader you can still use the old workflow, but I would recommend migrating to the new system.
{% endhint %}


# Material Settings

{% embed url="<https://youtu.be/kiMk--uVFFI>" %}
A general introduction for the DirectX 11 Grass Shader
{% endembed %}

This section will walk though the material settings, which includes most visual and performance related options of the asset.

## Shader Versions

* `Stix Games / Grass`: The regular grass shader with all its features
* `Stix Games / Grass Forward Only`: Like the regular grass, but deferred shading is disabled. Use this to enable all lighting features in deferred rendering. Be aware that this might cause performance loss.

## Shader Settings

Material settings for the DirectX 11 Grass Shader can be categorized in the following categories

* [Shader Variants](/general/material-settings/shader-variants): Settings that change the general behavior of the shader.
* [Performance Settings](/general/material-settings/performance-settings): Settings that change the density and level of detail of the grass. They have a high impact on performance.
* [Visual Settings](/general/material-settings/visual-settings): Settings that change how the grass looks. They generally have a low impact on performance.

{% hint style="warning" %}
This documentation is meant as a general overview of the concepts used in the shader, if you want to know what a specific setting does, look at its tooltip for more information.
{% endhint %}


# Shader Variants

Shader variants make it possible to change the shader code from within the editor, which allows for very different behavior, without having to use costly branching in the shader itself. Changing one of these settings causes the editor to recompile the shader and can increase the build time immensely.

With shader variants, it is possible to have one large shader that is very customizable, without sacrificing any performance. More info about shader variants can be found in the [Unity documentation](http://docs.unity3d.com/Manual/SL-MultipleProgramVariants.html).

If you are using more than one very complex shader, Unity might encounter errors because there are too many shader keywords. It can also cause extreme compile times, as Unity is trying to compile all combinations of shader variants. More about these in the Performance Optimization section.

## Grass Modes

### **Grass Types**

This setting is the most important for the visual appearance of the grass material. It can also have a high-performance impact. In short: "Simple" is the cheapest and "4 Textures" is the most expensive shader version.

* **Simple Grass**: In this mode, the shader generates simple, textureless blades of grass. This mode is ideal for large areas with high view distance and fits perfectly into stylized games.
* **1 - 4 textures**: This mode allows you to have up to 4 different textures. You can set their density either by using absolute values, textures, or vertex colors, each channel controls one grass type.

### **Density Mode**

The density modes can be used to add variation, so the grass is not equally distributed over your mesh, and to set areas for different grass types. You could for example have a field of wheat right next to a field of grass with occasional patches of grass using a single material.

{% hint style="danger" %}
You should never use the density modes to reduce the density of the whole material, for example having a density value of 0.5. This would cost performance, without any benefit. Instead, change the target density setting.
{% endhint %}

* **Texture density**: In this mode the shader uses a grass density lookup texture. This is perfect if you want to have control over small details in the grass. This mode requires UV coordinates on your mesh. You can use the grass painter to directly change the density texture.
* **Vertex density**: Use the vertex color to set grass densities. This mode is perfect for procedurally generated content, or if you don't need small details and want to save performance.
* **Value Based density**: If this option is checked, you can set the grass density directly via a shader variable. Use this option if you want to have a large field with uniform densities.

### **Randomize grass orientation**

This setting randomizes the direction each blade of grass is looking at, instead of being oriented towards the camera, like a billboard. This can be used to create a more realistic style and reduce visual problems in VR. When using deferred rendering this setting is mandatory. When using this setting, [subsurface scattering](/general/material-settings/visual-settings#subsurface-scattering) can be used to improve the visual quality of your grass.

This setting is performance costly, each blade of grass has to render a front and back side, instead of only once.

{% tabs %}
{% tab title="Oriented towards camera" %}

<figure><img src="/files/uNOWree5MIJ9cz1dsgkI" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Randomized  orientation" %}

<figure><img src="/files/11V8XkY1xx7N2vmYFZeK" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

The difference is fairly subtle, however the grass oriented towards the camera fakes the lighting calculations, which is not possible in deferred rendering. Note that the randomized grass in this screenshot uses a high [subsurface scattering](/general/material-settings/visual-settings#subsurface-scattering) value, so the lighting is comparable.

## Grass Lighting

The grass lighting dropdown can be used to change how grass reacts to light sources and the environment. They can have performance impact. These settings are not available in deferred rendering, as all lighting will be handled by the shared deferred rendering shader.

### **Lighting Mode**

* **Unlit**: If you are going for a very stylized look, or just don’t want to waste unnecessary performance you can completely ignore the lighting and just output the unaffected color of the grass.
* **Unshaded**: The grass will be colored by lights, but it will ignore the light angle, so no matter how the grass moves or how a light rotates, it will always have the same color. The grass will still be affected by shadows. The unshaded mode is ideal for art styles with clear color schemes and uniform colors, that are still affected by lights and shadows.
* **Inverted Specular PBR**: When using Unity's PBR rendering the specular highlights are visible in the opposite direction of the sun. While this may be realistic and can be observed in nature, however having the specular lighting in the same direction as the sun can look beautiful and fit perfectly with certain art styles. The inverted specular option switches the direction where the specular highlights can be seen. For this, a modified version of Unity's PBR lighting is used, which could result in slightly higher performance costs.
* **Default PBR**: This lighting mode uses the default Unity PBR.

{% tabs %}
{% tab title="Unlit" %}

<figure><img src="/files/Krn4dGLHURCSEsTqzxYD" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Unshaded" %}

<figure><img src="/files/iVEM46NMCfWnLQ0NrFoZ" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Inverted PBR" %}

<figure><img src="/files/WzTqShk6t4tWfyiAq2yV" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Default PBR" %}

<figure><img src="/files/uNOWree5MIJ9cz1dsgkI" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

### **Ignore specular global illumination**

Showing the reflection of the skybox or environment can make the grass appear more lifelike, but it can also cause strange-looking lighting effects. Activate this setting to ignore all global specular lighting.

### **Lighting normal mode**

This setting allows you to change the normal used for lighting calculations. You can use it to make the grass smooth into your floor object.

{% hint style="info" %}
The normal is a very important part of lighting calculations. It tells the renderer how to interpret the surface of your blades of grass. When it is changed, the renderer will calculate lighting as if they had a different orientation, even if the mesh itself doesn't change. This way you can smoothly blend grass into the floor.
{% endhint %}

* **Regular normal**: Uses the normal of the blades of grass/billboards.
* **Hybrid normal**: In this mode the diffuse calculations are done with the floor normal, but the specular lighting is done with the billboard normal. This results in grass that smooths into the floor without giving up the detailed specular highlights. However, the grass doesn't perfectly fit with the floor lighting. This mode is also more performance costly than the other two modes, as two different normals have to be used for lighting.

  This mode doesn't work in deferred rendering, it will fall back to surface normal mode instead.
* **Surface normal**: Uses the normal of the floor mesh. This mode perfectly matches the floor lighting, the grass should blend into the floor perfectly.

For the hybrid and surface normal mode, you should set the floor color parameter to be the same as your floor material. Especially for the surface normal mode, you should probably also copy the specular color and smoothness values, to create an exact match in the lighting calculations.

{% tabs %}
{% tab title="Regular normal" %}

<figure><img src="/files/FjkHGLMj11NW0EyQA9MB" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Hybrid normal" %}

<figure><img src="/files/6XjM0ykcVm3ESejot0mS" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Surface normal" %}

<figure><img src="/files/X8wpxTO6BwF8R9yyl2UD" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

Note that these screenshots don't have the same material settings. The floor color, grass color, specular color, and smoothness values have been changed to still look good with the other settings.

## Level of Detail Interpolation

With these options you can enable or disable different types of smoothing between tessellation (density) levels. They are purely visual and should only have a minor effect on performance. They can however have a significant impact on how smoothly the different levels of detail blend into each other. For a smooth result you should enable at least one of these settings.

## Object / World Space Modes

These settings can be used to change how the grass interprets the mesh it is rendered on. With "Object Space Mode" you can have grass that is on a moving platform and "Follow Surface Normal" can be used to create grass around a sphere.

## Other Shader Variants

These are general settings that change the visuals of the shader, like improving how the grass looks when directly viewed from above if you want to use the wind setting in the shader or set it manually through the density system, and most importantly if the material uses texture atlases.

## **Use texture atlas**

When this setting is enabled, each grass type will be interpreted as a texture atlas. You can set the amount of columns (width) and rows (height) individually for each grass type. The shader will randomly select one of the possible textures for each blade of grass.

This setting is probably the most powerful way of creating variation and making your material more visually appealing. You could for example create a material with 2 grass types and add various stylized blades of grass in one and different stylized flowers, or use photography-based textures to create a realistic field of grain. The amount of blades of grass per atlas is not restricted, except for the texture size limit by Unity.

{% hint style="info" %}
You can use the texture atlas creation tool to input individual blades of grass and generate a finished texture atlas. See how to use this tool in [Grass Texture Atlas Templates](/advanced-features/grass-texture-atlas-templates).
{% endhint %}


# Performance Settings

The following settings do not cause a recompile of the shader, unlike [shader variants](/general/material-settings/shader-variants), but they still have an extreme performance impact.

## **Density Settings**

The 4 density settings are the single most important settings in regards to performance and visual appearance.

* **Target Density**: This setting represents the maximum density of your grass. You should use the highest value where the material still looks good, in order to improve performance.
* **Density Falloff Start**: The distance after which grass density will start to decrease. Everything between the camera and this distance will have exactly the **Target Density**.
* **Density Falloff Scale**: Scales the falloff speed linearly. A higher value causes the density to decrease more quickly.
* **Density Falloff Power**: Scales the falloff speed non-linearly. A higher value increases the speed at which density increases.

{% hint style="info" %}
The density falloff scales like this: $$(s d)^p$$, where $$s$$ is the scale, $$d$$ is the distance from the falloff start, and $$p$$ is the falloff power.
{% endhint %}

{% hint style="warning" %}
Don't use **Target Density** like an arbitrary slider. It should represent a specific maximum density. You should use a mesh with sufficient polygon density (or use mesh normalization on the mesh filter) and select a value that represents the density you want for your scene. When you follow this rule, you will prevent artifacts, make the material more predictable, and improve your visual appearance.
{% endhint %}

{% tabs %}
{% tab title="Low target density" %}

<figure><img src="/files/oU7PU2yCjH1zEtCV1fWz" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="High target density" %}

<figure><img src="/files/WzTqShk6t4tWfyiAq2yV" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="Low falloff start" %}

<figure><img src="/files/L2Ir8xHmu3rwRPtnRNAO" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="High falloff start" %}

<figure><img src="/files/gt74ZjdxOSjDTUFv38f6" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="High falloff scale" %}

<figure><img src="/files/lXl9iXpAo9WCdSrCLQwy" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Low falloff scale" %}

<figure><img src="/files/cWJdqBun9vti76OY7sxr" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="High falloff power" %}

<figure><img src="/files/Uvs5M5NtCplcO6eP2F4M" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Low falloff power" %}

<figure><img src="/files/WzTqShk6t4tWfyiAq2yV" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

## **LOD Settings**

These settings change how many polygons are used per blade of grass. This can be used to improve performance.

## **Fade Settings**

These settings define at which distance the grass starts to fade into the ground. All blades of grass further away than **Grass Fade End** will not be rendered at all, which improves performance.


# Visual Settings

Visual settings have minor to no performance impact. They primarily influence the appearance of your material.

## **Grass Floor Color**

These settings can be used to blend the grass into the floor. The mesh filter can automatically set both materials, however, this requires a unique material per mesh, or the different mesh filters will interfere with each other.

## Wind settings

Changes the global wind. If you want to have wind areas or dynamic wind, you should disable global wind and use the interaction system instead.

## Base Textures

Textures that influence the grass material over the whole mesh, can change the color, height, base displacement (for example for crop circles, although using the interaction system instead would be recommended), and grass density.

## Grass types

These settings define the look of each grass type. Check the tooltips for more information on each setting. Most of them are either obvious, like main texture, height, and width, or are equivalent to Unity's PBR materials, like color, specular color, and smoothness.

## **Softness**

The softness setting defines how easy it is to interact with the grass type. A low softness will make the grass stiff and for example sway less in the wind.

## **Subsurface Scattering**

Subsurface scattering is available when the setting [Randomize grass orientation](/general/material-settings/shader-variants#randomize-grass-orientation) is used, however it is not possible when using deferred rendering. Grass that is oriented towards the camera calculates the grass normal as if it was always rotated towards the sun, this results in a beautiful stylized look, however, it is not realistic and can't be used in deferred rendering, where the same normal is used for all lighting calculations. With randomized grass orientation the grass has a front and back side, which can result in a very dark appearance. In reality, the grass is still lit, by light that refracts through the grass itself. The subsurface scattering setting is a very simple approximation of this, with almost no performance cost.

{% tabs %}
{% tab title="No subsurface scattering" %}

<figure><img src="/files/kcFvFmumZQd6FUWLI5mm" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="With subsurface scattering" %}

<figure><img src="/files/mopUIUG0h5gfuct1vYVk" alt=""><figcaption><p>This picture uses subsurface scattering of about 0.3, which is low enough so the front and back sides are still differently bright. You can use this to fit the grass perfectly into your art style.</p></figcaption></figure>
{% endtab %}
{% endtabs %}

## **Texture atlas settings**

The texture atlas settings are only available when [Use texture atlas](/general/material-settings/shader-variants#use-texture-atlas) is enabled in the *Other Shader Variants* setting. They tell the shader how many rows and columns are used for this texture type.


# Grass Painter

{% embed url="<https://youtu.be/CFql3cRzsf4>" %}

The grass painter is a tool that simplifies the creation of density textures. Instead of having to edit the texture in an external program, you can paint directly on your mesh or terrain. It also includes some helper functionallity, like changing the density mode and creating textures automatically.

{% hint style="info" %}
Alternatively, you can still create the texture in any application you want, for example procedurally create it in substance designer, or your terrain creator of choice.
{% endhint %}

## Opening the grass painter

To open the grass painter window you can either select the grass object, expand the Grass Renderers material settings and click on the button *"Open Grass Painter"* in the material settings, or click the menu item `Window / Stix Games / Grass Painter`.

{% hint style="danger" %}
Closing the grass painter window or switching grass objects will make changes permanent, so undoing previous changes will be impossible.
{% endhint %}

## Targets

* **Color / Height**: Modifies the color and height of your grass material. On the texture, the channels RGB are used for color, and the alpha channel is used for height.
* **Density**: Modifies the density of your grass material. Each color channel represents one grass type.

## Brush Mode

* **Add**: Add more grass. By drawing on the same area, you will add grass depending on your strength setting, until you reach the maximum.
* **Remove**: Remove grass. By drawing on the same area, you will remove grass depending on your strength setting, until no grass is left.
* **Set**: Set the amount of grass exactly to your strength setting. Drawing on the same area will not make changes, once you’ve reached the desired density.

## Other Settings

Check the tooltips of each setting for more information.

## Careful: Material Duplication

Be careful when using the same material on multiple objects. Changing one object will edit the grass on all other objects.

To solve this, you can duplicate the material and duplicate the changed textures.

{% hint style="danger" %}
If you don't remove or duplicate the textures you wish to paint on the duplicated material, you will still paint on the same texture, even though it's a different material.
{% endhint %}


# Interaction System

{% embed url="<https://youtu.be/ECD5htgbB4k>" %}

The interaction system is a flexible and customizable system that can be used to add a variety of effects to your project. While it doesn't contain any simulations, it uses a performance rendering system that enables you to have hundreds of interactors. With careful grouping, even thousands of interactor could be supported.

### How-To: Set up grass interaction rendering in your scene

1. Create a new empty object in your scene.
2. Add Component: `Stix Games > Interaction > Render Texture Interaction`, this will also create a camera component, which should be set up and disabled automatically.
3. Change the Size field on the Camera component. The size will define the area where grass interaction will be rendered. Outside, no grass interaction will occur.
4. Change the settings of the Render Texture Interaction component to fit your use case. Tooltips explain the settings in more detail.
5. Optional: Add Component: `Stix Games > Interaction > Camera Follow`
6. Add your main camera to the Camera Follow component.

If your camera size is large enough, you should never be able to see the area outside of the interaction area, as long as the interaction renderer is kept close to your main camera.

{% hint style="info" %}
Like with any other camera, the interaction renderer can't render anything outside its near and far plane, for example, objects above it. You should try to keep your interaction objects at reasonable heights, even though their height doesn't matter. You could also change the near and far clipping planes as necessary.
{% endhint %}

### How-To: Create an interaction object

### Create an interaction material

1. In the project window, navigate to the folder where you want to create your grass material.
2. Right click > Create > Material
3. Select the shader: `Stix Games / Grass Interaction / Interaction`
4. Add any normal, alpha, or burn maps you require.
5. Create a mesh for your displacement object, for example a quad object, and add the new material as usual.
6. Add Component to the new object: `Stix Games > Interaction > Interaction Object`
7. Disable the mesh renderer, but don't delete it, it is used to store the material. You can enable the mesh renderer for debugging your interaction object.

If your new interaction object is within the render area of your interaction renderer, all grass materials should react to it automatically.

### Interaction Shaders

### Interaction Shader

The Interaction shader can be used for a variety of interaction effects, for example, characters walking through the grass and leaving a trail, explosions burning away grass, new buildings dynamically removing grass, etc.

#### Influence Strength

This setting doesn't change the strength of your setting, but it will change how strongly it will override other interactors. If an interactor with influence 100 is overlapping an interactor with influence strength 1, it first one will override the second one.

You can use this to create an interaction area around your character, that will be stronger than any other interactor effect, so even with trails on the ground or explosion shockwaves, the grass will still move away from the character.

#### Grass Interaction Direction

The Interaction shader has two ways of defining the direction of grass movement:

1. Normal Map: Usually normal maps are used for additional lighting information. They tell the shader which direction the area at the position of each pixel is oriented in, e.g. which normal is at the surface's position.\
   It is the same for the Interaction shader, the grass will move approximately in the direction of your surface normal.
2. The interaction mesh itself. The shader will take the normal / direction of your object and apply the normal map to it. For example, a pyramid without a normal map would push away the grass in 4 separate directions, a cone would push the grass away in a circle.

#### Mask

You can use a mask texture to mask out certain areas of your normal and burn maps.

#### Burn Interaction

The interaction system not only supports moving the grass in any direction but also dynamically removing and coloring grass.

The RGB channels of your burn map and burn color define the color the grass will be burned in, usually, this would be a dark brown. The color is changed with a "Multiply" operation, in other words, the grass color can only be darkened and a white burn color will leave the grass untouched.

The alpha channel of your burn map is used to define how much grass will be removed in the area.

{% hint style="info" %}
You can use this feature for burning grass after explosions or fire, but you could also use it to dynamically remove grass in the area of player-built buildings, or other dynamic elements. Simply leave the burn map empty and the burn color white.
{% endhint %}

### Wind

You can use the wind interaction shader to create wind areas with the same wind algorithm as the global wind in the grass shader. If you disable the global wind on your grass material, you could use interaction objects with this shader to create complex weather systems.

### Interaction Renderers

### Interaction Object

Add this script to an object with a mesh renderer and it will automatically submit it to a render queue for all interaction objects. You don't have to manage the objects layer, simply add the component and the interaction system will be able to handle it.

### Interaction Trail Renderer

The interaction trail renderer, as the name suggests, renders a trail behind an object. It will automatically keep track of the object's position and create a trail dynamically.

The trail renderer's material must have a normal map to define the interaction.

#### Animation curve controls

The trail renderer uses animation curves to give more customizability to some of its controls. This might seem strange at first, but it's quite easy to use.

The animation curve is used to calculate the value depending on its lifetime, it starts at 0 and ends at 1 (the end of the trails lifetime). At each point, the base value of the parameter (like width) is multiplied by the corresponding animation curve.

For example: If you have a width of 1 and an animation curve that linearly decreases from 1 to 0, your trial will have a width of 1 at the start and linearly get smaller with age, until it has a width of 0. You can use this to create complex patterns and have perfect control over your application.

In this example, you can see an animation curve for the `Strength` variable. The strength starts at `Base Strength` (1), slowly starts to decrease and smoothly fades to 0, where the trail won't be visible at all.

{% hint style="info" %}
You should try to smooth the strength (and/or width) to 0 at the end of the trails lifetime (time value 1), so the trail doesn't end abruptly.
{% endhint %}

#### Jump Detection

If enabled, the jump detection will check the current distance from the defined floor layers. While the object is further down than the Jump Detection Distance, the trail will not be rendered, leaving a gap between the start and the end of the trail.

### Performance

To support multiple interactors to stack on top of each other, without losing information, it was necessary to create a custom renderer. Each render pass causes a fairly large overhead (compared to other render passes), so it is recommended to either keep the interactors as low as possible or combine multiple interactors into one. For example, if you have a large number of Units in an RTS game, where you are sure that they will never occupy the same grass area, you could create a custom mesh, where each unit has a textured quad centered at its position. If you are doing this correctly, it can be very fast. The interaction renderer will then use this procedural mesh to render a single pass, which reduces the overhead significantly.

As long as you stay below several hundreds of interactors, this should not be a problem, however. I would recommend using the profiler to find your performance bottlenecks in general.


# CPU Fallback

{% embed url="<https://youtu.be/EmygWbou-uM>" %}

The CPU Fallback is meant as an easy to use alternative to the DirectX 11 Grass shader. As Unity's OpenGL cross compiler has some problems and instabilities when used with high-end shader effects (e.g. geometry shaders and tessellation), it is still impossible to use the grass shader for consoles and mobile devices (although some consoles have been reported to work, you should try it yourself to be sure).

Instead of having to create a billboard texture manually, the goal of the grass fallback system is to automatically render a snapshot of your grass material in action, which can then be used on non-PC hardware, or lower end devices.

Alternatively, you could also use it as your main grass solution, by designing the material with the shader and using the fallback as your main grass renderer.


# How-To: Set up the grass fallback component

1. Select your grass object, where your Nature Mesh Filter and your Grass Renderer component should be located.
2. Add Component: `Stix Games > General > Grass Fallback`
3. Set up the fallback component.
4. Press the `Generate Texture Atlas` button.


# Texture Atlas Renderer Settings

These are the settings for the grass fallback preprocessor. It automatically creates a texture atlas from your grass material (taken from the Grass Renderer component).

Read the tooltips for more information on each setting. If you'd like to have more detailed explanations for one of the parameters, or for the tool in general, please use the contact form for your feedback!

The grass fallback and the grass shader aren't perfectly equivalent, so you'll have to do some fine-tuning yourself. The following settings are the most important ones for achieving this goal are the following:

## Texture Atlas

### Target Texture Size

Sets the size of the fallback texture. All density types will share this atlas, so the texture should be fairly large.

### Rows Per Grass Type

How many variants of each grass type will be used? With one row this will be 4 variants, with two rows 8 variations. Higher values will cause more variations, but lower texture quality, per billboard.

### Dilation Steps

{% hint style="warning" %}
Dilation works well for textures with very hard borders, e.g. full alpha where the grass is visible and zero alpha where the grass isn't. Textures with smooth borders can cause problems, so you should set dilation steps to 0.
{% endhint %}

Textures have a color value, even when the texture is transparent at this position. If the color is black, this can cause black borders around the texture, when mipmaps are used, or the alpha cutoff isn't set perfectly. Texture dilation takes the color of the texture and copies it into the transparent areas.

## Grass Amount

### Blades of grass

Probably the most important setting for visuals. This setting defines how many blades of grass will be rendered per billboard at full grass density. You can use this setting to match the fallback closer to the original shader.

## Density

### Density Cutoff

To prevent grass types with very low density from being rendered, adjust this setting. If one of the grass types is in areas where it shouldn't be, increase this value. If a type isn't rendered in an area for the grass fallback, decrease the cutoff value.

### Density Randomization

In an area with equal density, this setting prevents the same texture being used for all billboards. If the setting is 0, the same density will lead to exactly the same billboard texture. If the setting is too high, grass density will no longer be accurate and densities will appear stronger or weaker than intended.


# Grass Fallback Renderer

The controls for the grass fallback renderer are created to mimic the behavior of the grass shader. Further visual improvements can be expected in future updates.

## Instancing

Grass fallback can be run purely on the CPU, or use GPU instancing to optimize the renderer. If your hardware supports it, you should probably use instancing.

## Levels of Detail

The fallback renderer runs on the CPU, so we can have more control over LOD than with the shader.

Set the number of levels in the LOD array, then configure the following settings:

* **Density**: The number of billboards per unit.
* **Fade Start**: The distance at which the billboards will start to fade away.
* **Fade End**: The distance where the level of detail will be completely faded away.

{% hint style="info" %}
Unlike the grass shader, where Target Density is still a fairly vague value, the density for the grass fallback represents the number of billboards per Unity unit (meter).
{% endhint %}


# Grass Texture Atlas Templates

{% embed url="<https://youtu.be/JCWJ-2YOd2I>" %}

Creating a texture atlas manually is tedious and time-consuming. Texture Atlas Templates automate this process, effectivly eliminating the manual work, once the individual textures have been created.

### How-To: Create a Texture Atlas Template

1. Create your grass textures. Each texture should have exactly one blade of grass. They should be in sRGB mode (as color textures should always be; unless you know what you're doing).

   Try to have as little empty space as possible, you don't have to add a border padding, the template can handle that for you. The height and width of each texture should be approximately the same, however, this isn't a hard requirement. The template will balance them automatically.
2. Right-click in your project folder > `Stix Games` > `Grass Texture Atlas Template`
3. Rename and select your new template
4. Change settings, like texture size, rows, etc.
5. Lock your inspector, with the lock icon in the top right of the inspector, so you can select other files, while the template is still selected.
6. Select all your blade of grass textures, then drag and drop them into the textures field of the template. You could also set them individually, no locking will be necessary.
7. Unlock your inspector again.
8. Press the `Create texture` button and create the texture where you want it.

### Texture dilation

{% hint style="warning" %}
Dilation works well for textures with very hard borders, e.g. full alpha where the grass is visible and zero alpha where the grass isn't. Textures with smooth borders can cause problems, so you should set dilation steps to 0.
{% endhint %}

Textures have a color value, even when the texture is actually transparent at this position. If the color is black, this can cause black borders around the texture, when mipmaps are used, or the alpha cutoff isn't set perfectly. Texture dilation takes the color of the texture and copies it into the transparent areas.

### Random variations

Instead of fitting all blades of grass into a texture atlas, you can also decide to create random combinations of each blade of grass. Each variation will be a random selection of blades of grass.

The number of blades per texture can be changed with the `Overdraw` setting.

`Variations` defines how many textures will be created.


# Global Shader Variables

You can use global shader variables to change all materials at once. This can be helpful for creating in-game graphics settings.

{% hint style="warning" %}
Global Shader Variables stay changed when you exit Play Mode!
{% endhint %}

The following table contains the currently supported global shader variables.

| Shader Variable                  | Description                                                                                                                                                                                                                                                                                    |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `_GlobalTargetDensityMultiplier` | <p>Gets multiplied with the Target Density of each grass material.<br>Since Target Density is higher when the number is smaller (for historical reasons), be careful: A multiplier above 1 <strong>reduces</strong> the density, while a multiplier below 1 <strong>increases it</strong>.</p> |


# Changing the grass density center

When working with a top-down perspective, it's often preferable to move the center of the grass density somewhere other than the camera. Since version `2.10.0` it's possible to do that by adding the `Grass Density Center Override` component to the object you want as the new center. The script automatically sets the required shader keywords and updates the density center to the transform's position in `LateUpdate`.

If you want to switch between camera-based and object-based density centers, you can disable or remove the component.&#x20;

{% hint style="warning" %}
Make sure that only one Grass Density Center Override is active at a time. If more than one is active during the components `OnEnable` event, the second component will be ignored and won't function until you disable and re-enable it again.
{% endhint %}


# Performance Optimization

The following optimization areas are ordered by severity, so you shouldn't think about fill rate or pixel shader cost if your scene is full of small lights that could be optimized.

### Reduce Draw Calls

The grass shader works 100% on the GPU, each material draws all blades of grass at once. This is great performance wise, as long as this performance is done as few times as possible. Ideally deferred rendering could be used, where it would only be drawn once per camera and once per shadow caster. However deferred rendering makes it impossible to use different lighting modes or subsurface scattering, so here are a few tips for improving performance in forward rendering:

1. Reduce the number of lights that affect the material. Each light source will cause the grass to be re-rendered. You could set the culling mask of the grass material, to specifically exclude the grass from some lights.
2. Reduce shadow casters. As with lights, each time the grass casts shadows, the whole area will be rerendered. This is also true in deferred rendering. Either disable shadow casting on the material or use as little shadow casters as possible.
3. Reduce shadow cascades. Each shadow cascade causes an additional draw call, so in practice 4 shadow cascades quadruple the performance cost of the shader.
4. If your scene includes many small light sources and you can't use deferred rendering, try to split up your grass area into smaller areas. This will increase the draw calls for directional lights, but it will reduce the amount of grass that will have to be rendered per light source and make the individual draw calls smaller. With some experimentation, this could help improve performance.

### Reduce Geometry

The most performance costly part of the DirectX 11 Grass Shader is generating each blade of grass. While it is still magnitudes faster than on the CPU, the easiest way to improve performance is to simply reduce the polygons. Here are a few rules you should follow:

1. Use the Target Density to set the maximum density, in the closest areas to the camera. If the Target Density is maxed out before you reach your goal, use mesh normalization and subdivision to increase the maximum possible density. Don't set the Target Density higher than your mesh can support, this will lead to unwanted behavior.
2. The 3 other density settings can be used to change the grass falloff. Try to draw as little grass in the distance as possible. High density in the distance consumes more performance, as there is more area to cover. Keep the dense area small and centered around your camera. Use the floor texture to hide the missing grass.
3. Instead of using very small blades of grass, either use an art style that works with wide grass or bundle together multiple smaller blades of grass. You don't have to make billboards, but using a texture to represent 5-10 small blades of grass can work great as a tradeoff between performance and visuals. You can use the texture atlas tool to automatically combine multiple blades of grass.
4. Do not use the Randomized Grass Orientation mode, in this mode each blade of grass must render a front and a back side, doubling the number of triangles. However, you can ignore this tip in case you are using deferred rendering. There the benefit of only having to render the grass once, instead of per light source, likely outweighs the cost of randomizing grass orientations.

### Reduce Fill Rate

The triangles of each blade of grass have to be filled with pixel information on the GPU. This cost is minor compared to the topics above, however, if you are using a high amount of very large billboards, it could become a limitation. Either use a large number of small blades of grass or a smaller amount of large blades of grass.

Also try not to waste any texture space, try to create your textures like the right side, not like the left:

<figure><img src="/files/SdT7i0pcVrlWNqvQ6ov3" alt=""><figcaption><p>The left side is very inefficient, there's a lot of empty space on the texture</p></figcaption></figure>

### Reduce Pixel Shader Cost

Different lighting models and shader features can have different performance costs. You should use the least costly lighting mode that is compatible with your art style. For example, if you don't need specular highlights, you should use the Unshaded lighting mode, if you don't use lights at all, you should use the Unlit lighting mode. Only enable texture atlases if you are actually using them.

This is a last resort of optimization, you should always concentrate on the topics above first, however, you could gain some milliseconds for free if your art style allows it.

### Reduce Shader Compilation Time

### Make sure the shader is not in "Always Included"

There have been cases where a background script automatically moved one of the grass shaders (`Grass.shader`, `Grass Forward Only`, or `Grass URP`) in the "Always Included" list in `Project Settings > Graphics`. When the shader is in there, *all* variants will be compiled, which can take weeks.

### Skip unused shader features

Make sure the "Skip unsused shader\_feature" is enabled on all variations of the grass shader in your project, e.g. `Grass.shader`, `Grass Forward Only`, or `Grass URP`.

<figure><img src="/files/SXd6CtYoeCZFpy28DGus" alt=""><figcaption></figcaption></figure>

### Strip unused shader instances

Go to `Project Settings > Graphics`, then make sure that instance stripping is enables.

<figure><img src="/files/PuWaQxQVjljHcEkbys8G" alt=""><figcaption></figcaption></figure>

### Use a shader stripping tool

If Unity's shader compiler is still unable to reduce the shader compilation times to acceptable levels, it can be necessary to use an additional shader stripping tool. You can either create one yourself, by following the [blog post by Unity](https://blogs.unity3d.com/2018/05/14/stripping-scriptable-shader-variants/), or use a ready made tool, like the [UnityShaderStripper](https://github.com/SixWays/UnityShaderStripper). For example by following [this guide](https://github.com/SixWays/UnityShaderStripper/wiki#shaderstrippervariantcollection).

{% hint style="warning" %}
I am not a developer of the Shader Stripper tool, so I can't provide support for it. If you have any problems, please contact their developers. If you have tips that may help other developers, please contact me through the contact form and I will share them here!
{% endhint %}

### Reduce Shader Keywords

{% hint style="info" %}
With shader keywords, it’s possible to switch between multiple variants of a single, large shader. [More info in the Unity documentation.](http://docs.unity3d.com/Manual/SL-MultipleProgramVariants.html)
{% endhint %}

While this does not actually affect the performance of the shader, it can change the compile times. In some cases, Unity could even not compile at all, because of too many keywords.

To remove shader keywords, open the Grass.shader file and search for the shader-feature blocks:

```
#pragma shader_feature SIMPLE_GRASS SIMPLE_GRASS_DENSITY THREE_GRASS_TYPES FOUR_GRASS_TYPES
#pragma shader_feature __ PBR_GRASS_LIGHTING
#pragma shader_feature __ UNIFORM_DENSITY
#pragma shader_feature __ NO_TESSELLATION_SMOOTHING
```

If you want to remove a keyword, replace the shader\_feature line like this:

```
#define SIMPLE_GRASS
#define PBR_GRASS_LIGHTING
#define UNIFORM_DENSITY
//NO_TESSELLATION_SMOOTHING is not defined
```

You can replace one, or multiple lines, but they have to be identical in every shader\_feature block in the shader. " \_\_ " is an empty keyword, which can be used to switch a single feature on or off. If you want to disable a keyword using it, just don’t create a #define line, like shown with the NO\_TESSELLATION\_SMOOTHING keyword above.

There are multiple shader feature blocks per shader file, make sure all of them are identical.


# Improve Visuals

### Grass Density

Depending on your art style, you should try to have dense grass close to the camera and relatively high falloff, so it blends with the floor texture fairly fast. This way you can have a tradeoff between performance, while still having high grass density close to the camera.

### Base Geometry

Having an irregular mesh, for example, using a mesh consisting of very differently shaped polygons can cause artifacts in the grass density. Either use a mesh made out of very regular polygons or enable mesh normalization in the Nature Mesh Filter.

### Fine Tuning Wind

There are no real rules for setting the wind and you will have to find out the details through experimentation, but there might still be some guidelines to get a nicer look:

1. **Making the wind too slow will make the scene look like it's underwater.** While long grass in real life can look remarkably similar to underwater scenes (believe me, I've checked), wrong settings can exaggerate this, which looks unnatural and strange.
2. Try balancing the wind ripples to the weather you are trying to create. Wind waves alone won't be able to create a convincing result. Wind ripples can also help the lessen the underwater look.
3. If you have balanced both wind waves and ripples, but the grass is still looking too regular, try changing the grass disorder parameter.

### Low density when viewed from above

If you are using a top-down camera, like in an RTS or a city building simulator, the grass directly below your camera seems very low density. You can easily fix this, by enabling the "Improve viewing from above" option in the shader variants settings. It makes grass appear wider when directly below the camera.


# Fix Visual Artifacts

## Point lights cause some blades of grass to be extremely bright

Change the [color space](https://docs.unity3d.com/Manual/set-project-color-space.html) of your project to linear. If that's not possible for your project, please contact me and I'll investigate the problem!


# Virtual Reality

### Fix visual artifacts

In VR the camera renders 2 perspectives per frame, one for each eye. The billboard, screen-oriented grass looks good in 2D, however, this relies on some visual faking which will cause a perceived flickering in VR. It is recommended to use the randomized grass orientation, which ensures that the grass is rendered perspectively accurate for each eye.

### Optimization

As performance is extremely important in VR, you should look at the page about performance optimization in detail.

### Grass Fallback

Consider using the grass fallback instead of the shader itself. While the grass shader is very performant, it is still a high-end effect. The grass fallback could be used to reduce this performance cost, while still keeping your art style. This is especially useful if you are creating an application or game that supports both 2D and VR: On regular screens, you could use the shader, while in VR the fallback could be used to improve the performance and reach even higher FPS.


# Render Pipelines

## Universal Render Pipeline

Switching to URP is very straight forward. Simply select your grass material and change the shader to `Stix Games / Grass URP`.

## High-Definition Render Pipeline

HDRP is not supported yet. There is already some code, but it doesn't do anything remotely correct at the moment.


# Introduction

{% embed url="<https://www.youtube.com/watch?v=H9B88kh6ECs>" %}

## Introduction to Tile Composer

Before diving deep into the individual parts of Tile Composer, let's start with what its goal is and what the workflow looks like.

***

Tile Composer is a constraint based model generator, so basically you give it a set of constraints (your tiles) and it tries to fill a grid without breaking any of your rules. Depending on your rules the result might be unexpected, but with some refinement you'll be able to prevent the generator from taking any shortcuts.

Here's a simplified version of how you can use the asset:

1. Create a tileset: An artist (or programmer, with nice programmer art) creates a set of models or textures that can be used to fill a grid.
2. Define neighbor restrictions: Use one of the different workflows to define which neighbors are allowed for each tile.
3. Create a grid where you want to place your tiles.
4. Optionally: Add additional constraints, like blocking tiles (e.g. you want a house at one position, but nowhere else), change the probability of each tile, etc.
5. You're done: The algorithm tries to find a combination of tiles that fits perfectly into the grid.

{% tabs %}
{% tab title="1. Create Tiles" %}

<figure><img src="/files/wck36lIoS3EjfQV6hdYR" alt=""><figcaption><p>Setup your tile models or textures</p></figcaption></figure>
{% endtab %}

{% tab title="2. Define neighbors" %}

<figure><img src="/files/fL95Hee7p9yr42n5iKrK" alt=""><figcaption><p>Define neighbor restrictions with one of the workflows</p></figcaption></figure>
{% endtab %}

{% tab title="3. Create grid" %}

<figure><img src="/files/RO279hWhZ5mX9N53Qcq8" alt=""><figcaption><p>Create a grid where the tiles will be randomly placed</p></figcaption></figure>
{% endtab %}

{% tab title="4. Additional constraints" %}

<figure><img src="/files/24td5op9tTML4LVhCfeH" alt=""><figcaption><p>Add additional constraints, like setting the grid border to be empty</p></figcaption></figure>
{% endtab %}

{% tab title="5. Generate model" %}

<figure><img src="/files/t2Pbw3tpLK78vOYOH49y" alt=""><figcaption><p>Generate a model</p></figcaption></figure>
{% endtab %}
{% endtabs %}

Now in reality it's not quite as simple, each tile constraint can have a lot of unexpected consequences, but with a bit of tinkering and trail and error, you've just created your own bit of procedural creation, without having to touch any code!

In this documentation, I will walk through all parts of this process:

* Creating tilesets using a variety of different methods of creating the initial constraints, for example, directly from a base mesh, using connectors, or by defining every constraint by hand
* How to create a tile set that can be easily solved
* How to accomplish complex restriction (which is always a trade of complexity vs speed)
* Defining the model, including the two types of solvers, with their various advantages and disadvantages.


# Tile Collections

Tile collections are, as the name suggests, the container of tiles. Here you can change settings that affect all tiles in the collection. It also provides functionality to simplify creating the neighbor restrictions.

## Tile Collection Editor

### Automatic Neighbors

The editor tools in this category allow you to automatically set neighbor restrictions.

### **Clear neighbors**

In case you want to start from scratch, for example if you wish to switch to another workflow, you can press this button to clear all neighbors.

### **Auto-set neighbors from mesh**

This button can be used to create neighbor restrictions from the mesh of each tile. It compares each pair of tiles and checks if their borders fit together perfectly. If yes, it allows the tiles to be neighbors, otherwise they are blocked from being neighbors. For more information about this workflow check [Neighbors from mesh](/tile-composer/tutorials/neighbors-from-mesh).

### Empty Tile Assignment

Instead of having to make neighbor changes to each tile individually, you can use this tool to set empty connections on all tiles simultaneously. Select one of your empty tiles, then you can use the circles in the scene view to toggle which tiles are allowed to have this empty type as neighbor.

### Connector Assignment

Instead of adding connectors to each tile individually, you can use this tool to add/remove them on all tiles simultaneously.

To use this feature you need to add connectors in the tile collection settings.

## Tile Collection Settings

These settings change the size and shape of your grid and let you change settings that are shared by all tiles in this collection.

### Grid Type and scale

The grid type changes the shape and behavior of your tiles. For example a box grid, with box shaped tiles, makes it possible to create models with straight lines, while triangle shaped tiles can create hexagonal or rounded shapes. In the end it depends on what you want to accomplish, for most cases you will probably want to use a box or a rectangle grid.

The grid scale defines the size of your tiles. This has to match the size of your tiles perfectly, or your final model will not look right. You can still resize the model generator later.

### Grid Specifics

Some grid types have different settings, read the tooltips to see what each of them does.

### Empty tiles

Empty tiles are placeholders for spaces in the model where you don't want any tiles at all. For example in a city, you don't want to have any tiles above streets. Without an empty tile, it wouldn't be possible to create the model, because no tile is allowed to be above the street tile.

You can create multiple empty tiles, in case you want to have different empty areas that must not touch each other. Using our city example again: You can create an "Inside" empty type, to allow buildings to have space between their walls. Using the same empty type as outside here can lead to wrong models, for example a wall might be rotated inside out.

The weight of an empty type defines the probability at which it is selected in the model (same as for regular tiles).

**Is compressible** makes is easy to allow tiles with the same empty type to neighbor each other. For example, you might want to allow very small alleys between buildings, by neighboring the outside tiles of buildings directly. With the help of empty compression, you simply set both tiles to have the same empty neighbor and set it to compressible, the tiles are now allowed to neighbor each other.

### Connectors

Connectors are the basis of one of the workflows for creating neighbor restrictions. Instead of looking at each pair of tiles individually, you create connection types between multiple tiles. For example, if you want to create a street system, you could use a "Street" connector and put it on each tile side where the street will be continued, e.g. a crossing would have sides with the street connector, while straight roads and curves would have 2. Once you start the generation process, the system matches up all tiles with the same connector. Read more about this workflow on it's [documentation page](#connectors).

`Is Bidirectional`makes it possible to toggle between connectors that have directional information or not. A bidirectional connector can be connected to all instances of itself if rotation and direction make it possible. A directional connector has an "In" and an "Out" variant. Only In-Out connections are allowed, In-In and Out-Out connections are forbidden. One possible use is to create rivers or roads that go from a goal to a target.

### Custom Properties

You can use custom properties to add additional information to your tiles, then add additional constraints based on them. For example, you could add the properties "Weight" and "Cost" and restict the maximum and minimum for the model.

{% hint style="warning" %}
Not all solver types support custom properties. For example, Wave Function Collapse does **not** work with custom properties.
{% endhint %}


# Tile

Tiles are the building blocks for your model. The tile script has to be on the root of your tile, its children can be anything your want (except other tile components, that would probably lead to problems). In theory you could even create tiles that consist of Tile Composer components, so each tile in turn generates another model. Each tile has to be part of a tile collection.

## Editor Settings

These settings are meant to help you get information about the tiles faster and other tools to simplify your workflow. Read the tooltips for more information.

## General Settings

### Base Tile

The base tile setting can be used if you want to create a slight variation of another tile type. The child tile will have the same tile type as the parent tile. For example if you have a wall type and want to have a window type with the same neighbor restrictions.

A tile with a base tile can use overrides to change some of the parents settings. This can be useful if you want to have a tile that is not distinguished from the base tile, but has slight additional constraints, e.g. a wall with door shares neighbors with a regular wall, but must be placed at the ground floor.

### Tile Type

The name of your tile type. This name has to be unique.

### Base Weight

At its core the base weight simply increases the probability at which the tile will be selected in the model. However this doesn't necessarily mean it will also occur more often in the final model.

The probability is calculated for all currently allowed tiles, so if your tile has very hard restrictions, it might be that it doesn't get selected, even with a high weight. On the other hand it's possible that your tile collection frequently leads to situations where only low weight tiles are possible, in that case those tiles will be selected frequently as well.

In the end you will have to use slow generation to look at the dynamics of your model and change weights of secondary tiles.

### Can neighbor self

As the name suggests, this setting can be used to prevent automatic workflows from allowing the tile to neighbor itself. If you use the Tile Neighbor settings manually, you can still overwrite this feature, it is only relevant for the automatic workflows.

## Variations

### Rotation axes

If you want a street tile to be rotated in different directions, it's not necessary to create two tiles, instead you can select the rotation axis and the tile collection will automatically create all rotated versions along this axis.

The system will automatically remove variations with the same rotation, so you don't have to be careful when rotating around multiple axes.

## Connectors

[Connectors ](/tile-composer/tutorials/connectors)are a way of defining neighbor restrictions, without having to handle each pair of neighbors individually.

Each side of the tile can have any amount of connectors, once you generate your model the editor will match up all tiles with the same connector.

If the selected connector is not bidirectional, you also get a dropdown selector for `In`, `Out`, and `Both`. Only connections between `In` and `Out` are accepted, `Both` can connect to either. Connections between `In` - `In` or `Out` - `Out` are not allowed.

## Neighbors

These settings can be used to manually select the possible neighbors for each side of your tile.

### Empty Neighbors

This area is used by all workflows to specify which empty types are allowed on each side of your tile. Simply enable the check if the empty type is allowed on this side. You can use the "Show connection names" editor setting the check if you have selected the correct sides.

### Tile neighbors

Here you can match up each side of your current tile with any side (in case they are rotated) of other tiles.

#### Use connection lines

For ease of use you could use the "Use connection lines" feature instead of setting the neighbor matrix manually. Simply drag a line from one of the circles to another circle, either on the same tile or another tile, to allow or to prevent two tiles from neighboring each other.

#### Neighbor matrix

This is basically the raw view on how the connections are saved. There are probably easier ways of editing neighbor restrictions, but in case you need to use is for one reason or another, here's how the connections are defined:

1. Tile neighbor: The first level defines which pair of neighbors you are editing, e.g. the currently selected tile and another tile of your collection. All changes are bidirectional, so if you change something on one tile, the other tile will be updated with the same setting.
2. The side of your own tile: E.g. the left side of your tile can connect to the (...) side(s) of the other tile.
3. The sides of the other tile: E.g. the left side of your tile can connect to the right side of another tile.

<figure><img src="/files/V2kCKeLpQPHMNLuqQXNm" alt=""><figcaption><p>Here we can see that the current tile's right side is allowed to neighbor the tile SolarPanelStartRight's left side.</p></figcaption></figure>

You can also use the editor settings "Show Connection Names" and "Show Connection Lines" to visualize the allowed connections.


# Tile Composer

## Documentation: Tile Composer

The final piece for using the Tile Composer asset, is the name giving Tile Composer. This component takes a tile collection, either from the same scene or from a prefab, and generates a model from it.

### How to generate a model

The component immediately starts generating once it is activated in the scene, but you can also generate a model in the editor, by pressing the "Generate model in editor" button. Be aware that the editor doesn't support slow generation, if you want to debug your model, you should press play instead.

## General settings

Look at the tooltips for general information of all controls.

### Tile Collection

Select your tile collection here. The Tile Composer will try to create a model that follows all constraints you have set in your Tile Collection.

### Solver types

Creating a model from tiles is a very general problem (basically a SAT problem), so there can be multiple ways of solving it. The component lets you select between multiple solvers, which have different advantages and disadvantages. Look at the documentation page for [solvers ](/tile-composer/documentation/solvers)for more information.

### Generate Asynchronously

This setting let's you generate the model in a separate thread. Be careful though, it is not supported to abort calculations, so even if you leave play mode, the thread will continue trying to generate the model and use performance.

## Grid Settings

### Grid size

This setting defines the size of the grid, where tiles will be placed. Be careful, larger grids will take longer to calculate, so always try to increase the size in small steps.

### Tile restrictions

* **Blocked Tiles**: Block a certain tile type on a grid position.
* **Fixed Tiles**: Block all tiles except this grid type (this overwrites blocked tiles)

Both settings work in the following way:

<figure><img src="/files/LmXCXJM1GjpSgz08AZcU" alt=""><figcaption></figcaption></figure>

As you can see, in this example there are negative numbers. Those work like slices (for example in Python): If one of the numbers is negative, it will start at the end of the grid and walk backward. -1 represents the last grid position in that coordinate. This way you can easily define constraints that adapt to different grid sizes.

{% hint style="warning" %}
Be careful, using the scene view editor tools to change the selected area will remove negative numbers, so the slice will no longer scale with your grid.
{% endhint %}

## Solver specific settings

The solver settings let you change the inner workings of each solver and add additional constraints that may not be possible with other solvers.

Look at the documentation page for [solver](/tile-composer/documentation/solvers) for more information.

## Debug Settings

These settings allow you to debug the generation process of some solvers (at the moment only Wave Function Collapse). Look at the tooltips for more information.


# Solvers

Creating a model from tiles is a very general problem (basically an SAT problem), so there can be multiple ways of solving it. Each solver has their advantages and disadvantages. Use this guide to help you choose the right solver for your project.

## Wave Function Collapse

Wave Function Collapse is a fairly new technique. Its basis is quite simple:

1. Select a grid position (in most implementations based on entropy; simplified: select the grid position where the least number of tiles are possible)
2. Randomly select one of the tiles that are allowed at this position.
3. Tell all neighboring grid positions which tiles are no longer allowed next to the selected tile. This process is propagated, so if one of the neighbors can no longer be a certain tile, it continues informing neighbors of the change.
4. Repeat until tiles have been selected for all grid positions.
5. In case there is a grid position where **no** tiles are allowed, either abort or start failure recovery.

A lot of work while developing this asset has gone into failure recovery techniques. You will likely have to play around with the different settings yourself, as each tile collection requires very different error handling. Even with the improved error handling, it is still a fairly simple technique, so if you want to use a very complex tile collection, with dependencies over multiple tiles (e.g. one tile requires exactly one other tile, which again requires exactly one other tile...) you should consider another solver type, or if possible simplify your model dramatically, to decrease the calculation time.

Wave function collapse always operates within the grid (unlike Z3, which works with logical formulas), so it is possible to watch it work. This can be extremely helpful for debugging your tile collections. Use the Debug Settings on the Tile Composer component to enable slow debug generation.

Unlike for example the Z3 solver, Wave Function Collapse never realizes when a model is impossible, so in case your tile definitions are wrong, it might not be obvious when using this solver.

### Settings

For more information on each of the settings specific to Wave Function Collapse, look at their tooltips.

### Comparison

**Advantages:**

* Very fast for simple models
* Model generation can be slowed down and viewed, for debugging

**Disadvantages:**

* Can't solve very complex models
* Can't detect impossible models#

**Use cases:**

* Tile collection where there are almost no failure states, e.g. add a tile for each combination of neighbors.
* Tile collections with some complexity, like the "asian village" example or the "cyberpunk city" example" , can be solved for some seeds and the right failure recovery settings, but might be impossible with others.

## Z3 Solver

The Z3 Solver is a SMT solver originally developed by Microsoft and is now freely available under the MIT license. An SMT solver is a program that lets you input formulas or more mathematical theorems and logically tries to find an answer to the problem. It is far more complex than wave function collapse, which helps it solve extremely complex problems, but unlike Wave Function Collapse, it was not created for this specific problem. Both the complexity and the lack of specialization make the solver a lot slower in our case. That still doesn't mean the Z3 solver can't be useful.

### Settings

Z3 allows more complex rules, so it is possible to restrict the count of a tile type, instead of changing its weight. Be careful, percentage and absolute constraints can make the solver extremely slow.

For more information on each of the settings specific to the Z3 solver, look at their tooltips.

### Comparison

**Advantages:**

* Can solve extremely complex problems.
* Allows additional restraints, for example, a minimum or maximum count of a specific tile.
* Can mathematically prove if your problem is impossible. This way you can easily test if your tile or model definition is wrong.

**Disadvantages:**

* Slower than wave function collapse (at least for simple models)

**Use cases:**

* Models with high complexity
* Very small models
* Models where complex restrictions are necessary
* Debugging your model, e.g. checking if it is possible to create a model with your current settings


# Helpful Tools

The asset includes several helpful editor tools that make it easier to set up tile collections.

You can access them through the menu bar `Tools / Stix Games | Tile Composer`.&#x20;

<figure><img src="/files/XKmU441m7XMWtmfowH92" alt=""><figcaption></figcaption></figure>

## Create tile component on selected

This helper creates a tile component on each selected object.

## Create a tile hierarchy from selected

This helper treats the selected objects as a hierarchy of tiles, e.g. the parent will be the base tile and children will be tiles that inherit properties from it.

Additionally, the tool creates a parent object for each tile.

## Create tile variation

If you want to create a slight variation of a finished tile, use this helper, it will copy the selected tile and make the original the base tile of the parent.

## Create tile replacement

When using the `Auto-set neighbors from mesh` feature there can be situations where you want to make manual changes, but still want to be able to iterate the base mesh.

In this case you can create a tile replacement: Create a copy, make the original the base tile, then deaktivate the original. `Auto-set neighbors from mesh` will still use the disabled original, and your changes will not be overridden.


# Empty Tiles

It might be obvious that empty space is important for creating models. In Tile Composer this is even more true, as empty spaces shape the model itself.

Early during development, I noticed that a single empty type could be too restricting for some models, which is why Tile Composer supports adding as many empty types as necessary. In this short tutorial, I will explain what empty types are and how to use them to create a simple building tileset.

## Basics

First of all, empty tiles are not special in any way, they are regular tiles with some automatically added neighbor restrictions. The only real difference is that the Tile Composer component will leave an empty slot while creating the model, instead of instantiating a tile. Each empty tile can neighbor itself in all directions but is forbidden to neighbor any other empty type. You can either use the empty neighbors toggles on each tile or use the tile collection empty assignment tool to change which tile sides may neighbor an empty tile.

<figure><img src="/files/MZ1tVplDrpkpAIqRr1Hx" alt=""><figcaption><p>When you select a tile component, you can toggle which sides are allowed to neighbor an empty tile. </p></figcaption></figure>

<figure><img src="/files/q1Zd6izo69GwfQsb9R7Y" alt=""><figcaption><p>Select the tile collection and you can use the empty tile assignment tool, to toggle which sides are allowed to neighbor each tile. Simply click on the circles to toggle if the empty is allowed there, or not. </p></figcaption></figure>

## Multiple empty tiles

Whenever you have empty spaces that will never touch each other, you should probably use multiple empty tiles. For example the inside and outside of a building, where the inside will never be visible. The constraint solvers will likely have an easier time if you have stronger restrictions, so differentiating between empty spaces could be a good start. Splitting empty spaces could make tile definitions in general much easier. However you should always try to make the neighbor restrictions as restrictive in possible, at least when using Wave Function Collapse, block as many tiles as possible, so the solver can reach a valid model as soon as possible. Read the [Wave Function Collapse documentation](/tile-composer/documentation/solvers#wave-function-collapse) for more information about optimizing tile collections for that solver.

***

Here's an example of a model that is only possible with an inside and outside tile type, at least not easily.

<figure><img src="/files/7HP5J4CTyDHvp1x50vVL" alt=""><figcaption><p>The tiles meet perfectly at the diagonal, so they technically don't neighbor each other. With an inside empty type this becomes quite easy. The top roof tiles neighbor <code>inside</code> on the bottom, the diagonal roof tiles neighbor <code>inside</code> on their inner side. The solver handles the rest.</p></figcaption></figure>

{% hint style="warning" %}
The house example is included with the asset, in `Examples / Showcases / House`. Please be aware that this model is not optimized, it's merely a demonstration of using the inside type.
{% endhint %}


# Connectors

The connectors workflow is the last I developed, but in my opinion it is the easiest to used and most expressive workflow in most situations. The only situation when for example the [neighbors from mesh workflow](/tile-composer/tutorials/neighbors-from-mesh) would be better, is when you have a large amount of unique neighbors, so you would need a large amount of connectors, which could be hard to manage.

## 1. Tile set

In this tutorial I will define the connections for the spaceship example scene, here you can see the tileset:

<figure><img src="/files/mw8lZQG8RKnxwUvO6L14" alt=""><figcaption></figcaption></figure>

I've already created a TileCollection component as parent for all tiles. Each of the tiles has to have the Tile component, you can use one of the [helper tools](/tile-composer/documentation/helpful-tools) to add batch add the tile component to all objects. The TileCollection uses a Box grid, but in this case it could have been a Rectangle grid instead, as the model always stays in one layer. You could easily extend it to create spaceships with 3d structures.

The ring tile isn't composed of multiple tiles, instead it is a single tile that goes beyond its tile size. Without additional constraints, the ring tiles can intersect with other parts of the spaceship. The second ring uses the first ring as base tile, the only difference is that it rotates in the opposite direction.

The only tile that will be rotated is the transition between thin maintenance and thick spaceship sections. We could also duplicate the tile and rotate it by 180°, that would also improve the performance of the Wave Function Collapse solver.

## 2. Empty tiles

We only need a single empty type, all outside areas of the spaceship are allowed to neighbor it, while the connection parts, where the spaceship will be connected to other spaceship tiles must not neighbor empty areas.

I'm using the Tile Collection Empty Assignment tool to change which sides may neighbor empty tiles.

<figure><img src="/files/txKUAf6WJ2zNdrPeEDzw" alt=""><figcaption><p>To activate the empty assignment mode, press the assign button, right of the empty types name.</p></figcaption></figure>

<figure><img src="/files/BhfZkTgjZiViI9jjpxqZ" alt=""><figcaption><p>Then click all circles where you want the empty tile to be allowed. If the circle is green, it means that the tiles side may neighbor the empty tile.</p></figcaption></figure>

## 3. Connectors

Next let's set up the connectors themselves. In the tile collection I've created 4 connectors. One each for the large and small connections between spaceship parts, I called them Main and Maintenance, both of them bidirectional. Next we need two directional connectors, I called them Utility and Solar panel.

{% hint style="info" %}
Bidirectional means that the connector doesn't have a direction, all sides with this connector can be connected, at least if their rotation allows it. Directional connectors have in and out directions. Outgoing connectors can only be connected to ingoing connectors, connectors with the same type can't be connected. You can still add both In and Out to a tile side, which means it can be connected to all sides with the same connector type.
{% endhint %}

<figure><img src="/files/ivvHkvUH7N2f2IAU1tHs" alt=""><figcaption><p>The final connector setup.</p></figcaption></figure>

Next we have to assign connectors to the tiles. Once again, I'm using the Tile Collection assignment tool. Here are the final assignments:&#x20;

{% hint style="info" %}
The color of each circle represents their status with the connector you're currently assigning. Yellow represents connections that are bidirectional, Green is In, Red is Out
{% endhint %}

{% hint style="warning" %}
Be careful, some of the circles are colored more transparent, because the editor doesn't recognize orthographic view at the time of writing this tutorial.
{% endhint %}

<figure><img src="/files/1RpGs5Zi7KjvhD07DLlh" alt=""><figcaption><p><strong>Main</strong>: All sides with a large spaceship opening.</p></figcaption></figure>

<figure><img src="/files/vsDz1Loipkxg3CBUEjr9" alt=""><figcaption><p><strong>Maintenance</strong>: All sides with a small spaceship opening.</p></figcaption></figure>

<figure><img src="/files/ty5EY0SkMBomJ0SDKCMr" alt=""><figcaption><p><strong>Utility</strong>: We want solar panel sockets to only connect to the spaceship utility sockets, not to each other (which would lead to free floating solar panels), so we use an In connector for each utility port on the spaceship and an Out connector on each solar panels base plate. </p></figcaption></figure>

<figure><img src="/files/xEhFssbEam6pGqyqk44O" alt=""><figcaption><p><strong>SolarPanel</strong>: Once again, we don't want free floating solar panels, to we use In and Out connectors to restrict their direction. Now solar panels can only connect to each other and have to be connected to a spaceship at their base.</p></figcaption></figure>

## 4. Tile Composer

The last step is to set up the Tile Composer component. There are a few steps for this model:

* Add the tile collection to the Tile Composer component.
* Block the cockpit tile on the whole grid, we only want a single spaceship.
* Create a border of empty space around the model, otherwise we might get cut off spaceship parts at the border.
* Set a fixed position for a cockpit tile, this overrides the block.
* Optional: Select a seed with a good looking result (you can fine tune the weights of each tile to improve the results)

<figure><img src="/files/ZcPN4LZ5fEtEeo2mqIQX" alt="" width="563"><figcaption><p>The final Tile Composer settings.</p></figcaption></figure>

## 5. Result

<figure><img src="/files/eOYxVk3xI0EtwvHHSQfr" alt=""><figcaption><p>One of the possible results.</p></figcaption></figure>


# Neighbors from mesh

Instead of using the editor to change tile neighbors, you can use the mesh itself to define which tiles may neighbor each other. This way you can stay inside your modeling software and can rapidly iterate different ideas.

I developed this approach before creating the Connectors workflow and I believe that in most situations the latter is more powerful and easier to use, but there might be situations where working with the mesh directly could be advantageous.

Possible use cases:

* Working with an artist with no knowledge of Unity
* Dynamically loading tile collection during runtime, for example for modding
* A tile collection with a huge amount of different connectors, where it would be hard to manage them manually, but easy to match vertices

<figure><img src="/files/PG3Dq33XpZQls5Uv8RDm" alt=""><figcaption></figcaption></figure>

## How to use Neighbors from mesh

1. Select you tile collection
2. Press the `Auto-set neighbors from mesh` execute button

All previous neighbor connections will be overwritten, but empty types will be preserved, as long as the side has no possible tile neighbors.

## How are neighbors matched?

The editor automatically changes the neighbors matrix, so each tile with the same vertices on one border can neighbor each other.

Here is how the editor decides if two tiles may neighbor each other:

1. Select two tiles with any of their allowed rotations.
2. Select a side and move them together as if they were neighbors in a grid
3. Only look at the vertices that are exactly on the tile border (you should use a snap to vertex / edge / face feature of your modelling tool)
4. For each vertex on one tile (and vice versa), there should be at least one vertex on the other tile with the following conditions:
   1. The vertices have exactly the same position (with a small variance for floating point errors)
   2. The normals of the vertices have to be on the same side of a triangle (vertex order is ignored, only normals are considered)
5. Repeat this for every combination of tiles and rotations.

{% tabs %}
{% tab title="Rendered" %}

<figure><img src="/files/fbpXwkUWAOGQS5GywWmp" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Wireframe" %}

<figure><img src="/files/zyhp0huKzkshOSq76DOc" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

In short, match each vertex of one tile with at least one vertex of the other tile and be aware of normals.

## Manual changes

Not all types of connection can be realized with mesh borders. In terms of the connector workflow, mesh borders are always bidirectional, all tiles with the same border match each other. If you want to add additional restrictions or wish to allow additional tiles you may notice a problem:

Executing `Auto-set neighbors from mesh` overwrites all neighbor settings, so if you manually change the neighbors matrix you can't use the feature any more.

The simple solution is to create a replacement tile, e.g. copy the tile, make the original base tile of the copy, then disable the original. Alternatively you can use the [helper tool](/tile-composer/documentation/helpful-tools) `Tools/Stix Games | Tile Composer/Create tile replacement`.

You can use the tile replacement to override neighbors from the original, but whenever you use the neighbors from mesh feature, the changes will still be made to the disabled original.

## High poly models

Matching every single polygon to neighbor tiles can be very time consuming, so instead of creating the final model I recommend using the following workflow:

1. Create a simple base mesh that has the basic structure you are aiming for.
2. Test generating models with the base mesh, iterate until the results are as planned.
3. Create replacement tiles for each tile, replace the mesh with a higher poly / detailed version of the tile set.

This way you can quickly see if the model works and can iterate quickly before moving to time consuming modling.


# Neighbor matrix editing

The most fine grained way of editing the tile neighbor matrix manually. In other words you take a tile and define which of it's sides may neighbor the side of another tile.

This is definitely the most work intensive way of working with Tile Composer, but there are some situation where it might be useful:

* Your tileset has many tiles that can only neighbor few other tile types, so you would need a huge amount of connectors.
* Creating a custom tool that automatically changes the neighbors

The neighbor matrix works has multiple layers:

1. The tile you are editing, each tile has a matrix of all other tile types
2. The target tile type, the next layers will decide if and where the two types may neighbor each other. This could be an empty type, but also the same tile type.
3. The side on the first tile: Can the target tile type neighbor our current tile *on this side*?
4. A selection of sides of the second tile: The selected sides may neighbor the current tiles side.

{% hint style="info" %}
You have to select the sides on the neighbor tile, because it may be rotated in any direction. The neigbor matrix always uses the original rotation to check compatibility. Just select any sides that are allowed to neighbor each other and Tile Composer will handle the rest.
{% endhint %}

<figure><img src="/files/GstrVkv4uXDmBUSVVWrb" alt=""><figcaption><p>In this example the left side of the selected tile can neighbor the right side of the tile type "Cockpit".</p></figcaption></figure>

## Use Connection Lines

In practice you should probably use the "Use Connection Lines" feature of the tile editor. When enabled, each side of you tile will have a circle. Click and drag this circle to the side of another tile and the connection will either be allowed or prevented.

<figure><img src="/files/ZZChy54vRmojoo5H7pMQ" alt=""><figcaption><p>The line between the two tiles connects the forward side of the engine with the back side of the crossing tile. The green circle shows that once the mouse is released, the two sides may connect each other. (The mouse was removed by the screenshot, it is in the green circle) </p></figcaption></figure>


# Combining Workflows

All of the workflows supported by Tile Composer can be used in combination with each other.

## Workflow execution order

1. **BaseTile Overrides**: A copy of each tile is created, base tile values are overwritten by children. They use the neighbor matrix that is shown in the editor, so neigbors from mesh and manual changes are already included.
2. **Tile Connectors**: Tile connectors are used to add additional connections, this overwrites the previous matrix. Connectors can only *add* allowed neighbors, not remove them.
3. **Empty Type Compression**: Tiles with the same compressible empty type neighbor can now neighbor each other
4. **Tile Rotation**: Tiles are rotated, their weight is divided between all rotations.
5. **Model Generation**: The tile variations are now handed to the selected solver, with their additional settings.


# Multiple Tile Composer Passes

When working with Tile Composer, it is often easier to create a Tile Collection that generates a simple model in the right shape, than getting the right shape with all visuals tiles. For example dungeon walls can have their own constraints, which reshape the room layouts.

In cases like this, you can create your model in multiple passes, for example:

* Create the room layout first, then using a complex tile set in the next step.
* Generate the basic shape of an island, then add rivers, decoration etc.
* First basic building shapes, then detailed tiles with complex rules.

{% hint style="danger" %}
You'll have to be careful that your first pass doesn't create restrictions that are impossible to solve with your second Tile Collection. When in doubt, switch the second solver to Z3, it can tell you if restrictions are impossible. It's quite quick at it too.
{% endhint %}

Here's how you can set up multiple passes:

1. Create two Tile Composers with two Tile Collections (You could also use the same one twice, but that probably doesn't make sense, unless you want to create a cellular automaton...)
2. Create a GameObject and add a Multi Pass Adapter component.
3. Select the tile collection of the first Tile Composer and the target Tile Composer
4. Add conversion rules. You can convert a tile type to multiple tile blocks or to a fixed tile.
5. Disable `Instantiate Model When Generate` on the Source Tile Composer.
6. Disable `Generate On Start` on the Target Tile Composer.
7. Add the Multi Pass Adapter's `Next Pass` to the `On Model Generated` event on the source Tile Composer. Don't forget to change the event to `Editor and Runtime` if you want to generate the model in the editor. It should look like this:

   <figure><img src="/files/e124tMLtXxz9qPBszBWU" alt=""><figcaption></figcaption></figure>
8. Finished! When you press `Generate model in editor` on the first Tile Composer or press Play, the second pass will automatically be triggered after the first one finishes.

{% hint style="info" %}
You could also use multiple Source Tile Composers as long as they have the same Tile Collection (or Tile Collections with the same Tile Types).
{% endhint %}


# Custom Grid Types

{% hint style="danger" %}
&#x20;I'm not sure how much demand will be for custom code like this, so for now it will be a fairly minimalistic guide. In case you need more information, please contact me. I will try to help you with your problem and consider extending this guide.
{% endhint %}

{% hint style="info" %}
&#x20;In case you're wondering why the IGrid interface is so large: It's mostly for optimization and because of annoying properties of grids that aren't rectangular. I'm always open for ideas how to simplify the whole thing, especially as most of the functions are only used at a single point in the code.
{% endhint %}

## Create an implementation of IGrid

Look at the Doc comments of IGrid and the implementation of hexagon grids (I've tried to keep this one clean) for help.

You should be aware of the following implementation details:

* The grid itself is stored as a single array, the IGrid is responsible for mapping the represented grid to this array.
* The implemented solvers (Wave Function Collapse, Z3) support arbitrary grids, so the IGrid has to tell them details about their nature, e.g. how many rotational axes exist for tiles of this grid, how many sides per tile, etc.

I personally find it extremely helpful to put as much of the internal implementation into helper functions, so you don't have to think about Coordinate - Index relationships, or which index is the neighbor in a certain direction.

## Add the new grid to other scripts

1. Add the grid to the GridType enum, in `Scripts/Grid/GridType.cs`.
2. Add it to the TileCollection. Just search for all uses of GridType in that file and imitate what's being done with the other grid types.


# Text Animations for UI Toolkit

<figure><img src="/files/utzbCSUIMcRBqvr1ecwS" alt=""><figcaption><p><em>Text Animations for UI Toolkit</em> used in UI Builder</p></figcaption></figure>

**Welcome!** Text Animations for UI Toolkit is an asset for animating text in UI toolkit. Animations can be added by writing rich text tags (like `<rainbow>`) into your text. It's perfect for making your UI elements juicy and giving life to your dialogues.

Check out the [Getting Started](/text-animations/getting-started) guide to set up Text Animations for UI Toolkit in your project as fast as possible. The asset also includes a showcase scene that shows how to use text animations with a simple dialogue system.

To quickly see which types of animations are supported, look at the [Built-in Text Appearance / Vanishing Animations](/text-animations/typewriting/built-in-text-appearance-vanishing-animations) and the [Built-in Animations](/text-animations/animations/built-in-animations) pages. If that's not enough for you, check out [Custom Animations](/text-animations/animations/custom-animations) and [Custom C# Animations](/text-animations/c-extensions/custom-c-animations), to create anything you can imagine.

***

**Have fun** and don't forget to join my [Discord](https://discord.gg/jvBFhQA) to share what you've created, or to start a discussion!

If you're having problems with something, or if you want to request a feature, contact me via the [contact form](https://stixgames.com/contact/).


# Getting Started

This guide will help you get started with Text Animations for UI Toolkit and how to get started with some of the most important features. If you already have a scene or existing UI Toolkit UI where you want to integrate text animations, you can skip the step(s) for settings up a new scene and a UXML file.

## Setting up your scene and adding an Animated Label

1. Import the Text Animations for UI Toolkit asset using the Unity package manager.
2. Create a new scene.
3. Create a new GameObject and add a UI Document component:

<figure><img src="/files/nGqOI7Iiz62NJDvtEnd6" alt=""><figcaption><p>A new UI Document component</p></figcaption></figure>

4. Open UI Builder and create a new document (or edit your existing one)
5. Add a AnimatedLabel element in UI Builder:

<figure><img src="/files/tFMeZTbATcS3amysO5t0" alt=""><figcaption></figcaption></figure>

6. Add the following text to the `text` field of the AnimatedLabel: \
   `Hi, welcome to <wave>Text Animations</wave> for UI Toolkit`

<figure><img src="/files/pNsH6vBcnTvqyuuxBTtU" alt=""><figcaption></figcaption></figure>

7. Save the `uxml` file and add it to the UI Document component you've created before:<br>

   <figure><img src="/files/1SF8PlkIgZCqYpYp0EIe" alt=""><figcaption></figcaption></figure>
8. Press play and you'll see your text being animated

You can change the text like any other `Label` in UI Toolkit, by setting a value to the `text` property. The text will start animating immediately.

Don't stop here, or you'll miss most settings and customizations! The next section will explain how to create a *Text Animation Settings* asset and how to add it to your animated text.

## Creating a Text Animation Settings and adding it to the Animated Label

1. Open the context menu of your Project Panel and create a Text Animation Settings object with `Create > Stix Game > Text Animations for UI Toolkit > Text Animation Settings`
2. Add your newly created settings file to the Animated Label in UI Builder, then save the document:

<figure><img src="/files/rw9WQUR8Z2x9R6hs3lGU" alt=""><figcaption></figcaption></figure>

3. The settings are now applied to the element and can be used to set up typewriting, default and fallback animations, performance settings, and more. \
   For more detailed information, read the documentation page [Text Animation Settings](/text-animations/text-animation-settings).

## Adding event handlers

Now that we have text animations set up, the text step is to let other systems react to the animations.

1. Let's assign a name (id) to our Animated Label in UI Builder. It can be whatever name you want, but you'll need to use the same name in the event handler components later:

<figure><img src="/files/dvdHU1Q6dkycqbxipqKY" alt=""><figcaption></figcaption></figure>

2. Create a new GameObject with an `Audio Source` component.
3. Add a `Animated Text Audio Emitter` component.
4. Drag the `Audio Source` into the field `Source` in the emitter.
5. Drag the `UI Document` into the field `Ui Document` in the emitter.
6. Add one or more audio files to the List `Sounds` on the emitter.

<figure><img src="/files/v5I4qu0BcFx2dhDGXh3U" alt=""><figcaption><p>The fully set up audio emitter</p></figcaption></figure>

Press Play and you'll hear sounds whenever text is written on the screen.

Next, you could check out the `AnimatedTextEvents` component. It is similar to the audio emitter, but can be used to integrate animation events with your own scripts.

***

**Have fun** creating animated text! Check out the rest of the documentation. You could start with [Built-in Animations](/text-animations/animations/built-in-animations) and add different animations to your text.

If you're still confused or if you have any requests for this guide or the asset in general, contact me via the [contact form](https://stixgames.com/contact/), or join my [Discord](https://discord.gg/jvBFhQA). Of course, you're also welcome to show off your creations or start discussions!


# Animated Visual Elements

<figure><img src="/files/tFMeZTbATcS3amysO5t0" alt=""><figcaption><p>Animated visual elements can be found under <code>Custom Controls (C#)</code> in UI Builder</p></figcaption></figure>

## AnimatedButton

The animated equivalent of the built-in Button. You can change the animated text by setting the `text` property via script.

## AnimatedLabel

The animated equivalent of the built-in Label. You can change the animated text by setting the `text` property via script.

## Other Elements

If you are missing an element type you need for your project, contact me via my [contact form](https://stixgames.com/contact/), or join my [Discord](https://discord.gg/jvBFhQA)!&#x20;


# Text Animation Settings

<figure><img src="/files/LG9DNurpXhj6Ijb4xs17" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Check the tooltips for each setting for more information.
{% endhint %}

*Text Animation Settings* can be used to customize your animated text. Create a new *Text Animation Settings* object by right-clicking in your project folder, then `Create > Stix Games > Text Animations for UI Toolkit > Text Animation Settings`. Then add the new object to your animated text element in UI builder.

{% hint style="warning" %}
Make sure to add your Text Animation Settings to all your animated text elements in UI Builder, or the settings won't have any effect.
{% endhint %}

<figure><img src="/files/u6dHCl5lJRWtspaYFS9G" alt=""><figcaption><p>A settings object was set in UI Builder. The Text Animation Settings will be used for this object.</p></figcaption></figure>

## Changing Text Animation Settings at runtime

It's possible to change animation settings at runtime, but some of the settings may not update unless you regenerate your text, i.e. by changing `text` on your animated text element.


# USS Properties

Currently, Text Animations for the UI Toolkit cannot be configured using USS properties, except for Unity's built-in text settings, such as font size and text color.

If you have a use case where you would profit from being able to configure animations with USS styles, please contact me via the [contact form](https://stixgames.com/contact/), or join my [Discord](https://discord.gg/jvBFhQA)!


# Templates

Templates can be used to create shortcuts or presets for multiple tags. You define a new tag that gets replaced by some other tags before the text is processed by the animated text element.

<figure><img src="/files/iaOy2OUpt1q3oS8qnO2i" alt=""><figcaption><p>Templates can be found in the General section of your Text Animation Settings</p></figcaption></figure>

The replacement is done in a pre-processing step via string replacement. It's simple but powerful.

## Example

Let's start with a template like this:

| Property    | Value                      |
| ----------- | -------------------------- |
| Tag         | angry                      |
| Opening Tag | \<b>\<color="red">\<shake> |
| Closing Tag | \</shake>\</color>\</b>    |

If you use the tag like this:

`Hey, I'm a <angry>very angry</angry> character! I bet you're <wiggle>scared</wiggle>.`&#x20;

The `<angry>` and `</angry>` tags will be replaced like this:

`Hey, I'm a <b><color="red"><shake>very angry</shake></color></b> character! I bet you're <wiggle>scared</wiggle>.`&#x20;

Very intimidating. Since it's just string replacement, you can add any tags you want. Rich text tags, built-in animation tags, custom animations, etc.

{% hint style="info" %}
If you want to go crazy, you could even include template tags *inside* other style tags, but it will only work with some extra care: Each style is only replaced **once**. They get executed sequentially. That means if your first style contains a tag for your second style, the replaced tags will get replaced too, but it won't work the other way around.
{% endhint %}


# Performance Optimization Guide

Text Animations will likely not be a significant performance cost in your project. In case you should still run into problems, this guide may help you with your problems.

If you still have performance after reading this guide, make sure to contact me via [my support email](mailto:support@stixgames.com), the [contact form](https://stixgames.com/contact/), or on my [Discord](https://discord.gg/jvBFhQA).

## Avoid adding/removing classes high in the hierarchy

{% hint style="info" %}
Special thanks to Discord user HenryHoffman for profiling and figuring out this problem!
{% endhint %}

Text Animations for UI Toolkit creates a complex hierarchy of elements. Because of this, it's especially important to follow [Unity's best practice](https://docs.unity3d.com/Manual/UIE-USS-WritingStyleSheets.html): Use BEM to target the animated labels directly, instead of changing classes high in the hierarchy, and target the animated visual elements directly.

Changing classes for a large number of animated elements is better than making a single change on the document root element.

To clarify, it's not necessary to target individual letters, add and remove classes to the animated visual elements themselves.

## Keep your text short

You should only animate short pieces of text. Instead of animating a large section at once, show the text sentence by sentence. If you can't avoid animating a large text, you could inline an [Animated Visual Elements](/text-animations/animated-visual-elements) into a larger text, or split the large text into multiple smaller animated text elements that get shown with a delay, instead of putting the whole text into a single [Animated Visual Elements](/text-animations/animated-visual-elements).

Most of the performance cost will occur when you set the `text` property of the animated text element. Your text gets parsed (searching for tags in the text) and Labels are created for each letter. Text Animations for UI Toolkit tries to reuse visual elements, so the first call will most likely be the most performance costly one.

## Reduce the animation framerate

If you haven't already done so, create a *Text Animation Settings* object in your project folder (`Create > Stix Games > Text Animations for UI Toolkit`). Add the settings object to your Animated Text Element in UI builder or via script.

You can change the *Target Frame Rate* in the Performance section of the Text Animation Settings object. A lower target frame rate means the text is updated less frequently, improving performance.

{% hint style="warning" %}
Make sure to add the *Text Animation Settings* object to your animated text elements (in UI builder or via script) or the settings will be ignored!
{% endhint %}


# Built-in Animations

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><strong>Tag</strong>: <code>&#x3C;bounce></code></td><td><strong>Params</strong>: <code>a</code>, <code>f</code>, <code>l</code>, <code>w</code></td><td><a href="/files/TV08CTqjiBThCLp7BdeK">/files/TV08CTqjiBThCLp7BdeK</a></td></tr><tr><td><strong>Tag</strong>: <code>&#x3C;rainbow></code></td><td><strong>Params</strong>: <code>d</code>, <code>f</code>, <code>l</code>, <code>w</code></td><td><a href="/files/gmO6P8R8IfjVeok2oBcM">/files/gmO6P8R8IfjVeok2oBcM</a></td></tr><tr><td><strong>Tag</strong>: <code>&#x3C;rot></code></td><td><strong>Params</strong>: <code>f</code>, <code>w</code></td><td><a href="/files/kaiTrDH8QQWpcZgP7Sym">/files/kaiTrDH8QQWpcZgP7Sym</a></td></tr><tr><td><strong>Tag</strong>: <code>&#x3C;shake></code></td><td><strong>Params</strong>: <code>a</code>, <code>d</code>, <code>f</code>, <code>l</code></td><td><a href="/files/6eAxuVjUpjGJveILWI2j">/files/6eAxuVjUpjGJveILWI2j</a></td></tr><tr><td><strong>Tag</strong>: <code>&#x3C;size-wave></code></td><td><strong>Params</strong>: <code>a</code>, <code>d</code>, <code>f</code>, <code>l</code>, <code>w</code></td><td><a href="/files/T4glUrEOMFw6WZcapP8k">/files/T4glUrEOMFw6WZcapP8k</a></td></tr><tr><td><strong>Tag</strong>: <code>&#x3C;swing></code></td><td><strong>Params</strong>: <code>a</code>, <code>d</code>, <code>f</code>, <code>l</code>, <code>w</code></td><td><a href="/files/A74uiSXlSTJvntq5tuk4">/files/A74uiSXlSTJvntq5tuk4</a></td></tr><tr><td><strong>Tag</strong>: <code>&#x3C;wave></code></td><td><strong>Params</strong>: <code>a</code>, <code>d</code>, <code>f</code>, <code>l</code>, <code>w</code></td><td><a href="/files/mkkj15UIQ6KFZJRCErdx">/files/mkkj15UIQ6KFZJRCErdx</a></td></tr><tr><td><strong>Tag</strong>: <code>&#x3C;wiggle></code></td><td><strong>Params</strong>: <code>a</code>, <code>d</code>, <code>f</code>, <code>l</code></td><td><a href="/files/9g8hR9gpjxyO2465YayH">/files/9g8hR9gpjxyO2465YayH</a></td></tr><tr><td><a data-mention href="/pages/Spoh6KZjl3s07INjuOp3">/pages/Spoh6KZjl3s07INjuOp3</a></td><td><strong>Params</strong>: <code>a</code>, <code>d</code>, <code>f</code>, <code>l</code>, <code>w</code></td><td><a href="/files/zUDPepqNm6CmggdlDP8P">/files/zUDPepqNm6CmggdlDP8P</a></td></tr></tbody></table>

### Parameter Types

<table><thead><tr><th width="178">Name</th><th>Description</th></tr></thead><tbody><tr><td><code>a</code></td><td><p><strong>Amplitude</strong>, the strength of an effect. A higher amplitude creates a stronger effect.</p><p>For example: the height of a wave, the amount shake offsets letters.</p></td></tr><tr><td><code>d</code></td><td><strong>Delay</strong>, the time in seconds before the effect starts.</td></tr><tr><td><code>f</code></td><td><strong>Frequency</strong>, the speed of an animation. A higher frequency creates a faster effect.</td></tr><tr><td><code>l</code></td><td><strong>Limit</strong>, the number of cycles (or seconds for animations without cycles) before the animation stops.</td></tr><tr><td><code>w</code></td><td><strong>Wave Size</strong>, for effects that work in waves (<code>&#x3C;wave></code>, <code>&#x3C;rainbow></code>, etc.). For example, a wave size of 5 means the full wave will be completed after 5 letters.</td></tr></tbody></table>

## Examples

<table><thead><tr><th width="452">Code</th><th>Explanation</th></tr></thead><tbody><tr><td><code>Example &#x3C;wave>text&#x3C;/wave>!</code></td><td><code>text</code> is animated as a wave, it uses default parameters.</td></tr><tr><td><code>&#x3C;wiggle>Example&#x3C;/wiggle>&#x3C;wave>text&#x3C;/wave></code></td><td><code>Example</code> wiggles with default parameters; <code>text</code> waves with default parameters</td></tr><tr><td><code>&#x3C;wave>Example &#x3C;swing>text&#x3C;/swing>&#x3C;/wave></code></td><td>Animations can be combined</td></tr><tr><td><code>&#x3C;wave f=5>Example&#x3C;/wave></code></td><td><code>Example</code> waves 5 times per second.</td></tr><tr><td><code>&#x3C;wave a=3 d=3 f=5 w=10>Example&#x3C;/wave></code></td><td><code>Example</code> waves with an amplitude of 3 (very large), a frequency of 5, and a wave size of 10 letters. The animation starts 3 seconds after the text appears.</td></tr></tbody></table>

## Performance cost

The type and amount of animations you use should not significantly impact performance. Most of the performance cost is up-front when you set your text and is mostly dependent on the length of your text.

Check out the [Performance Optimization Guide](/text-animations/performance-optimization-guide) for more information.

***

Check out [Custom Animations](/text-animations/animations/custom-animations) and [Custom C# Animations](/text-animations/c-extensions/custom-c-animations) if you want to extend the asset with your own animations.

Is an important animation missing? Or maybe an animation tag doesn't support a parameter you'd like to use? Contact me via the [contact form](https://stixgames.com/contact/), or join my [Discord](https://discord.gg/jvBFhQA) and I'll try my best to help you!


# Custom Animations

## Custom Animation Preset

If the built-in animations aren't enough for you, don't worry! You can easily create your own animations by creating a *Custom Animation Preset*. Press the *Create custom animation* button in your [Text Animation Settings](/text-animations/text-animation-settings) or [Typewriter Animation Settings](/text-animations/typewriting/typewriter-animation-settings), or right-click in your project view, then `Create > Stix Games > Text Animations for UI Toolkit > Custom Animation Preset`.

<figure><img src="/files/iu1W9DZuf9M1I7Q8E1Hr" alt=""><figcaption><p>A custom animation that wiggles the letters vertically.</p></figcaption></figure>

Set up your custom animation in the preset object. Read the tooltips for more information on some of the settings.

### Usage Example

You use the animation by adding your tag to the text like this:

```
This is how to use the <vertical-wiggle>animation</vertical-wiggle> shown above.
```

## Text Appearance and Vanishing

You can convert a custom animation into a appearance and/or vanishing animation by setting the `Is Text Appearance Effect` and `Is Text Vanishing Effect` properties to true. You can also them to your [Typewriter Animation Settings](/text-animations/typewriting/typewriter-animation-settings) or trigger it with a tag as usual.


# Shader Graph Animations

In Unity 6.3 and later, it's possible to use Shader Graphs in UI toolkit. This page describes how you can use this feature with *Text Animations for UI Toolkit.*

## Import the utilities and sample package

Import the `Shader Animation Utilities & Sample for Unity 6.3 and later` Unity package into your project. It's in the `StixGames/TextAnimationsForUIToolkit` folder.

This package contains an example scene and a few utility sub-graphs that can be used to create your own effects.

## How to use animations

Create a UI shader graph following [Unity's documentation](https://docs.unity3d.com/6000.3/Documentation/Manual/ui-systems/ui-shader-graph.html), create a material, and add the material to the Animated Visual Element, as you would with any other Visual Element. That's already everything you need to get started. You can use the time node or the [special shader properties ](#special-shader-properties)for animations. Everything else is up to your imagination!

## Changing material properties with tags

Use the `<shader>` tag to change material properties for parts of your text. For example, if you set the strength of your effect to 0, you can enable it only for specific parts of the text.

The shader tag can currently be used to set the following kinds of value:

<table><thead><tr><th width="106">Value Type</th><th>Example</th></tr></thead><tbody><tr><td>Float</td><td><code>&#x3C;shader property="_FloatProperty" value="0.1">Animated text&#x3C;/shader></code></td></tr><tr><td>Color</td><td><code>&#x3C;shader property="_ColorProperty" value=#FF0000>Animated text&#x3C;/shader></code></td></tr></tbody></table>

## Special shader properties

{% hint style="info" %}
Don't forget to check out the utility sub-graphs in the included `Shader Animation Utilities` package. They can help you with setting up appearance and vanishing animations quickly. Also check out the sample scene to see this feature in action.
{% endhint %}

The text renderer sets the following shader variables. Add them to your shader graph blackboard, or use the helper sub-graphs to access them.

<table><thead><tr><th width="179">Property Name</th><th></th></tr></thead><tbody><tr><td><code>_AnimationTime</code></td><td>The current internal animation time of the Animated Visual Element. You can also use the Time node if you don't need your shader to use the exact same time as the text.</td></tr><tr><td><code>_AppearanceTime</code></td><td>The time when the current letter <em>starts</em> to appear.</td></tr><tr><td><code>_VanishingTime</code></td><td>The time when the current letter has <em>fully</em> disappeared.</td></tr></tbody></table>

## Technical details

The animation renderer creates a copy of your material for every single letter. This makes it possible to change material properties dynamically as needed. If you need to make changes on the fly, you could create a new material with the updated settings.&#x20;

If that's not performant enough for your use case or you have any other questions or problems, please contact me via the [contact form](https://stixgames.com/contact/), or join my [Discord](https://discord.gg/jvBFhQA). Of course, you're also welcome to show off your creations or start discussions!


# Changing Text Mid-Animation

By default animated text elements reset their animation whenever you change the value of `.text` . To create a continuous animation while changing text it's possible to use the `SetTime()` function to manually manage the animation progress.

### Example

The following script pauses the text element, which keeps it from advancing the internal timer on its own, then it manually sets the time each frame.

```csharp
using TextAnimationsForUIToolkit;
using UnityEngine;
using UnityEngine.UIElements;

public class ChangeTextMidAnimation : MonoBehaviour
{
    public UIDocument uiDocument;

    private IAnimatedTextElement _element;
    private float _startTime;

    private void Start()
    {
        _element = TextAnimationUtility.GetAnimatedTextElement(uiDocument, "animated-timer");

        // Stop the visual element from automatically advancing time
        _element.Pause();
        _startTime = Time.time;
    }

    private void Update()
    {
        var currentTime = Time.time - _startTime;
        _element.text = $"<wave>Timer: {currentTime:F}</wave>";
        _element.SetTime(currentTime);
    }
}
```

{% hint style="warning" %}
Note that using `.SetTime` to manually manage an animation currently does not support [Events](/text-animations/events/events). If you need both of these features combined, please contact me via the [contact form](https://stixgames.com/contact/), or join my [Discord](https://discord.gg/jvBFhQA)!
{% endhint %}


# Built-in Text Appearance / Vanishing Animations

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><strong>Tag</strong>: <code>&#x3C;fade-in></code></td><td><strong>Parameters</strong>: <code>d</code></td><td><a href="/files/F8TloxY49dwosTaVh82K">/files/F8TloxY49dwosTaVh82K</a></td></tr><tr><td><strong>Tag</strong>: <code>&#x3C;fade-out></code></td><td><strong>Parameters</strong>: <code>d</code></td><td><a href="/files/a9ziVxHbP3O0aE8j5m4Z">/files/a9ziVxHbP3O0aE8j5m4Z</a></td></tr><tr><td><strong>Tag</strong>: <code>&#x3C;offset-in></code></td><td><strong>Parameters</strong>: <code>d</code>, <code>x</code>, <code>y</code></td><td><a href="/files/ms10NfcpQ9XKgzFb4RvE">/files/ms10NfcpQ9XKgzFb4RvE</a></td></tr><tr><td><strong>Tag</strong>: <code>&#x3C;offset-out></code></td><td><strong>Parameters</strong>: <code>d</code>, <code>x</code>, <code>y</code></td><td><a href="/files/jMTeN34W7n1dgtjMSo0E">/files/jMTeN34W7n1dgtjMSo0E</a></td></tr><tr><td><strong>Tag</strong>: <code>&#x3C;random-in></code></td><td><strong>Parameters</strong>: <code>a</code>, <code>d</code></td><td><a href="/files/aSI4TsOuqMwczS45PEGC">/files/aSI4TsOuqMwczS45PEGC</a></td></tr><tr><td><strong>Tag</strong>: <code>&#x3C;random-out></code></td><td><strong>Parameters</strong>: <code>a</code>, <code>d</code></td><td><a href="/files/AUX22UkRplrakFpk9LwC">/files/AUX22UkRplrakFpk9LwC</a></td></tr><tr><td><strong>Tag</strong>: <code>&#x3C;size-in></code></td><td><strong>Parameters</strong>: <code>a</code>, <code>d</code></td><td><a href="/files/p0G9Uv8ZzUkOBdMwn25X">/files/p0G9Uv8ZzUkOBdMwn25X</a></td></tr><tr><td><strong>Tag</strong>: <code>&#x3C;size-out></code></td><td><strong>Parameters</strong>: <code>a</code>, <code>d</code></td><td><a href="/files/CD3b0RS0He0EZ778zX6J">/files/CD3b0RS0He0EZ778zX6J</a></td></tr><tr><td><a data-mention href="/pages/Spoh6KZjl3s07INjuOp3">/pages/Spoh6KZjl3s07INjuOp3</a></td><td><strong>Parameters</strong>: <code>a</code>, <code>d</code></td><td><a href="/files/NTcf6AV93QMfXqaxqPDG">/files/NTcf6AV93QMfXqaxqPDG</a></td></tr><tr><td><a data-mention href="/pages/Spoh6KZjl3s07INjuOp3">/pages/Spoh6KZjl3s07INjuOp3</a></td><td><strong>Parameters</strong>: <code>a</code>, <code>d</code></td><td><a href="/files/MLHyeWfQu4nScQCYfMUU">/files/MLHyeWfQu4nScQCYfMUU</a></td></tr></tbody></table>

### Parameter Types

<table><thead><tr><th width="178">Name</th><th>Description</th></tr></thead><tbody><tr><td><code>a</code></td><td><strong>Amplitude</strong>, the strength of an effect. A higher amplitude creates a stronger effect.<br>For example, the distance a letter moves in <code>random-in</code> or <code>random-out</code> or the target font size (in percent) for <code>size-in</code> and <code>size-out</code>.</td></tr><tr><td><code>d</code></td><td><strong>Duration</strong>, the time in seconds until the text has fully faded in or out.</td></tr><tr><td><code>x</code></td><td><strong>X Offset</strong>, the amount of horizontal offset.</td></tr><tr><td><code>y</code></td><td><strong>Y Offset</strong>, the amount of vertical offset.</td></tr></tbody></table>

## Changing text appearance / vanishing speed

The speed at which text is appearing and vanishing can be changed in the [Text Animation Settings](/text-animations/text-animation-settings). Make sure you've added your text animation settings object to your animated text element in UI builder, or the settings will not be applied to your element.

There is also a special control tag (`<speed>`) for speeding up or slowing down text dynamically, more in [Typewriter Control Tags](/text-animations/typewriting/typewriter-control-tags).

## Examples

<table><thead><tr><th width="452">Code</th><th>Explanation</th></tr></thead><tbody><tr><td><code>Example &#x3C;fade-in>text&#x3C;/fade-in>!</code></td><td>The word text uses the <strong>Fade in</strong> text appearance animation. If the <a data-mention href="/pages/u2YsdNO4kxnKeOrYDdbY">/pages/u2YsdNO4kxnKeOrYDdbY</a> have default animations, the fade-in is layered on top of them. <br>If the settings has <strong>Fallback Animations</strong> set up, the fade-in replaces them.</td></tr><tr><td><code>&#x3C;fade-in>&#x3C;fade-out>Example text</code></td><td>It's not necessary to close the tags at the end, if you want to change text appearance / vanishing animations for the whole text.</td></tr><tr><td><code>&#x3C;fade-in>Example &#x3C;size-in a=2>text&#x3C;/size-in>&#x3C;/fade-in></code></td><td>It's possible to layer different kinds of animations.</td></tr></tbody></table>

## Performance cost

The type and amount of animations you use should not significantly impact performance. Most of the performance cost is up-front when you set your text and is mostly dependent on the length of your text.

Check out the [Performance Optimization Guide](/text-animations/performance-optimization-guide) for more information.

***

Check out [Custom Animations](/text-animations/animations/custom-animations) and [Custom C# Animations](/text-animations/c-extensions/custom-c-animations) if you want to extend the asset with your own animations.

Is an important animation missing? Or maybe an animation tag doesn't support a parameter you'd like to use? Contact me via the [contact form](https://stixgames.com/contact/), or join my [Discord](https://discord.gg/jvBFhQA) and I'll try my best to help you!


# Typewriter Animation Settings

*Typewriter Animation Settings* can be used to setup default and fallback animations in the [Text Animation Settings](/text-animations/text-animation-settings). You can create a *Typewriter Animation Settings* object with the create buttons in the **Text Animation Settings** object or the Create Asset menu.

<figure><img src="/files/3kLKG7pMdLrGO1zMnyWt" alt=""><figcaption></figcaption></figure>

## Performance Cost

The type and amount of animations you use should not significantly impact performance. Most of the performance cost is up-front when you set your text and is mostly dependent on the length of your text.

Check out the [Performance Optimization Guide](/text-animations/performance-optimization-guide) for more information.


# Typewriter Control Tags

The following table contains special control tags than can be used to influence the typewriter.

| Tag                                       | Description                                                                                                                                                                                                         |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `<pause=0.3>`, `<pause=5>`                | Adds a typewriting pause in seconds. For example `<pause=0.5>` will create a half-second break in text appearance and text vanishing.                                                                               |
| `<speed=0.3>`, `<speed=120%>`, `</speed>` | <p>Change the speed of the typewriter.<br>Influences both appearance and disappearance speeds. <br>Adding a new speed tag overwrites the last speed, and closing the tag resets the speed to the default speed.</p> |


# Events

Text Animations for UI Toolkit includes an event system that can connect the animations to other systems, such as creating sound effects when text appears, or showing a skip / next button.

You can use the [Built-in Event Handlers](/text-animations/events/built-in-event-handlers) to react to events. If that's not powerful enough for you, it's also possible to create [Custom Event Handlers](/text-animations/c-extensions/custom-event-handlers).

<table><thead><tr><th width="332">Event Name</th><th>Description</th></tr></thead><tbody><tr><td><code>LetterAppearanceEvent</code></td><td>Get raised for every single letter that appears. You can offset the timing of this event with the <code>Letter Appearance Event Offset</code> in the <a data-mention href="/pages/u2YsdNO4kxnKeOrYDdbY">/pages/u2YsdNO4kxnKeOrYDdbY</a>, which can help synchronize sound effects with text appearing while using fade-in effects.</td></tr><tr><td><code>TextAppearanceFinishedEvent</code></td><td>The event is emitted when the last letter has appeared. It can be used to handle <em>Skip</em> and <em>Next</em> button functionallity. Check out the example scene to see it in action.</td></tr><tr><td><code>CustomEvent</code></td><td>A custom event created with the <code>&#x3C;event="name"></code> tag. The name you specify in the tag is saved in the <code>name</code> field of the event.</td></tr></tbody></table>


# Built-in Event Handlers

## Animated Text Audio Emitter

<figure><img src="/files/yCkACC35FTP8rSVKQZvn" alt=""><figcaption><p>The Animated Text Audio Emitter is an easy way to create sounds for your dialogues.</p></figcaption></figure>

Use this component to create sound effects based on your animated text with the Unity default Audio Source. The component receives letter appearance events from the animated text and selects sound effects from a list of sounds.

To avoid too many sounds being played, use the `Min Time Between Sounds` option.

## Animated Text Events

<figure><img src="/files/I7LBVxADwJEYiYoMqoRu" alt=""><figcaption><p>A generic interface for text animation events</p></figcaption></figure>

The *Animation Text Events* component is an easy way to interface text animations with your code. Unity Events are triggered whenever a text animation event is received. It also includes filtering options, like limiting the time between letter appearance events.

## Missing Something?

Check out [Custom Event Handlers](/text-animations/c-extensions/custom-event-handlers) if you want to create your own event handler.

Do you have a use case you think should be included as a built-in component? Maybe you need third-party integration with FMOD or something similar? Contact me via the [contact form](https://stixgames.com/contact/), or join my [Discord](https://discord.gg/jvBFhQA) and I'll try my best to help you!


# Custom Events

You can emit custom events by using the `<event="customEvent">` tag. Adding this tag will create a `CustomEvent` with the `name` field set to "customEvent".&#x20;

For example, the following text would emit two events:

```
<event="wave">Hi! I hope you enjoy using <event="jump"><bounce>animations</bounce>
```

At the start it emits a `CustomEvent` with the name "wave", later it emits an event with the name "jump" right when the word "animations" starts to appear.

{% hint style="warning" %}
Custom events only work when you have Text Appearance enabled in your [Text Animation Settings](/text-animations/text-animation-settings).
{% endhint %}

## Reacting to events with the Animated Text Events component

<figure><img src="/files/KcAUWAINzpWGW04GcbUl" alt=""><figcaption></figcaption></figure>

You can add as many custom events as you want. Use the `On Custom Event` UnityEvent to interact with your scene.

## Reacting to events from C\#

You can add an event handler to the `customEventTriggered` event on your animated visual elements.

```csharp
var animatedLabel = uiDocument.rootVisualElement.Q<AnimatedLabel>("animated-label");
animatedLabel.customAnimationTriggered += YourEventHandler;
```


# Custom C# Animations

{% hint style="info" %}
Unless you want to create an animation that dynamically reacts to external events, or an animation that includes randomness, like `<shake>` you can use [Custom Animations](/text-animations/animations/custom-animations) instead of Custom C# Animations.
{% endhint %}

To create a custom animation you need 3 steps:&#x20;

* Create a class inheriting from `TextAnimation`. It will be responsible for animating the text.
* Create a class inheriting from `TextAnimationTagParser`. It will parse the tag and create a `TextAnimation` object with the right parameters.
* Register the parser.

## Text Animation

In this example we'll create a simple animation that moves opacity between 0 and 1.

<figure><img src="/files/WbkEaxbaQxRbFfqrTlgi" alt=""><figcaption><p>The annimation we're going to create in this short tutorial.</p></figcaption></figure>

```csharp
public class OpacityPingPong : TextAnimation
{
    // The frequency of the animation with a default value.
    // The default value is going to be used if no parameter is specified in the tag
    public float frequency = 1;

    // The construction takes the tag used to create the animation object.
    // In case of our simple animation that wouldn't be necessary,
    // but it's useful for animations that have different variants (fade-in / fade-out)
    public OpacityPingPong(string creatorTag) : base(creatorTag) { }

    // Here's where the animation happens.
    // This function is called every frame for every single letter, 
    // even if they are invisible, so try not to do anything crazy in here.
    public override void Animate(
        Letter letter, // The current letter being animated
        int letterIndex, // The index of the currently animated letter
        float time, // The current time of the animation
        AnimationResult result // Contains all modified animation properties
    )
    {
        // Calculate a triangle wave between 0 and 1, that's our opacity!
        var opacity = Mathf.PingPong(time * frequency, 1);
        
        // Multiply the current opacity with our new value.
        // It's important to always modify properties in a way that doesn't overwrite
        // the changes set by other animations.
        // If we wrote `result.opacity = opacity;` here, this animation would break
        // all other animations that use opacity.
        result.MultiplyOpacity(opacity);
    }
    
    // Optimization hints for UI Toolkit.
    public override bool animatesColor => false;
    public override bool animatesTransform => false;
}
```

## Text Animation Tag Parser

```csharp
public class OpacityPingPongParser : SimpleTextAnimationTagParser
{
    public override IEnumerable<string> GetTagNames()
    {
        // This animation parser only supports a single tag
        return new[] { "ping-pong" };
    }

    public override TextAnimation CreateAnimation(string tag, Parameters parameters)
    {
        // Create a new object of our new animation class.
        var pingPong = new OpacityPingPong(tag);

        // Check if the animation tag has the parameter "f" set.
        // If yes, set the value in our ping pong class
        if (parameters.TryGetFloatValue("f", out var frequency))
        {
            pingPong.frequency = frequency;
        }

        // Return the animation object with the right parameters.
        // The animation will be applied to all letters within the tag.
        return pingPong;
    }
}

```

## Registering the parser

There are two ways to register an `AnimationParser` for your text elements:

```csharp
// Register the parser for a single text element
animatedText.AddAnimationParser(new OpacityPingPongParser());

// Register the parser globally
TextAnimator.AddGlobalAnimationParser(new OpacityPingPongParser());
```

## How to use the new animations

Now everything is set up, you can use the animations like any other:

```
Hello, let's try our new <ping-pong>animation</ping-pong>!
```

***

You can also look at the code of all built-in animations for inspiration.

If you need help developing custom animations or want to share your creations, join my [Discord](https://discord.gg/jvBFhQA) and start a discussion!


# Custom Event Handlers

## Using events in custom MonoBehaviours

When the *Animated Text Events* component is not good enough or too inconvenient to use, you may want to register your own event listeners. After reading this short guide, I recommend looking at the code of the built-in event handlers and the *Example Dialogue* component, from the example scene, for inspiration.

1. To get started, your component needs a reference to the UI Document containing your animated text element.&#x20;
2. Then you can use `TextAnimationUtility.GetAnimatedTextElement` to find your text element. If you need a specific type of animated text element instead of the interface `IAnimatedTextElement`, use `uiDocument.rootVisualElement.Q<AnimatedLabel>("dialogue-box")` instead.
3. Register handlers for the events you're interested in.
4. Make sure to unregister all events in `OnDisable`, or your component will continue working when disabled.

```csharp
public class CustomEventHandler : MonoBehaviour
{
    // 1. Reference your UI Document
    [SerializeField]
    private UIDocument uiDocument;

    private IAnimatedTextElement _dialogueBox;

    private void OnEnable()
    {
        // 2. Find your animated text element
        _dialogueBox = TextAnimationUtility.GetAnimatedTextElement(uiDocument, "dialogue-box");
        
        // 3. Register the events you're interested in
        _dialogueBox.animationEvent += OnAnimationEvent;
        _dialogueBox.letterAppeared += OnLetterAppeared;
        _dialogueBox.textAppearanceFinished += OnTextAppearanceFinished;
    }

    private void OnDisable()
    {
        // 4. Unregister your events in OnDisable, 
        // or your component will continue to work when disabled.
        _dialogueBox.animationEvent -= OnAnimationEvent;
        _dialogueBox.letterAppeared -= OnLetterAppeared;
        _dialogueBox.textAppearanceFinished -= OnTextAppearanceFinished;
    }

    private void OnAnimationEvent(TextAnimationEvent ev)
    {
        Debug.Log("Received animation event");
    }

    private void OnLetterAppeared(LetterAppearanceEvent ev)
    {
        Debug.Log("Received letter appearance event for letter: " + ev.letter);
    }

    private void OnTextAppearanceFinished(TextAppearanceFinishedEvent ev)
    {
        Debug.Log("Received text appearance finished event");
    }
}
```

***

Are you stuck? Maybe you need another kind of event that isn't supported yet?&#x20;

Contact me via the [contact form](https://stixgames.com/contact/), or join my [Discord](https://discord.gg/jvBFhQA) and I'll try my best to help you!


# Limitations

*Text Animations for UI Toolkit* use visual elements for each letter. Visual Elements are created with performance hints, so UI Toolkit can optimize the elements in the background, making the animations very fast once all elements are created.

Because each letter is a UI Toolkit `Label` we are limited to anything supported by visual elements, which means we are limited to animating the following properties:

* Vertical and Horizontal Offset
* Color
* Opacity / Alpha
* Size
* Rotation


