All posts by Vegard

Generating Gladiators

Some time ago now, we made a decision on Ludus which was a particularly tough call to make. We had been working on Ludus for a while, art, code and design all along side eachother. We had made economical decisions based on our scope and our minimal budget.

I’ve been working as a technical artist for 10 or so years now, so I have come to expect that expectations tend to change over the course of a production, but I somehow didn’t quite foresee that my own would change quite so much. Nevertheless, through habit more than clairvoyance, I knew things tend to change, and I knew that the best way of dealing with this is to always try to build a system that does whatever some job is, rather than focusing on doing the job itself.

Arena

So when it came to creating the characters, I set out making a system that would instead generate characters on my behalf from a set of models that had the same topology so that they could morph into each-other and consequently be mixed in any variation.

I started by grabbing some gladiator armor meshes from TurboSquid and Rob fitted them to a model exported from MakeHuman, then I exported some more characters of different shapes from MakeHuman to serve as the morph targets. I linked the bone positions to the vertex positions in the mesh so that I could correct the rig after morphing the vertices, and computed an automatic weight for the clothing meshes to follow the underlying geometry.

Character generator v1

The results seemed promising and after a while of ironing out some vertex order and other kinks we had a system that could produce characters of lots of different shapes and sizes. As you can see from some of the in-progress images below, this process was easy peasy lemon sqeezy.
FunnyhatUnfortunateSpike

We continued working with these models and preparing new gladiator armour models for them. Time passed by, and after a while we had quite a lot of art built around this system. But something wasn’t quite right; the model we used was from an earlier version of MakeHuman, and the base model itself had some slightly peculiar proportions. All the variations consequently just looked a bit off.

ShipIt

We made the call to change the base mesh, and with it, all the character art had to be altered as well. A tough call to make on a minimal budget. So I made another system, this one ripped some code from the character generator to morph all the clothing meshes into a new base pose, which we made by pushing the rig into a pose similar to the new character base mesh we had, and then refining the model somewhat using standard modeling tools.

Mesh refitting

Bar a few errant vertices that needed to be cleaned up by hand, this system was able to salvage most of the data.

Adding the new character and new rig to the old system was an immediate success as made evident by the image below.

ImmediateSuccess

After a bit of massaging (read: near complete rewrite) the system was able to produce some  plausible looking characters of many different shapes and sizes though, and we had improved the overall quality in the process without completely killing the art budget.

2016-01-08_20-20-58

In the game, we have also tied the attributes of the characters to their visual appearance, so a generated character with a high strength value will look stronger, or a character with a high constitution appear more full bodied. After a little while of playing, you get quite good at judging the abilities of an opponent.

 

 

 

 

 

 

 

Spherical Spline Quaternions For Dummies

or: How I Learned To Stop Worrying And Embrace The Math

My artsy illustration degree was about as useful as a chocolate teapot in setting me up for my job as technical director.  When I read white papers, I feel dyslectic when looking at the wall of math and the academic wording. Now after some years of experience, I want to share some core code bits and understandings of the stuff that makes it possible to make pretty pictures, animations and games on the computer in a wording that I hope will be a bit more understandable than many of those white papers. First up: Spherical Spline Quaternion Interpolation or SQUAD for short.

chocolate teapot

What is it?
It’s a formula that makes it possible to smoothly go between a set of rotations.

Where would I use it?
If you were making some animation code where you wanted some 3d object to go through a set of keyframes of different rotations for example, ‘tweening’ smoothly.

What do I need to understand to use it?
A basic understanding of Quaternions helps, but mainly you need to know that:
– Quaternions are rotations
– They are different to Euler angles, but they don’t suffer from gimbal lock.
– They’re not as straightforward to understand as Euler angles and have different problems to Euler angles.
– If you try to visualize them, your head explodes.

How does it work?
Do you know splines / curves from animation programs or vector drawing programs? It’s a lot like that but in crazy quaternion space. The trick is that you need to compute something sensible as the tangents so that you can go smoothly through a bunch of keyframes.

What problem does it solve?
Normally, you might reasonably interpolate between Quaternions using SLerp (Spherical Linear Interpolation) or Lerp (Linear Interpolation) but if you’re going to go between more than two key rotations, these functions are visually to the surface of a sphere what a straight line is to a sheet of paper.

Let’s take a look at it visually. Here is a vector being rotated by SLerp through several rotations:

SLerp

Although it’s smoothly interpolating in time, it’s not really affected by what the next quaternion after the current two is, so it just moves in a straight line from one quaternion to the next. If you have lots of keyframes this could still appear smooth, but with just a few spaced out ones, it doesn’t look smooth. Now let’s look at what this looks like with SQUAD interpolation:

