Graphics

From OniGalore
(Redirected from LOD)

Here we explain various aspects of Oni's graphical code, with introductions to basic computer graphics concepts and links to further reading.

Coordinate system

3D coordinate systems with Oni added.jpg

In Oni's world, the Y axis is up, the X axis extends rightward, and the Z axis is depth, or "forward". This is referred to as a righthanded Y-up system, with the "hand" referring to a conventional mnemonic aid for keeping track of axes, pictured on the right. When compared with other game engines, Oni's coordinate system is not unusual, however it has a difference of opinion with Blender on the subject of which axis is up. Since Blender is now the 3D modeler most commonly used by modders, recent versions of our modding tool OniSplit have offered an argument, -blender, for converting between axis conventions automatically. Note that Oni has a BSL command, am_show_axes, for showing the world axes as a handy reference, except that it's wrong, showing a lefthanded Z-up system, only used by Unreal Engine.

Environment mapping

Wikipedia article: Environment mapping

It's a technique to simulate reflectivity: the diffuse texture is mapped using regular texture coordinates (UVs), and there's an additional texture layer, the UVs for which are generated from the vertex normals and the orientation of the object in space (and, ideally, the orientation of the camera). While env mapping is the most advanced shader in Oni, it's about the worst implementation of env mapping there ever was (the projection is planar and the camera angle is not taken into account at all).

Fog

