FPS 3D game
16 Weeks Part-Time (4h/day)
Created with our own Cobra engine
Group of 15 people
- Tools / Editor / Pipeline
- Engine back-end
Creating Our Level Editor
During the first weeks of the project, I worked a lot on making our Cobra Editor easy and stable to use. I have written about our editor and my contributions to it here.
Since we used our own level editor, we needed a way to create navmeshes. I wrote a pipeline for exporting the walkable level geometry from Cobra and then importing that and creating a mesh from it in Maya. Read more here.
Me and Jonathan then used these navmeshes for pathfinding. Our solution used the regular A* algorithm. A nice optimization we implemented was the ability to divide the searching of a path over several frames. We also implemented a post step smoothening of the found path.
Extending the graphics engine
During this second game created in our Cobra Engine, I also continued working on the graphics engine, adding new features and extending existing ones.
Area Lights with Linearly Transformed Cosines
In Buddhetti, the only lighting we had was an environment light and point lights. In this game, I wanted to extend that and add more light sources. Based on this work by Eric Heitz and others, I implemented rectangle lights.
This lighting fitted in very well with the sci-fi style of the game, and it was also used to fake indirect local lighting.
Editor interface for the rectangle lights
Rectangle lights used for fake indirect lighting
Lights with projected textures
Based on this tutorial by Rastertek, I also implemented lights with projected textures. This was used to create some interesting "fake shadow" patterns, as well as giving lights a shape or texture filter to make it look more interesting as shown below.
In Buddhetti, the only shadows we had came from one global directional light. In this game, the main lightening came from smaller, local, light sources, and I therefore had to extend our shadow system. I implemented cube shadow maps for point lights, which were also used for the rectangle lights. For the light projectors and spot lights, regular shadow maps were implemented.
To achieve realistic looking soft shadows, I used a variation on the method described here. At each point being lit, I created an orthonormal basis using the normal vector. I then generated points in the plane defined by it by sampling a vogel disc.
Rays from these points to the light source were then used to sample the shadow map.
By varying the radius used for generating new sample points, the softness of the shadows could be adjusted.
Vogel disc sampling with different number of samples
Example of different shadow softnesses achieved by varying the sample radius
I also implemented Screen Space Ambient Occlusion, with my implementation based on this tutorial. Even though it was a bit performance heavy, the result really improved the overall look of the game.
The result from the FXAA, based on this implementation, was more subtle than the SSAO. However, the overall effect of it still did a lot to improve to overall graphical quality of the game.
FXAA. The difference is most noticable if you look around the edges of the lamp.
I also added a motion blur effect to the game. I cranked it up a bit in the gif to the right to show the effect more.
Screen space deferred decals
I also implemented a system for screen space deferred decals, based on this tutorial.
It supported both decals with color and normal, and also normal-only decals.
It was used for decorating levels and also for bullet holes and blood splatter.
Bullet holes and muzzle flash
Editor interface for creating decals
Together with Jonathan, I also added support for detail normal mapping, with variable scale and strength.
Experimental: Local parallax corrected cubemaps
In my spare time, I also wrote a system for creating local cubemaps in Cobra. It worked by rendering the scene from certain probe positions, then saving these cubemaps to DDS files. These were then automatically opened in (an adjusted version of) IBLBaker, which converted them to one irradiance map and one pre-filtered environment map, following the image based lightening tutorials here.
These maps were then parallax corrected (based on Sébastien Lagarde's work) in a shader, creating a really nice result with local reflections and lightening. Sadly, this was never used in a game and I had to abandon it because of time constraints. However, it was a fun experience and I learned a lot.
Here's a list of some additional things I implemented in this project:
Helped implement our threaded loading system
Culling system and instanced rendering