2017 March 6,
This is a benchmark for the course. You will hand in 160mainDiffuse.c, 170mainSpecular, 180mainAmbient.c, 190mainFog.c, and all of the files on which they depend. Make sure your files are functional, clean, and commented. Make sure that all contributors are credited. Make sure that all contributors have copies of the files. One student then uploads the files to COURSES.
510vector.c: In a copy of 100vector.c, replace all doubles with GLdoubles.
510mesh.c: This is a clean copy of 100mesh.c, with a few changes. All doubles have been replaced with GLdoubles. All ints have been replaced with GLuints, except in the return values for meshInitialize... functions. In meshSetTriangle and the three functions after it, the <= tests have been removed, because they are now vacuous and raise warnings. Finally, the Rendering section has been replaced with an OpenGL section, with some incomplete functions. Your job is to finish implementing those functions. Specifically, there are two spots, marked with !!, where you need to write code. If you are unsure what should happen, then examine 500openGL20.c and 510mainMesh.c.
510mainMesh.c: Study. Do not alter. Use this file to understand how 510mesh.c should work, and to verify that it works. Here's a screenshot of mine:
camera
scene graph
500time.c: Study. If you're working on Windows, and you want your animations to be good, then figure out the analogous code there (and please tell us).
520matrix.c: In a copy of 130matrix.c, paste the mat44OpenGL function from 500openGL20b.c. Insert a comment before it, to document/specify what it does. Then, throughout the file, replace all doubles with GLdoubles. While we're here, add the following functions to build identity matrices, if you don't already have them.
void mat33Identity(GLdouble m[3][3]) void mat44Identity(GLdouble m[4][4])
520camera.c: This file implements a camera data type, with both low- and high-level interfaces. Your job is to implement camRender, consulting 500openGL20b.c and 520mainCamera.c as needed.
520mainCamera.c: Study. Do not alter. Use this file to understand how 520camera.c should work, and to verify that it works.
530scene.c: This file implements a scene graph data type (with no texturing yet). Your job is to implement sceneRender. You may find 500openGL20b.c helpful. You will also need the following functions for setting uniform variables. Pass 1 for the count parameter.
glUniform4fv(GLint location, GLsizei count, GLfloat values[4]); glUniform3fv(GLint location, GLsizei count, GLfloat values[3]); glUniform2fv(GLint location, GLsizei count, GLfloat values[2]); glUniform1fv(GLint location, GLsizei count, GLfloat values[1]);
530mainScene.c: Study. Do not alter. Use this file to understand how 530scene.c should work, and to verify that it works. Here's a screenshot of mine:
perspective vs. linear texture mapping
lighting
530vector.c: Move the vecOpenGL function from 530scene.c to 530vector.c. (We're correcting an oversight of mine in the last homework assignment.)
530mainScene.c: Include 530vector.c and check that everything is still working correctly.
540texture.c: Study.
540scene.c: Add a texTexture **tex member to the scene node. Alter sceneInitialize so that it begins like the code below. Add new accessor functions sceneSetTexture and sceneSetOneTexture, mimicking sceneSetUniform and sceneSetOneUniform. Add a new parameter, GLint textureLocs[], to the end of sceneRender's parameters. Update that function to correctly activate and deactivate textures, using the first node->texNum texture units. You may assume, if you like, that node->texNum ≤ 8.
int sceneInitialize(sceneNode *node, GLuint unifDim, GLuint texNum, meshGLMesh *mesh, sceneNode *firstChild, sceneNode *nextSibling) { node->unif = (GLdouble *)malloc(unifDim * sizeof(GLdouble) + texNum * sizeof(texTexture *)); if (node->unif == NULL) return 1; node->tex = (texTexture **)&(node->unif[unifDim]); mat33Identity(node->rotation); ...
540mainTexturing.c: Make a demonstration program. Use at least two scene graph nodes and at least three textures. You are not allowed to use every texture at every node (because we're trying to verify that your sceneRender correctly activates and deactivates textures).
550light.c: Study.
550mainLighting.c: Make a demonstration program, that works with the following shader code. (Whenever I give you GLSL, study it. It's easiest to learn GLSL from examples like this.) In my program, specular comes from the scene node uniforms, so that different nodes can have differing specular reflectivity. All other uniforms are set in my render function, in various ways.
GLchar vertexCode[] = "\ uniform mat4 viewing;\ uniform mat4 modeling;\ attribute vec3 position;\ attribute vec2 texCoords;\ attribute vec3 normal;\ varying vec3 fragPos;\ varying vec3 normalDir;\ varying vec2 st;\ void main() {\ vec4 worldPos = modeling * vec4(position, 1.0);\ gl_Position = viewing * worldPos;\ fragPos = vec3(worldPos);\ normalDir = vec3(modeling * vec4(normal, 0.0));\ st = texCoords;\ }"; GLchar fragmentCode[] = "\ uniform sampler2D texture0;\ uniform vec3 specular;\ uniform vec3 camPos;\ uniform vec3 lightPos;\ uniform vec3 lightCol;\ uniform vec3 lightAtt;\ varying vec3 fragPos;\ varying vec3 normalDir;\ varying vec2 st;\ void main() {\ vec3 surfCol = vec3(texture2D(texture0, st));\ vec3 norDir = normalize(normalDir);\ vec3 litDir = normalize(lightPos - fragPos);\ vec3 camDir = normalize(camPos - fragPos);\ vec3 refDir = 2.0 * dot(litDir, norDir) * norDir - litDir;\ float d = distance(lightPos, fragPos);\ float a = lightAtt[0] + lightAtt[1] * d + lightAtt[2] * d * d;\ float diffInt = dot(norDir, litDir) / a;\ float specInt = dot(refDir, camDir);\ if (diffInt <= 0.0 || specInt <= 0.0)\ specInt = 0.0;\ float ambInt = 0.1;\ if (diffInt <= ambInt)\ diffInt = ambInt;\ vec3 diffLight = diffInt * lightCol * surfCol;\ float shininess = 64.0;\ vec3 specLight = pow(specInt / a, shininess) * lightCol * specular;\ gl_FragColor = vec4(diffLight + specLight, 1.0);\ }";
interlude: debugging, clarifying
lighting
560light.c: Study.
560mainSpot.c: First get the omnidirectional light from 550mainLighting.c working with the new light code in 560light.c. Then change the light to a spot light. Most of that work is in GLSL. Here is a screenshot of mine:
This is a benchmark for the course. You will hand in 550mainLighting.c, 560mainSpot.c, and all of the files on which they depend. Make sure your files are functional, clean, and commented. Make sure that all contributors are credited. Make sure that all contributors have copies of the files. One student then uploads the files to COURSES.
miscellany
570mainDirectional.c: This exercise is optional and not difficult. Demonstrate a directional light. (Whether or not you do this exercise, you are expected to know how directional lights work.)
580mesh.c: We have to make four major changes to the OpenGL section. First, the meshGL data type now stores the number of attributes, the dimensions of those attributes, and an array of VAOs. The initializer is as follows. Update the meshGLMesh struct accordingly.
/* Initializes an OpenGL mesh from a non-OpenGL mesh. vaoNum is the number of vertex array objects attached to this mesh storage. Typically vaoNum equals the number of distinct shader programs that will need to draw the mesh. Returns 0 on success, non-zero on failure. */ int meshGLInitialize(meshGLMesh *meshGL, meshMesh *mesh, GLuint attrNum, GLuint attrDims[], GLuint vaoNum) { meshGL->attrDims = (GLuint *)malloc((attrNum + vaoNum) * sizeof(GLuint)); if (meshGL->attrDims == NULL) return 1; for (int i = 0; i < attrNum; i += 1) meshGL->attrDims[i] = attrDims[i]; meshGL->vaos = &meshGL->attrDims[attrNum]; glGenVertexArrays(vaoNum, meshGL->vaos); meshGL->vaoNum = vaoNum; meshGL->attrNum = attrNum; meshGL->triNum = mesh->triNum; meshGL->vertNum = mesh->vertNum; meshGL->attrDim = mesh->attrDim; glGenBuffers(2, meshGL->buffers); glBindBuffer(GL_ARRAY_BUFFER, meshGL->buffers[0]); glBufferData(GL_ARRAY_BUFFER, meshGL->vertNum * meshGL->attrDim * sizeof(GLdouble), (GLvoid *)(mesh->vert), GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshGL->buffers[1]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, meshGL->triNum * 3 * sizeof(GLuint), (GLvoid *)(mesh->tri), GL_STATIC_DRAW); return 0; }
Second, the initializer above allocates space to hold the VAOs, and even requests those VAOs from OpenGL, but does not really initialize those VAOs with any useful information. The following function does the initialization of a single VAO. Write it, using 500openGL32.c as a guide.
/* attrLocs is meshGL->attrNum locations in the active shader program. index is an integer between 0 and meshGL->voaNum - 1, inclusive. This function initializes the VAO at that index in the meshGL's array of VAOs, so that the VAO can render using those locations. */ void meshGLVAOInitialize(meshGLMesh *meshGL, GLuint index, GLint attrLocs[])
Third, meshGLRender now takes just two parameters: the mesh, and a VAO array index like the one above.
Fourth, meshGLDestroy has more resources to clean up. It already deallocates the VBOs. It should also deallocate the VAOs. It should also free the one pointer that was malloced in meshGLInitialize. We haven't talked much about malloc and free in this course, but they're not hard. Mimic the malloc/free pair that you see in meshInitialize and meshDestroy.
580scene.c: Change sceneRender to account for the changes to meshGLRender. That is, where it used to take three parameters for passing on to meshGLRender (between unifLocs and textureLocs), it now takes a single VAO array index.
580mainSpot.c: In a copy of 560mainSpot.c, make the changes needed to incorporate OpenGL 3.2, GL3W, 580mesh.c, and 580scene.c. Because you have just one shader program (don't try to be a hero), pass 1 as the value for voaNum, and initialize just one VOA per mesh. Your program should use a scene graph of at least two nodes and two meshes, to demonstrate that everything is working correctly. If your 560mainSpot.c already satisfied that requirement, then the new program should be visually identical to it.
shadow mapping
project work
Read the project details and ideas in the Materials section of the course web page. Do some preliminary exploring online. Come up with your own project ideas if you like. Find a partner, or ask me to find you a partner.
shadow mapping
project work
590matrix.c: To get shadow mapping to work, I eventually resigned myself to OpenGL's left-handed depth convention. So, edit the two functions that construct projection matrices. In each one, negate the third row (that is, row 2).
590shadow.c: Study.
590mainShadowing.c: Study. Find your own image files to supply the five textures to this program. Then run the program. It should draw a scene with a single shadow-mapped spot light. There is no attenuation, diffuse reflection, or specular reflection. Merge this code with your own, to supply those features. Test.
590mainShadowing.c: Add a second shadow-casting spot light. This addition requires changes throughout your code. Here is a screen shot of mine, with a white light and a pink light:
cel shading
project work
Work on your project. By Saturday at 11:59 PM, each project sends me a single e-mail with the following information about what the project is and how it is feasible.
Exam: There is no class today. Instead we have individual oral exams today and tomorrow. No computers, notes, or other aids are allowed. This exam is cumulative, covering all material up to and including shadowing. However, it will focus disproportionately on topics that did not appear on the first exam. Here are some study questions.
This is a benchmark for the course. You will hand in 590mainShadowing.c and all of the files on which it depends. Make sure your files are functional, clean, and commented. Make sure that all contributors are credited. Make sure that all contributors have copies of the files. One student then uploads the files to COURSES.
Then work on your project.
picking and other mouse interaction
project work
Work on your project. Remember that in about a week you will give a progress report to the class.
scientific visualization example (orientational data from structural geology)
design choices for OpenGL bridged from R, Python, etc.
project work
Work on your project. Don't forget to sign up for a report/demo slot, using the sheet posted on my office door.
deferred shading
antialiasing and depth of field, briefly
dissecting a frame of a modern video game, such as here or here (content warning: guns and gore)
project work
Work on your project.
reports and demonstrations
Work on your project.
reports and demonstrations
Work on your project.
Your final project is due at 5:00 PM on this day.
abstracting the program? textured light? mesh file formats? CGI movie examples? 000mallocFree.c? OpenGL 4.x?