Assignment 4: Lighting
- Due Mar 13, 2020 by 11:59pm
- Points 10
- Submitting a file upload
Objectives
To have a single point light that illuminates your objects.
Description
The basic assignment requires a cube and a couple spheres, and a single point light that will illuminate the objects of your world using the Phong Shader. Your application is required to have the following features:
- A Cube - The most basic object that you should be able to create by now.
- Add two spheres to your world. Why? Its easier to tell if lighting is working correctly on spheres.
- A single point light that rotates (e.g. by 5 degrees) around the world over time simulating a day/night cycle.
- Some method of moving the camera around the objects, either rotation slider or keyboard
-
Each object (ground, walls, animal, and spheres) of the world is illuminated using a Phong Shader
- Phong Shader models a combination of ambient, diffuse and specular lighting.
- Specular and Diffuse lighting calculations require the normal of the vertices. So you will have to calculate the normal of each vertex and pass this as input to the shader.
- A button to turn lighting on/off
- A button to turn normal visualization on/off
-
Extras for an A!
- Integrate lighting into your virtual world
- Have your blocky animal in your world also (with lighting of course)
Hints for how to approach this assignment
- This description assumes you are starting from your prior code. Choose either your animal or your virtual world. However its allowable to start over from scratch. If so then just get a single cube on the screen, and make sure you can change the camera angle somehow.
- We need to calculate and pass normals to the shaders. In the same way that we previously created a buffer to pass UV coordinates for texture, we now need another buffer to pass a Normal for each vertex. Create a new attribute variable in your vertex shader, and modify your javascript code to create and bind this buffer.
- In order to test that the Normal attribute is getting passed correctly, lets build Normal Visualization in early. Change your object color (temporarily) from whatever it was to instead set gl_FragColor = Normal. That is, we just take the value in Normal and stick it in the color. We haven't calculated Normals yet, so just set all the Normals to (1.0,1.0,0.0) in javascript and your objects should all be yellow.
- Add a button to turn Normal Visualization on/off. It should toggle you between your actual color/texture and just looking at what is in the Normal attribute. Use a uniform variable to pass this status to your shader and just use an 'if' statement in the shader to decide which way to color the object.
- Now its time to actually pass some real normals. For your cube object, you will need to define the vertex Normals (similar to how you defined the vertex UV coordinates in the last assignment). For cubes you can just draw a picture on paper and figure it out and type the normals in. Alternately you could write a function that looks at the triangle and uses 'edge1 cross edge2' to find the normal or the triangle. Either way, calculate some normals, and check that they are coming through to your shaders as expected using your Normal Visualization.
- Now lets add a sphere. I suppose it would be possible to calculate the vertices by hand and hard code them, similar to the cube, but its likely more convenient to write a loop, and use some trig to calculate the vertex locations. Similar to calculating a circle in the first assignment. Add the vertex locations to the attribute buffer. Check that you see a sphere on screen (it will just look like a circle since there is no lighting yet).
- Add normals to your sphere. Note that spheres are convenient objects in that if they are centered on the origin, then Normal = Position for each vertex, so you can just copy the prior buffer. Check that these normals are coming through with Normal Visualization. Google 'sphere normals' and look at images to make sure yours look sort of like what is expected.
- Now we are ready to add a light. Make a global variable in javascript for the light position, and a new uniform variable to pass this information to your shaders. Update your render() function to pass the current light position.
- In your animation tick() function update the javascript global light position so that it takes an additional step to circle around your world.
- Now we need to add the most basic lighting to make sure we are passing the light into the shaders correctly. In your vertex shader calculate 'normalize(Light) dot normalize(Normal)' and assign this to a varying variable v_Lighting. In your fragment shader modify your pixel color as gl_FragColor = v_Lighting *(whatever it was before). You should now see something that looks like lighting variation that seems to rotate around but is sort of weird if your object has been rotated. It will be right on objects that were never rotated.
- Add a button to turn lighting on and off. Keep a javascript global variable for this status, create a uniform variable to pass the information to GLSL, and update your render() function to pass the current state. Modify your fragment shader to use lighting or not depending on status. Verify that you can turn lighting on/off.
- So far our light is probably in world coordinates and our normals are in object coordinates. We need to make the coordinates match. If you are calculating glPosition = u_projMatrix * u_viewMatrix * u_modelMatrix * a_position, then your positions are undergoing transforms to get to screen space. We want to get our lighting and normals both into 'World Coordinates'. You will need to find your vertex in world coordinates as worldPos = u_modelMatrix * a _position (ignoring camera and projection). The proper light vector at this vertex is then lightVector = u_LightPos-worldPos. The normal also needs to transform into world coordinates, so you will need a 'normal matrix' to transform the normal. You could calculate the normalMatrix either in javascript or GLSL. Calculate these, and update your (N dot L) calculation to use these proper values with everything in world coordinates.
- Move our lighting calculation to the fragment shader. You previously calculated N dot L in the vertex shader and just passed v_Lighting to the fragment shader. Instead pass v_NormalDir and v_LightDir to the fragment shader, and calculate lighting in the fragment shader.
- Finally we have all the data needed passed all the way to the fragment shader. Modify the fragment shader to calculate Phone shading - ambient + diffuse + specular. You can just hard code values for ambient and specular coefficient. The only things that actually will be getting passed from javascript are the diffuse colors. That is the texture or color values that you were previously using. Everything else is calculated in the shader.
- Done!
- But I wanted an A!!! - If you started from your working previous assignment, it should still be working at this point.
Resources
- Readings:
- (WebGL) Matsuda/Lea Ch8, (Chp 6 and Appendix B are GLSL reference)
- (WebGL) The normal matrix: http://www.lighthouse3d.com/tutorials/glsl-12-tutorial/the-normal-matrix/ Links to an external site.
- Generating a sphere mesh: https://medium.com/game-dev-daily/four-ways-to-create-a-mesh-for-a-sphere-d7956b825db4 Links to an external site.
- (WebGL) Phong shader: http://www.mathematik.uni-marburg.de/~thormae/lectures/graphics1/code/WebGLShaderLightMat/ShaderLightMat.html Links to an external site.
What to Turn in
1. Canvas Submission
Zip your entire project and submit it to Canvas under the appropriate assignment. Name your zip file "[FirstName]_[LastName]_Assignment_5.zip" (e.g. "Lucas_Ferreira_Assignment_5.zip").
2. Live Hosted Submission
Host your assignment on your UCSC portal. This can be achieved by just putting your entire project directory into the 'public_html' folder which you can access via the UCSC Unix timeshare. Your site link is 'https://people.ucsc.edu/~ucsc_user_name/'.
WHEN SUBMITTING YOUR PROJECT ON CANVAS, PLACE YOUR SITE LINK AS A COMMENT OF THE SUBMISSION.
Read the SubmissionGuide.txt file for further explanation on how to submit your assignment.
Rubric
Criteria | Ratings | Pts |
---|---|---|
Have at least one cube
threshold:
pts
|
pts
--
|
|
Created two spheres.
threshold:
pts
|
pts
--
|
|
Lighting works on the spheres correctly. (ambient+diffuse+specular)
threshold:
pts
|
pts
--
|
|
Lighting works on the cube correctly. (ambient + diffuse+ specular)
threshold:
pts
|
pts
--
|
|
A user interface button to turn on and off lighting
threshold:
pts
|
pts
--
|
|
The point light rotates around the world over time simulating a day-night cycle.
You (as a programer) decide the axis in which the point light rotates around.
threshold:
pts
|
pts
--
|
|
Extra for A - Your blocky animal exists in the world.
threshold:
pts
|
pts
--
|
|
Extra for A - Your map/terrain/world exists
threshold:
pts
|
pts
--
|
|
Button to visualize normals with color
threshold:
pts
|
pts
--
|