SQUAD

Much better!  The rotations appear to be anticipating where it’s going to go next, and we get a smooth curve occuring on the surface of the sphere. These rotations are much more visually pleasing and we need a lot fewer keyframes to achieve a smooth looking motion.

Because it’s properly interpolating over all the different axis we can now get some interesting tangents by rotating the quaternions about the twist axis:

SQUAD_Banked

Unity Implementation
The unity project with source code and an example of use file can be downloaded here

Unity’s Quaternion class isn’t quite enough for to implement SQUAD, so we need to expand on that a bit first. The first script in the package below (QuaternionExtensions.boo) helps us extend the Quaternion class with functions that we need to complete the SQUAD calculations. Among other things we need a version of SLerp that’s a bit different to the SLerp method in Unity in that it doesn’t flip, as well as some basic things like scaling or adding to the Quaternion directly.

The second script (SQUAD.boo) contains the implementation of SQUAD itself. Looking at the code top down, our entry point might be something like the method Spline() with a number of quaternions that make up the spline, and a value t along that curve.

SplineSegment() returns the interpolated value between the 4 quaternions it’s operating on (the part it’s working on is the “line segment” between q1 and q2, the first and final quaternion are the previous and next quaternion after this line segment).

Intermediate() is the function that produces the nice and smooth tangent values between the rotations. There’s some magic stuff going on in there and I’ll let you play with the -0.25 value yourself. I’ll cover briefly what is happening but I don’t have a very deep understanding of why this works myself.
First it transforms the first and last quaternions by the inverse of the middle quaternion putting them in world space.
It then performs the quaternion Log function on them that we added in QuaternionExtensions.boo, adds them together, scales them by a magic number and performs quaternion Exp before transforming them back into the space of the middle quaternion and normalizing the Quaternion.

SQUAD() is then called on q1 and q2 with the two tangent values we got from Intermediate().  This is where we need to use the SlerpNoInvert() method we added to the Quaternion class. If we just use the Slerp() function from Unity there will come a point where unity clamps the domain of the Quaternion which basically looks like our poor vector travels through interdimensional space and ends up in some completely different place in our puny 3 dimensional world.

Special thanks to Pekka Kytölä for helping me learn this.

Terraingulation

As we mentioned in the previous blog-post we want to make Ludus very easily mod-able, and because we are a small team we need to make sure that the tools we create help us fill in the world as quickly and easily as possible. We decided that the most efficient way of making the world was to generate a part of it procedurally whenever practical. At the same time we want to maintain control over the design and make it as easy as possible to design new areas of the world, both for us and the modders. The system we came up with was kind of interesting so we wanted to share the thinking behind it in this blog-post.

LudusAreaMap

This picture is all that’s needed to design the terrain for one of the levels in Ludus. but how does it work? Let’s break it down.

LocalLudusRed

The red channel indicates the area where the buildings will be. We want to make sure that the ground here is relatively level, and we also artistically decided to slightly raise the ground just beyond where the buildings make contact with the ground. This channel is currently derived from the 3d placement of the buildings rather than the other way around, and only affects the terrain.

LocalLudusGreen

The green channel dictates the playable area, this is what should be accessible to the player, the system should make sure that this area looks and acts like a walkable terrain and that it doesn’t contain any overly steep inclines etc. It also helps indicate where to use most of the vertices of the terrain itself.

LocalLudusBlue

Finally the blue channel is used in the texturing process, it instructs the material to say that this area should be using a second blended material (specifically in the current case, this makes it a paved area, while the rest is sand, but this is set up in the material settings)

ProceduralTexture

The image we had before is the final output of the ‘design’ image, All the modder/designer needs to define is there. This is then processed and combined in a procedural material from substance designer to output the image we see above. You can recognize some parts but others have come from procedural noise and various processes the image goes through to create a heightmap that is usable in the terrain generation in substance designer. The playable and building area is leveled out and raised, and a bit of height is added just around the buildings.

DelaunayMesh

Each pixel in the procedural texture is scored by neighboring height difference and whether it’s in the playable area, and we create a vertex on each ‘important’ pixel. This makes sure that the vertex budget we have for the terrain is used in an optimized way. In the image above you can see the resulting mesh. Note that it uses fewer vertices on the flat areas and that the area defined as non-playable has a natural in-accessibility because of the steep inclide.
Lastly, similar to the Mosaic effect, we use Delaunay triangulation of these vertices to combine it into a mesh.

Although the coding and procedural material process to achieve this takes more time than making one or two terrain models, the ease with which we can add new areas, using a very broad-strokes method, to the game means we can make a much more interesting and expansive world. We intend to take the system further and add set dressing like barrels etc automatically based on the original image input as well.

