# Guideline for making 3D models for Ultimate Stunts

### Introduction

Ultimate Stunts is a 3D game, and it uses 3D models to build the track from and for the cars. These 3D models can be created in external 3D modelling software, imported with the stunts3dedit program, transformed and colored, and saved in Ultimate Stunts' internal .glb format. This document does not describe how to do this. Instead, it describes what kind of 3D models fit the goals of Ultimate Stunts.

### Goals for good 3D models

A 3D model is good if it meets two objectives: it has to look good, and it has to be displayed fast. Of course, these objectives often have opposite effects on the 3D model: a good looking model is displayed slowly, and a fast displayed model often looks bad. In this document, some tricks will be given to make 3D models both fast and looking good.

### Performance requirements, and target platforms

Of course, the right equilibrium between performance and detail depends on the hardware. Ultimate Stunts uses openGL, which can be many times faster when it uses hardware acceleration. The Ultimate Stunts project tries to be very flexible in its hardware requirements: people with poor hardware should be able to get an acceptable frame rate (with poor graphics) , and people with good hardware should get high-quality graphics. The user can set various graphics settings in Ultimate Stunts, like the texture level of detail, enabling/disabling blending of translucent surfaces and even enabling/disabling the z-buffer.

### Level Of Detail (LOD)

For the 3D geometry designer, it is important to know that Ultimate Stunts uses different Levels Of Detail (LOD) in different situations. The 3D geometry of every LOD should be defined in the .glb file (of course you can use a single model in each LOD, but that's not the optimal situation). Currently there are six LODs: 1 (most detail) to 4 (least detail), c (for collision detection) en s (for drivable surfaces).

### Polygon count

Even on high-end hardware, the number of polygons in a model can make it too slow. Every polygon has a number of vertices, and for every vertex a number of transformations and tests has to be applied in order to project it onto the screen's surface. Actually, the vertex count is more important than the polygon count; there can be a difference if vertices are shared between polygons.

Of course a model with fewer polygons is always less detailed than a model with more polygons. Especially curved surfaces can look bad if they are made of too few polygons. A number of tricks can be applied to hide the fact that a model has only a few polygons:

- Curved surfaces can be made with smooth shading, or "Gouraud shading". Normally the eye can see the boundary between the faces because the faces have different colors intensities, which is caused by the different orientations of the faces relative to the light source. With "flat shading", every polygon has a uniform color, so at the boundary between polygons of a curved surface, the user can see an intensity difference. With "smooth shading", the shadow intensity is not calculated per face, but per vertex. Within the polygon, the intensity is interpolated between the vertices. Now, as two polygons of a curved surface that are next to each other share vertices, their color intensities at the boundary are also the same. The result is that the user cannot see the boundary between the polygons.

  In order to let this work, a "normal vector" needs to be defined for every vertex. The normal vector defines the direction of the surface at the position of the vertex, which is used to calculate the shadow intensity. Many 3D modelling programs can generate these normal vectors automatically, by enabling "smooth shading" for a group of polygons.

  The effect of smooth shading can really be spectacular. A cylinder can be made with only 10 polygons, while the low number of polygons is only visible at the flat sides of the cylinder. Generally, it's a good idea to use more polygons for large and important objects, like loopings and wheels, and less polygons for small and unimportant objects, like in scenery. You could also make it different for different LODs.

- Many details can be done with textures instead of polygons. For instance, a door of a building can be a single polygon with a door texture on it. A fence can be built of many cylinders, each having many polygons, but it can also be made of a single polygon with a fence texture on top of it. Textures are mapped on polygons by defining "texture coordinates" for every vertex. For every pixel of the polygon, the texture coordinates are interpolated, and the color corresponding to those coordinates is found in the texture image. These operations do not really depend on the texture size, so they can be done much faster than 3D vertex transformations for an equally detailed model made of polygons instead of textures. So, if you want both speed and quality: use textures.

### Textures

So, textures can be used to make highly detailed models with a low polygon count. The disadvantage is the extra number of per-pixel calculations required to find the texture color of that pixel. On hardware-accelerated systems, those operations are done by the video card processor instead of the main processor. The video card processor is optimised for doing the same thing many times simultaneously, so it can do the per-pixel operations many times faster than the main processor. The problem is that the video processor needs access to the texture data. With modern AGP/PCIe ports the communication between video card and CPU/main memory is really fast, but transferring all texture images at a 25 fps rate would still to much bandwidth. That's why textures should be placed in the video card's memory, and that's why it's important to have enough video card memory.

For the 3D modeller, it's important to realise that the performance will drop down if not all textures fit in the video memory. Of course the memory usage can be reduced by using smaller textures (even the user can do this in Ultimate Stunts' settings: Ultimate Stunts resizes textures before it gives them to openGL). This resizing is so simple that it's not really important for the modeller. Another way to reduce texture memory is important to know: sharing textures between models. A texture that is used by many models is loaded only once, so it uses memory only once. So instead of using a different grass texture on every tile, it's better to use the same grass texture.

