Arkwood said, ‘The time has come to shine the light on me.’ He put on the Oculus Rift virtual reality headset and waited.
I had already shone some dim ambient light into the virtual room. But now it was time to create a bright white light source and shine its rays upon the furnishings.
Learn OpenGL explains how to calculate the diffuse lighting for each fragment rendered to the Rift. We need the light’s position in the 3D world, the fragment’s position, and the normal. Fortunately, I have created my virtual room in Blender – the 3D creation suite – which can provide the normal for each vertex of my room’s walls, ceiling and floor. And any other object I proffer to put in the room – which, for the purpose of this post, will be a coral cube.
We can see how the side of the coral cube facing the light source is brightly lit.
But the back of the cube, not facing the light source, is dark.
Not only that, but the part of the ceiling where its fragments are closely aligned to the light rays is much illuminated.
It’s all to do with calculating the direction of the light ray, which is the difference between the light’s position and the fragment’s position. And then working out the angle it hits the fragment’s surface – which is where the normal helps out, as it is perpendicular to the fragment’s surface.
Let’s take a look at how this all comes together in the fragment shader. First, let’s recap how we get the ambient component:
"float ambientStrength = 0.1f;\n" "vec3 lightColor = vec3(1.0f, 1.0f, 1.0f);\n" "vec3 ambient = ambientStrength * lightColor;\n"
Good. The ambient component provides dim light to the virtual room. We may want to pass the light colour to the fragment shader as a uniform, but it’s fine for now.
Next, the diffuse lighting:
"vec3 norm = normalize(oNormal);\n" "vec3 lightDir = normalize(lightPos - FragPos);\n" "float diff = max(dot(norm, lightDir), 0.0);\n" "vec3 diffuse = diff * lightColor;\n"
Great. The direction of the light is calculated, and then we use the normal value from Blender to produce the diffuse component.
Finally, we put the ambient and diffuse together to give our fragment some light. If the fragment is from a texture – such as the wallpaper on the walls – then we do:
"vec3 result = (ambient + diffuse) * texture2D(Texture0, oTexCoord).xyz;\n" "FragColor = vec4(result, 1.0f);\n"
Otherwise we handle the object’s colour:
"vec3 result = (ambient + diffuse) * oColor.xyz;\n" "FragColor = vec4(result, 1.0f);\n"
Now we have a fragment with ambient and diffuse lighting added. Ready for the final component of our Phong lighting model – specular lighting. But that’s for another day.
Here’s a closer look at that cube – you can see how the light is different on each side, with the brightest facing the light source.
I ran my C++ Microsoft Visual Studio application, which makes use of the Oculus SDK for Windows and OpenGL graphics library. Arkwood lay down on the carpet with the headset on and basked in the glory of the light. Reborn.
The only object in the virtual room that we do not apply lighting to is the white light source itself. That would be stupid. Either use separate shaders for the light source or perhaps pass a bool uniform to the existing shader to tell it to bypass the lighting calculations.
Of course, you could add the directional impact a light source has on a room without actually rendering the light source. But it generally makes sense to see where the light comes from.
Here’s a video of me strolling about the virtual room, examining how the ambient and diffuse lighting has affected the coral cube and ceiling, walls and floor.