Mod-ern game development

Making a game properly mod-able and data driven is something one should make a decision about early on because it impacts so much of the structure of the code and data. In our case with Ludus we decided that the mod-ability would be a  key focus both because we are interested in what players will do with it and because we want to be able to easily extend the game without having to re-work things at the core of the code-base. Keeping things easy to change is hugely important when projects grow into a larger scope. It also forces us to drive a bit of a wedge between data and the core systems that process that data in a good way.

Kilroy

We use a number of external tools when developing the game such as Chat mapper (A great non linear dialogue editor with Lua support) and a whole host of graphics programs. Unity’s general approach to data loading at runtime is to have ‘asset bundles’ but this would require that the asset are first opened by the modder in Unity Pro (a paid license) and then turned into asset bundles one by one. We instead wanted to use more open, easily editable file formats that can be edited by standard programs for its data type, and also be editable using only cost free software so we don’t place any extra cost on people who would want to mod the game.

Helpfully, Unity comes with a ‘StreamingAssets’ folder which doesn’t get compressed when built, so we have an easy place to put any files that we want to ship with the game, and in doing so providing a great example of how to create content for the game for the modders since that is also where we store most of our own data. We make extensive use of this folder and have made several simple file loaders in the game to deal with each type of data. The data ranges from simple things like weapon attributes and character names to more extensive data like dialogue files, scripts and graphics.

Gladius
The ‘Gladius’ equipment folder containing all the information needed to load the sword in game.

The image above is a typical data folder as we have it right now. The game knows to look in the Equipment folder any time it needs to load (Surprise!) equipment data into the game, and all the file types are easily editable. The .obj file for the mesh can be edited in any 3d program, the stats/attributes and descriptions can be opened in any text editor, and the diffuse, normal and specular maps can be opened in regular image editors. The folder contains everything the game needs to know about the piece of equipment, and can be copied and renamed to make a new version of the Gladius.

Stats
The equipment stats and other small data are done as easily readable .txt files with key-value pairs.

Luckily there isn’t anyone in the executive, legal or marketing departments that have thrown a fit about us openly sharing the raw content from our game with the players, mostly because those departments don’t exist, so we will most likely share all this content under the CC by NC license.

One of the issues of making the game so mod-able is the impact it has on performance and this is a compromise we have to work with. Luckily since we made the choice to make it mod-able early on, we could have this and other pit-falls in mind from the start and do some things to mitigate this such as compiling new assets automatically and thereby loading them faster next time.

 

Inventory.GetGladiator()

In Ludus we are trying to make the code completely modular, so all the systems exist on their own with as few dependencies as possible. The systems fetch all their information from the world, process it, and then put the information back into the world instead of sending information around to different systems.

We don’t have too many things in the architecture that we are strict about but this part is important because we want to be able to replace and improve the systems independently without affecting too much of the code-base.  The bigger the code base becomes and the more sub-systems that are put into the simulation, the more important it becomes to be able to work on something without breaking something else. It also helps make it easier to implement and debug just one aspect of the game, and also means by serializing just one class we can save and load everything we need simply by ‘saving the world’.

saveTheWorld

In our case, the world object currently keeps track of only a handful of primary things:
-The characters in the world.
-The relationship between those characters.
-The upcoming set of gladiator games.
-The active rumours in the world.
It also has a bunch of helper methods to for example find a character with a certain profession or to get the asymmetrical relationship between two characters (I like you but you don’t necessarily like me).

Almost all the characters in our game are generated at runtime and as I mentioned are stored as data in the world object. The world object is persistent between the scenes and so when we for example need to load the slave trader into the market scene, we first use a simple proxy object to place the character visually in the level editor. The proxy object has a little replacement script on it that finds the world object and requests any character in the world that fits the description, in this case: the occupation ‘slave trader’.  The world object finds the most appropriate character or generates a new one with the required properties so the important professions will always available in the game. This is extra important because in our dynamically changing world with senators vying for position and fighting out personal vendettas, some of them have a tendency to lose their heads, both figuratively and literally. In other words, if something unfortunate has befallen Quintus the slave trader; Julia, whom just so happened to recently move here from Aegyptus, will be there to replace his function in the game. She may not be as friendly on the prices, but she’s got a keen eye for gladiator talent and you can start a brand new professional relationship with her. That’s a good thing  because Quintus had been getting on your nerves and that was why you told everyone he was sleeping with the magistrate’s wife .

Quintus gets replaced by a more favorable Julia.
Quintus position has become untenable and he gets replaced by the more favorable Julia.

