Lab Five
Lab Five Shading and Materials
CSE 287
Description: This is the second lab on ray tracing. In this lab, you will implement shading calculations to simulate ambient, diffuse, and specular illumination by one or more light sources. The calculations will be based on properties of the viewing ray being traced, the surface that is intersected, and the light sources in the scene.Your ray tracing work will continue in the next lab with texture mapping and will conclude with a project that will require you to implement shadow feelers, reflection, and add additional types of shapes. Your starting point for this lab is your completed lab four.
Getting Started
1. Use MSVC 2017 to open your CSE287Lab4 solution.
2. Change the default color used by the RayTracer class to black.
3. Modify your traceIndividualRay method so that it calls the illuminate method for each of the light sources in the scene whenever the view ray intersects a surface. It should sum up the colors that are returned by the illuminate calls. The sum of the contributions from the light sources should be returned by the method if a ray intersection occured.
for(auto light : lightsInScene ) {
totalLight += light->illuminate( viewRay.direct, closestHit,
surfacesInScene);
}
If you don’t understand the use of the auto keyword in the code fragment above, you can create the for loop using the more traditional approach.
for (unsigned int i = 0; i < lightsInScene.size(); i++) {...
Modify Code So Lights and Can Be turned On and Off
Add a data member of type bool called enabled to the LightSource struct in Lights.h
/*
CSE287- Page 1 of 8
Lab Five
* Shading calculations are performed if true. BLACK (no light)
* is returned otherwise.
*/
bool enabled = true;
Add global declarations to the top of RasterUser.cpp.
// Vector holding all the light sources in the scene
LightVector lights;
// Light sources in the scene
shared_ptr
shared_ptr
shared_ptr
Remove local declarations from the statements that instantiate the light sources in the buildScene function in RasterUser.cpp and modify the instatiation of the ambientLight as shown.
ambientLight = make_shared
ambientLight->ambientLightColor = color( 0.15, 0.15, 0.15, 1.0 );
lightPos = make_shared
color(1.0, 1.0, 1.0, 1));
Add cases to the switch statement in the KeyboardCB function in RasterUser.cpp that
will make it possible to toggle the light sources on and off.
case( ‘a’ ):
// Toggle light on and off
ambientLight->enabled = (ambientLight->enabled) ? false : true;
break;
case( ‘p’ ):
// Toggle light on and off
lightPos->enabled = ( lightPos->enabled ) ? false : true;
break;
…
Ambient, Diffuse, and Specular Reflection
Lights.h contains declaration/definitions of different structs that can be used to hold properties of three different types of light sources. The LightSource struct is the parent of both PositionalLight and DirectionalLight. Each of the structs have an illuminate method that returns a color. For each type of light source, the illuminate method needs to contain shading calculations that calculate a color that represents
lightDir = …
CSE287- Page 2 of 8
Lab Five
simulated ambient, diffuse, or specular reflection for a light source. Due to its limited properties, the LightSource struct can only support ambient reflection. The PositionalLight and DirectionalLight illuminate methods have the necessary input to calculate ambient, diffuse, and specular reflection for a light source.
4. Modify the illuminate method of the LightSource struct so that it performs the calculations for ambient reflection and returns the associated color. When performing the calculation, use the ambientColor property contained in the Material struct of the HitRecord that is passed to the method and the ambientLightColor of the light source.
5. ModifytheilluminatemethodofthePositionalLightstructsothatitreturnsthe ambient reflection value returned by the super struct illuminate method. This will make sure everything is wired up correctly.
return LightSource::illuminate( eyeVector, closestHit, surfaces );
Run the program. Your scene should show ambient reflection. Other than the new default color and not being quite as bright, it won’t be much different from what you had before.
CSE287- Page 3 of 8
Lab Five
You will now be implementing diffuse and specular reflection calculations. These results will be summed along with the ambient reflection calculated by the super struct.
In general, the best to organize your code so that it first calculates all the necessary vectors and then carries out the lighting calculation.
6. Instead of simply returning ambient reflection calculated by its parent, modify the illuminate method of PositionalLight so that it does the calculations for diffuse reflection and returns the sum of this value and what is returned by the super struct illuminate method. When performing the diffuse calculation, use the diffuseColor property contained in the Material struct of the HitRecord that is passed to the method and the diffuseLightColor of the light source.
7. Add a Shiness property to the Material struct. Initialize it so 128.0.
// Shininess exponent for specular lighting calculations.
double shininess = 128.0;
8. ModifytheilluminatemethodofPositionalLightsothatitdoesthecalculationsfor specular reflection, adds the result to the result of the ambient and diffuse calculations and returns this sum. When performing the specular calculation, use the specularColor and shininess properties contained in the Material struct of the HitRecord that is passed to the method and the specularLightColor of the light source.
When trying to create specular reflections, both the specular surface color and the specular light color are both some form of white. Higher values for the shininess exponent will produce “brighter” and the tighter highlights. Shininess values are usually not greater than 256.
CSE287- Page 4 of 8
Lab Five
Directional Light
9. Add a DirectionalLight to the scene. Remember the direction supplied to the constructor is pointed opposite the direction the light is shining. It is the light vector for both diffuse and specular calculations.
10. Implement the illuminate method for the DirectionLight struct that calculates both diffuse and specular reflections and adds them to the calculation carried out in the super struct illuminate method. It can be exactly like the illuminate method of the PositionalLight with the exception that the light vector does not need to be calculated. Instead, it is the direction data member.
CSE287- Page 5 of 8
Lab Five
SpotLight
11.Add an additional struct to Lights.h called SpotLight. It should be a child of the PositionLight struct and it should have data members that represent the direction in which the spotlight is shining and the width of the spotlight beam.
/**
* Struct for simulating light sources that have an explicit position
* and shine in a specified direction.Width of the associated beam of
* light is controlled using a spot cutoff cosine. Instantiations
* of the struct will have position and direction properties along with
* a color and intensity of the light given off by the light source.
*/
struct SpotLight : public PositionalLight
{
SpotLight( dvec3 position, dvec3 direction,
float cutOffCosineRadians, const color & colorOfLight )
: PositionalLight( position, colorOfLight ),
spotDirection( glm::normalize( direction ) ),
cutOffCosineRadians( cutOffCosineRadians )
{ }
virtual color illuminate( const glm::dvec3 & eyeVector,
HitRecord & closestHit,
const SurfaceVector & surfaces )
{
}
// TODO
return BLACK;
/**
* Unit vector that points in the direction in which the light
* is shining.
*/
dvec3 spotDirection;
/**
* Angle in radians of half the spot light beam
*/
double cutOffCosineRadians;
CSE287- Page 6 of 8
Lab Five
};
12.Implement the illuminate method for the spotlight. It should not contain lighting calculations. Instead, determine if the point of intersection is in the beam of the light. If it is, call the super class illuminate method and return the results from that call. Otherwise, just return BLACK.
13.Add a spotlight to the scene.
Emissive Materials
14. Add another new data member to the Material.h struct of type color. Initialize it to BLACK (a dvec4 in which all elements are zero).
// Emissive color of the surface
color emissiveColor = BLACK;
15.Modify your traceIndividualRay method in the RayTracer class so that whenever a ray hits a surface, it returns the sum of all illumination method calculations plus the emissive color held in the Material struct of the HitRecord representing the intersection that is closest to the origin of the ray being traced.
16.Use the emissiveColor property to make one object in your scene “glow.” Turn it in
1. Copy the folder containing your solution to the desktop.
2. Change the name of the folder to CSE287LabFive followed by your unique identifier. For instance “CSE287LabFiveBachmaer.”
3. Open the solution. Make sure it still runs.
4. Clean the solution by clicking on clean.bat. (The will delete all the intermediate temporary files that are part of your project and reduce the size of your submission.)
5. Zip up the solution folder using the standard windows compression tool. (No 7zips, rars, etc.)
6. Submit your zip archive of the solution through canvas.
You will need to have this project available and complete when you start
CSE287- Page 7 of 8
Lab Five
the next lab.
CSE287- Page 8 of 8