I've been working on the material system lately. A material handles the textures and shaders used when rendering a mesh. Every material has its own shading program, which consists of a vertex shader, a fragment shader and an optional geometry shader. Some of the material's properties, like its number of texture layers, are compiled directly into the shaders, while others, like material colors, can be updated at run-time using uniform variables.
Materials can be made up of several layers which are blended on top of each other with a variety of blend modes, very similar to Photoshop. A texture layer can contain a diffuse texture with an optional alpha channel (for transparency effects), a normal map with a height component stored in the alpha channel (for parallax mapping and similar effects) and a specular map. Internally, texture layers are represented by array textures. This brings the advantage that only one texture object has to be bound per layer, effectively reducing the number of texture binds by two thirds (diffuse, normal and specular maps are all adressed by the same sampler in the shader).
In addition, texture layers can be scrolled, stretched or rotated for effects like animated computer screens etc. This was heavily used in Quake 3, for example. I'll show an example of that later (if I don't forget as usual).
The wall on the screenshot is composed of four images (as seen on the left). You can see the material definition in the upper left corner.
Monday, January 23, 2012
Monday, January 9, 2012
Level export and portal rendering
I've been a busy bee these past months even though I failed, as usual, to report on my progress.. so here's a short recap.
I designed the engine's level format and wrote a Blender script which creates levels from prepared .blend files. Levels use portals and bounding volume hierarchies for fast visibility detection. This way, both indoor and outdoor scenes can be rendered reasonably fast and, most importantly, mixed. For now, portals have to be set manually in Blender. It works like this:
The next step was to put the new information to use. When a camera's render routine is called, it first determines the smallest sector it is in. Then it traverses the portals connected with this sector and recursively performs the following steps:
The player's camera sees what is displayed in the top-right viewport. It is positioned in the first room. The doorway acts as a portal to the adjacent corridor, which in turn acts as a portal to the next room, and so on. This means that only parts of all rooms following the first are visible from the camera's current position, and only these parts and the entities they contain have to be rendered.The white frustum visualizes the camera's perspective from the first room, the turquoise frustum its perspective from the adjacent corridor, etc.
I designed the engine's level format and wrote a Blender script which creates levels from prepared .blend files. Levels use portals and bounding volume hierarchies for fast visibility detection. This way, both indoor and outdoor scenes can be rendered reasonably fast and, most importantly, mixed. For now, portals have to be set manually in Blender. It works like this:
- The artist creates an indoor level as a series of connected rooms. Every room must be a separate object.
- Portal polygons are created for every door, window, etc. which connects two rooms or a room with the outside. Every portal polygon must be kept as a separate object, its name must begin with "p_" to tell the export script it's a portal.
- The export script creates a list of rooms and portals and their connections. In addition, a bounding volume hierarchy is created from the rooms and free objects (landscapes, detail meshes, etc.)
This way, portals are merely an optional optimization; if the scene you're working with it rather simple or you simply want to preview a complex level and don't care to much about speed, you can simply skip portal creation; potential rooms will then be placed in the bounding volume hierarchy.
A portal's definition in the level file may look like this:
portal02 // portal's name
room02 // target room's name
4 // number of vertices
-2.947355 0.001296 -4.529554 // vertex #1
-2.947347 3.001296 -4.529551 // vertex #2
-4.947346 3.001301 -4.529550 // vertex #3
-4.947354 0.001301 -4.529554 // vertex #4
The next step was to put the new information to use. When a camera's render routine is called, it first determines the smallest sector it is in. Then it traverses the portals connected with this sector and recursively performs the following steps:
- If it is not completely visible, the portal is clipped to the screen.
- If the clipped portal has more or less than four vertices, it is replaced by its projected bounding rectangle.
- A new view frustum is computed from the clipped portal, using the portal's plane as the new near clipping plane.
- The sector is rendered using the new frustum.
- The entity components (meshes, sprites, etc.) contained in the sector are rendered.
- Sub-sectors are rendered.
Here's a screenshot with debug visualizations of the portals created during the recursive process:
The player's camera sees what is displayed in the top-right viewport. It is positioned in the first room. The doorway acts as a portal to the adjacent corridor, which in turn acts as a portal to the next room, and so on. This means that only parts of all rooms following the first are visible from the camera's current position, and only these parts and the entities they contain have to be rendered.The white frustum visualizes the camera's perspective from the first room, the turquoise frustum its perspective from the adjacent corridor, etc.
Wednesday, October 12, 2011
AABB vs. OBB
The lack of posts in the last weeks was not due to a lack of progress on the engine.. what I've been working on is just not very interesting: I've ported the frustum culling and collision detection code from the old framework into the new engine and it's finally all working as it should.
I've been struggling to implement culling and intersection tests for oriented bounding boxes (OBB) and discarded them eventually; instead, I simply rotate the eight corner points of an entity's axis-alinged bounding box to dynamically compute a larger AABB which encompasses the rotated entity. This is still pretty fast and works just as well.
Next task: Bullet integration.
I've been struggling to implement culling and intersection tests for oriented bounding boxes (OBB) and discarded them eventually; instead, I simply rotate the eight corner points of an entity's axis-alinged bounding box to dynamically compute a larger AABB which encompasses the rotated entity. This is still pretty fast and works just as well.
Next task: Bullet integration.
Tuesday, September 6, 2011
Just a small update
I've added project serialization using boost::serialization; although it was rather easy to implement, it took some time until I fully understood how to serialize classes which inherit from one or several base classes. For example, all entity components inherit from a base class EntityComponent which among others serializes the component's parent transform. Similarily, all resources inherit from a common base class Resource, which stores the resource's file path. In order to make sure that the desired inherited class members are serialized properly as well, one should use the BOOST_CLASS_EXPORT_GUID macro, which has to be defined for every class at the top of each source file from which these classes are serialized:
If not used, your program may simply crash without telling you where and why. At least that's what happened to me, ruining an otherwise perfectly fine Saturday afternoon :/
Also, it's now possible to create and attach cameras to entities through the editor. In addition to their primary free-fly camera, all 3D viewport can then select and preview all available cameras. This is useful to set up and test in-game cameras. The screenshot illustrates how a third person camera may be set up for a mech game:
BOOST_CLASS_EXPORT_GUID( EntityComponent, "EntityComponent" )
BOOST_CLASS_EXPORT_GUID( ModelController, "ModelController" )
BOOST_CLASS_EXPORT_GUID( CameraController, "CameraController" )
BOOST_CLASS_EXPORT_GUID( SkeletonController, "SkeletonController" )
If not used, your program may simply crash without telling you where and why. At least that's what happened to me, ruining an otherwise perfectly fine Saturday afternoon :/
Also, it's now possible to create and attach cameras to entities through the editor. In addition to their primary free-fly camera, all 3D viewport can then select and preview all available cameras. This is useful to set up and test in-game cameras. The screenshot illustrates how a third person camera may be set up for a mech game:
Subscribe to:
Posts (Atom)