As you trade and talk with this new character, the state of your relationship is updated from the conversation system to and from the world object, but the character placement system only knows that there has to be a character in this 3D position with the occupation ‘slave trader’ and the corresponding conversation trigger on it.

Now a small anecdote which originally lead to this blogpost:
Upon realizing that I needed to store all the things in the world in some way, I adapted the already existing inventory system to use as a kind of world state for the prototype. Gradually I added more things and realized I needed to store arrays of characters in there. This lead to conceptually peculiar parts of the code-base like Inventory.AddSlave() and Inventory.GetCharacter(occupation as string). The principle of idea of the world object was good though, and it’s still called Inventory in the codebase.

Inventory.GetSlave()
Inventory.GetGladiator()

 

 

Rendering crowd agents in Ludus

Crowd

The trouble with rendering a lot of different looking characters is that they tend to require a lot of drawcalls. Normally when making a crowd, the way to do this is to combine several skinned meshes together into a single skinned mesh and then send this to the GPU as one mesh. For Ludus I wanted to draw a huge amount of characters in the crowd, with sufficient visual variety that they looked like a crowd of individuals as opposed to multiple copies. I also wanted to control their animation independently to display things like a mexican wave, and different other ‘multiple people doing the same thing’ type of motions.

I was thinking a bit about the kind of motions that the chinese olympic opening ceremony showed so well with lots of people doing something with a slight delay to eachother, but almost completely in synch. For example everyone holding up a card at the same time, or doing some arbitrary motion. There’s something very appealing with those motions because as synched up as they are, they are also subtly offset because however trained they are, there are always some minor differences in reaction time etc.

20080809120355

In order to do this I figured I needed to be able to control the animations of the characters individually, but still send it to the GPU in as few draw calls as possible.

Unity will try to dynamically batch any unskinned mesh together that is less than 900 vectors of complexity, including UV coordinates and normals. That leaves us with a budget of around 300 vertices + 300 uv coordinates + 300 normals. To achieve this while keeping the overall shape I first cut the body up into the major parts that I wanted to animate, used an automatic polygon reduction tool to hit the target vertex amount while maintaining the shape as much as possible.

Crowd mesh
Each major movable area is cut into it’s own model

Now animating the mesh only using these major areas instead of a skinned mesh, I can get enough animation fidelity for the crowd agents without using bones at all. Since the crowd is far away, there’s no way of seeing the bad interesctions etc, so even though the model parts are completely rigid, we don’t really percieve it as wrong from the distance we see them at.

Up close of course, the mesh is not sufficient, but as soon as it goes somewhat into the distance we stop paying attention to a lot of the details and start seeing the agents as a crowd.

CrowdCloseUp

When we look at a large crowd, the thing that affects us the most in terms of perceiving the characters as a group of individuals as opposed to a group of copies is colour.  Shape and animation are both secondary to this. We can easily see how big an impact this has on our perception by comparing the two images below.

CrowdColour

In order for dynamic batching to work in a complex scene we have to make the rendering instruction as simple as possible. This means excluding the crowd from shadow computation, and basically using vertex colours as much as possible. I wrote a simple unlit vertex colored shader, and then computed on the CPU the shading of the characters per vertex at spawn time. This way we don’t need to compute anything substantial on the GPU. not even a dot product. So each character is vertex coloured using a random skin tone and their rest value normal dot product to the light forward direction.
This might seem strange as the characters move around their lighting is effectively baked in, but because of the distance and the multitude of characters, we don’t really perceive the ‘error’. In the end we save a huge amount of drawcalls using the dynamic batching method and can still maintain individual agents for animation purposes, and have about as many of them as our CPU can handle.
drawcalls

And here’s the final test from unity, 1200 individual crowd agents running in the editor on an Intel HD 4000 integrated graphics card.

And there you have it, dynamic draw call batching for use in crowds.

 

Procedural mosaic using Voronoi diagrams

Mosaic2

I’m a big fan of procedurally created or assisted artwork. It’s something that’s both kind of complicated to do and makes for some unique and interesting variations in a game. In Ludus I wanted to be able to produce a procedural mosaic and then link this to the Player’s story. The idea was that after a particularly exciting match, a local artist NPC might come to the Player and ask if the Player would like to commission a special mosaic to commemorate the fight. This kind of decoration can then be used to impress people that come to visit the Ludus and is visible in game.

Now of course, this could have been just represented by some pre-made picture of two gladiators fighting, but I thought it would be much more interesting if it captured a real moment from the fight. So to do that, I decided the best way forward was to actually capture a frame from the 3d scene and see if I could get this to look like a mosaic.

