My work on this project

Carousel imageCarousel imageCarousel imageCarousel image

Shader pipeline

The existing pipeline had some issues and was missing some features so it was rewritten.

It all starts with the wrapper which is a templated class with a specialized CreateShader function for each supported type. This class also inherits from FileObserver which allows us to have the shaders update during runtime.

The handling of custom shaders were moved from the mesh component to their own custom shader component. This also made it easy for us to distinguish what should be rendered using deferred and forward. The component itself contains a reference to a shader and an additional four texture slots. The shader loading is handled through the resource manager.

I wanted a fast way to get basic data on to the GPU to allow for quick testing and tuning of shaders. This is where the CustomBufferDataComponent comes in. It's essentially an opaque dictionary with some editing tools. Simple, but it allows for shaders to be developed and tested without any additional programming. The data can also be manipulated through node scripting which is pretty nifty.

Entity editor

This is something I really missed in the previous project. We didn't really have a way to dynamically create objects in runtime which made some aspects of testing difficult. Since we already had ImGui in the project I thought I'd give it a shot.

Ease of use was my priority when I designed this system. I wanted each component and respective author to have ownership of the tool for that component. A base component had to be implemented for all the migrated components. The base component generates the component name in a string format for displaying and adds an empty interface for implementing tools.

Making a component appear is as simple as inheriting from the base component and adding the class to a list.

The container provides the window and populates it by iterating all entities in the active registry, calling their draw function if it is expanded. This is achieved by recursive template functions.

If I had done if from scratch I would've separated the entity list from the component list as it does get a bit cluttered once there's a lot of entities with children.

Carousel imageCarousel imageCarousel imageCarousel image
Carousel imageCarousel image

Terrain generation

I was responsible for the terrain pipeline. Getting terrains out of Unity (we used Unity as a level editor) was a bit of a pain. There was external tools that allowed terrains to be exported as a single model but that's difficult to cull. In the end I went with a height- and splatmap approach. There was native support for exporting these images so they were used to generate smaller sections.

While I was working on render targets I stumbled upon compute shaders so I thought this would be a good opportunity to try them out. I thought I would have to generate all the normal data and I wanted to speed that up. In the end it turns out the library we used for importing and exporting (Assimp) did all that work for me. The performance gain was probably non-existent but at least it gave me an easy way to sample the height- and splatmap and I also learned a lot. Compute shaders does seem like a very powerful tool though and I am definitely going to read up on them.

The splatmap gets baked into the meshes vertexcolor which we later use to texture the terrain.

Render targets

The plan was to have snow deformation in our game and for that we needed render targets.

My implementation is probably not optimal but I wanted to show how the shader pipeline could be utilized. Here we have a script outputting coordinates to a buffer component which is then read by a pixel shader outputting to the render target. That render target is then inserted into the vertex shader on the model as a custom texture and displaces the vertices as if it was a heightmap.

It's a small extension to the custom pixel shader component with it's own renderer.