This blog series is a part of the write-up assignments of my Real-Time Game Rendering class in the Master of Entertainment Arts & Engineering program at University of Utah. The series will focus on C++, Direct3D 11 API and HLSL.

In this post, I will talk about how I enable alpha blending for the effects and how they are differentiated from the normal draw calls in my current engine system

Alpha Blending Effect

StandardEffectWithAlpha.JPG
Alpha blending enabled effect file

With the effect format that we set up a long time ago, it is really easy to modify an effect to enable alpha blending. However, a dependent draw call might depend on some more criteria other than just alpha blending. What we can do is adding the check into our effect builder, and allow it to set the dependent bit. Right now, I am just checking whether the alpha blending is enabled or not.

EffectBuilderCehckAlphablendingEnable.JPG
Setting dependent draw bit inside effect builder

Now every time the game thread submits new meshes to the rendering thread, the graphics system will check the draw call type and encode it accordingly.

SubmitMeshAndMaterial.JPG
Submitting meshes and material

Render Commands Sorting

For our independent draw calls, we’re just gonna use the same sorting scheme (effect -> material -> depth -> mesh). However, it’s a different story for the dependent draw calls. The dependent draw calls demand strict drawing order from the back to the front, otherwise, the alpha-blending result won’t be correct. To achieve this, I made separate encoding functions for each type.

NewRenderCommandTypes.JPG
Different draw call types
NewRenderCommandFunctions.JPG
New render command encode/decode commands

You can see that the dependent draw call has a larger value in the enum, which guarantees that it will be sorted after the independent draw calls. After the render commands are arranged and sorted correctly, we can easily call the same sorting function as before.

Results

AlphaBlendedSpherers.JPG
Alpha blending enabled spheres

You can clearly see the blending effects between the meshes in the front and the meshes in the back. The blending results look correct, green plus red turns into yellow, and blue plus red turns into purple. Now let’s take a look at the rendering order and see if it is doing what we expected.

RenderingOrder.gif
GPU rendering order

Note how the independent draw calls (solid objects) are being drawn in groups of effects and materials, and also from front to back. While the meshes with alpha blending enabled are being drawn from back to front, and the overlapping fragments changed color when a new mesh is being drawn onto it!

Depth Test/Writing

Currently, in my engine’s render state, two flags are actually getting set when I enable depth buffering. The two flags are depth testing and depth writing

DepthBufferingEnabled
Depth state description setting with depth buffering enabled

However, do we really need both settings when rendering alpha-enabled object? Well, we definitely still need to do the depth test, otherwise, a transparent object that should’ve been blocked by an opaque object will now suddenly be rendered in front of it! But I could essentially disable depth-writing for the alpha-enabled objects since I ordered them to be rendered from back to front. Generally speaking, the later draw calls for transparent objects should always be in front of the previous ones. Therefore, I don’t really need to write into the depth buffer anymore, but I could just check against the depths of the opaque objects. To achieve this, I need to modify my effect format, render state class, and the builder program.

NewRenderStateInLua.JPG
New render state in Lua format
NewRenderState.JPG
New render state bit masks
NEwRenderStateInitDepthTEstingWriting.JPG
New render state initialization

The builder application will respect the settings in the Lua format, but try to make a reasonable default assumption if it is not given the settings. The depth testing bit will be defaulted to true, while an object with alpha blending enabled will have the depth writing bit default to false to save some resources!

DepthWritingDefault.JPG
Reading and setting default depth writing

Different Blend Modes

There are multiple different blend modes that we can set in our render target blend descriptions apart from the basic alpha blending. We can set multiple render target blend description with different blend operations and the blend factors to achieve different blending effects.

BlendDesc.JPG
Current blend description

To enable different blend modes,  the whole building scheme and render state setup need to be revisited. Instead of only using a one-bit flag to specify whether alpha transparency is enabled or not, I am using two bits to specify the alpha blending modes. When initializing the render state, I support different presets of blending description according to different blend modes.

NewAlphaBlendingModeEnum.JPG
Blend modes enums
SwitchingDifferentBlendDesc.JPG
Blend descriptions initialization

As you can see, I am supporting two extra special blend modes right now, one for additive (linear dodge), and one for multiplicative. Generally speaking, since the additive is adding two layers directly together and creating a brighter effect while multiplying the layers together gives a darkening (since we will only be multiplying by numbers smaller than 1.0) effect.

AdditiveBlendMode.gif
Additive blend mode
MultiplicativeBlendMode.gif
Multiplicative blend mode