First up, some inspiration:Gladiators-from-the-Zliten-mosaic-400

First I started by rendering just the characters and ignoring all the background layers with a special camera that is attached to the main camera into a texture.  Since most of the mosaic backgrounds I found are just a single colour with some random variation, we don’t need any of that information.

alpha

Then I tried doing a normal Voronoi diagram over this image. Just placing random points all over the size of the 2d texture, computing the Delaunay triangulation and drawing lines between each center point of the triangles.

After the lines were in place I sampled the rendered texture we had from earlier at the vertex where the random point in the voronoi diagram was, and performed a flood fill from there. If there was no alpha value in the rendered image, I instead picked a random colour.

Flood fill algorithm

This left a few areas unfilled because they happened to overlap with a  vertex that had also been shaded as a line, but otherwise gave the impression I was looking for, so I just pre-filled the computed pixels with one of the same colours as I was using for the background.

Mosaic

The effect wasn’t quite good enough, in particular I felt that the shape of the outline was a bit too blotchy compared with the real mosaics which usually have quite a strong outline, often re-inforced by an extra black line. I decided that I needed to draw an outline of the characters, so this would always be clearer. To do this I sampled the alpha values of the rendered image, and whenever it changed from its neighbours, it would draw a black outline on this pixel.

outline

The second thing I noticed was that  I needed more ’tiles’ in the internal shape of the characters but this was wasted if distributed evenly everywhere on the image. I decided to change the algorithm for the initial random points of the Voronoi diagram so that instead of being completely random, each pixel was scored randomly but the score would increase if the alpha value was over 0.5, which meant that there would be more random points inside of the character, and thus more tiles used.  Mosaic2

So there you have it, prodecural mosaic, or at least as far as I got with it before having to move on to something else. One of the things I think is interesting here to link it further to gameplay, is that for example if you decide to commission the artist to make the mosaic, but give him less money than necessary, he can produce a mosaic with fewer tiles, giving less visual fidelity to the action.

 

Game play

Ludus is a business simulation game crossed with a role-playing game, where you play as the head of a gladiator school. In your pursuit of becoming a successful Lanista, you must procure good slaves, train them as gladiators of the arena and put on amazing shows to the roar of the crowds.

In order to be commissioned for new games, you must also pick your friends and enemies carefully as you navigate your way through the deceitful social environment where every pleb, magistrate and senator is looking out for themselves. Socialize with the best people in society, and cut deals with the worst.

The gameplay consists of two phases; the Managerial & Role-playing phase and the Games Resolution phase

During the Managerial & Role-playing phase, you have many options available to you, but only a limited amount of Action Points [AP]. You can upgrade your Ludus and the Arena, hire new staff and set out the training schedule of your gladiators. You may also choose to buy slaves at the market, buy new armour and weapons from the blacksmith, advertise your up-coming games to build hype, visit the bath-house for a chance of bumping into the upper echelons of society (and gain new patronage), visit the tavern to learn about rumours and place unsavoury bets, or carry out missions to gain the patronage of ambitious magistrates. Various events will take place in this phase where you have multiple options to choose from and that affect your social position, the gladiators, your Ludus, or even your personal character. The role-playing aspects of the game immerses you in the role of the gladiator manager, and provides you with a lot of options to fit your player style and helps you carve out your character’s vices and virtues.

In The Games Resolution phase of the game, you take the role of the tactical coach, while the matches that you have set up for the current Games play out in the arena. You shout instructions to your gladiators to change their stance or alter their attacking intensity. The gladiators attempt to follow your orders as best they can, though it is not always easy to get a new order across to a gladiator mid-fight when his leg has just taken a knock from a sledge hammer and his helmet is obscuring his vision and hearing. Your objective is to give the audience a great show whilst not killing off or heavily injuring too many of your gladiators. The gladiators play as either Heroes or Villains, and their aptitude for this is determined by their statistics as well as how you have kitted them out. It is not enough to just fight, the gladiators must excite their audience by doing so in an impressive manner. The excitement of the audience must at least match the hype that you have built up for the games for the audience not to go home unimpressed, and the Editor/Sponsor of the games being displeased with your show.

Ludus is a game

Screenshot2LUDUS is a business simulation game crossed with a role-playing game, where you play as the head of a gladiator school. In your pursuit of becoming a successful Lanista, you must procure good slaves, train them as gladiators of the arena and put on amazing shows to the roar of the crowds.

In order to be commissioned for new games, you must also pick your friends and enemies carefully as you navigate your way through the deceitful social environment where every pleb, magistrate and senator is looking out for themselves. Socialize with the best people in society, and cut deals with the worst.