Textures for Ultimate Stunts can also have an alpha layer, which can be used for transparency effects. For example, the leaves of a tree can be drawn in a texture with an alpha layer, with the part of the texture outside the leaves being transparent. Then a tree can be made with very few polygons, while they are still very detailed. A disadvantage of textures with very large transparent areas is that for many pixels, a lot of calculations are made to get to the conclusion that nothing has to be drawn. For large objects (that appear large on the screen, so that they take a lot of pixels) it could be better to define a more detailed polygon model and to reduce the number of unneccesary pixel operations. Another disadvantage is that for users who disable transparency blending, the transparent areas display as opaque. For these users, a more detailed polygon model might be a better solution.

### The z-buffer

In a correctly rendered 3D image, objects that are in front of other objects cover those other objects, so that they are not visible. There are a couple of ways to reach this goal. One way is to sort the objects and draw them from back to front. When an object is drawn on top of another one, it replaces those pixels, and the result is correct. Another way to do it is to remember the depth of each drawn pixel (the z-coordinate) in a buffer, the z-buffer. When a new pixel is drawn, its depth is compared to the existing pixel, and the new pixel is only drawn if it is in front of the old one. This method is more accurate than the other one, because it compares per-pixel instead of per-object. In theory it should always give the correct result, but in reality there are some problems.

One of these problems is that the z-buffer has a limited accuracy. Polygons that are very close together, like a window on top of a wall, sometimes get mixed together in an ugly way because the z-buffer cannot see which of them is closer to the camera.

Another problem has to do with translucent surfaces. When those surfaces are drawn before the objects behind the surface are drawn, then the objects behind the surface are not drawn because the z-buffer values are set to the depth of the translucent surface. Ultimate Stunts solves this by trying to render objects from back to front as much as possible, but inside an object it doesn't change the drawing order. This drawing order should be set in such a way that it gives a correct result from most viewpoints. The drawing order is also important if no translucent surfaces are in the object, because the z-buffer can be turned off for performance reasons. The only thing that keeps things right in such situations is the drawing order.

### Design decisions

So, concluding, the following decisions have to be made:

- The number of faces for round shapes. You can vary this for different LODs. Generally, a low number is good enough if you use smooth shading.
- The details that are in textures versus details that are in geometry. Generally, texture is better if the player doesn't need to see depth differences.
- Recycling of textures: use textures that are already used in Ultimate Stunts, or use textures that can be re-used in the future.

### Collision detection

I forgot to tell you about collision detection. Till now, we've only been talking about the graphics, but the geometry of objects also influences their physical interaction by collisions. There are separate LODs ("c" and "s") for the collision model.

The collision models for tiles, car bodies and car wheels are defined differently. Tile collision models are a set of polygons, just like the graphics model, so for many tiles the graphics model can also be used for collision detection.

The only special thing about tiles is that "surface" polygons should be in the "s" LOD, and not in the normal "c" LOD. This is because Ultimate Stunts treats drivable surfaces differently from collision surfaces. Water surfaces should be part of both "s" and "c".

The car's body collision model is a "bounding volume", which approximates the body's shape with a set of planes. Every plane splits the entire space in two parts, and says "the car is on this side of the plane". With enough planes (with cleverly chosen orientations), only a small volume remains, and this volume should be an approximation to the shape of the car. The planes are defined with polygons in the "c" LOD. In the existing cars you can see examples of collision models, where the collision planes are usually translucent blue.

The wheels have cylindrical collision models. The cylinder is defined by two polygons at the positions of the "end caps" of the cylinder. (the wheel's symmetry axis is the x-axis, so those polygons should be perpendicular to the x-axis.) The height (y-direction) of those polygons defines the diameter of the cylinder. Again, you can see examples in existing cars.

A very detailed collision model can make the collision detection very time-consuming, and luckily a detailed collision model is not needed as much as a detailed graphics model. Some complex shapes with many polygons can be approximated with a simpeler collision model, and some objects don't need a collision model because the cars wil never collide with them. In some situations it is even desirable that an object doesn't generate collision effects, e.g. with bushes or flowers.