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.

I have implemented normal mapping in one of the previous posts, so I will be talking about a different approach to implement it and also look at its effect with specular lighting, along with trying to create one normal map from scratch.

Normal Vector Calculation

In my last post, what I did to calculate the lighting with our tangent-space normal vector was to convert the directional light direction in the world into tangent space using the inverse of TBN matrix. In this post, I am just going to convert the local normal, tangent, and bi-tangent vectors into the world space, and then construct the TBN matrix inside the fragment shader. This is a more straight forward approach and would make sense if we actually need the TBN matrix in the fragment shader for something more. However, the original approach is less memory and computation intensive since we are performing the calculation in the vertex shader and just let the hardware interpolate the result.

NewVertexShader_ConvertAllToWorldSpace.PNG
Transform vectors into world space in the vertex shader.
NewFragmentShader_ConvertTexNormToWorldNorm.PNG
Constructing TBN matrix and calculating the adjusted normal vector in the fragment shader.

Speculat Lighting Effect

When I implemented normal mapping before, I hadn’t added in specular lighting. However, specular lighting can contribute a lot to the illusion of geometry using normal mapping, so let’s take a look at the same Sting model that I used for the previous tests.

(Update: After my teacher pointed out that the normal map looks incorrect, I went back and looked at it. In order to have the blade texts raised and the hilt texts be sunken, I actually needed to flip the red channel of the normal map, below are the results!)

Custom-made Normal Map

Now let’s try to create a normal map on our own from scratch (well, sort of). I’m gonna create one in Photoshop with texts simply say raised and sunken. Inside Photoshop, there is a filter that is, conveniently, generate a normal map. Let’s do some testing, let’s assume that white color is treated as higher heights, while black is treated as lower.

RaisedSunkenMapBefore.png

RaisedSunkenNormalMap_1.png

We can see that there is actually a problem with the generated normal map. We know that the RGB color in a normal map is actually xyz values. More specifically, the results in a normal map mean “given a surface normal that is (0, 0, 1), what should the normal transform to.”

We can conclude that given the right-hand coordinate space (x is right, y is up, z is out of the screen), the upper part of the “RAISED” texts and the lower part of the “SUNKEN” texts should be green-ish. This happens because of how coordinates are represented in Photoshop, where the top-left corner is the origin.

To fix this problem, we can simply flip the curve of the green channel and we should get the expected result.

FlippingGreenYChannelInPS.PNG
Flipping the green channel
RaisedSunkenNormalMap_2.png
New normal map after flipping the green channel

Results

Now let’s see how the normal map looks in the engine. First, we will look at how it reacts to directional lights. You can look at the earth sphere to get a sense of direction of the light.

DirecitonalTopLeft.PNG
Direction light from the top left corner.
DirecitonalTopRight.PNG
Direction light from the top right corner.
DirecitonalTopForward.PNG
Direction light from the front.

Now let’s flip the directional light over and just focus on the point specular light. First, we will look at the “RAISED” part and then move onto the “SUNKEN” part.

RaisedSpecTopLeft.PNG

RaisedSpecTopRight.PNG

SunkenSpecTopLeft.PNG

SunkenSpecTopRight.PNG