This is an OpenGL based 3D graphics and physics engine, written in C++. It runs on most Unices, including Mac OS X. Code-wise the program is portable to Windows as well, even though I'm not offering such a port at the moment. It runs on OpenGL 1.4 or later, but some of the more advanced features require an OpenGL 2.0 implementation.
This software has been a project for me to experiment with, and especially to learn from. The software isn't actually used for any specific purpose, but rather acts as a platform for me on which to implement new ideas or effects that I find interesting.
A demonstration of water and HDR rendering.
It's not precalculated and it's dynamic, rendered on a single polygon using shaders. |
water_hdr_low.avi 800x600, low quality, 2Mbps, 36MB, Windows Media Player compliant
water_hdr_high.mp4 800x600, high quality, 5.4Mbps, 125MB, high-profile h264
Various miscellaneous shaders are implemented, such as ones suited to simulate cars with metallized paint jobs.|
viper_medium.avi A medium quality video capture. 800x600, 4.5Mbps, 28MB
viper_long_hq.avi A high quality video capture. 800x600, 8.9Mbps, 114MB
|FLTK (2.0) is used as the user interface. Objects can be loaded and managed with the UI. None of the OpenGL specific code is handled via the FLTK, only the user input is; the graphics engine isn't dependent on FLTK.|
A smaller part of the engine is the physics engine.
It simulates object dynamics in a physically realistic fashion.|
3d_physics.avi 800x600, 1.5Mbps, 13MB, 75s, Windows Media Player compliant
|The engine has a Lightwave 3D object (LWO2) loader for importing modelled objects. Support for Lightwave scene files was once partially implemented, but I didn't have use for it, so it's not included.|
The eye (or the camera, if you like) is also a controllable object, as are the light sources. Light sources can represent solid objects at the same time.
|For shadowing objects, shadow volumes are supported. Shadow volumes are rendered using shadow polygons that are rendered to stencil buffer, which is then rendered on the screen appropriately.|
The same object shadowing technique was used in Doom 3, for example. Shadowing techniques more suitable for surface self-shadowing are implemented using shaders (see self-shadowing).
For an environment having no singular lights, ambient occlusion needs to be implemented for a realistic lighting of objects. The engine computes vertex specific ambient occlusion coefficients -- optionally in multiple passes -- for any object, and also accounts for indirect lighting from other polygons.
|Normal (not ambient) lighting. A spot light above the car provides the light.|
|A flat ambient environment lighting. This type of ambient lighting was used in the car in section 3.5.|
||Ambient occlusion computed in 1 (above) and 2 (below) passes.|
|Ambient occlusion with indirect light (from other polygons) simulated.|
The shader programs are written in GLSL (OpenGL Shading Language), and some of the techniques, especially the more advanced ones, require a GPU with dynamic branching capabilities. OpenGL 2.0 implementation is preferred.
|Toon shading is implemented in fragment shader, where light intensity is divided into predefined discrete values. It is only applicable to directed lights, as the limited light intensities don't have the resolution for spot lights.|
||Per-fragment ("per-pixel") lighting is implemented using a fragment shader, for both directed lights and point lights. The technique is in active use in most modern computer games. Texture mapping is also implemented.|
|Normal mapping is supported. Per-fragment lighting calculations are done based on the supplied normal map. Ambient, diffuse and specular light types are simulated. This technique is also often implemented in modern computer games.|
|Offset mapping is supported. Texturing coordinates are adjusted during the rendering in fragment shader, based on height information supplied by a height map. This technique is a fast, but an inaccurate way to simulate height differences within a surface. Offset limiting is also applied to control the simulation to some extent.|
||Relief mapping techniques are implemented for accurate simulation of height variations on the surface. Linear and binary searches are implemented. Linear height field approximation is used as well to enhance the appearance with only a slight increase in computation time.|
|Self-shadowing of surfaces is implemented through light ray occlusion searches, using methods based on relief mapping. Self-shadows are physically correct.|
|In addition to hard self-shadowing, also soft self-shadows are implemented. The implemented soft self-shadows are not approximated; they are physically correct, and react properly to light source size, distance, and direction.|
Translucency and transparency effects are applied to two-layer relief-mapped surfaces. The simulated surfaces consist of a solid bottom layer, similar to the ones simulated previously. Per-pixel lighting, texture mapping, normal mapping and relief mapping techniques can be applied on the solid layer.
The upper layer of the surface represents the upper limit of a material that has an index of refraction (optical density) different than of the environment. The space between the lower and the upper layer thus consists of the optical medium. The index of refraction for the medium can be freely chosen (for example to match that of water (1.34), glass (1.6) or diamond (2.42)). A normal map and a height map is supplied for the upper layer.
The phenomena responsible for the appearance of optically denser materials, such as glass or water, are well known in physics, and are caused by reflection and refraction.
|Refractions and reflections are traced either to the solid layer of the surface, or to the environment, with physically correct light ray paths. The refraction and reflection intensities are calculated according to the Fresnel terms. Thus the resulting appearance isn't fake; it's physically correct and behaves the same way as real mediums.|
|Local refractions and reflections are traced using relief mapping based techniques. A cube map is used for environment mapping, although practically any environment mapping technique can be applied.|
|Light rays from light sources are traced to the rendered fragment to determine the amount of light occluded by the translucent layer. Light reflection and refraction are taken into account in calculating the final light intensity reaching the surface.|
|The medium can also be made to absorb light. Light absorption within a medium makes it hued or dim, along with its shadows. The absorbed light intensity is calculated based on the distance the light travels within the medium, and is a physically correct way to simulate light absorption.|
Water rendering is one of the many applications of the translucent medium rendering technique.
In the following screen captures, the previously presented rendering techniques are used to render water.
The visual simulation of the water is physically correct.
Water dynamics is implemented in software.
I have also taken a video capture of the water:
water_win.avi 800x600, 2Mbps, 13MB, low quality, Windows Media Player compliant|
water_mac.mp4 800x600, 2Mbps, 13MB, low quality, QuickTime compliant
water_hq.mp4 1200x900, 7Mbps, 47MB, high quality, H.264 encoded
The translucency/transparency rendering techniques, and the water dynamics, are my design. You can see my master's thesis for more detail about the rendering technique.
|The car paint is rendered in 3 layers. The first layer is a reflective coating, rendered using an index of refraction of 1.2. The second layer, beneath the first one, contains tiny random chips of metal, as metallized car paints do. The bottom layer is a solid-colored diffuse paint.|
|Metal rendering is done in 2 layers. The first layer has static-intensity environment reflectivity, and the bottom layer is solid gray.|
|Windows are rendered in 2 layers, as well. The first layer is glass with an index of refraction of 1.6, and the bottom layer is pitch black. Lamps are rendered as simple HDR values based on their angle to the viewing point. The glass casing is rendered the same way as the windows, but instead of using static background, alpha blending using Fresnel terms is used.|
viper_medium.avi A medium quality video capture. 800x600, 4.5Mbps, 28MB|
viper_long_hq.avi A high quality video capture. 800x600, 8.9Mbps, 114MB
Image captures from the video in left.
||High dymamic range rendering is implemented through floating point color maps, and light intensity is calculated in a physically realistic fashion. Light blooming is implemented using frame buffer objects (FBOs) and custom shaders for highpassing, sqrt-based value controlling, interpolative downsampling, and gaussian blurring.|
The physics engine is fps independent. During each frame update, events are processed in the order they occur in time -- objects are updated after each event, and the remaining frame timeline is kept consistent until no more events need processing. As some physical effects are near-impossible to keep analytical relative to arbitrary advances in time, linear and real object trajectories are intelligently applied in order to produce realistic behaviour and accurate collision detections.
Collisions with arbitrary polygons and other objects are computed. During collisions, both linear and angular momenta are calculated, resulting in rather realistic dynamics. Objects have physical properties, such as mass and moment of inertia, based on which calculations are done. Some more trivial effects are simulated as well, such as the gravity and air friction.
3d_physics.avi 800x600, 1.5Mbps, 13MB, 75s, Windows Media Player compliant|