Real-Time Vehicle Trails in Deformable Terrain

Real-Time Vehicle Trails in Deformable Terrain
Real-Time Vehicle Trails in
Deformable Terrain
Alexander Frisk
Alexander Frisk
VT 2017
Master Thesis, 30 hp
Supervisor: Matti Larsson (Zordix), Stefan Johansson(Umeå University)
Examiner: Henrik Björklund
Civilingenjörsprogrammet i datavetenskap, 300 hp
One way to make racing games more realistic is to have the
vehicles in the game deform the terrain and leave permanent
trails when driving them. This master thesis presents algorithms and theories about generating those trails behind the
vehicles in real-time applications. The proposed trail system
is based on Bézier curves to represent and store the path of
the trails. All the steps in the algorithm needed to create the
trail and handle some of the edge cases are explained in detail. The game called Snow Moto Racing Freedom by Zordix,
which is used for testing and implementing the solutions, is
covered as well. The finished trail system has both been implemented as a CPU and as a GPU based version, where the
two implementations have been tested to see which one is the
most effective in the game used.
The report is summarized with a list of extensions which can
be used to further develop and enhance the trail system. It
ends with a summary of the project as a whole with some
advices for a similar projects.
I would like to thank Zordix for giving me the opportunity to do this master
thesis at a game company as I have been able to learn a lot about game
developing by being there. Thanks to Matti Larsson, for being my supervisor
at Zordix and for always being positive and helping out by bringing new ideas
to the table. I also need to thank the programmers that helped me out during
the project. Both by explaining how the game was built and suggesting ways
to solve the problems I had.
Warm thanks to Stefan Johansson, my supervisor from Umeå university, for
continuously correcting this thesis. He taught me a lot about academic writing
and without his help, this thesis would not be what it is today.
1 Introduction
Project goal
2 Theory
Computer graphics
The Graphics Pipeline
Compute shaders
Shaders in Unity
Representing a curve
The trail path
Bézier curves
3 The Game
Game modes
Project focuses in the game
Current implementation
Benefits and drawbacks
4 New Trail System
Implementing composite Bézier curves
Trail creation
Masking the sampling close to the snowmobile
Handling long trails
Avoiding trails in the air
Mapping the trail to the ground
Sharp turns
CPU implementation
GPU Implementation
5 Testing
Test sequence
Test results
6 Results
Test results
CPU implementation
GPU implementation
7 Extensions and improvements
Handling trail crossing
Avoiding trails in certain areas
Combining deformation and trail creation
Saving the trail paths
Level of detail
Bézier simplification
8 Discussion
Project problems
Conflict with existing trail generation system
Project adjustments
Trail visuals
Developing in Unity3D
Developing in an existing game
Project summary
9 Conclusion
The future of trail systems
1 Introduction
This project is about implementing and testing prototypes of a novel trail
rendering algorithm for the game company Zordix. The results will be the
basis for further development of improving the realism of the games made
When vehicles are driving through deformable terrain, such as snow or sand,
they leave trails behind them. When making a racing game in that setting, it is
important to give the players the feel that they are blazing through the terrain
and actually affecting it. By having the vehicles leave permanent trails, the
player will feel the weight and impact of the vehicle which adds to the realism.
Therefore, it is desirable to have a system which can create the trails left
behind by the vehicles.
Unity, the engine being used, already have a feature which is called Trail Renderer which can be used to create trails behind objects. It has a lot of features
and it follows the objects perfectly, but the trails are always temporary which
is not good enough if it is desirable to keep the trails permanent. Therefore
we have to implement our own system which can create permanent trails like
we want.
There are a few different implementations done in other games for simulating
trails, but none of them are a perfect fit for creating trails behind the vehicles
realistically. One notable implementation is the snow deformation in the game:
Batman: Arkham Origins[1] where the snow deforms when characters moves
through it. There are also some other implementations of the same type of
system in Unity asset store [2]. Zordix is using a similar system in their games
right now. The problem with these solutions is that they only deform the
terrain according to a given shape. Because of that, the deformation does
not leave any marks which tells the direction the deformation was created
in. So when there are multiple trails crossing and overlapping each other, the
deformation overlap and it all becomes the same height. Because of that, the
sense of direction is lost and they will not look like trails anymore. There
is also the problem that it is desirable to have the trails leave some texture
to look like the pattern of the wheels leaving the trails, which is why those
solutions are okay, but they do not perfectly reflect reality.
There are some other solutions where skidmarks are added after vehicles with
a texture [3]. These solutions are good in that they show both the shape
and the direction of the wheels leaving the trails. The problem is that they
usually take up too much resources (in respect to speed and memory) to be left
permanently in the terrain so they are removed after a while. Moreover, these
solutions usually do not deform the terrain either so even if the skidmarks was
effective enough, there would not be any deformation to the terrain which is
more important when the game takes place in a deformable terrain.
The purpose of this project is to examine the possibility to have the trails left
behind the vehicles in a deformable terrain to be automatically generated in
a large scale. If possible, the trails left by the vehicles should be able to stay
there for an unlimited time to make it look like the player actually deforms the
surrounding environment permanently like in real life. There are two different
implementations which are covered in this project: one for the CPU and one
for the GPU. The algorithm for generating the trails should be as similar as
possible for both implementations to more accurately measure the differences.
In order to find the most suitable solution of the two, a performance test is
conducted. The performance test is done to ensure that the solution is fast
enough to be used in real-time applications, like games.
Project goal
The goals of the project are:
• Create a system for generating permanent trails behind vehicles traveling
through deformable terrain.
• The trail system should be able to create realistic trails in real-time.
• The principles used in the trail system should be generic so they can be
used in multiple settings.
• Testing the differences between a CPU and a GPU implementation, and
find out which one is more suitable depending on what is needed.
Zordix started out as a company developing powersports racing games, e.g.
snow-mobiles and jet-skis, for handheld devices. Their games became a suc12
cess which gave Zordix the ability to expand. Now the company focuses on
developing games in the same franchise but focuses on the current generation
of gaming consoles and PCs instead of handheld devices. These machines have
much higher performance capabilities than handheld devices, which raises the
customers expectations of the games’ quality. In order to meet those expectations, Zordix develops their games in a cross-platform game engine called
Unity3D. Unity3D provides basic frameworks and tools for developing games
and without that it would be impossible to develop games at this level for a
small company like Zordix. The gaming industry as a whole has gotten tougher
since there are a lot of games to compete with nowadays, especially with the
huge amount of cheap games that are released every day. That means it is really important to have something that makes their games stand out from the
rest in order to sell enough to profit from them. One possible idea to make the
games stand out is to have the vehicles leave permanent trails on the terrain,
like they do in real life, as that has not yet been done in a good way by their
2 Theory
Since the problem is grounded in computer graphics, understanding of some
basic concepts in computer graphics is needed. As the project is developed in
Unity, the quirks of Unity are also explained a bit more in detail.
Some common terms in computer graphics used throughout the report:
• CPU - Central Processing Unit is the main processing unit in a machine.
• GPU - Graphical Processing Unit is the graphical unit which handles the
graphics rendering and computations on the graphics card.
• Vertex - Points in space the graphic lines are drawn through.
• Face normal - The direction a surface (face) is facing.
• Triangulation - The method of dividing a plane into triangles for easier
• Maps - An image containing information for each position.
• Texture - An image which is drawn onto the objects in a predefined way.
• UV-coordinates - Coordinates which define what part of the texture
should be mapped to which pixel on the object.
• Splat map - A map where the colors define how the textures should be
blended with each other.
• Graphics pipeline - The process on the GPU for rendering objects to
• Tessellation - A step in the graphics pipeline where existing geometry is
subdivided into primitives.
• Primitive - The smallest shape making up the objects on screen.
• Shaders - A program in the graphical pipeline which defines how the
objects should be drawn when rendered.
• Command buffer - A buffer used in Unity to manipulate the order of the
shaders for the rendering.
• FPS - Frames Per Second. The number of times the objects on the screen
is refreshed per second.
• Z-fighting - When planes are placed at the same distance so the shader
cannot tell which object is in front of the other and surface will be a
blend of both objects.
Computer graphics
In computer graphics, there are a lot of different parts used to generate all
the information needed to draw the objects to the screen. All the parts which
makes up an object can be seen in Figure 1. First of all we have vertices which
are the cornerstones of the object. A vertex is a point in space defined in all
dimensions which is used to position the lines of the graphics drawn to the
screen. These vertices are used to create lines and planes which make up the
geometry on the screen [4]. In order to know which line goes where there is
a list containing which vertices to connect called triangle indices. In order for
the GPU to efficiently render the objects, the individual planes needs to have
a simple form and triangles are most commonly used. Therefore, the vertices
are numbered and added to the triangle indices list in the order they should
be connected with each other.
When a triangle is rendered it will be shown as a surface between the points. By
stringing multiple triangles together it is possible to create all kinds of shapes.
To know which direction light should reflect on the surfaces, each plane needs
to have a normal. A normal is a vector that points in the direction the surface
is facing. For each triangle, each vertex in the triangle have a normal which
is perpendicular to the triangle’s surface which is used to calculate the normal
for the surface.
Figure 1: Figure showing the different graphics parts of a rendered object.
The surfaces are colored by the colors defined in the vertices which often makes
a blend of them to get the final appearance. This can be further enhanced by
using textures for the surfaces instead. A texture is an image which is mapped
onto surfaces in certain ways. How the textures should be rendered are defined
in the UV-coordinates either at startup or calculated during runtime. By using
textures, the objects can become much more detailed as it is cheaper to render
detailed images than detailed objects. In order to further enhance the surface
of the object there are ways to alter how the objects surfaces looks like by
using maps.
A map is an image which instead of looking like a picture that are supposed to
be rendered to the screen, the red, blue, and green (RGB) values of the image
is used to manipulate the normals or textures of the surfaces it is applied to.
This allows for very detailed surfaces even though there is only a few vertices
and normals defined in the object. There are a few different maps which can
be used for different things but the most common ones are normal maps and
height maps.
A normal map is an image containing information on how much the normals
of the surface should be modified. By distorting the normals of the surface,
the light will reflect in a different direction and the surface looks like it is
uneven and therefore more realistic [5], see the middle picture in Figure 2.
Normal maps can manipulate the surface quite a lot and is a cheap way of
simulating rough surfaces so they are used a lot. Height maps are also used
for manipulating the surfaces but it is done in a different way [5].
Figure 2: Figure showing the difference normal and height mapping makes.
From left to right: without mapping, with normal mapping, and
finally with both normal and height mapping [5].
A height map is a greyscale image which contains information on how much
the surfaces should be offset in different positions. The brighter a pixel is
the more the corresponding surface pixel should be offset. The offset is done
by shifting the surface around according to the height map which creates the
effect that front part of the surface is occluding the parts further back, see the
rightmost picture in Figure 2. It is more performance-expensive so they are
not as common as normal mapping but the effect is more pronounced. But it is
still cheaper than to have the objects themselves reflect the height differences.
The thing these mappings does not solve on the other hand is that they do not
actually change the surface, just changing the way the shadows are drawn so
the surface looks uneven, and the surfaces can still look really flat in certain
The Graphics Pipeline
In order to have the computer render all the graphics to the screen, the data is
sent to the graphics card. That data will then be used to generate the things
rendered to the screen. This is done in a few different steps called the graphics
Figure 3: An overview of the graphics pipeline used in OpenGL 4.5 [6].
In the modern graphics pipeline, there are five main stages when rendering the
objects to the screen. Some of them are further divided into multiple smaller
stages as well. The stages are from start to finish:
• Vertex shader
• Tessellation and geometry shader
• Clipper and primitive assembler
• Rasterizer
• Fragment shader
Below, a short description of each stage follows. We will use the description
of the OpenGL graphics pipeline [6] shown in Figure 3 as the example for
explaining all the steps in the pipeline. There are smaller differences between
rendering languages but the parts of the graphics pipeline which are locked to
the GPU are the same for all of them. What differs between the languages
is how to write the programs and some optional functionality in the graphics
Programmable shaders
In order to manipulate how objects should be rendered to the screen, programmers can create shaders which contains information on how the objects should
be rendered. This works like programming in that shader files containing the
code are created. These shader files are then compiled and sent to the graphics
card. That way, how the objects should be rendered can be altered in many
ways and new geometry can even be created. There are a few different languages for shaders. Some of the more common ones are OpenGL’s GLSL[7]
and DirectX’s HLSL[8].
Vertex shader
The Vertex Shader is the first stage in the graphics pipeline. In this stage
the vertices are modified using a programmable vertex shader specified in the
application. The job of the vertex shader is to manipulate each vertex usually
different kinds of transformations. It can also do some per-vertex lighting or
some preparatory work for the later stages of the pipeline. All the work for
vertex shaders are done in local space and the vertices are then converted to
screen space before they are sent to the fragment shader. But before that, the
optional tessellation and geometry shader step might manipulate the vertices
a bit more.
Tessellation and geometry shader
During the tessellation stage, larger surfaces defined in the vertex data are
divided into smaller shapes called primitives. This is done to have each surface
in the geometry as similar as possible since that will make the processing more
effective and therefore triangles are most commonly used as they can make up
almost any kind of shape.
The geometry shader is the last thing which happens before the vertices are
done. The geometry shader can be used to manipulate and create geometry
from a small amount of vertices. This can be done very effectively if the shape
of the geometry added has the same shape. That means that the geometry
shader also acts like a second vertex shader which are good at handling other
things. This is also the stage where the compute shaders are used and therefore
also get a chance at manipulating the vertices.
Clipper and primitive assembler
During this stage the image is clipped in order to remove the parts of the
image which is not visible from the current viewpoint of the screen. It also
adjusts the size to match the screen ratio of the screen. Then in the primitive
assembler, all the primitives in the scene are ordered and grouped for rendering. Then something called Face culling takes place. Face culling is done by
checking which direction all the triangles are facing and discard the triangles
which are facing the opposite direction. That way, the number of primitives
to manipulate in the later stages is reduced which is good as the later stages
are more expensive to run.
In this stage, each primitive left from the last stage will be converted from their
original shape to fragments. These fragments are later used by the fragment
shader to calculate the pixels shown on the screen. This is done specifically
because the pixels can not represent non-integer data and the algorithms for
converting the primitives are quite expensive.
Fragment shader
In the last step before the finished image, the fragments from the previous
stage are used to calculate how the pixels should be shown on the screen. This
is all done using a fragment shader which defines how each fragment should
be rendered, either to the screen or to memory. Depending on the rendering
technique used, the fragments are accompanied with different data to correctly
display the fragments. That can be the depth of the fragment or how much
light the fragment should reflect. When the fragment shader is finished there
are some tests and other miscellaneous things that needs to be done before the
finished image can be rendered to the screen, like depth test and blending.
Compute shaders
Compute shaders are a type of shader which is used to do some of the calculations on the GPU instead of the CPU. This is done using one of the many
shader programming languages, e.g. CG/HLSL, which is used in Unity. That
means that it is possible to use them to write programs for the GPU to reduce
the workload for the CPU by moving some of the calculations to the GPU. But
in order to use them effectively, the programmer need some knowledge about
the architectures of the GPUs as the GPU is not good at certain things, mainly
branching programs, as the GPU is optimized for running things linearly.
The GPU’s ability to process large amounts of data in parallel makes it useful
for handling manipulations which requires the same small operations to be
done multiple times on a lot of objects. That is why they are mostly used
to calculate certain effects for each pixel on the screen, as the same thing will
need to be done for all pixels which can be millions with the monitors of today.
Special caution needs to be made when writing for the GPU as it works quite
differently from the CPU. The GPU is very good at doing a lot of calculations
in parallel as it has access to a lot of threads. On the other hand, the GPU is
bad with branching code because it is optimized for running things serialized.
That means it might actually be faster to run everything than to skip certain
parts of the shading, as the check to see if something should be skipped will
slow everything down.
2.2. UNITY3D
Unity is a cross-platform game engine developed by Unity Technologies and
are used to develop video games for PC, consoles, and mobile devices. First
announced only for OS X, at Apple’s Worldwide Developers Conference in
2005, it has since then been extended to target 27 platforms [9][10]. Unity is
regularly updated and are currently on version 5. Programming in Unity is
done by both drag and drop, writing values into fields, and scripting using C#
or their own dialect of Javascript called Unityscript [11].
Unity includes a physics engine called Physx[12] which deals with object collisions and other physic related calculations. Unity also handles a lot of different
lighting models for lighting scenes in games. There are also a lot of assets available on the Unity Store which speeds up development as well. The assets that
are available are pre-made objects, textures, or scripts which can be used in
the game development. The main drawback of using a game engine developed
by another company like Unity is that the developers do not have access to
how everything is implemented and can therefore not micro manage the code
to optimize it perfectly. They are also depending on the company developing Unity to handle all the bugs in the engine which may hinder their own
development if it is not working correctly.
Shaders in Unity
In Unity, the shading process to determine the color of the surfaces are divided
into four different parts: model, materials, shaders, and textures.
The model defines what the object should look like. This is where the vertices
and normals are put together to form a mesh which defines the shape of the
object. Then a material containing the shader, textures, and colors is added
to the mesh and it defines how the mesh should be colored and rendered.
Shaders defines how to render the object as was described in Chapter 2.1.
The shader defines how all the lights and vertices should look like using the
information in the material. It can also define different ways to render in
the shader to match the hardware the program is running on. This is where
how the colors and textures should be applied to the objects are defined.
Using shaders, it is possible to create really complex calculations, especially if
compute shaders are used to do some of the calculations.
Textures are images which are drawn on the surfaces of the objects on the
screen. They can be used to both draw complex images as well as simulating
bumps and scratches in the surface. How the texture should be mapped to the
objects are defined in the shaders so by changing the shader the appearance
of the texture can be changed. There are different types of textures which can
be used for texturing, regular textures and tiled textures. Regular textures
are just one image which is either stretched or tiled to match the surface it is
drawn on. The tiled textures on the other hand is divided into a grid used to
cut out pieces of the texture to draw on the surfaces. That means one texture
can be used for a lot of different objects, which saves space as there is no need
to have a lot of textures loaded at the same time.
Representing a curve
Whenever a line is drawn on the screen, the computer needs to know what
function the curve should follow. The simplest example in 2D is a straight line
which uses linear interpolation from point A to point B to calculate a straight
line between those points. This is very simple as the formula is just y = kx
which gives a straight line in the angle defined by k. When trying to draw a
curve, the computer needs a function which can represent the line. One way
would be to place the points in a curved line and then draw straight lines
between each point and the line will end up looking like a curve. The problem
is that a lot of points is needed to get the curve smooth and there is going to
be a lot of calculations needed to create all the lines creating the curve. And
often when curves are used, a lot of them is used so this option is not very
good. Instead we create a different function, called a Spline [13] which defines
the position for each point on the curve mathematically without the need of a
lot of points.
The trail path
In the new implementation for the path of the wheel trails, covered in this
thesis, Bézier curves are used to represent the curvature of the trails. A Bézier
curve is a type of spline which is very commonly used in computer graphics.
Bézier curves are a good choice for making a spline as they do not need a lot
of points to create an expressive curve. A Bézier curve can have any number
of degrees from two and upward, see Chapter 2.3.2 for the mathematical definition. The more degrees the curve has the more control points is used to
represent it, which makes the curve more expressive. The problem with Bézier
curves of high degree is that they are harder to manipulate as each point effects
a larger part of the curve. Therefore the most commonly used type of Bézier
curve is the cubic one, as that is enough to define a unique curve in 3D space
while still having few control points so it is easy to manipulate. These curves
will not be too expressive as there are only 4 points in the curve but a simple
way to make more complex curves is to combine several Bézier curves into a
composite Bézier curve.
Bézier curves
Bézier curves are smooth curves which can be generated from a set number
of control points. The curves are easy to modify and does not require a lot of
information to be generated. That means it is possible to have more curves
in memory at the same time. Here is a brief introduction to Bézier curves to
understand the trail creation used in this project. For a more in-depth reading
on the subject, "A Primer on Bézier Curves" [14] would be an excellent choice.
It is a free online book written by Mike Kamermans, which has been used as
the base for this brief explanation as well.
A Bézier curve is a representation of a curve using two endpoints the curve
should interpolate between. That creates a straight line. Then additional
control points are added around the line to make the line bend towards the
control points which makes the line bend into a curve. The more control
points the more bends on the curve as there are more points for the curve to
interpolate, see Figure 4. The number of control points used defines the degree
which will always be one more than the number of control points. The most
commonly used Bézier Curves have two control points, which means they are
of degree 3 and are therefore called cubic Bézier curves. The drawback of using
a lot of control points is that the curve gets unstable because all control points
for the curve affects the overall form of it. So whenever a point needs to be
changed or added in the curve, the whole curve is affected and the weights of
the points need to be rebalanced in order to retain the same shape as before.
Figure 4: Various Bézier curves of different orders. We can see that adding
control points yields more bends to the curve but makes it harder
to change the shape of the curve.[14]
The definition of a Bézier curve is based on linear interpolation but with control
points added to allow the curve to bend. The first three orders of Bézier curves
are defined the following way:
Linear(t) = a(1 − t) + b ∗ t,
Square(t) = a(1 − t) + 2b ∗ (1 − t) ∗ t + c ∗ t ,
Cubic(t) = a(1 − t)3 + 3b ∗ (1 − t)2 ∗ t + 3c(1 − t) ∗ t2 + d ∗ t3 ,
where a, b, c, and d are the weights of the points on the curve and t ∈ [0, 1]
is a real number which determines the position on the interval. We can also
generalize this to get a Bézier curve of order n instead:
Bezier(n, t) =
X n
∗ (1 − t)n−i ∗ ti ∗ wi ,
where the order of the curve is n and w is the weight of each point in the curve.
Composite Bézier curve
A composite Bézier curve is a type of Bézier curve which is made up of multiple
Bézier curves following each other to form one long curve. This is done by
ordering the Bézier curves so that each starts where the previous curve ends.
That way, the complete curve does not need to have a high order of complexity
to be expressive as each section of the curve can together create any type of
curve. There are a few different levels of restriction that can be used at the
points two curves is connected. For cubic curves, C 0 , C 1 , C 2 , or G1 levels of
continuity is possible, see Figures 5, 6, and 7. The difference between different
levels of continuity are covered below.
Figure 5: Various levels of continuity for Bézier curves. We see that the
higher order of continuity, the smoother the curve but it also
have a wider curvature.
The easiest level of continuity to achieve is C 0 . To achieve that, the start and
end points needs to be in the same place, i.e. the two curves are continuous
in the connection point. How they curve before or after that point does not
matter. By making the points coincide the curves will look like a long curve
but it is apparent that the curve is made up of several smaller curves as the
connection point can look jagged, see Figure 5.
Figure 6: Various levels of continuity for Bézier curves. We see that higher
orders of continuity yields smoother curves [15].
The next level for the points is C 1 continuity. To achieve that, the two curves
must have the same derivative in the points they are joined. That means both
the angle and the amplitude must be the same. This is achieved by having the
closest control points on each side mirror each other in the connection point
in both distance and angle. This makes the curve look really smooth as can
be seen in Figure 5.
The third level of continuity called C 2 continuity and is similar to C 1 continuity
but with an additional requirement. First of all, all the requirements of C 1
continuity needs to be fulfilled. Furthermore, the second derivative for the two
curves also needs to be equal. That means that the second closest curve points
around the connection point needs to mirror each other as well in both angle
and distance. That will make the curve look even smoother, see Figure 7
Figure 7: Relation between the control points for C 2 continuity, where the
two curves are connected in P3 . The direction between P2 and
P4 is the same as the direction between P1 and P5 [15].
There is also another level of continuity for composite Bézier curves called G1
that is a more lenient requirement than C 1 continuity. It is almost the same
in that the start and end points need to coincide and the first and second
derivatives need to to be the same as well. The difference is that the control
points does not have to be mirroring the distance from the connection point.
With this restriction, the curve will still look smooth but might change its
bending just after the connection point which could look a bit unnatural for a
complete curve, see Figure 6
In general, using a higher level of continuity yields a much smoother and
coherent curve but might make it harder to fit the curve perfectly. Since the
control points adjacent to the merge point needs to be in certain ways to fulfill
the continuity, it will limit the shapes the curve as a whole can take. Therefore,
a lower degree of continuity might be a better fit for the given application if
it is desirable to have the curve take sharper turns.
3 The Game
Since this project is about generating trails in a deformable terrain, it will speed
up the process to have access to an environment with deformable terrain to use
for testing. For this project the game, currently in development at Zordix called
Snow Moto Racing Freedom, is used for testing the implementations of the
solutions. Freedom is a racing game with snowmobiles where the players get to
drive on both pre-made tracks and through uncharted terrain. When running
through the uncharted terrain, the snow deforms and the vehicle should leave
trails behind it. At the moment there is already a simple system in place for
generating trails behind the snowmobiles, so the game is not depending on the
results of this project to be released. But the current system has some flaws
covered below so improvements can be made.
Figure 8: How the two main game modes look like. To the left is Sprint
and to the right is Snowcross. [16]
Game modes
The game itself is not the main focus of this thesis but it is still covered here
briefly in order to allow the reader to get a feel for how these kinds of games
look like. There are four different competitive game modes in the game and a
free play mode called Leisure. The first game mode is Snowcross and that is
like a normal racing game with a race track the players race around a certain
number of laps, see Figure 8. In this game mode, they have generated a track
with uneven surface to look like a lot of snowmobiles have run there. Then
we have the next game mode which is called Freestyle where the goal is to
drive around in a small area and do tricks to get points. The player needs to
accumulate as many points as possible in the allotted time to win. The third
game mode is called Sprint where the player races against opponents to pass
a certain amount of checkpoints before reaching the finish line, see Figure 8.
This kind of track does not loop around like a normal racetrack. Instead it
is about getting from point A to point B though the checkpoints on the way.
Then we have the last game mode which is Time trial mode where the goal is
to get to the finish as fast as possible and beat the best times for both sprint
and snowcross tracks.
Project focuses in the game
The focus of this project will be on the game modes with powder snow which
can deform. The Sprint and Leisure game modes are good examples of this
as there is no predetermined track to follow, so the player is free to find the
shortest way though the terrain. Therefore, there are plenty of times the
snowmobiles would leave trails behind them. The Sprint game mode can be
used to see if the solution is efficient enough to handle multiple vehicle creating
trails at the same time. The Leisure game mode can be used to see if the
solution can handle huge trails as there is no time limit which means it is
possible to drive around on a huge map for as long as desired.
The landscape in the game is vast and there are a lot of hills and mountains
so the surface is not even. That means the solution needs to be able to handle
uneven surfaces when generating the trails behind the vehicle. When playing
the game, it is possible to choose between having the camera in first-person
or third-person mode, which will either have the player look through the eyes
of the character driving the snowmobile or position the camera a bit behind
the snowmobile. Because the trails is visible behind the player’s snowmobile
when in third-person camera or behind one of the opponent snowmobiles when
playing the game, the system needs to be able to create the trails right behind
the vehicles in an efficient way.
Current implementation
In the terrain the player are driving though, there are powder snow almost everywhere in the field. So there have to be trails left behind by the snowmobiles
when they pass though the snow to give it a more realistic feeling. If possible,
the powder snow should also be removed from the area passed over to make it
look like it actually alters the terrain like in real life.
The current system for generating trails behind the vehicles uses a camera for
each vehicle to sample the area under the vehicle to see where it touches the
ground. Using that area and the current traveling speed how much the snow
at the location should deform is calculated. This change is then stored in the
red channel of a texture to create a height map. The higher the red value of
a pixel is, the more snow should be removed from that area. In conjunction
with the heightmap, a splat map is used to control where the powder snow
should appear. A splat map is a map where the colors of the splat map is used
to mark different regions for blending textures. By marking the regions where
there should not be any snow in the splat map, there can be areas without any
powder snow, like steep mountain sides or ice-covered lakes, see Figure 9.
Figure 9: Using splat maps, it is possible to avoid having powder snow on
steep slopes and ice-covered lakes.[16]
Benefits and drawbacks
There are a few drawbacks to the current implementation and because of that,
there are reasons to find a better system. Since there is only a single heightmap
containing all the trails for the whole track. Each pixel in the height map
corresponds to a small area in the real world, so the more pixels the better
resolutions can be achieved. But a larger height map also requires more memory, so there it a limit to that given the hardware. To work around that, the
developers have tried to limit the playable area to so the height map will not
have to cover as large area. This works fine in the racing game modes as the
track can be made to fit the area. The problem is in Leisure where the player
have access to the whole area which means that the height map will have to
cover the whole area. Because of that, the resolution for the trails are lower
as can be seen in Figure 10 compared to the higher resolution in Figure 11.
Figure 10: On the large maps, the resolution of the trails get reduced.[16]
Another drawback with the current system is that the trails made in the snow
does not have a direction or pattern. Since it is only a heightmap for each
position on the map, there is no information on how the height for each pixel
are related to each other. When there is only one vehicle running in a straight
line, it looks good since the adjustment of the powder snow is shaped like a
snowmobile. But when the trails start intersecting into each other, the lines
blur and it turns into a flat surface of compressed snow instead, see Figure 11.
But there are some advantages as well to the current system which needs to
be taken into account when designing the new system. One advantage is that
the current implementation is able to handle trails crossing each other without
having the trails look weird. Since the vehicles only removes from the height
map area it passes over, it does not matter if there is already a trail at the
same location, it will just manipulate the heightmap as normal. That way, it
does not have to do any additional calculations and the result looks good.
Another advantage to the system is that it it very efficient, since all that is
needed to generate the powder snow is stored in the height map and the terrain
data. The GPU therefore only needs to render the information without doing
any additional calculations. That makes the whole system very efficient as
soon as it has created the data.
Figure 11: After a while, the trails blur together into a flat surface and the
sense of direction for the trails are lost.[16]
4 New Trail System
In this chapter, the steps and algorithms used to generate trails are explained.
The first steps generate the basic trails but they are not good looking so
there are a lot of additional steps required to improve the look on the trail
and make them fit with the terrain. There are two different implementations
of the algorithm, one for the CPU and one for the GPU. The differences are
documented in the implementation part, Section 4.2, and the result is discussed
in Chapter 6.
A system for generating trails behind vehicles was made using the following
• Implementing composite Bézier curves
• Trail creation
• Dealing with the trail closest to the snowmobile
• Handling long trails
• Avoiding trails in the air
• Getting the track on top of the ground
• Handling sharp turns
The first two steps created some simple trails and the rest of the steps improved
on them and made them more realistic.
Implementing composite Bézier curves
The first step of the implementation was to implement a spline representation
of the trail path using Bézier curves for the representation, since they are easy
to implement and light-weight, see Chapter 2.3.2. That is important, as there
can be a lot of trails on the tracks at the same time. As Bézier curves are not
implemented in Unity we first had to implement them. The implementation
Figure 12: The Bézier interpolation is done by approximating the two yellow control points. The distance from the middle point changes
the shape of the curve [18].
is based on the Curves and Splines tutorial from Catlike Coding [17] and the
tutorial covers how to represent and manipulate composite Bézier curves.
When implementing composite Bézier curves, there is usually a need to implement a certain level of continuity at the points the curves are connected, see
Figure 5. But since the trail is made by a vehicle, the vehicle itself will limit
how much the spline can turn at any given time. It is therefore no need to
implement any restrictions to the curve to artificially make it smoother. By
restricting the curves, there is also the risk of making the curve not follow the
vehicle as tightly as desired, because it might need a different angle to meet
the continuity requirements.
Trail creation
The trail path is generated by having a trail object follow each vehicle and
store points with an even interval. These points are then converted into a
cubic Bézier curve, defined in Section 2.3.2, and added to the composite Bézier
curve of the path. The shape of the path is then used to create a mesh which
is drawn as a trail.
The trail object has a list of the last points passed through. When the distance
from the last recorded point exceeds a predetermined distance the current
position is recorded. The distance can be adjusted depending on how powerful
the machine running the game is. The more points the smoother the curve,
but it is possible to get a relatively smooth curve with only a few points.
When a point is recorded the last points are used to generate the extension
of the spline using a simple Bézier interpolation between three points. The
version used here is described in an article for Dev.Mag by Herman Tulleken
[18]. Because the curve is generated continuously and the curve can get quite
long, the implementation needs to be efficient. It is therefore more efficient
to estimate the next part of the curve using the last points than to use more
exact calculations. The curve still looks good even though the approximation
is a bit cruder.
The interpolation is done by taking three sample points to make a curve between, marked with orange in Figure 12. The angle between the first and third
point is calculated and the same angle is used to angle the two new control
points marked in yellow. These two new points are added to the curve and
the middle point is not used but instead stored for the next calculation where
the point is going to be the first point on the curve. The shape of the curve
can be changed by adjusting the distance the yellow control points are placed
from the middle point.
After every curve section added to the spline, the mesh representing the spline
is recalculated to reflect the curve added. This is only going to be shown as
an image for the trails behind the vehicles so there is no collision mesh, which
is good as that is very expensive to generate. Due to that, the trails are not
interactable but that is not necessary as they are only there to show what the
trails look like.
Masking the sampling close to the snowmobile
A Bézier interpolation needs one more point than what is shown to have something to interpolate over. That causes a gap behind the vehicle as there first
is some distance until the vehicle have traveled far enough to sample the next
point. Using that point, the curve is created up to the point before the newly
sampled point. Because there is not much to do about the gap without guessing where the player is heading, the gap caused by the interpolation close to
the vehicle needs to be masked some other way. One way to work around
this is to decrease the sampling distance as that would reduce the distance it
would take to get the points. But that would make the splines more dense
with points which requires more memory and reaches the limits of the meshes
used for the trails faster.
Figure 13: How the two trails are overlapping each other. The temporary
trail has been colored and raised to show the offset more clearly.
The chosen solution is to mask that the trail path is created at the back of
the vehicle by using a temporary trail close to the vehicle. The temporary
trail path uses linear interpolation which makes it more jagged. To smooth it
the sampling points are taken much closer to each other instead. But since
the temporary trail is rather short it does not matter that there are a lot of
sampling points for the trail, as it will not reduce the performance of the game.
At the moment the sampling level is ten times denser than the regular trail
and there is only 22 points in the trail. The only problem which needed to be
addressed was to make the overlap look good, see Figure 13. This is especially
important at the end of the temporary trail as that is where it is removed and
the permanent trail below it will replace it. To avoid having the trails cutting
into each other the temporary trail is created a little bit above the permanent
Handling long trails
There is a problem with having the mesh for the trail grow too big because
the time it takes to generate it is proportional to the size of it. And since the
whole mesh needs to be remade each time something is added to it, the mesh
needs to be generated a lot of times. Therefore Unity have added a limitation
to the size of meshes to avoid that. But the trails are supposed to be infinite
so there needs to be a way to divide the trails into multiple meshes to avoid
this limitation. This is solved by creating a new mesh to add curve sections
to when the old one grows too large. The old mesh is then left unchanged in
place so the trail still looks like one complete trail. This has the added benefit
of reducing the size of the meshes which needs to be generated as well since
only the last mesh section of the trail needs to be updated instead of the whole
The drawback of dividing the mesh is that it creates more objects which needs
to be rendered to the screen. Because each draw call to the GPU is expensive
and each object requires their own draw calls it will be more expensive in the
end. However, as the meshes are updated so often there should be merits in
using smaller meshes instead. But thorough testing is required to find the
optimal size for the meshes.
Avoiding trails in the air
When the vehicles travels through the terrain there are moments when they
leave the ground, either from jumping or due to bumpy terrain. When that
happens no trail should be created otherwise it will look like Figure 14.
Figure 14: In the basic version, the system generates trails even when the
snowmobiles are in the air.[16]
There are two main ways to avoid trails in the air. The first method is to end
the current spline whenever it leaves the ground and then create a new spline
when the vehicle touches the ground again. That way, no splines are created in
the air which removes the problem. The other method is to continue creating
the trail as normal even when the vehicle is in the air but without rendering
the sections in the air. That way, the spline is whole and the sections in the
air are not visible anymore.
We have chosen the second approach for our solution. An advantage of this
method is that the path is not subdivided into many short splines when the
terrain in bumpy. By keeping the spline intact, the number of expensive draw
calls is also kept at a minimum. That is good as draw calls are one of the most
expensive parts of rendering objects to the screen. A drawback on the other
hand is that this method still creates points for the spline even though they
will never be used. This requires a bit more memory than necessary, especially
if the vehicle is in the air a large portion of the time. However the difference
is so small that it is negligible.
Figure 15: Unless the cut-off point is right at the position the vehicle leaves
the ground, the trail will either continue into the air or end
To hide the sections of the spline which are in the air, each point on the spline
has a value set to whether they are in the air or not. Using that value, it is
possible to skip rendering a section if either of the end points of the section
is in the air, see trail A in Figure 15. But there is a big problem with this
simple solution. As can be seen for trail B in Figure 15, if the sample point is
not at the location where the vehicle leaves the ground, the trail will disappear
before the vehicle leaves the ground. One approach to solve that issue is to not
render the next section when the last sample point are in the air. The results
is shown as trail C in Figure 15. But that solution has the drawback that the
trail extends into the air a bit. So it is not possible to solve the problem by
just avoiding to render some of the sections of the spline.
In order to solve the problem, the spline needs to be manipulated a bit to
always end up like trail A in Figure 15 since that situation is possible to solve
in a simple way. By keeping track of the exact moment when the vehicle leaves
the ground we know at what position that happens. We can then add that
point to the current spline. That way, there will always be a point at the
correct position. Another point is added when the vehicle lands on the ground
again as well. By not rendering the section where the next sample point is in
the air, the trail have the desired look, see Figure 16.
Figure 16: By adding additional points to the spline, we can make sure the
cut-off points are at the right positions.
For the temporary trail close to the vehicle, the solution can be more simple
since the temporary trail is done using linear approximation with a narrower
interval of point sampling. Therefore, there is always a sampling point close
enough to the location where the vehicle leaves or touches the ground so there
is no need to add additional points.
The problem on the other hand, is to make sure that the track starts in the
same position as the permanent track. Since the temporary trail overlaps with
the permanent trail a bit, the trails need to look the same at the place they
are overlapping. This is solved by ignoring the first two sampling points when
landing. That makes the close trail have the same landing location as the
permanent track. When jumping though, there is no need to do anything
special as the result is the same as for the permanent trail. This difference is
caused because there are different algorithms used to create the trails. Bézier
curves requires a few points before there is enough information to calculate
the curve, while linear approximation do not. By ignoring the first two points
after landing, the linear approximation starts at the same time the Bézier have
enough information to create a curve.
Mapping the trail to the ground
A spline path is only a single line of points, how the terrain is angled does not
affect it. But when the trail is extended sideways, there are cases where the
trail cuts into the ground or hangs in the air as can be seen in Figure 17. This
makes the trails looks unrealistic and reduces the overall experience.
Figure 17: Without taking the terrain into account, sometimes some part
of the trail is either floating or inside the ground.[16]
A first attempt to solve the problem would be to use the normal of the snowmobile to angle the trail in the same way as the snowmobile making the trail.
Since the snowmobile should be leaning as much as the terrain does, the trail
will therefore lean as much as the terrain as well. By doing it this way, the
shape and the size of the trails stays the same as the trails are only rotated.
That means the trail will not be stretched or look really wide or thin when
the terrain changes like in other solutions. Unfortunately, there are two problems with this approach. The first problem is that the snowmobile might not
always be angled in the same direction as the terrain. This is caused by the
physics implementation and the positioning of all the different parts of the
snowmobile. Therefore, the trail might be angled too much or too little which
makes it cut into the ground or start to float again. The other problem with
this approach is that the best result this solution can achieve is to have the
edges of the trail rotated equally to match the middle point of the trail. A
visualization of this can be seen in Figure 18 if we assume that points r1 and r2
are made by rotating the trail. As can be seen in the figure, the trail both cuts
into the ground and floats a bit in the air. Also, as can be seen in Figure 18,
the straight line between r1 and r2 does not intersect the middle point which
means the trail needs to be raised a bit to have the edge points of the trail
perfectly placed on the ground.
To avoid having the trails cut into the ground or float in the air, the angle
of the underlying terrain needs to be taken into account. The trail is just
extruded horizontally from the point which works when the surface is flat. In
order to handle that without making the trail smaller the edges are used as the
base for calculating new points. By using raycasting, as suggested by alucardj
in the Unity forum [19], the distance to a surface from a given point can be
measured. By doing a raycast from the trail to the terrain, the distance to the
actual ground can be calculated and the trail points can be offset to match the
snow. The process is depicted in Figure 18.
Figure 18: Figure showing how the edges for the trail is calculated through
raycasting. The original trail edges are between p1 and p2,
which are projected to r1 and r2 respectively.
If we look at Figure 18, we can see that the sampling point P is sampled in the
middle of the terrain. Then, the edges are placed at both sides horizontally
depicted with dark grey between p1 and p2. Using those two points we create
two new points a bit up in the air R1 and R2. Those are the points the raycast
is used from. The brown arrows are the raycast sent from those points and
the position they hit the ground are shown as the points r1 and r2. Those two
points are the new trail edges and are used to render the trail like the light
grey line.
The line is still intersecting the terrain at some points but the result is much
better. In order to further improve the result, we can calculate more points
on the interval on the terrain. By drawing more lines on the interval, the trail
can get a better fit to the terrain.
One disadvantage to this technique is that the trail gets stretched. Looking at
Figure 18, we can see that the length of the light grey line is longer than the
dark grey original line. When looking from the side, the shape is triangle which
is why the light grey line is longer. The trail is therefore wider than normal
which might look strange in certain occasion. Another thing that might look
weird is the texture, since the texture on the trail is stretched when the trail is
made wider. When textures are stretched they do not look as sharp as usual
which reduces the appeal of the trails. One way to remove this problem is to
combine this solution with the one previous mentioned. That way, the shape
of the trails will stay about the same as they are first rotated and then the
new edge points are used for the raycasting.
The difference in length of the trails is directly related to the angle of the
terrain below with the following equation:
= Lengthnew .
In the equation, we can see that when the angle is less than 10 degrees, the
new trail will only be expanded by about 1.5%:
≈ 1.015.
cos(10◦ )
That is not really noticeable unless the player are able to compare two trails
of different sizes.
When the angle is more than 45◦ the width of the trail starts to change a lot
more so it will be quite more noticeable because of that. The thing which makes
it acceptable is that it only occurs when the terrain is really steep. When the
terrain is that steep, it is not unusual for the vehicle to start slipping and sliding
down the slope. If the vehicle is sliding a bit, then the trail becomes wider as
a result which is almost simulated in this way. Luckily, the snowmobiles are
implemented in the game in a way that the vehicle is not considered on the
ground when the underlying terrain is really steep. As there is no trail when
the vehicle is in the air, the cases where the angle is large enough to matter is
not visible to the player.
Sharp turns
The trail is created behind the snowmobile by sampling the position and rotation at the back of the vehicle. That way the rotation of the trail is the same
as the vehicle which looks good most of the time. But because the snowmobile
can powerslide, the rotation of the vehicle is different from the direction the
snowmobile is traveling. That makes the trail look like the one on the left side
in Figure 19. The trail is straight even though the snowmobile is turning. It
also shrinks in width and almost disappear at the end of the sliding. In order
to make it more realistic, the trail should look more like the the one on the
Figure 19: Shows the difference for the slide rotation does. With the slide
rotation the trail looks more rounded.[16]
The points for the trail are sampled following the path of the vehicle and
not from the current speed of the vehicle. The rotation should therefore also
be derived from the direction the vehicle is traveling in. That way the trail
becomes more rounded and looks like it is turning like the vehicle, see right
image in Figure 19.
Figure 20: If the rotations of the samples are a bit off, the trail will get
thinner as can be seen by comparing the width of the two trails
which is shown in the middle figure. The angles in the figure
are exaggerated to more clearly show the difference.[16]
Another thing which happens when the snowmobile powerslides is that the
rotation of the snowmobile differs from the direction both of the snowmobile
and of the path it is traveling in. When the rotation for the samples of the
curve is different from the direction the path are sampled in, the trail will
shrink in width. This can be seen in Figure 20 where the right trail has the
wrong rotation which changes the width of the trail. Since the rotation is a bit
off, the whole width is not used for creating the trails which is why the trails
become thinner. In order to avoid that, the rotation of the sampling points
need to be rotated in the same direction that the snowmobile is traveling in.
Luckily, the solution suggested above solves this problem as well.
There are two different implementations of the algorithm that is tested. One of
the implementations uses the CPU and lets Unity handle all the mesh rendering
while the other implementation uses the GPU and handles the mesh rendering
on its own.
CPU implementation
The CPU implementation does all the calculations on the CPU. The trail
is made using procedural mesh generation as explained in a presentation at
the GDC by Joachim Holmér [20]. The trail is made by creating a mesh
with the desired shape. The mesh acts like an object in the game, so Unity
handles the rendering of the object as long as all the information is correctly
set. Since Unity handles the rendering of the meshes, there is no need for
any special shaders which makes this version easier to implement. All vertices
the trail shape should follow, the normals, how to map the texture, and how
the triangles are arranged need to be specified in order to create the mesh.
The triangles are made by triangulation and needs to be done manually when
changing the shape of meshes. Since Unity handles the rendering of the meshes
it restricts the control the programmer have over how the meshes will look like.
Also, because the mesh implementation is general and should work in most
cases, it might not be the most optimized implementation for this specific
There are a few drawbacks to this version. Due to there being a separate
implementation for the powder snow in the compute shader on the GPU side,
it complicates the placing of the trails. The height information for the powder
snow are only available on the GPU. There is therefore no good way to know
the offset the trail should be placed from the ground on the CPU side. If the
trail are placed too low, the powder snow covers it and it will not be visible.
On the other hand, if the trail is placed too high it will sometimes float in the
air which is not very realistic. The solution used right now is to place the trails
at an average height from the ground which makes the trails visible most of
the time without having them float in the air very often.
GPU Implementation
Instead of using the CPU for creating the trails, the GPU can be used. By
using the GPU for generating the trails, the workload for the CPU is reduced
which can be useful if most of the game is using the CPU. There are also
certain cases when the GPU is much faster than the CPU. This is due to the
GPU being good at running things in parallel, so the GPU is much faster than
the CPU when there are a lot of simple calculations which needs to be done.
Since the trails do not not have a lot of computations but there are a lot of
them, moving the trails to the GPU has benefits.
When implementing the GPU version of the algorithm, most of the calculations
originally done on the CPU are moved to the GPU using compute shaders. The
spline information is sent to the GPU and used as the base for creating the
trail. That information is used to create the mesh manually in the shaders.
Unity does not handle the meshes automatically when the mesh is created
manually and therefore the mesh generation has to be taken care of in the
shaders as well.
The process starts with sending the control points of the splines to the GPU.
Those points are then sent to the compute shader which calculates the edges of
the trail and then converts the points to triangles. Those triangles represents
the trail in the same way the meshes are built up in the CPU version. After
that, the mesh information is sent to a shader that renders the trail to the
Since Unity does not handle the rendering of the meshes for us when they are
manually made, there is a need for a shader as well. But because there are
more shaders active in the pipeline at the same time there have to be a way to
control when the trails should be rendered. If they are rendered too early, it
will look like they are in front of all other objects even though they are behind
other objects. In order to control this, something called Command Buffers
are used. A command buffer holds a list of commands the GPU should run
when rendering the scene. Each camera have their own command buffer so
it is possible to create different effects for different situations. In this case,
the trails are rendered between the geometry and lighting step in the pipeline,
see Figure 3. This is done to ensure that all the geometry in the terrain is in
place before adding the trail on top of it and that the trails are there when
the lighting is calculated.
This version handles the snow depth fine as the snow depth data is already
available on the GPU so it does not take much time to access it. That makes
it possible to place the trails at the correct hight on top of the snow which
makes the trails look really good.
There are disadvantages to the GPU version as well. It does not handle the
trails crossing each other either. Because the points in the spline does not
take the other points into account when the trail is created, the trail will look
weird when the points overlap in some way. For this version, when the trails
cross each other, the points will be placed in the same location and there are
some z-fighting where they overlap. This looks a bit better since the trails are
created before a lot of the other steps in the graphics pipeline so it is not as
big of a problem as for the CPU version. But it still does not look good so it
needs to be solved. Some other disadvantages to this version are that it needs
to use the command buffer to correctly position the order for the shader and
a custom made shader to render the trail to the screen. Consequently, there
are more work to get it set up.
5 Testing
In order to verify that the solutions found in this project is efficient enough to
be useful, a few different tests were run. The tools used are described below,
as well as how the tests were conducted. The test results are presented in
Table 1.
Unity has an FPS-display included in the game which shows the FPS the
game is currently running at if it was unlimited. The FPS is a good is a
good measurement of how fast the game can run and can be used to see if the
game is fast enough to reach the desired speed aimed for. But the FPS-display
included in Unity can not store the measured FPS for test results, so a custom
FPS-counter has been created to be able to store and calculate the average
speed. Inspiration for the FPS-counter used here is taken from the Unity wiki
for FPS-counters [21].
In Unity there is a profiler which is a tool used to measure how much time,
memory, and calculations each method in the game does when the game is
running. This can be used to see what parts of the game takes a lot of time
and if there are any unnecessary calls and allocations during the game. Using
the profiler during development is a good way to do a sanity check on the
solutions as it is quick and easy to use. That way, it is easy to see if the
solutions look like they are going to work by just running the game. It can
also be used to identify which parts of the solution need to be optimized which
is very useful.
Test sequence
To test the efficiency of the solutions, a special feature was added to them.
This feature allows the snowmobiles to create multiple trails at the same time
behind them. This is done to see the impact the number of trails has on the
performance without having to make a system for running multiple snowmobiles at the same time. It is also used to avoid having to drive around for really
long to create a lot of trails to test how well it performs when there are a lot
of other trails around.
Figure 21: The test track used in the tests. The tests were done by circling
the small forest for a specified time in order to see what happens
when there are a lot of trails at the same place. [16].
To ensure that the test runs are equivalent for all test runs, the trails was
created by driving around a small forest in the game in a predetermined path.
That way, the performance impact the game itself would have on the tests
would be the same for every test. Several parallel trails are created behind the
vehicle with an offset in X-direction to have as many trails as possible visible
at the same time. Since the trails are only rendered when they are visible to
the player, they need to be visible to have an impact on the performance. The
snowmobile was driven around the test track to create trails on the path. By
driving multiple laps around the same path, all the trails left by the snowmobiles will be visible on the screen so the game has to render all the trails. That
way, the impact of having a lot of trails on the screen at the same time can be
measured as well.
The tests were done using the FPS counter to measure the average speed of
the game during the tests. Then, the snowmobile was run around the test
track for 5 minutes. During that time, the average FPS was logged. There are
a few different cases to test. First the current trail system are run normally
without the new trail systems to create a baseline to compare the other tests
to. Then both the CPU and GPU implementation was tested together with
the current trail system. For the solutions, tests were done on both a single
trail, 10 trails, and finally 50 trails. Even though the game does not need to be
able to render 50 trails at the same time, it will be a good test case to test the
limits of the solutions. After running all the tests the results were averaged
and summarized in Table 1.
Test results
Running the tests yielded the results found in Table 1. For each test case,
the total average for all 1000 samples are in the last column. The other three
columns are averages for different groups of samples instead. This is done to
show the difference in time it takes when more and more trails are added to
the terrain. Especially when a lot of trails are created at the same time, the
impact the trails have is quite big, which is shown in the table.
Table 1 Test results of the two implementations showing the average FPS.
Test run
1 - 200 201 - 500 501 - 1000
Average Average
1 Trail - Standard 132,71
1 Trail - CPU
1 Trail - GPU
10 Trails - CPU
10 Trails - GPU
50 Trails - CPU
50 Trails - GPU
6 Results
Here the results from the tests are summarized and explained. They are also
analyzed in order to see if the trail system is efficient enough to be useful.
Test results
When running the tests, the results in Table 1 was acquired and are summarized in Table 2. As can be seen, the FPS is dependent on the amount of trails
that needs to be rendered. There is also a graph for how the average FPS
changes over time, see Figure 22. In that graph, the average FPS for different
times during the tests are shown and it shows that the amount of trails that
have already been added to the field impacts the time it takes to render the
Table 2 The total average FPS when running with different trail systems.
Summary of Table 1.
CPU Implementation
1 trail 10 trails 50 trails
No trail system
CPU version
121,76 110,70
GPU version
If we look at the average FPS for the different test cases in Table 2 we can see
that the number of trails impacts the time it takes to render the trails. First
we have the base FPS at 124, 36 which was achieved when the was deactivated
and only the current trail system was used. Looking at Figure 22, the FPS does
actually drop after a while, when there has been more changes to the terrain.
This is due to the terrain becoming uneven, so there are more shadows to
calculate and render. The other test cases are done by adding the trail system
on top of the current trail system so the impact the new trail systems have on
the FPS can be clearly visualized.
Figure 22: Graph showing the average FPS achieved with different settings. The original data is found in Table 1. 60 FPS is considered the target FPS to aim for.
CPU implementation
If we first look at the normal case where there is only one trail added behind
the snowmobile, we can see that there is not a noticeable difference in average
FPS. The FPS drops at about the same rate as without trails, so the impact
is not that dependent on the number of trails in the terrain which is good.
But when there are ten trails created behind the snowmobile, the FPS starts
to drop a bit faster than without the trail system. When the number of trails
are increased to 50 the impact is must bigger. This is probably because it
takes a lot more time to generate all the trails when there are 50 trails which
is generated at the same time. But the FPS also starts dropping a lot faster
than normal as well. This might be because the amount of trails increases in
a much higher rate and the effects of having a lot of trails at the same time
are amplified. This shows that the system is not efficient enough to have an
infinite amount of trails at the same time as the FPS starts to drop quite fast
when there are a lot of trails at the same place. Especially when the FPS
drops below the target FPS at 60 FPS for 50 trails where there are a lot of
trails. The game will never have to render that many trails at the same time
as there is only a single trail for each snowmobile, but it shows how many more
calculations needs be done when there are more trails on the screen. However,
since there is only a single trail behind each snowmobile, its impact during
normal gameplay will not be noticeable.
GPU implementation
In the GPU implementation, the trail created behind the vehicle is done with
shader trails, and When there is only a single shader trail behind the vehicle,
the FPS actually increases even though the original trail system is still used.
That is due to the shader trails not decreasing the FPS as much when there
are a lot of trails at the same time so the average ends up better than without
the shader trail. This is probably due to the shader trails getting added before
the lighting pass in the graphical pipeline so the shader trails will obstruct
the original trails. Therefore, there is no need to render the shadows in the
original trails and that saves some time. But when the number of trails that
are created behind the snowmobile increases the FPS starts to drop quite
drastically. When there are 50 trails that are created, the game does not even
manage to achieve the target FPS which is not good. This is quite the opposite
of the results with only one trail. Luckily, the game will not have to deal with
that many snowmobiles at the same time but it shows that the solution is not
very optimized. The reason behind this probably lies in the generating of the
trails. Because the generating of shader trails is not that optimized, it takes
a lot of time when there are a lot of trails to create at the same time. The
rendering is probably not that effective either so when the shader trails do not
have the benefit of reducing the rendering of the original trails, their impact
is noticed. But since there is only going to be one trail generated behind the
snowmobile, the impact of the shader trails is not noticeable unless there are
a lot of trails at the same location which will not happen that many times
during normal gameplay.
7 Extensions and improvements
The finished result of the project is not perfect as there are a lot of additional
features which can be added to the system to compensate for some of the
disadvantages or to improve the usefulness of the system.
Handling trail crossing
The first and probably the most wanted improvement is to handle trails crossing each other. If it is desirable to have the trails look really realistic then it
is required. Right now, the system does not handle it at all so when the trails
cross each other the trails starts flickering. The flickering is caused by the
trails being placed at the same height so the computer does not know which
trail to render above the other. Because of that, it randomly decides which
trail is above the other every time and the trail will therefore start flickering.
Avoiding trails in certain areas
Since there is not snow everywhere in the areas, see Figure 9, there would
be useful to let the trail system take that into account. Right now, the trail
system creates trails as long as the vehicle is on the ground no matter what
the surface is. Because of that, there are trails in areas without snow which
looks really out of place. One way to handle it is to use the splat map used
for the powder snow to figure out where there should be trails. The problem
with that is the data is only available on the GPU, so there is no good way for
the CPU implementation to access the data. But it should not be a problem
to add to the GPU implementation in a similar manner as when the vehicle is
leaving the ground.
Combining deformation and trail creation
Another point of improvement for the system is to integrate the powder snow
deformation with the trail creation. Since both the deformation and trail
generation are related and does about the same thing, it might be more effective
to combine them. One advantage to combining them is that it will be easier
to maintain the system as all the data will be in the same location.
Saving the trail paths
By saving the information in the splines, it would be possible to reapply the
trails when the track is loaded the next time. That way, the users can realize
that they have already been there some other time they played the track and
that the terrain is altered even more when they play it again. By being able
to save and load the data it is possible to use the system for a lot of other
applications as well. By using the trail, it could be possible to generate replay
data to show which path all players took during the race and even allow the
game to show races long after they are finished.
Level of detail
If there is going to be a lot of trails on the track at the same time there
might be some need for adding level of detail to the trail generation. This can
be done in a few different ways depending on what is most important to the
performance. One way of doing it is to reduce the amount of sample points
for the spline when the sections starts to get old, i.e. when a certain number
of new splines have been created. By reducing the number of sample points
in the splines, the meshes will be sparser. Sparser meshes are smaller in size
since they have less points even though the size would be roughly the same.
When the meshes contains a lot of points, it can take a long time to calculate
them, so using sparser meshes can reduce the calculations a lot.
Bézier simplification
One way of reducing the points without losing the shape of the curve is to use
a technique called Bézier simplification. One way to do Bézier simplification is
described in the article by Herman Tulleken[18]. The outline of the algorithm
is: Take sample points from the spline with a larger interval than the original
spline. Then a new spline is approximated using the selected points instead.
That way, the amount of sample points are reduced but the shape still have a
similar shape as the previous one.
8 Discussion
There were a few things which did not go as planned which are covered below.
Some of them had so big impact that the scope of the project had to be changed
as well. Most of the problems arose from the choices made at the start of the
project, e.g. choice of engine to develop in and the goal of the project. At
the end of the chapter, the project as a whole is summarized as reference for
similar projects.
Project problems
The project was not smooth sailing the whole time. There were a lot of things
which went wrong and took more time than estimated. Mostly they were small
things but the biggest problem was because of conflicts with the current trail
system in the game. These conflicts took time from the project so the project
scope had to be reduced.
Conflict with existing trail generation system
As explained in Chapter 3.3, there is already a trail system in the game used
in this project. Due to the way that system was implemented, it started to
conflict with the trail system I made in this project. Therefore, a lot of time was
spent trying to get the two trail systems to work together. That also caused the
system to be less generalized as it needed to handle the current implementation
in the game which is not very useful for other games or systems.
Project adjustments
There are some choices made during the project which were not the best and
if a similar project was done there are some changes which probably will yield
a better result.
Trail visuals
The visuals of the trails is not part of the project itself as it depends on the
game the system will be used in. But it still effects the first impression of the
results in this project since one of the goals for this project is to have the trail
system generate trails which looks realistic. Since the trails themselves looks
out of place, it makes the whole system look less realistic. So if any visual
tests are done for the trail systems, they have to take that into account. That
makes it harder to estimate how good the trails will look when the visuals are
Developing in Unity3D
By implementing the trail systems in Unity, it was a lot easier to get a simple
test program. Since Unity has a lot of things already implemented there was no
need to first create a graphics engine which could render the trails created. The
physics engine was also used to make a fast implementation which saved a lot
of time initially. But one of the problems with using Unity in the end was that
the documentation was not satisfactory when developing the GPU version of
the trail system. Since the GPU implementation needed both compute shaders
and the command buffer in Unity to implement the desired solution which I
had not used before, there had to be enough documentation to figure out how
to use them. That was not the case so a lot of time was spent researching
how to use them. In the end, it might have been faster to not use Unity at
all because of the time it took to understand how to use compute shaders and
command buffer. But on the other hand, the capabilities to do this advanced
stuff might not have existed if a normal programming language was used, so
it is good to have been able to do it in the end.
Developing in an existing game
By using an existing game as the base for developing the trail system there
were a lot of time which could be saved. For example, there was no need to
make a simple vehicle system to have a vehicle to try the trail system on when
there already was vehicles implemented in the game. But there are not only
good things which comes with using an existing system as test environment.
The game used is a full game with its own trail system and other environment
variables which might interfere with the new trail system. That was exactly
what happened in this project which caused a lot of things to take longer time
than what was first planned.
The main problem with using Snow Moto Racing Freedom for implementing
the trail system was that the existing system for the powder snow made it
hard to get the trails placed in a good way. Since the powder snow system
is extruded from the terrain with a given offset. Then the trails are made by
reducing the offset in the trails’ path which makes it look like a vehicle have
passed. But changing the offset for the powder snow makes it really hard to
find the correct height to place the trails in the new system. What made it even
more difficult was that the height data of the powder snow is only available on
the GPU. Therefore, the original CPU implementation which was originally
planned could not achieve a good placement of the trails as it could not know
at what height to place them. Therefore, additional time had to be spent to
learn and implement a GPU version of the system which could work well with
the existing systems.
Project summary
Doing a project for a game developing company have been a lot of fun. Snow
Moto Racing Freedom, which I used to help with the implementation of the
trail systems was in development during the project. That means that while I
was doing my project, the game was being developed as well and it has been
fun to follow that development. I have been able to talk to the developers
about the design of the game and how different things are implemented so I
have learned a lot from that.
However, if I were to do the project again I would not use an existing game to
make the implementations and testings easier, as in the end, it caused more
trouble than it helped. I think it would not be too hard to make some kind
of prototype for trying out the techniques without having to deal with a lot
of other parameters from already implemented features. The main focus of
the project should be about techniques to create trails and not about trying
to implement and fit the algorithms into an existing game. If I did not have
to deal with some of the complications caused by the current trail system, I
might have been able to do some of the extension features as well during this
project which would have been interesting.
9 Conclusion
The results and the project as a whole is summarized below. How the future
for the trail system looks like is discussed as well.
The future of trail systems
The finished trail system is unfortunately not good enough to use as it is since
the new trails does not look better than the current trails. But with a little
time, the GPU implementation could handle the rendering steps better and
they might look good enough. But the techniques and ideas used in this project
can be used as a starting point for making a better trail system.
Since this project only scratches the surface of what can be done for a trail
system, there is not too much that can be said about the future. Given the
results though, it shows that it is certainly possible to have quite advanced
features in a game as long as it is possible to keep the trails light-weight.
It is certainly possible to combine the trail system with a system for deforming
the terrain as they are using similar principles which can make for some really
cool looking trails. The biggest hurdle to overcome though is to find a good
way to handle trails crossing each other. As long as that is possible to do in
reasonable time, there is definitely possible to have a trail system which can
be used to make realistic trails in real time.
[1] Colin Barré-Brisebois. “Deformable Snow Rendering in Batman: Arkham
Origins”. In: Game Developers Conference (GDC), San Francisco, California, March 2014. [Accessed on 21 Mar 2017]. url: https://www. deformable- snow- renderingin-batman-arkham-origins.
[2] V0odo0. Deformable Surface. Released 2016. [Accessed on 21 Mar 2017].
[3] Moment Studio. A skidmark effect for vehicles in Unity3D. November
2015. [Accessed on 21 Mar 2017]. url:
[4] Scratchapixel. Scratchapixel 2.0 - Points, Vectors and Normals. 2016.
[Accessed on 7 Mar 2017]. url:
[5] Unity Technologies. Unity Documentation - Material parameters. 2017.
[Accessed on 6 Mar 2017]. url:
[6] OpenGL Wiki. Rendering Pipeline Overview. February 2017. [Accessed
on 16 May 2017]. url: https : / / www . khronos . org / opengl / wiki /
[7] OpenGL. OpenGL Shading Language. 2017. url: https : / / en .
[8] Microsoft. HLSL. 2017. url: us/
[9] Wikipedia. Unity description. 2017. [Accessed on 7 Mar 2017]. url:
[10] Unity Technologies. Unity Multiplatform. 2017. [Accessed on 7 Mar 2017].
[11] Unify Community. UnityScript versus JavaScript. 2014. [Accessed on 7
Mar 2017]. url:
[12] Anthony. High-performance physics in Unity 5. 2014. [Accessed on 08
May 2017]. url:
[13] Wikipedia. Spline (mathematics). 2017. [Accessed on 24 Mar 2017]. url:
[14] Mike Kamermans. A Primer on Bézier Curves. Online book, 2017. [Accessed on 7 Mar 2017]. url:
[15] Fuhua Cheng. Curves and Surfaces I. Lecture notes on the course Intermediate Computer Graphics, Fall 2015, Dept. Computer Science, University of Kentucky, USA. [Accessed on 17 May 2017]. url: http://
[16] Zordix. Snow Moto Racing Freedom. 2017. url: http : / / store .
[17] Jasper Flick. Curves and Splines, making your own path. 2017. [Accessed
on 6 Mar 2017]. url:
[18] Herman Tulleken. Bézier Path Algorithms. Dev.Mag, 2011. [Accessed on
6 Mar 2017]. url:
[19] alucardj. Rendering permanent trails? (such as footsteps). 2013. [Accessed on 6 Mar 2017]. url: http : / / answers . unity3d . com /
questions / 475795 / rendering - permanent - trails - such - as footsteps.html.
[20] Joachim Holmér. “A coder’s guide to spline-based procedural geometry”.
In: Unity Unite 2015, Boston, 2015. [Accessed on 6 Mar 2017]. url:
[21] Unify Community. FramesPerSecond. 2015. [Accessed on 16 May
2017]. url: http : / / wiki . unity3d . com / index . php ? title =
Was this manual useful for you? yes no
Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Download PDF