See BSL:Frustum and fog on how to alter fog using BSL.
In mid-to-late 1990s games, when processing power was not enough to render far viewing distances, clipping was employed. However, the effect could be very distracting since bits and pieces of [objects] would flicker in and out of view instantly; by applying a medium-ranged fog, the clipped polygons would fade in more realistically from the haze. — Wikipedia article Distance fog
For more technical information on fog and on frustum-based space (or whatever it's called), see here and here and elsewhere.

The frustum (see below) defines a set of coordinates in which the near plane is at Z = 0 and the far plane at Z = 1 (X = -1 and X = 1 correspond to the left and right side of the frustum; the top and bottom of the frustum are planes with Y = -a and Y = a, with a the aspect ratio of the screen).

The important thing for fog is Z (the depth coordinate in frustum-based space). Every pixel of every object within the frustum is blended with a color (the fog color), depending on the amount f of fog in front of that pixel. The default fog color is 25% gray.

For f < 0, there is no fog in front of the object and the pixel retains its original color. For f > 1 the object is completely fogged and the pixel has the color of the fog. For 0 < f < 1, the color is interpolated linearly between the original pixel color and that of the fog.

The value of f is taken to be 0 on the fog's "start" plane and 1 on the fog's "end" plane and is interpolated/extrapolated linearly elsewhere, in the frustum-based coordinates. The natural order is: near clip plane, fog "start" plane, fog "end" plane, far clip plane.

The conversion formulas between z (units of distance from the camera) and Z (percentage of frustum depth) are:

Z = z_f * ( z - z_n ) / [ z * ( z_f - z_n ) ]
z = z_n * z_f / [ z_f - Z * ( z_f - z_n )]

By default, z_f is 10,000 world units and z_n is 4, so Z = 0.925 corresponds roughly to z = 53.07 world units (or 5.307 m, or 17.411 ft).

Frustum

See BSL:Frustum and fog on how to alter the far clip plane and field-of-view (FOV) using BSL.
In 3D computer graphics, the viewing frustum or view frustum is the region of space in the modeled world that may appear on the screen; it is the field of view of the notional camera. The exact shape of this region varies depending on what kind of camera lens is being simulated, but typically it is a frustum of a rectangular pyramid (hence the name). The planes that cut the frustum perpendicular to the viewing direction are called the near plane and the far plane. Objects closer to the camera than the near plane or beyond the far plane are not drawn. — Wikipedia article Viewing frustum
Field of view (FOV)
Oni defines the vertical field-of-view (FOV), i.e., the angle between the top and bottom planes of the frustum as measured at the camera's location, and its default value is 45°. On a 4:3 screen, the corresponding horizontal viewing angle is 2 * arctan(4/3 * tan(45° / 2)) = 57.8°.
Widescreen FOV
On a 16:9 or 16:10 screen, the horizontal viewing angle for a vertical FOV of 45° is larger: 2 * arctan(16/9 * tan(45° / 2)) = 72.7° and 2 * arctan(16/10 * tan(45° / 2)) = 67.1°, respectively. This causes objects to show up in some of Oni's cutscenes which aren't meant to be seen, for example the opening cutscenes of CHAPTER 02 . ENGINES OF EVIL, CHAPTER 11 . DREAM DIVER, and CHAPTER 14 . DAWN OF THE CHRYSALIS (the camera even becomes blocked by a wall in Ch. 2). A quick way to fix this is to bring the horizontal viewing angle down to the intended 57.8° during the cutscene: the 4:3 viewport will then effectively be trimmed vertically rather than extended sideways. On 16:9 and 16:10 screens, the corrected vertical FOV will be 2 * arctan(3/4 * tan(45° / 2)) = 34.5° and 2 * arctan(5/6 * tan(45° / 2)) = 38.1°, respectively. Remember to set it back to 45° after the cutscene to fully enjoy the extended viewport. (Note that the Anniversary Edition contains widescreen patches for some of the affected cutscenes, making this unnecessary.)

Occlusion

A game rarely needs to draw every object in the world at all times; many polygons or objects can thus be "culled" (not drawn) to save CPU time. Culling an object is typically done for one of two reasons:

  • it's outside of the camera's field of view (view frustum culling)
  • it's within the camera's field of view but it's hidden by other objects (occlusion culling)

Culling speeds up the drawing process, but the catch is that it also takes time to determine which objects need to be culled for each frame that is to be rendered. Rather than consider every polygon individually, the standard approach is to use a hierarchical subdivision of the scene whereby the children (subparts) of a large object are automatically culled if their parent is determined to be hidden or out of sight.

To store the hierarchy, Oni uses an "oct tree". They combined this with a somewhat unique approach to culling which they called "ray casting"; we'll consider these one at a time. The purpose of these two choices was to lighten the load for the level designers, who were accredited architects and not game developers. The content authoring workflow for Oni was designed to allow direct exporting of level geometry from AutoCAD, the architects' tool, into Oni as "dumb" polygons without special preparation by the designers.

Oct trees
This structure is more commonly spelled "octree" in the computer science field, but was typically written as two words by Bungie West. Unlike the more common "visibility groups" placed manually by the level designer (commonly called BSPs), Oni uses an automatic partition of the visible space into smaller and smaller cubes, until each "leaf" cube holds no more than a certain small number of polygons (see OTLF for details). Environmental polygons, characters, particles, etc. will only be drawn if they are in a leaf node of the oct tree which is detected as visible. Unusually, the detection of whether a leaf node is visible is done with ray casting.
Ray casting
Wikipedia article: Ray casting
If you've ever thought that you briefly saw flashes of color while turning the camera, now you know why. This picture was taken while quickly turning leftward. Wherever a portion of the level geometry has not yet been flagged as visible by the ray casting, the level's skybox will be visible.

Brent Pease, Oni's project lead, introduced this original algorithm for both frustum and occlusion culling. During each frame, 16-20 rays (depending on the graphics quality setting) are shot from the camera into the environment, distributed randomly within the frustum. Along the path of each ray, the engine first determines the relevant leaf node of the oct tree (either by navigating the oct tree or using the information on the neighbors of the previously traversed leaf node), and then the ray is tested for collision with non-transparent environment quads intersecting that node (if the ray is stopped by a quad, then its further path is ignored). Quads thus detected with collision will be drawn.

An overview of the algorithm is presented in Brent Pease's paper "An Algorithm for Hidden Surface Complexity Reduction and Collision Detection Based On Oct Trees", which he presented at GDC 2000. The original Word file can be found HERE. You can view it in convenient HTML form HERE, but note that figure 1 and 2 have become transposed and all of the illustrations are in lower quality.

Just a side note: the ray casting feature which handles occlusion is not to be confused with the common term "ray tracing", a CGI rendering method where a ray is cast for every rendered pixel, achieving a high degree of photorealism. This method is very CPU intensive and is typically used only for still images, short video sequences, or CGI movies (which take months to render). Implementations of real-time ray tracing for gaming are slowly being introduced, but still need to be complemented with the standard scanline rendering and rasterization approaches for performance reasons.

Pease acknowledges that even ray casting was too CPU intensive until they lowered the number of rays being emitted and started randomizing their emission angles even when the camera remained still, in order to catch any polygons that the first emission of rays missed; this is why distant polygons, when suddenly entering the scene, sometimes are culled at first (pictured above) and then appear a moment later: because the rays didn't hit them on the first pass. A second problem is that a distant face in the environment can be accidentally culled if it's only visible through a narrow slit, because the rays have a low probability of passing through the slit and hitting the objects behind it. A similar problem occurs when modders experiment with outdoor levels that have uneven ground (natural terrain): many of the ground polygons will be culled because they are nearly end-on to the camera, making the map look like there are holes everywhere.

General problems with excessive culling can be alleviated by casting more rays, which is extremely feasible with modern computers, though it's a brute force solution. A more optimized solution for the specific problem of "skybox flashing" would be to group the rays on the side of the frustum which is being revealed as the player moves the camera in order to score hits on new polygons more quickly. A proven solution for rendering levels with natural terrain is to use fewer polys for the ground and to make them quads, not triangles.

LOD

Oni uses the graphics quality slider in Options to help determine what level of detail (LOD) at which to render characters. Each character has up to 5 LODs, though one 3D model can be used in as many of the 5 slots as desired. The first step in determining which LOD to draw each character at is to consult this table found in the character's ONCC.

After that distance-from-camera filter is applied, Oni counts the total polygons of all characters in the scene (henceforth "TPCS"). If TPCS is not above the maximum character polys in the scene ("MCPS") which is allowed by the game's graphics quality setting, the game then experiments with raising the LOD of all characters one level at a time, stopping when it would pass MCPS. If TPCS is starting off above MCPS, it lowers all characters' LOD one level at a time until it gets below that limit.

For reference, here is the table of MCPS by graphics quality level: (1500, 2200, 3000, 3400, 4000). Note that there is no consideration at all for how many environmental polys are in the scene.

Next, iterating over each character from closest to farthest, the LOD of that character is raised by 1 as long as this won't raise TPCS over MCPS. Thus Oni seeks towards the maximum detail level that it can use for each character, prioritizing the closest ones. As a special consideration, if the closest character is below Medium LOD, it is raised to Medium regardless of MCPS, and the second-closest character is raised to Low if it was Super-Low.

Once the desired LOD is determined for a character, they will be switched to it immediately if they are not standing still (which would make the switch too noticeable). If they are moving, the game waits several frames to make sure the new LOD is continuously being requested by the above algorithms and then they are switched. The goal is to avoid a character rapidly switching back and forth between LODs.

After all the above considerations, one more: if a cutscene is playing, every character is guaranteed a minimum LOD of Low so that no one will be rendered at Super-Low detail.