In the past few months, we've been diving
deeper into the world of PCG and experimenting with different techniques to generate content
for our projects. It's been an exciting journey, and we've discovered
a lot about procedural generation and how to create unique and interesting experiences. In this video, we're going to share with you
what we've learned about PCG. We'll take a look at how it works and how
to use it to generate some cool content in Unity. So sit back, relax, and join us on this PCG
adventure! The first step is to understand what procedural
generation means. At first, it can seem scary or even magical,
and it's often confused with randomness. But procedural generation is not random. Let's think about it as a set of rules or
algorithms to automatically generate data or content. The key difference between procedural generation
and random generation is that with proc-gen, we have control over the rules and can adjust
them to produce specific types of content. This means that, while the results may appear
unpredictable, they are actually deterministic. In other words, randomization alone does not
generate something meaningful, which is something that proc-gen can do. Let's do an example:
We can ask our pc to generate a series of numbers, in which each number is the sum of
the two preceding ones. Also known as the Fibonacci series. Well, this is really basic but it is in fact
an example of proc-gen. And you can even do art with that. Let's try with something more visual. In Unity, there is a built-in component that
is a perfect example of procedural. The particle system. You have a bunch of modules, and you can customize
them, their rules, to achieve a lot of different results. Every little change has a huge impact on the
final effect. Of course, remaining deterministic doesn't
mean that proc-gen cannot take advantage of random, or pseudo-random to be more precise. In fact, randomness is used a lot, driven
by a seed. Imagine the random function as a black box
that takes your inputs and returns an arbitrary value as output. You cannot foresee the output because you
don't know what happens inside it. However, there is a way to do that. Because there is a secret input that determines
the initial state of the random sequence: the seed. The seed is a value that you provide to the
random function, usually a number, that serves as the starting point for generating the values. If you use the same seed, you will get the
same sequence of random values every time, which is useful for creating reproducible
output. This is because the random function is actually
a deterministic algorithm that uses a mathematical formula to generate seemingly random numbers
based on the seed and other internal state variables. The output appears random because the formula
is designed to be very sensitive to changes in the seed and other inputs, so even small
differences in the input values will result in very different output sequences. In short, the seed is what we use to keep
our result deterministic. Ok, that's all well and good, but how can
we use procedural generation to create something truly magical? We are used to seeing a lot of video games
that use proc-gen as a way to create a bunch of unique and interesting content. Talking practically, this can be achieved
in many ways. Let's divide our problem into two parts:
Generating the data and rendering the content Well, procedural generation focuses only on
generating the data, and there are various algorithms and techniques available to accomplish
this. All of them have many pros and cons and, unfortunately,
there isn't a straightforward way to choose one among the others. Which one is better for our scenario? Well, is not easy to answer that question. It's essential to familiarize ourselves with
as many techniques as possible and consider them as tools. With experience, we will learn how to recognize
which techniques are best suited to our specific needs. For example:
There is grammar-based PCG, which is a technique that uses a grammar to provide a set of rules
and symbols that define how the content should be structured and generated. And it's often used to generate buildings
or cities. Or there is L-Systems, used a lot to generate
plants or trees. (A method for generating shapes and patterns
by recursively applying rules to a starting shape.) or again, Wave Function Collapse, Cellular
Automata, the various form of Noise functions, Distributions, Binary Space Partitioning,
and many more. But you might find a list of the most used
techniques everywhere. Let's create something using a Parametric
approach and render it. As the name suggests, the parametric approach
is basically the definition of a set of parameters that can be adjusted to produce different
results. This is what we want to generate, a procedural
room for a fantasy dungeon. The input we want to specify is only the room
size, and we want our algorithm to create the wall layouts for us. Our walls are composed of smaller pieces,
let's call them modules. One module is just a mesh that represents
the smallest part of what we want to create. Identifying all the modules of our procedural
content is really important to define all the rules and compose our algorithm. Knowing the size of our module and the room
size, is easy to calculate how many modules we need and what are their positions. Also, we can think about rescaling them a
bit in order to fit the measure more precisely. Of course, you can also create a completely
different configuration by arranging them using a different formula, rather than in
a straight line. To render the wall, we can use the "DrawMeshInstanced"
API which is perfect for our case, since we will change the room dimension at run-time. To use that we just need a list of matrices
that defines the modules' properties. To add variation to our basic case, we can
introduce different modules and choose between them with some kind of rule. We can also use randomness to lead the choice,
the important thing is to remember to set the random initial state with a seed. To move from a single wall to a room, we can
just repeat the procedure for the missing walls, the floor, and all the other pieces
we want to add. To populate the room, we first created a grid
system and assigned to each cell a tag based on its position and its side. So we have the inner cells and the outer cells. But also, we can discriminate north, south,
east, and west cells. To insert props, we checked all the available
positions in the grid and performed a probability check based on the cell's zone. Each zone had a different pool of possible
objects, and every object had a different chance of being placed and a specific size. Once an object was placed, we updated the
list of available cells by removing the occupied ones. In addition, we could also mark certain areas
as forbidden to prevent object placement in those locations. By iterating through this simple algorithm,
we were able to fill the room with a diverse range of objects, resulting in a fully decorated
space. This is a basic scenario but with the same
techniques, we have built all these other examples. Of course, sometimes, we also added more polished
rules or different inputs. Here, for instance, we used the mouse path
rather than a length, but the core of the generation is the same. Procedural generation is a huge topic and
we really loved to experiment with different techniques and approaches. If you found this video interesting, we encourage
you to try it out for yourself. In the description below, you'll find some
resources, talks and articles, that we found extremely helpful. Let us know what you think in the comment
below. Don't forget to subscribe, smash the like
button and follow us on the other socials. See you next time,
cheers