Practical 4 - Local Illumination¶
Objectives of this practical:
introduce lighting in your scenes
improve your understanding of illumination models
implement the Phong illumination model, as seen in the lecture
Pre-requisites:
it is best but not mandatory to have completed Practical 2 - Meshes and modeling
you can have a look at the GLSL tips page to get familiar with additional GLSL operations needed for this practical (
normalize()
,dot()
,reflect()
,pow()
…)
For this practical, we provide a new set of files
viewer.py
phong.vert
phong.frag
,
to be used with the
core.py
transform.py
given in the previous practicals.
The provided viewer.py
is a very simple skeleton
to load objects from files using the generic load()
function,
provided in the core.py
utilities and render them all with the Phong
shader. We now work with complete implementations of Mesh
and
Viewer
from core.py
.
For this practical, you will thus be mainly working on the GLSL shader code.
Most 3D file formats are able to
specify Phong parameters, for example .obj
files have sister material files
with .mtl
extension which store these parameters in readable ASCII format.
For testing, you can find different material samples in
this material file
.
To use, insert the following lines with any material name found in the above
file, at the head of the
suzanne.obj
3D file:
mtllib vp.mtl
usemtl aqua
Exercices¶
1. The Lambertian model¶
Until now, we mostly studied how to create complex geometry and how to use OpenGL functions to manipulate shaders and buffers on the GPU. Today, you will mainly work on the shaders themselves using the GLSL programming language.
Your first task will be to implement the Lambertian model, defined at any surface point by the following function:
\(I = K_d (\mathbf{n} \cdot \mathbf{l})\),
where \(K_d\) is the color of the object (also called albedo or diffuse color), \(\mathbf{l}\) is the direction of the light (a unit vector) and \(\mathbf{n}\) is the normal of the surface.
This function will have to be written in the fragment shader to obtain the final rendering. The light vector defined is passed as a uniform variable. Make also sure to take the following remarks into account to obtain a proper result:
as shown in the figure above, the convention is to use only vectors directed outward with respect to the object surface.
if the light is located under the surface, the scalar product will result a negative value and should thus be clamped to 0.
after being rasterized, the normal might not be a unit vector anymore. Make sure to re-normalize it in the fragment shader.
the illumination computation must be done with data located in the same coordinate frame. If the normal is defined in the camera frame, the light direction must be expressed in the same space.
Note
Passing the NIT matrix
In case of non-uniform scaling, the model and view matrices cannot be used
directly to transform normal vectors. As seen in lecture 1,
the proper way to tranform a normal is to use the NIT matrix:
\((M^{-1})^\top\) where \(M\) is the upper left 3x3 matrix of
the modelview matrix. Look up the inverse()
and transpose()
GLSL functions to do it in GPU, or use numpy.linalg.inv()
and
a.T
to transpose a Numpy array a
on the CPU side.
2. The Phong model¶
The Phong model uses an additional term that accounts for specular reflections:
\(I = K_a + K_d (\mathbf{n} \cdot \mathbf{l}) + K_s (\mathbf{r} \cdot \mathbf{v})^s\),
where \(K_a\) is a constant ambient color that approximates complex inter-reflections between objects in the scene by a constant term, and \(K_s\) is the color of highlights, or specular color (usually white). The exponent \(s \in (0,\infty)\) is the shininess and controls the shape of the specular lobe. Tiny lobes (or mirror-like) surfaces are obtained with high values of \(s\).
\(\mathbf{r}\) is the reflected light vector and can easily be computed
using the GLSL built-in reflect()
function. The view vector
\(\mathbf{v}\) can be either given as a uniform variable or directly
computed in the shader via the model and view matrices. Note that a position
defined in camera space (after the transformation by the model and view
matrices) already provides a non-normalized view vector. Once again, be careful
with negative values that must be clamped to 0 (a shading function should not
create negative energy).
Optional Exercises¶
The exercises below are all independent except 4 and 5.
3. Control light and shading parameters¶
Level: easy
Assign some key handlers to control the parameters of the Phong model. You may want to change the color of the surface (\(K_d\)) or to modify the shininess \(s\) for instance.
Animate the light direction \(\mathbf{l}\) in such a way that it rotates
around the scene. Hint: a uniform timer will be necessary in the shader to
compute the new direction at each frame, which you can retrieve with
glfw.get_time()
.
4. Point light¶
Level: medium
Previous exercices only consider a directional light (where the direction is the same everywhere on the surface). This definition is usually used when considering distant lights, such as the sun.
The goal here is to use a point light instead, for which the direction changes locally. Moreover, its intensity decreases with the square of the distance between the surface and the light. Formally, the Phong model becomes:
\(I = K_a + \frac{1}{d^2} [K_d (\mathbf{n} \cdot \mathbf{l}) + K_s (\mathbf{r} \cdot \mathbf{v})^s]\),
where \(d\) is the distance between the position of the light and the surface point at which the illumination is computed.
5. Multiple lights¶
Level: easy
Complex scenes usually use multiple lights to obtain more realistic renderings. Your goal is to define and animate/control 2 or more directional and/or point lights. The equation becomes:
\(I = K_a + \sum_k \frac{1}{d_k^2} [K_d (\mathbf{n} \cdot \mathbf{l_k}) + K_s (\mathbf{r_k} \cdot \mathbf{v})^s]\).
When using multiple lights, the result is simply computed as the sum of all contributions. You may try to assign a different color to each light in order to see them separatly in the rendering.
Elements of solution¶
We provide a discussion about the exercises in Practical 4 - Elements of solution. Check your results against them.