1 00:00:00,941 --> 00:00:05,590 - We are now going to look at the actual fragment shader. 2 00:00:05,590 --> 00:00:07,506 This fragment shader corresponds 3 00:00:07,506 --> 00:00:10,461 to the mytest3 program. 4 00:00:10,461 --> 00:00:14,900 Your homework 2 will require a slight generalization 5 00:00:14,900 --> 00:00:18,317 in order to extend it to multiple lights. 6 00:00:20,175 --> 00:00:24,229 Let's look at the fragment shader setup again. 7 00:00:24,229 --> 00:00:27,838 Notice that the version is GLSL 330, 8 00:00:27,838 --> 00:00:30,505 that's what version 330 core says. 9 00:00:31,372 --> 00:00:35,362 Notice that the inputs coming into the fragment shader 10 00:00:35,362 --> 00:00:39,932 are the myvertex, which was from the vertex shader, 11 00:00:39,932 --> 00:00:42,873 mynormal, and texture coordinate. 12 00:00:42,873 --> 00:00:46,882 These values will be interpolated from the vertex shader 13 00:00:46,882 --> 00:00:50,893 and provided to each pixel or fragment. 14 00:00:50,893 --> 00:00:53,795 We will output the fragment color, 15 00:00:53,795 --> 00:00:56,912 which is the key value you get out from the fragment shader, 16 00:00:56,912 --> 00:01:00,064 what should be the color of the corresponding pixel. 17 00:01:00,064 --> 00:01:03,605 And we have some uniform variables. 18 00:01:03,605 --> 00:01:06,795 The texture, tex, corresponds to the texture, 19 00:01:06,795 --> 00:01:09,471 istex says are we texturing or not, 20 00:01:09,471 --> 00:01:13,638 islight, are we lighting or not, and uniform vec3, color. 21 00:01:19,276 --> 00:01:23,435 We then have the fragment shader variables. 22 00:01:23,435 --> 00:01:27,194 Notice that in the mytest sequence of programs 23 00:01:27,194 --> 00:01:30,700 we always assume two lights. Light 0 is directional, 24 00:01:30,700 --> 00:01:33,379 light 1 is a point light. 25 00:01:33,379 --> 00:01:35,559 The actual light values are passed 26 00:01:35,559 --> 00:01:38,578 in from the main OpenGL program. 27 00:01:38,578 --> 00:01:41,227 So, we simply have light 0 direction, 28 00:01:41,227 --> 00:01:45,038 light 0 color. The color is in RGBA, 29 00:01:45,038 --> 00:01:48,710 which is why it's a vec4, whereas the direction is a vec3. 30 00:01:48,710 --> 00:01:52,457 Light 1 position in homogenous coordinates is a vec4, 31 00:01:52,457 --> 00:01:56,124 and light1color, which is in RGBA is a vec4. 32 00:01:57,871 --> 00:02:01,846 In your homework 2, you will have to generalize this 33 00:02:01,846 --> 00:02:04,929 and handle general numbers of lights. 34 00:02:07,386 --> 00:02:10,698 We also define the material parameters. 35 00:02:10,698 --> 00:02:13,568 In this case they are uniform for the object, 36 00:02:13,568 --> 00:02:15,758 which is simply the ambient, diffuse, 37 00:02:15,758 --> 00:02:17,547 specular, and the shininess. 38 00:02:17,547 --> 00:02:21,200 Note that ambient diffuse, and specular are RGBA colors, 39 00:02:21,200 --> 00:02:24,033 while shininess is a single value. 40 00:02:26,944 --> 00:02:30,520 Here is the code to compute the lighting 41 00:02:30,520 --> 00:02:32,437 in the fragment shader. 42 00:02:33,731 --> 00:02:36,354 Notice the ComputeLight command. 43 00:02:36,354 --> 00:02:40,754 It takes in the direction for the light source, 44 00:02:40,754 --> 00:02:44,504 the light color, the normal, the half vector, 45 00:02:47,551 --> 00:02:51,154 and the shading parameters for the materials, 46 00:02:51,154 --> 00:02:52,773 which is the diffuse component, 47 00:02:52,773 --> 00:02:56,296 the specular component and the shininess. 48 00:02:56,296 --> 00:02:59,296 Thereafter, it computes the shading. 49 00:03:01,198 --> 00:03:05,599 So in the first part of it is the Lambertian shading, 50 00:03:05,599 --> 00:03:09,516 which is simply nDotL, which is the dot product 51 00:03:10,460 --> 00:03:14,627 between the surface normal and the direction corresponding 52 00:03:15,488 --> 00:03:18,571 to the direction to the light source. 53 00:03:19,531 --> 00:03:22,980 This is is simply N.L and we can see 54 00:03:22,980 --> 00:03:27,063 that if we have a surface and this is the normal, 55 00:03:28,011 --> 00:03:29,871 this is the lighting direction, 56 00:03:29,871 --> 00:03:34,038 then it simply corresponds to the cosine of this angle. 57 00:03:35,010 --> 00:03:37,174 The Lambertian shading is then given 58 00:03:37,174 --> 00:03:41,103 by the diffuse component times the light color, 59 00:03:41,103 --> 00:03:43,353 times max(N.L, 0). 60 00:03:44,671 --> 00:03:47,671 The max command just ensures 61 00:03:50,749 --> 00:03:54,916 that if you are below the surface the value will be 0. 62 00:03:57,059 --> 00:04:00,769 We now talk about the specular component 63 00:04:00,769 --> 00:04:03,186 and here I'm computing N.H. 64 00:04:05,639 --> 00:04:10,467 Again, if I have a surface and this is the normal, 65 00:04:10,467 --> 00:04:12,991 this is the lighting direction, 66 00:04:12,991 --> 00:04:16,250 this is the viewing direction, 67 00:04:16,250 --> 00:04:20,221 which is the viewer or the eye direction, 68 00:04:20,221 --> 00:04:23,841 then I will define the half vector in such a way 69 00:04:23,841 --> 00:04:28,123 that the lighting direction and the viewing direction 70 00:04:28,123 --> 00:04:31,913 have equal angle, and I will be interested 71 00:04:31,913 --> 00:04:34,064 in the angle between the normal 72 00:04:34,064 --> 00:04:36,273 and the half vector direction. 73 00:04:36,273 --> 00:04:39,991 So this is nDotH and then we multiply 74 00:04:39,991 --> 00:04:44,158 by the specular color of the surface, the light color, 75 00:04:45,092 --> 00:04:48,011 and we take max(N.H,0) 76 00:04:48,011 --> 00:04:51,612 and we raise it to the power of the shininess. 77 00:04:51,612 --> 00:04:54,492 So this goes to the power of s, 78 00:04:54,492 --> 00:04:58,238 where s is the value of myshininess. 79 00:04:58,238 --> 00:05:01,480 Finally, the return value from the shader is the sum 80 00:05:01,480 --> 00:05:06,027 of the Lambertian and Phong components and that is written. 81 00:05:06,027 --> 00:05:08,777 Let's look at the transformations 82 00:05:09,838 --> 00:05:12,379 applied in the fragment shader. 83 00:05:12,379 --> 00:05:14,837 The first step is to check whether 84 00:05:14,837 --> 00:05:17,670 texturing is greater than zero. 85 00:05:17,670 --> 00:05:20,270 If texturing is greater than zero, 86 00:05:20,270 --> 00:05:23,469 then the fragment color is simply given by the texture map. 87 00:05:23,469 --> 00:05:25,779 We don't do the lighting calculations. 88 00:05:25,779 --> 00:05:27,508 It would, of course, be possible 89 00:05:27,508 --> 00:05:31,831 to also multiply by the lighting calculations 90 00:05:31,831 --> 00:05:34,020 and modulate it with the texture. 91 00:05:34,020 --> 00:05:37,120 In this case we call the texture function, 92 00:05:37,120 --> 00:05:41,370 with tex being the texture map, and texture coordinate 93 00:05:41,370 --> 00:05:45,160 being the appropriate coordinates for the texture map. 94 00:05:45,160 --> 00:05:48,348 Otherwise, if islight is equal to zero, 95 00:05:48,348 --> 00:05:51,560 then there is no lighting and the fragment color 96 00:05:51,560 --> 00:05:54,111 is simply the value of the color variable, 97 00:05:54,111 --> 00:05:57,028 which was input promoted to an RGBA. 98 00:05:57,980 --> 00:06:00,029 Otherwise, we have to actually 99 00:06:00,029 --> 00:06:02,627 perform the lighting calculation. 100 00:06:02,627 --> 00:06:05,855 Note the OpenGL convention where the eye is always at 101 00:06:05,855 --> 00:06:10,022 the origin (0,0,0), looking down the -Z axis. 102 00:06:11,146 --> 00:06:14,146 Therefore we define the eye position 103 00:06:15,299 --> 00:06:18,466 as the origin (0,0,0) vector. 104 00:06:20,749 --> 00:06:23,999 Now we take my position to the position 105 00:06:25,353 --> 00:06:28,603 of the vertex involved, which is simply 106 00:06:29,912 --> 00:06:32,412 the myvertex xyz divided by w. 107 00:06:33,781 --> 00:06:36,112 This is simply a dehomogenization 108 00:06:36,112 --> 00:06:39,779 of the current vertex to define my position. 109 00:06:41,200 --> 00:06:43,650 We now need to know what is the direction 110 00:06:43,650 --> 00:06:46,700 to the viewer, or the direction to the eye. 111 00:06:46,700 --> 00:06:49,449 This will be given simply by eye position, 112 00:06:49,449 --> 00:06:54,160 where the eye is, minus mypos, where the vertex is. 113 00:06:54,160 --> 00:06:58,327 And we normalize this value in order to get unit vector. 114 00:06:59,758 --> 00:07:03,361 Finally, we need the normal, which is needed for shading, 115 00:07:03,361 --> 00:07:06,275 and that is simply computed by a normalization 116 00:07:06,275 --> 00:07:09,981 of the mynormal, which is passed in from the vertex shader. 117 00:07:09,981 --> 00:07:12,601 So this will be the normalized normal 118 00:07:12,601 --> 00:07:16,332 and the normalized viewing or eye direction. 119 00:07:16,332 --> 00:07:19,681 We now handle light 0 and light 1. 120 00:07:19,681 --> 00:07:23,054 Note that light 0 is a directional light source, 121 00:07:23,054 --> 00:07:24,670 so the direction to the light 122 00:07:24,670 --> 00:07:27,410 is simply given by light 0 direction, 123 00:07:27,410 --> 00:07:30,930 which again we normalize to get a unit vector. 124 00:07:30,930 --> 00:07:34,031 We are now computing the half vector, 125 00:07:34,031 --> 00:07:37,000 which is simply given by the bisector 126 00:07:37,000 --> 00:07:39,729 of the lighting and eye directions, 127 00:07:39,729 --> 00:07:43,470 which can be obtained simply by taking the vector sum 128 00:07:43,470 --> 00:07:46,989 of these directions and normalizing the result. 129 00:07:46,989 --> 00:07:49,992 To get the color corresponding to light 0 130 00:07:49,992 --> 00:07:52,581 or the shading corresponding to light 0, 131 00:07:52,581 --> 00:07:55,995 we now call ComputeLight given 132 00:07:55,995 --> 00:07:59,465 this direction 0 for the light source, 133 00:07:59,465 --> 00:08:01,845 given the light color, the normal, 134 00:08:01,845 --> 00:08:04,837 the half vector that we just computed and the diffuse, 135 00:08:04,837 --> 00:08:08,227 specular, and shininess material properties. 136 00:08:08,227 --> 00:08:11,760 For light 1, we have to first find the position 137 00:08:11,760 --> 00:08:14,247 by dehomogenizing, so this takes light 1 138 00:08:14,247 --> 00:08:17,591 position xyz and and divides by w. 139 00:08:17,591 --> 00:08:19,570 The direction to the light source 140 00:08:19,570 --> 00:08:24,059 is then the position of the light minus the vertex location. 141 00:08:24,059 --> 00:08:26,240 Remember that when we were computing the viewing 142 00:08:26,240 --> 00:08:28,491 direction, it was the eye position, 143 00:08:28,491 --> 00:08:31,691 which was just the origin - mypos, 144 00:08:31,691 --> 00:08:35,449 in this case it's the light position - mypos, 145 00:08:35,449 --> 00:08:38,587 and again normalized to get a unit vector. 146 00:08:38,587 --> 00:08:41,446 Notice that we are not computing attenuation 147 00:08:41,446 --> 00:08:43,307 in this example but you can of course 148 00:08:43,307 --> 00:08:45,562 do so in homework 2. 149 00:08:45,562 --> 00:08:49,117 To compute the half vector we again normalize the direction 150 00:08:49,117 --> 00:08:52,498 to the light plus the direction to the eye, 151 00:08:52,498 --> 00:08:56,047 and then we determine a color by calling 152 00:08:56,047 --> 00:08:59,045 the ComputeLight for function with the direction 1, 153 00:08:59,045 --> 00:09:02,076 the light color, the normal, the half vector, 154 00:09:02,076 --> 00:09:04,495 and diffuse, specular, and shininess. 155 00:09:04,495 --> 00:09:08,378 Finally, the fragment color is simply a sum 156 00:09:08,378 --> 00:09:11,795 of the ambient, the color from light 0 157 00:09:12,952 --> 00:09:14,875 and the color from light 1. 158 00:09:14,875 --> 00:09:18,126 We will now talk about the source code 159 00:09:18,126 --> 00:09:20,143 in the display routine. 160 00:09:20,143 --> 00:09:25,121 Let us see what the light set up in display looks like. 161 00:09:25,121 --> 00:09:28,616 It involves a whole bunch of parameters, 162 00:09:28,616 --> 00:09:30,537 which just correspond to the shading 163 00:09:30,537 --> 00:09:33,487 or the lighting parameters that we will use. 164 00:09:33,487 --> 00:09:35,959 So one is just white. 165 00:09:35,959 --> 00:09:40,936 Its RGB is (1,1,1), with 1 for the alpha channel, 166 00:09:40,936 --> 00:09:43,787 and we'll define these medium and small values. 167 00:09:43,787 --> 00:09:47,120 We defined high for the shininess, and zero. 168 00:09:47,966 --> 00:09:52,133 Light specular is now red, reddish, with some green tinge. 169 00:09:55,804 --> 00:09:59,971 Light specular 1 you have green and bluish tinge. 170 00:10:00,807 --> 00:10:04,757 For the light direction, for the direction of light, 171 00:10:04,757 --> 00:10:08,487 it's in the x is equal to 0.5 direction. 172 00:10:08,487 --> 00:10:10,565 For the positional light we define 173 00:10:10,565 --> 00:10:13,726 the positional light coordinates. 174 00:10:13,726 --> 00:10:17,226 And now we transform the light direction 175 00:10:17,226 --> 00:10:20,857 and the light position to get light 0 and light 1. 176 00:10:20,857 --> 00:10:24,889 This is a transformation by the current model view matrix, 177 00:10:24,889 --> 00:10:27,678 so that you have the light's position 178 00:10:27,678 --> 00:10:30,595 and direction properly transformed 179 00:10:30,595 --> 00:10:33,088 before you pass it to the shader. 180 00:10:33,088 --> 00:10:35,089 Why do we need to do this? 181 00:10:35,089 --> 00:10:37,699 So let's take a brief aside to talk 182 00:10:37,699 --> 00:10:40,515 about moving a light source. 183 00:10:40,515 --> 00:10:43,939 The lights transform like other geometry. 184 00:10:43,939 --> 00:10:46,119 Now since lighting is done in 3D 185 00:10:46,119 --> 00:10:48,527 and not projected onto the image, 186 00:10:48,527 --> 00:10:52,568 only the modelview matrix acts, not the projection matrix. 187 00:10:52,568 --> 00:10:54,768 And in fact lighting is the only place 188 00:10:54,768 --> 00:10:56,428 where you care about multiplying 189 00:10:56,428 --> 00:10:58,954 by the modelview matrix separately 190 00:10:58,954 --> 00:11:03,551 instead of a combination of projection times modelview. 191 00:11:03,551 --> 00:11:06,941 There are many different types of light motion you can have. 192 00:11:06,941 --> 00:11:10,351 So if the light is stationary, you just set the transforms 193 00:11:10,351 --> 00:11:13,202 to the identity before specifying the light. 194 00:11:13,202 --> 00:11:15,602 If you want to move only the light source you would 195 00:11:15,602 --> 00:11:18,771 push the matrix, move the light, pop the matrix. 196 00:11:18,771 --> 00:11:21,401 Sometimes you want something like a miner's hat 197 00:11:21,401 --> 00:11:23,680 or a light source attached to the camera 198 00:11:23,680 --> 00:11:26,550 where the light source is moved with the viewpoint, 199 00:11:26,550 --> 00:11:29,830 and so you can simply set the light to the origin 200 00:11:29,830 --> 00:11:31,972 and not have the modelview matrix act, 201 00:11:31,972 --> 00:11:35,272 or set it to the identity. In this case, the light 202 00:11:35,272 --> 00:11:38,615 is simply at the origin with respect to eye coordinates. 203 00:11:38,615 --> 00:11:41,476 However, in the previous slide what we were simply doing 204 00:11:41,476 --> 00:11:44,626 was moving the light into the correct location 205 00:11:44,626 --> 00:11:48,380 in eye coordinates by transforming by the modelview matrix. 206 00:11:48,380 --> 00:11:50,872 In fact this is the helper function 207 00:11:50,872 --> 00:11:53,777 transformvec I'm using for that purpose. 208 00:11:53,777 --> 00:11:56,676 It just takes as input four variables 209 00:11:56,676 --> 00:11:59,924 xyzw and output four variables. 210 00:11:59,924 --> 00:12:04,850 So it first defines a glm vector from the input variables 211 00:12:04,850 --> 00:12:08,780 and then defines a glm output vector as modelview times 212 00:12:08,780 --> 00:12:11,069 the input vector and then just sets 213 00:12:11,069 --> 00:12:14,038 the output values to output vector. 214 00:12:14,038 --> 00:12:16,548 So essentially, it's just multiplying by the modelview 215 00:12:16,548 --> 00:12:20,078 matrix to transform the lights appropriately. 216 00:12:20,078 --> 00:12:21,967 This is what we need to do to set 217 00:12:21,967 --> 00:12:25,364 up the lighting for the teapot. 218 00:12:25,364 --> 00:12:28,707 First, I set up a uniform vector, 219 00:12:28,707 --> 00:12:30,997 which is three floating point numbers, 220 00:12:30,997 --> 00:12:35,473 light 0 direction and I set it to the value light0. 221 00:12:35,473 --> 00:12:39,640 The 1 here just means that I'm specifying only one vector. 222 00:12:41,209 --> 00:12:44,228 So thereafter, I set up the light color, 223 00:12:44,228 --> 00:12:46,759 which is now a 4-vector because of RGBA 224 00:12:46,759 --> 00:12:48,849 and I set it to light_specular. 225 00:12:48,849 --> 00:12:51,920 Light1 position is set to light1. 226 00:12:51,920 --> 00:12:54,508 Light1 color is set to light_specular1. 227 00:12:54,508 --> 00:12:58,488 light_specular1 is now our four-vector 228 00:12:58,488 --> 00:13:01,968 that was specified earlier as just a constant. 229 00:13:01,968 --> 00:13:04,348 Then I set the material parameters, 230 00:13:04,348 --> 00:13:07,050 ambient, diffuse, specular, and shininess, 231 00:13:07,050 --> 00:13:09,469 again to variables that were defined 232 00:13:09,469 --> 00:13:13,878 as constants in my OpenGL program, small, medium, one, high. 233 00:13:13,878 --> 00:13:16,838 So essentially the ambient is a small value. 234 00:13:16,838 --> 00:13:18,708 Diffuse is a medium value. 235 00:13:18,708 --> 00:13:21,227 For specular it's just set to one. 236 00:13:21,227 --> 00:13:25,394 And the shininess is set to this high value of 100. 237 00:13:27,340 --> 00:13:30,959 We'll wish to enable and disable lighting along the teapot, 238 00:13:30,959 --> 00:13:35,220 so for the teapot you set the uniform variable islight 239 00:13:35,220 --> 00:13:39,640 to one, so that lighting will be done for the teapot. 240 00:13:39,640 --> 00:13:41,955 Normally in order to do lighting you'd also need 241 00:13:41,955 --> 00:13:44,483 to define normals for the teapot and so on, 242 00:13:44,483 --> 00:13:46,544 but the teapot object file, 243 00:13:46,544 --> 00:13:48,904 we've already done that within it. 244 00:13:48,904 --> 00:13:52,697 In the shader itself we need to do some mappings 245 00:13:52,697 --> 00:13:55,855 in order to keep the bookkeeping straight. 246 00:13:55,855 --> 00:13:58,897 So first you define the vertex shader by calling 247 00:13:58,897 --> 00:14:02,655 initshaders with the file name for the vertex shader. 248 00:14:02,655 --> 00:14:04,556 Similarly for the fragment shader, 249 00:14:04,556 --> 00:14:07,215 you define a program and now you set 250 00:14:07,215 --> 00:14:10,765 the shader parameter mappings, where islight 251 00:14:10,765 --> 00:14:13,894 tells you the location in the shader of islight. 252 00:14:13,894 --> 00:14:16,294 In this case I've just defined the variables, 253 00:14:16,294 --> 00:14:18,285 same as the source strings in the shader 254 00:14:18,285 --> 00:14:20,264 of the variable names in the shaders, 255 00:14:20,264 --> 00:14:22,283 so it's easiest to keep track of, 256 00:14:22,283 --> 00:14:23,711 but they could be different. 257 00:14:23,711 --> 00:14:27,074 But essentially this sequence of commands is required 258 00:14:27,074 --> 00:14:31,303 so that the variable specular in the OpenGL program 259 00:14:31,303 --> 00:14:33,412 stores the appropriate location 260 00:14:33,412 --> 00:14:35,832 for the specular variable in the shader, 261 00:14:35,832 --> 00:14:39,523 and then it can be assigned with the suitable value.