LIGHTING IN VERTEX AND FRAGMENT SHADER r囧r小猫 2022-08-20 05:16 19阅读 0赞 * [June 19, 2014][June 19_ 2014] * Category: [Game Development][], [OpenGL][] * Written by: [Sergiu Craitoiu][] * [Leave a reply][] ![Nvidia GPU Gems 3][]Nvidia GPU Gems 3 [![JShareFacebook.jpg][]][JShareFacebook.jpg 1] [![Jshareflipboard.jpg][]][Jshareflipboard.jpg 1] [![JShareGooglePlus.jpg][]][JShareGooglePlus.jpg 1] In this [post][], my friend Adrian Visan explained the importance of lighting in a 3D environment and the importance of all lighting model coefficients required to compute the actual light. Here I will talk about Gouraud , Phong and Blinn-Phong lighting models and a brief about multiple light sources, attenuation and gamma correction which are used to implement light in modern games. Gouraud reflection model can be calculated in vertex shader. This model computes a normal vector and an intensity for each vertex. To display the entire surface, points intensity on the lines are computed using linear interpolation between vertex intensities; Points intensity between the lines are computed using linear interpolation between the lines intensities. [![Gouraud only diffuse and specular][]][Gouraud only diffuse and specular] Gouraud model. Only diffuse and specular coefficients Phong shading model(reflection model) can be calculated in pixel shader. This model computes a normal vector for each vertex. After that computes a normal for each point on the surface using linear interpolation. Normal points on the lines are computing with linear interpolation between vertex normals. Normal points between the lines are computed using linear interpolation between the normal lines. Now we compute an intensity for each point. [![Phong Model][]][Phong Model] Phong model. Only diffuse and specular coefficients The general lighting equation is: [![Model Lighting in2gpu][]][Model Lighting in2gpu] Lighting equation Now let’s see how the reflected direction (R) is calculated: First, we simplify the image above keeping only incident ray (L or I), Normal Vector(N) and of course R. [![Compute reflection vector][]][Compute reflection vector] Denote L = I . It is the same thing(light ray/ reverse incident ray) Now we translate both u vectors and add them. And we can see that R is the result from vector addition between vector I and vector 2u. Keep in mind that here we reversed I, the final formula changes the signs if I is not reversed. [![Reflected Ray Equation][]][Reflected Ray Equation] Reflected Ray In GLSL and HLSL, there is a function called [reflect][](L,N) which computes the reflected direction for us. But be careful, because incident ray(I) is not reversed, so in order to have the same result as in the above images, you must make it negative [\-reflect][reflect](L,N). Before jumping into writing code we should take a look at some aspects of diffuse lighting, material coefficients, shininess and Blinn-Phong model. Lambert’s cosine law says that the amount of reflected light is proportional with the cosine(dot product) of the angle between the normal and incident vector (angle of incidence). To get light on our object, the angle of incidence should vary between 0 and 90 degrees: [![Diffuse light aspects][]][Diffuse light aspects] Lambert’s law.How angle affects the diffuse lighting We also need this angle to check for specular lighting otherwise it computes specular lighting for the back of our object and we don’t need this effect. Speaking of specular we should talk about shininess coefficient(n). If n is larger you will get narrower curves. Usually for metallic surface n is between 100 and 300, for plastic materials should be under 10. This diagram shows how cos function behaves for different n values. [![shininess variation][]][shininess variation] [Shininess variation(original image).][Shininess variation_original image_.] Below is a list with some material coefficients. Of course you can experiment with other values if you want. However, these values are found experimentally in research laboratories. [![material coefficients][]][material coefficients] [Material coefficients(original site)][Material coefficients_original site] Blinn – Phong reflection model or modified Phong model was the default shading model in fixed-function pipeline for OpenGL and DirectX. It produces more accurate results than Phong reflection for many types of surfaces and it’s cheaper to compute for a single light source. For multiple lighting sources it’s more expensive to compute than Phong model. [![Blinn Phong model][]][Blinn Phong model] Blinn-Phong model Blinn – Phong model uses the concept of Halfway vector(H) between Light source(L) and View direction (V) instead of Reflection(R). [![Halfway Vector][]][Halfway Vector] Blinn-Phong halfway vector Lighting in vertex shader, Gouraud reflection model: <table style=""> <tbody style=""> <tr style=""> <td style=""> <div style=""> 1 </div> <div style=""> 2 </div> <div style=""> 3 </div> <div style=""> 4 </div> <div style=""> 5 </div> <div style=""> 6 </div> <div style=""> 7 </div> <div style=""> 8 </div> <div style=""> 9 </div> <div style=""> 10 </div> <div style=""> 11 </div> <div style=""> 12 </div> <div style=""> 13 </div> <div style=""> 14 </div> <div style=""> 15 </div> <div style=""> 16 </div> <div style=""> 17 </div> <div style=""> 18 </div> <div style=""> 19 </div> <div style=""> 20 </div> <div style=""> 21 </div> <div style=""> 22 </div> <div style=""> 23 </div> <div style=""> 24 </div> <div style=""> 25 </div> <div style=""> 26 </div> <div style=""> 27 </div> <div style=""> 28 </div> <div style=""> 29 </div> <div style=""> 30 </div> <div style=""> 31 </div> <div style=""> 32 </div> <div style=""> 33 </div> <div style=""> 34 </div> <div style=""> 35 </div> <div style=""> 36 </div> <div style=""> 37 </div> <div style=""> 38 </div> <div style=""> 39 </div> <div style=""> 40 </div> <div style=""> 41 </div> <div style=""> 42 </div> <div style=""> 43 </div> <div style=""> 44 </div> <div style=""> 45 </div> <div style=""> 46 </div> <div style=""> 47 </div> <div style=""> 48 </div> <div style=""> 49 </div> <div style=""> 50 </div> <div style=""> 51 </div> <div style=""> 52 </div> <div style=""> 53 </div> <div style=""> 54 </div> <div style=""> 55 </div> </td> <td style=""> <div style=""> <div style=""> <code style="">//Gouraud Vertex Shader</code> </div> <div style=""> <code style="">//To keep it simple didn't add ambient and emissive lights;</code> </div> <div style=""> <code style="">//only diffuse and specular with white intensity</code> </div> <div style=""> <code style="">#version 330</code> </div> <div style=""> </div> <div style=""> <code style="">layout(location = 0) in vec3 in_position;</code> </div> <div style=""> <code style="">layout(location = 1) in vec3 in_normal;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform mat4 model_matrix, view_matrix, projection_matrix;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform vec3 light_position;</code> </div> <div style=""> <code style="">uniform vec3 eye_position;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform </code> <code style="">int</code> <code style=""> material_shininess;</code> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> material_kd;</code> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> material_ks;</code> </div> <div style=""> </div> <div style=""> <code style="">out </code> <code style="">float</code> <code style=""> light;</code> </div> <div style=""> </div> <div style=""> <code style="">void</code> <code style="">main(){ </code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">vec3 world_position = mat3(model_matrix) * in_position;</code> <code style="">//careful here</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">vec3 world_normal = normalize(mat3(model_matrix) * in_normal);</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">//don't forget to normalize</code> </div> <div style=""> <code style=""> </code> <code style="">vec3 L = normalize(light_position - world_position);</code> <code style="">//light direction</code> </div> <div style=""> <code style=""> </code> <code style="">vec3 V = normalize(eye_position - world_position); </code> <code style="">//view direction</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">//Lambert term</code> </div> <div style=""> <code style=""> </code> <code style="">float</code> <code style="">LdotN = max(0, dot(L,world_normal));</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">//consider diffuse light color white(1,1,1)</code> </div> <div style=""> <code style=""> </code> <code style="">//all color channels have the same float value</code> </div> <div style=""> <code style=""> </code> <code style="">float</code> <code style="">diffuse = material_kd * LdotN;</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">float</code> <code style="">specular = 0;</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">if</code> <code style="">(LdotN > 0.0)</code> </div> <div style=""> <code style=""> </code> <code style="">{ </code> </div> <div style=""> <code style=""> </code> <code style="">//can use built-in max or saturate function</code> </div> <div style=""> <code style=""> </code> <code style="">vec3 R = -normalize(reflect(L,world_normal);</code> <code style="">//reflection</code> </div> <div style=""> <code style=""> </code> <code style="">specular = material_ks * </code> <code style="">pow</code> <code style="">( max(0, dot( R, V)), material_shininess);</code> </div> <div style=""> <code style=""> </code> <code style="">}</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">//pass light to fragment shader</code> </div> <div style=""> <code style=""> </code> <code style="">light = diffuse + specular;</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">//How about with ambinetal and emissive?</code> </div> <div style=""> <code style=""> </code> <code style="">//Final light(with white(1,1,1)) would be:</code> </div> <div style=""> <code style=""> </code> <code style="">//light = ke + material_ka + diffuse + specular;</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">//final vertex position</code> </div> <div style=""> <code style=""> </code> <code style="">gl_Position = projection_matrix*view_matrix*model_matrix*vec4(in_position,1);</code> </div> <div style=""> <code style="">}</code> </div> </div> </td> </tr> </tbody> </table> <table style=""> <tbody style=""> <tr style=""> <td style=""> <div style=""> 1 </div> <div style=""> 2 </div> <div style=""> 3 </div> <div style=""> 4 </div> <div style=""> 5 </div> <div style=""> 6 </div> <div style=""> 7 </div> <div style=""> 8 </div> <div style=""> 9 </div> <div style=""> 10 </div> </td> <td style=""> <div style=""> <div style=""> <code style="">//Fragment Shader</code> </div> <div style=""> <code style="">#version 330</code> </div> <div style=""> <code style="">layout(location = 0) out vec4 out_color;</p></code> </div> <div style=""> <code style="">//from vertex shader</code> </div> <div style=""> <code style="">in </code> <code style="">float</code> <code style=""> light;</code> </div> <div style=""> </div> <div style=""> <code style="">void</code> <code style="">main()</code> </div> <div style=""> <code style="">{ </code> </div> <div style=""> <code style=""> </code> <code style="">out_color = vec4(light,light, light,1);</code> </div> <div style=""> <code style="">}</code> </div> </div> </td> </tr> </tbody> </table> Of course, Gouraud model is cheaper to compute than Phong model but inferior in quality especially for specular light. Although if the LOD(level of detail) is high, Gouraud model can give good results and it’s ok to use. Also you can use Gouraud model if you develop mobile games where you don’t have the hardware resources(…for the moment). Gouraud is way better than Flat Shading . ![Gouraud vs Flat Shading][] [Gouraud model vs Flat Shading][] Lighting in pixel shader, Phong reflection model: <table style=""> <tbody style=""> <tr style=""> <td style=""> <div style=""> 1 </div> <div style=""> 2 </div> <div style=""> 3 </div> <div style=""> 4 </div> <div style=""> 5 </div> <div style=""> 6 </div> <div style=""> 7 </div> <div style=""> 8 </div> <div style=""> 9 </div> <div style=""> 10 </div> <div style=""> 11 </div> <div style=""> 12 </div> <div style=""> 13 </div> <div style=""> 14 </div> <div style=""> 15 </div> <div style=""> 16 </div> <div style=""> 17 </div> <div style=""> 18 </div> <div style=""> 19 </div> </td> <td style=""> <div style=""> <div style=""> <code style="">//Phong Reflection Model Vertex Shader</code> </div> <div style=""> <code style="">#version 330</code> </div> <div style=""> </div> <div style=""> <code style="">layout(location = 0) in vec3 in_position;</code> </div> <div style=""> <code style="">layout(location = 1) in vec3 in_normal;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform mat4 model_matrix, view_matrix, projection_matrix;</code> </div> <div style=""> </div> <div style=""> <code style="">//send them to fragment shader</code> </div> <div style=""> <code style="">out vec3 world_pos;</code> </div> <div style=""> <code style="">out vec3 world_normal;</code> </div> <div style=""> </div> <div style=""> <code style="">void</code> <code style="">main()</code> </div> <div style=""> <code style="">{ </code> </div> <div style=""> <code style=""> </code> <code style="">//convert in world coords</code> </div> <div style=""> <code style=""> </code> <code style="">world_pos = mat3(model_matrix) * in_position;</code> <code style="">//careful here</code> </div> <div style=""> <code style=""> </code> <code style="">world_normal = normalize(mat3(model_matrix) * in_normal);</code> </div> <div style=""> <code style=""> </code> <code style="">gl_Position = projection_matrix*view_matrix*model_matrix*vec4(in_position,1);</code> </div> <div style=""> <code style="">}</code> </div> </div> </td> </tr> </tbody> </table> <table style=""> <tbody style=""> <tr style=""> <td style=""> <div style=""> 1 </div> <div style=""> 2 </div> <div style=""> 3 </div> <div style=""> 4 </div> <div style=""> 5 </div> <div style=""> 6 </div> <div style=""> 7 </div> <div style=""> 8 </div> <div style=""> 9 </div> <div style=""> 10 </div> <div style=""> 11 </div> <div style=""> 12 </div> <div style=""> 13 </div> <div style=""> 14 </div> <div style=""> 15 </div> <div style=""> 16 </div> <div style=""> 17 </div> <div style=""> 18 </div> <div style=""> 19 </div> <div style=""> 20 </div> <div style=""> 21 </div> <div style=""> 22 </div> <div style=""> 23 </div> <div style=""> 24 </div> <div style=""> 25 </div> <div style=""> 26 </div> <div style=""> 27 </div> <div style=""> 28 </div> <div style=""> 29 </div> <div style=""> 30 </div> <div style=""> 31 </div> <div style=""> 32 </div> <div style=""> 33 </div> <div style=""> 34 </div> <div style=""> 35 </div> <div style=""> 36 </div> <div style=""> 37 </div> <div style=""> 38 </div> <div style=""> 39 </div> <div style=""> 40 </div> <div style=""> 41 </div> <div style=""> 42 </div> <div style=""> 43 </div> <div style=""> 44 </div> <div style=""> 45 </div> <div style=""> 46 </div> </td> <td style=""> <div style=""> <div style=""> <code style="">//Phong reflection model; Fragment Shader</code> </div> <div style=""> <code style="">//To keep it simple didn't add ambient and emissive lights;</code> </div> <div style=""> <code style="">//only diffuse and specular with white intensity</code> </div> <div style=""> <code style="">#version 330</code> </div> <div style=""> <code style="">layout(location = 0) out vec4 out_color;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform vec3 light_position;</code> </div> <div style=""> <code style="">uniform vec3 eye_position;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform </code> <code style="">int</code> <code style=""> material_shininess;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> material_kd;</code> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> material_ks;</code> </div> <div style=""> </div> <div style=""> <code style="">in vec3 world_pos;</code> </div> <div style=""> <code style="">in vec3 world_normal;</code> </div> <div style=""> </div> <div style=""> <code style="">void</code> <code style="">main(){ </code> </div> <div style=""> </div> <div style=""> </div> <div style=""> <code style="">vec3 L = normalize( light_position - world_pos);</code> <code style="">//light direction</code> </div> <div style=""> <code style="">vec3 V = normalize( eye_position - world_pos);</code> <code style="">//view direction</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">LdotN = max(0, dot(L,world_normal));</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">diffuse = material_kd * LdotN;</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">specular = 0;</code> </div> <div style=""> </div> <div style=""> <code style="">if</code> <code style="">(LdotN > 0.0)</code> </div> <div style=""> <code style="">{ </code> </div> <div style=""> </div> <div style=""> <code style="">//choose H or R to see the difference</code> </div> <div style=""> <code style="">vec3 R = -normalize(reflect(L, world_normal));</code> <code style="">//Reflection</code> </div> <div style=""> <code style="">specular = material_ks * </code> <code style="">pow</code> <code style="">(max(0, dot(R, V)), material_shininess);</code> </div> <div style=""> </div> <div style=""> <code style="">//Blinn-Phong</code> </div> <div style=""> <code style="">// vec3 H = normalize(L + V );//Halfway</code> </div> <div style=""> <code style="">//specular = material_ks * pow(max(0, dot(H, world_normal)), material_shininess);</code> </div> <div style=""> </div> <div style=""> <code style="">}</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">light = diffuse + specular;</code> </div> <div style=""> </div> <div style=""> <code style="">out_color = vec4(light,light, light,1);</code> </div> <div style=""> <code style="">}</code> </div> </div> </td> </tr> </tbody> </table> Other things you should consider when you implement lighting is multiple light sources, attenuation and gamma correction. * If you have more than one light source the equation for reflection model will be: [![Lighting equation for more tahn one source][]][Lighting equation for more tahn one source] Lighting equation with multiple light sources * Light attenuation. You probably want to add this to your lighting model because it simulates the fading of light with the distance. In the real world the light intensity is proportional with the inverse of the distance squared but we can’t use it just like this because this it is not “natural” in a virtual environment due to fast chaning rate. There are several ways to compute attenuation but the most commonly used one is the constant, linear and quadratic method: [![Attenuation Equation][]][Attenuation Equation] Attenuation Equation <table style=""> <tbody style=""> <tr style=""> <td style=""> <div style=""> 1 </div> <div style=""> 2 </div> <div style=""> 3 </div> <div style=""> 4 </div> <div style=""> 5 </div> <div style=""> 6 </div> <div style=""> 7 </div> <div style=""> 8 </div> <div style=""> 9 </div> <div style=""> 10 </div> <div style=""> 11 </div> <div style=""> 12 </div> <div style=""> 13 </div> <div style=""> 14 </div> <div style=""> 15 </div> <div style=""> 16 </div> <div style=""> 17 </div> <div style=""> 18 </div> <div style=""> 19 </div> <div style=""> 20 </div> <div style=""> 21 </div> <div style=""> 22 </div> <div style=""> 23 </div> <div style=""> 24 </div> <div style=""> 25 </div> <div style=""> 26 </div> <div style=""> 27 </div> <div style=""> 28 </div> <div style=""> 29 </div> <div style=""> 30 </div> <div style=""> 31 </div> <div style=""> 32 </div> <div style=""> 33 </div> <div style=""> 34 </div> <div style=""> 35 </div> <div style=""> 36 </div> <div style=""> 37 </div> <div style=""> 38 </div> <div style=""> 39 </div> <div style=""> 40 </div> <div style=""> 41 </div> <div style=""> 42 </div> <div style=""> 43 </div> <div style=""> 44 </div> <div style=""> 45 </div> <div style=""> 46 </div> <div style=""> 47 </div> <div style=""> 48 </div> </td> <td style=""> <div style=""> <div style=""> <code style="">//Blinn-Phong reflection model wiath attenuation; Fragment Shader</code> </div> <div style=""> <code style="">//To keep it simple didn't add ambient and emissive lights;</code> </div> <div style=""> <code style="">//only diffuse and specular with white intensity</code> </div> <div style=""> <code style="">#version 330</code> </div> <div style=""> <code style="">layout(location = 0) out vec4 out_color;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform vec3 light_position;</code> </div> <div style=""> <code style="">uniform vec3 eye_position;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform </code> <code style="">int</code> <code style=""> material_shininess;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> material_kd;</code> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> material_ks;</code> </div> <div style=""> </div> <div style=""> <code style="">//attenuation coefficients</code> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> att_kC;</code> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> att_kL;</code> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> att_kQ;</code> </div> <div style=""> </div> <div style=""> <code style="">in vec3 world_pos;</code> </div> <div style=""> <code style="">in vec3 world_normal;</code> </div> <div style=""> </div> <div style=""> <code style="">void</code> <code style="">main(){ </code> </div> <div style=""> </div> <div style=""> </div> <div style=""> <code style="">vec3 L = normalize( light_position - world_pos);</code> <code style="">//light direction</code> </div> <div style=""> <code style="">vec3 V = normalize( eye_position - world_pos);</code> <code style="">//view direction</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">LdotN = max(0, dot(L,world_normal));</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">diffuse = material_kd * LdotN;</code> </div> <div style=""> </div> <div style=""> <code style="">//attenuation</code> </div> <div style=""> <code style="">float</code> <code style="">d = distance(light_position, world_pos);</code> </div> <div style=""> <code style="">float</code> <code style="">att = 1.0 / (att_kC + d * att_kL + d*d*att_kQ);</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">specular = 0;</code> </div> <div style=""> </div> <div style=""> <code style="">if</code> <code style="">(LdotN > 0.0)</code> </div> <div style=""> <code style="">{ </code> </div> <div style=""> <code style="">vec3 H = normalize(L + V );</code> <code style="">//Halfway(Blinn-Phong)</code> </div> <div style=""> <code style="">specular = material_kd * </code> <code style="">pow</code> <code style="">(max(0, dot(H, world_normal)), material_shininess);</code> </div> <div style=""> <code style="">}</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">light = att * diffuse + att * specular;</code> </div> <div style=""> </div> <div style=""> <code style="">out_color = vec4(light,light, light,1);</code> </div> <div style=""> <code style="">}</code> </div> </div> </td> </tr> </tbody> </table> * Last thing to discuss is gamma correction. Human eye doesn’t perceive lights in a linear way. Old CRT monitors and also new ones(LCD) are engineerd to have non linear response to pixel intensity. For example if a pixel has 25% brightness, at 50% it should be twice as bright, but is about 4.6 times brighter. Final color of the monitor can pe approximated by the following function: [![Gamma Corection][]][Gamma Corection] The standard gamma for monitors is 2.2 but may vary depending on the manufacturer. To undestand how gamma correction works here is a well-known diagram that shows how it’s done: [![Gamma Correction Diagram][]][Gamma Correction Diagram] [Source][] In this diagram, the bottom curve is the monitor response, the above curve is the gamma correction and the dotted middle line is the linear color space. Let’s say that you calculated a RGB value of 0.5 but because of monitor gamma, the final color will be 0.218. In order to see the correct result you have to apply gamma correction which will add brightness to final color. [![Nvidia GPU Gems 3][Nvidia GPU Gems 3 1]][Nvidia GPU Gems 3 1] [Nvidia GPU Gems 3][Nvidia GPU Gems 3 2]: a) With gamma correction b) Without gamma correction Gamma correction is very easy to implement in our fragment shader: <table style=""> <tbody style=""> <tr style=""> <td style=""> <div style=""> 1 </div> <div style=""> 2 </div> <div style=""> 3 </div> <div style=""> 4 </div> <div style=""> 5 </div> <div style=""> 6 </div> <div style=""> 7 </div> </td> <td style=""> <div style=""> <div style=""> <code style="">//fragment shader</code> </div> <div style=""> <code style="">//remeber that we have the same value on all RGB channels</code> </div> <div style=""> <code style="">//...</code> </div> <div style=""> <code style="">float</code> <code style="">gamma = 1/2.2;</code> </div> <div style=""> <code style="">float</code> <code style="">final_light = </code> <code style="">pow</code> <code style="">(light,gamma);</p></code> </div> <div style=""> <code style="">out_color = vec4(final_light,final_light, final_light,1);</code> </div> <div style=""> <code style="">}</code> </div> </div> </td> </tr> </tbody> </table> You have to be careful not to apply gamma correction twice. For example, textures can already have gamma correction and if you make another gamma correction the restult would be brighter. Here we didn’t applied any textures on the sphere but if you have textures and you want to keep gamma correction in shader you can load the image changing the internalFormat of the texture when you load it. Just change GL\_RGB to GL\_SRGB argument in glTexImage2D function. ##### [Source Code][] (VS 2013 OpengGL with C++ framework is based on one of my school projects) ##### Other resources: [http://people.csail.mit.edu/wojciech/BRDFValidation/ExperimentalValidation-talk.pdf][http_people.csail.mit.edu_wojciech_BRDFValidation_ExperimentalValidation-talk.pdf] [http://http.developer.nvidia.com/GPUGems3/gpugems3\_ch24.html][Nvidia GPU Gems 3 2] [https://developer.valvesoftware.com/wiki/Constant-Linear-Quadratic\_Falloff][https_developer.valvesoftware.com_wiki_Constant-Linear-Quadratic_Falloff] [http://www.farbrausch.de/~fg/stuff/phong.pdf][http_www.farbrausch.de_fg_stuff_phong.pdf] * [June 19, 2014][June 19_ 2014] * Category: [Game Development][], [OpenGL][] * Written by: [Sergiu Craitoiu][] * [Leave a reply][] ![Nvidia GPU Gems 3][]Nvidia GPU Gems 3 [![JShareFacebook.jpg][]][JShareFacebook.jpg 1] [![Jshareflipboard.jpg][]][Jshareflipboard.jpg 1] [![JShareGooglePlus.jpg][]][JShareGooglePlus.jpg 1] In this [post][], my friend Adrian Visan explained the importance of lighting in a 3D environment and the importance of all lighting model coefficients required to compute the actual light. Here I will talk about Gouraud , Phong and Blinn-Phong lighting models and a brief about multiple light sources, attenuation and gamma correction which are used to implement light in modern games. Gouraud reflection model can be calculated in vertex shader. This model computes a normal vector and an intensity for each vertex. To display the entire surface, points intensity on the lines are computed using linear interpolation between vertex intensities; Points intensity between the lines are computed using linear interpolation between the lines intensities. [![Gouraud only diffuse and specular][]][Gouraud only diffuse and specular] Gouraud model. Only diffuse and specular coefficients Phong shading model(reflection model) can be calculated in pixel shader. This model computes a normal vector for each vertex. After that computes a normal for each point on the surface using linear interpolation. Normal points on the lines are computing with linear interpolation between vertex normals. Normal points between the lines are computed using linear interpolation between the normal lines. Now we compute an intensity for each point. [![Phong Model][]][Phong Model] Phong model. Only diffuse and specular coefficients The general lighting equation is: [![Model Lighting in2gpu][]][Model Lighting in2gpu] Lighting equation Now let’s see how the reflected direction (R) is calculated: First, we simplify the image above keeping only incident ray (L or I), Normal Vector(N) and of course R. [![Compute reflection vector][]][Compute reflection vector] Denote L = I . It is the same thing(light ray/ reverse incident ray) Now we translate both u vectors and add them. And we can see that R is the result from vector addition between vector *I* and vector *2u*. Keep in mind that here we reversed *I*, the final formula changes the signs if *I* is not reversed. [![Reflected Ray Equation][]][Reflected Ray Equation] Reflected Ray In GLSL and HLSL, there is a function called [reflect][](L,N) which computes the reflected direction for us. But be careful, because incident ray(I) is not reversed, so in order to have the same result as in the above images, you must make it negative [\-reflect][reflect](L,N). Before jumping into writing code we should take a look at some aspects of diffuse lighting, material coefficients, shininess and Blinn-Phong model. Lambert’s cosine law says that the amount of reflected light is proportional with the cosine(dot product) of the angle between the normal and incident vector (angle of incidence). To get light on our object, the angle of incidence should vary between 0 and 90 degrees: [![Diffuse light aspects][]][Diffuse light aspects] Lambert’s law.How angle affects the diffuse lighting We also need this angle to check for specular lighting otherwise it computes specular lighting for the back of our object and we don’t need this effect. Speaking of specular we should talk about shininess coefficient(*n*). If *n* is larger you will get narrower curves. Usually for metallic surface *n* is between 100 and 300, for plastic materials should be under 10. This diagram shows how cos function behaves for different n values. [![shininess variation][]][shininess variation] [Shininess variation(original image).][Shininess variation_original image_.] Below is a list with some material coefficients. Of course you can experiment with other values if you want. However, these values are found experimentally in research laboratories. [![material coefficients][]][material coefficients] [Material coefficients(original site)][Material coefficients_original site] Blinn – Phong reflection model or modified Phong model was the default shading model in fixed-function pipeline for OpenGL and DirectX. It produces more accurate results than Phong reflection for many types of surfaces and it’s cheaper to compute for a single light source. For multiple lighting sources it’s more expensive to compute than Phong model. [![Blinn Phong model][]][Blinn Phong model] Blinn-Phong model Blinn – Phong model uses the concept of Halfway vector(H) between Light source(L) and View direction (V) instead of Reflection(R). [![Halfway Vector][]][Halfway Vector] Blinn-Phong halfway vector Lighting in vertex shader, Gouraud reflection model: <table style=""> <tbody style=""> <tr style=""> <td style=""> <div style=""> 1 </div> <div style=""> 2 </div> <div style=""> 3 </div> <div style=""> 4 </div> <div style=""> 5 </div> <div style=""> 6 </div> <div style=""> 7 </div> <div style=""> 8 </div> <div style=""> 9 </div> <div style=""> 10 </div> <div style=""> 11 </div> <div style=""> 12 </div> <div style=""> 13 </div> <div style=""> 14 </div> <div style=""> 15 </div> <div style=""> 16 </div> <div style=""> 17 </div> <div style=""> 18 </div> <div style=""> 19 </div> <div style=""> 20 </div> <div style=""> 21 </div> <div style=""> 22 </div> <div style=""> 23 </div> <div style=""> 24 </div> <div style=""> 25 </div> <div style=""> 26 </div> <div style=""> 27 </div> <div style=""> 28 </div> <div style=""> 29 </div> <div style=""> 30 </div> <div style=""> 31 </div> <div style=""> 32 </div> <div style=""> 33 </div> <div style=""> 34 </div> <div style=""> 35 </div> <div style=""> 36 </div> <div style=""> 37 </div> <div style=""> 38 </div> <div style=""> 39 </div> <div style=""> 40 </div> <div style=""> 41 </div> <div style=""> 42 </div> <div style=""> 43 </div> <div style=""> 44 </div> <div style=""> 45 </div> <div style=""> 46 </div> <div style=""> 47 </div> <div style=""> 48 </div> <div style=""> 49 </div> <div style=""> 50 </div> <div style=""> 51 </div> <div style=""> 52 </div> <div style=""> 53 </div> <div style=""> 54 </div> <div style=""> 55 </div> </td> <td style=""> <div style=""> <div style=""> <code style="">//Gouraud Vertex Shader</code> </div> <div style=""> <code style="">//To keep it simple didn't add ambient and emissive lights;</code> </div> <div style=""> <code style="">//only diffuse and specular with white intensity</code> </div> <div style=""> <code style="">#version 330</code> </div> <div style=""> </div> <div style=""> <code style="">layout(location = 0) in vec3 in_position;</code> </div> <div style=""> <code style="">layout(location = 1) in vec3 in_normal;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform mat4 model_matrix, view_matrix, projection_matrix;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform vec3 light_position;</code> </div> <div style=""> <code style="">uniform vec3 eye_position;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform </code> <code style="">int</code> <code style=""> material_shininess;</code> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> material_kd;</code> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> material_ks;</code> </div> <div style=""> </div> <div style=""> <code style="">out </code> <code style="">float</code> <code style=""> light;</code> </div> <div style=""> </div> <div style=""> <code style="">void</code> <code style="">main(){ </code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">vec3 world_position = mat3(model_matrix) * in_position;</code> <code style="">//careful here</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">vec3 world_normal = normalize(mat3(model_matrix) * in_normal);</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">//don't forget to normalize</code> </div> <div style=""> <code style=""> </code> <code style="">vec3 L = normalize(light_position - world_position);</code> <code style="">//light direction</code> </div> <div style=""> <code style=""> </code> <code style="">vec3 V = normalize(eye_position - world_position); </code> <code style="">//view direction</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">//Lambert term</code> </div> <div style=""> <code style=""> </code> <code style="">float</code> <code style="">LdotN = max(0, dot(L,world_normal));</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">//consider diffuse light color white(1,1,1)</code> </div> <div style=""> <code style=""> </code> <code style="">//all color channels have the same float value</code> </div> <div style=""> <code style=""> </code> <code style="">float</code> <code style="">diffuse = material_kd * LdotN;</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">float</code> <code style="">specular = 0;</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">if</code> <code style="">(LdotN > 0.0)</code> </div> <div style=""> <code style=""> </code> <code style="">{ </code> </div> <div style=""> <code style=""> </code> <code style="">//can use built-in max or saturate function</code> </div> <div style=""> <code style=""> </code> <code style="">vec3 R = -normalize(reflect(L,world_normal);</code> <code style="">//reflection</code> </div> <div style=""> <code style=""> </code> <code style="">specular = material_ks * </code> <code style="">pow</code> <code style="">( max(0, dot( R, V)), material_shininess);</code> </div> <div style=""> <code style=""> </code> <code style="">}</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">//pass light to fragment shader</code> </div> <div style=""> <code style=""> </code> <code style="">light = diffuse + specular;</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">//How about with ambinetal and emissive?</code> </div> <div style=""> <code style=""> </code> <code style="">//Final light(with white(1,1,1)) would be:</code> </div> <div style=""> <code style=""> </code> <code style="">//light = ke + material_ka + diffuse + specular;</code> </div> <div style=""> </div> <div style=""> <code style=""> </code> <code style="">//final vertex position</code> </div> <div style=""> <code style=""> </code> <code style="">gl_Position = projection_matrix*view_matrix*model_matrix*vec4(in_position,1);</code> </div> <div style=""> <code style="">}</code> </div> </div> </td> </tr> </tbody> </table> <table style=""> <tbody style=""> <tr style=""> <td style=""> <div style=""> 1 </div> <div style=""> 2 </div> <div style=""> 3 </div> <div style=""> 4 </div> <div style=""> 5 </div> <div style=""> 6 </div> <div style=""> 7 </div> <div style=""> 8 </div> <div style=""> 9 </div> <div style=""> 10 </div> </td> <td style=""> <div style=""> <div style=""> <code style="">//Fragment Shader</code> </div> <div style=""> <code style="">#version 330</code> </div> <div style=""> <code style="">layout(location = 0) out vec4 out_color;</p></code> </div> <div style=""> <code style="">//from vertex shader</code> </div> <div style=""> <code style="">in </code> <code style="">float</code> <code style=""> light;</code> </div> <div style=""> </div> <div style=""> <code style="">void</code> <code style="">main()</code> </div> <div style=""> <code style="">{ </code> </div> <div style=""> <code style=""> </code> <code style="">out_color = vec4(light,light, light,1);</code> </div> <div style=""> <code style="">}</code> </div> </div> </td> </tr> </tbody> </table> Of course, Gouraud model is cheaper to compute than Phong model but inferior in quality especially for specular light. Although if the LOD(level of detail) is high, Gouraud model can give good results and it’s ok to use. Also you can use Gouraud model if you develop mobile games where you don’t have the hardware resources(…for the moment). Gouraud is way better than Flat Shading . ![Gouraud vs Flat Shading][] [Gouraud model vs Flat Shading][] Lighting in pixel shader, Phong reflection model: <table style=""> <tbody style=""> <tr style=""> <td style=""> <div style=""> 1 </div> <div style=""> 2 </div> <div style=""> 3 </div> <div style=""> 4 </div> <div style=""> 5 </div> <div style=""> 6 </div> <div style=""> 7 </div> <div style=""> 8 </div> <div style=""> 9 </div> <div style=""> 10 </div> <div style=""> 11 </div> <div style=""> 12 </div> <div style=""> 13 </div> <div style=""> 14 </div> <div style=""> 15 </div> <div style=""> 16 </div> <div style=""> 17 </div> <div style=""> 18 </div> <div style=""> 19 </div> </td> <td style=""> <div style=""> <div style=""> <code style="">//Phong Reflection Model Vertex Shader</code> </div> <div style=""> <code style="">#version 330</code> </div> <div style=""> </div> <div style=""> <code style="">layout(location = 0) in vec3 in_position;</code> </div> <div style=""> <code style="">layout(location = 1) in vec3 in_normal;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform mat4 model_matrix, view_matrix, projection_matrix;</code> </div> <div style=""> </div> <div style=""> <code style="">//send them to fragment shader</code> </div> <div style=""> <code style="">out vec3 world_pos;</code> </div> <div style=""> <code style="">out vec3 world_normal;</code> </div> <div style=""> </div> <div style=""> <code style="">void</code> <code style="">main()</code> </div> <div style=""> <code style="">{ </code> </div> <div style=""> <code style=""> </code> <code style="">//convert in world coords</code> </div> <div style=""> <code style=""> </code> <code style="">world_pos = mat3(model_matrix) * in_position;</code> <code style="">//careful here</code> </div> <div style=""> <code style=""> </code> <code style="">world_normal = normalize(mat3(model_matrix) * in_normal);</code> </div> <div style=""> <code style=""> </code> <code style="">gl_Position = projection_matrix*view_matrix*model_matrix*vec4(in_position,1);</code> </div> <div style=""> <code style="">}</code> </div> </div> </td> </tr> </tbody> </table> <table style=""> <tbody style=""> <tr style=""> <td style=""> <div style=""> 1 </div> <div style=""> 2 </div> <div style=""> 3 </div> <div style=""> 4 </div> <div style=""> 5 </div> <div style=""> 6 </div> <div style=""> 7 </div> <div style=""> 8 </div> <div style=""> 9 </div> <div style=""> 10 </div> <div style=""> 11 </div> <div style=""> 12 </div> <div style=""> 13 </div> <div style=""> 14 </div> <div style=""> 15 </div> <div style=""> 16 </div> <div style=""> 17 </div> <div style=""> 18 </div> <div style=""> 19 </div> <div style=""> 20 </div> <div style=""> 21 </div> <div style=""> 22 </div> <div style=""> 23 </div> <div style=""> 24 </div> <div style=""> 25 </div> <div style=""> 26 </div> <div style=""> 27 </div> <div style=""> 28 </div> <div style=""> 29 </div> <div style=""> 30 </div> <div style=""> 31 </div> <div style=""> 32 </div> <div style=""> 33 </div> <div style=""> 34 </div> <div style=""> 35 </div> <div style=""> 36 </div> <div style=""> 37 </div> <div style=""> 38 </div> <div style=""> 39 </div> <div style=""> 40 </div> <div style=""> 41 </div> <div style=""> 42 </div> <div style=""> 43 </div> <div style=""> 44 </div> <div style=""> 45 </div> <div style=""> 46 </div> </td> <td style=""> <div style=""> <div style=""> <code style="">//Phong reflection model; Fragment Shader</code> </div> <div style=""> <code style="">//To keep it simple didn't add ambient and emissive lights;</code> </div> <div style=""> <code style="">//only diffuse and specular with white intensity</code> </div> <div style=""> <code style="">#version 330</code> </div> <div style=""> <code style="">layout(location = 0) out vec4 out_color;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform vec3 light_position;</code> </div> <div style=""> <code style="">uniform vec3 eye_position;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform </code> <code style="">int</code> <code style=""> material_shininess;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> material_kd;</code> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> material_ks;</code> </div> <div style=""> </div> <div style=""> <code style="">in vec3 world_pos;</code> </div> <div style=""> <code style="">in vec3 world_normal;</code> </div> <div style=""> </div> <div style=""> <code style="">void</code> <code style="">main(){ </code> </div> <div style=""> </div> <div style=""> </div> <div style=""> <code style="">vec3 L = normalize( light_position - world_pos);</code> <code style="">//light direction</code> </div> <div style=""> <code style="">vec3 V = normalize( eye_position - world_pos);</code> <code style="">//view direction</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">LdotN = max(0, dot(L,world_normal));</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">diffuse = material_kd * LdotN;</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">specular = 0;</code> </div> <div style=""> </div> <div style=""> <code style="">if</code> <code style="">(LdotN > 0.0)</code> </div> <div style=""> <code style="">{ </code> </div> <div style=""> </div> <div style=""> <code style="">//choose H or R to see the difference</code> </div> <div style=""> <code style="">vec3 R = -normalize(reflect(L, world_normal));</code> <code style="">//Reflection</code> </div> <div style=""> <code style="">specular = material_ks * </code> <code style="">pow</code> <code style="">(max(0, dot(R, V)), material_shininess);</code> </div> <div style=""> </div> <div style=""> <code style="">//Blinn-Phong</code> </div> <div style=""> <code style="">// vec3 H = normalize(L + V );//Halfway</code> </div> <div style=""> <code style="">//specular = material_ks * pow(max(0, dot(H, world_normal)), material_shininess);</code> </div> <div style=""> </div> <div style=""> <code style="">}</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">light = diffuse + specular;</code> </div> <div style=""> </div> <div style=""> <code style="">out_color = vec4(light,light, light,1);</code> </div> <div style=""> <code style="">}</code> </div> </div> </td> </tr> </tbody> </table> Other things you should consider when you implement lighting is multiple light sources, attenuation and gamma correction. * If you have more than one light source the equation for reflection model will be: [![Lighting equation for more tahn one source][]][Lighting equation for more tahn one source] Lighting equation with multiple light sources * Light attenuation. You probably want to add this to your lighting model because it simulates the fading of light with the distance. In the real world the light intensity is proportional with the inverse of the distance squared but we can’t use it just like this because this it is not “natural” in a virtual environment due to fast chaning rate. There are several ways to compute attenuation but the most commonly used one is the constant, linear and quadratic method: [![Attenuation Equation][]][Attenuation Equation] Attenuation Equation <table style=""> <tbody style=""> <tr style=""> <td style=""> <div style=""> 1 </div> <div style=""> 2 </div> <div style=""> 3 </div> <div style=""> 4 </div> <div style=""> 5 </div> <div style=""> 6 </div> <div style=""> 7 </div> <div style=""> 8 </div> <div style=""> 9 </div> <div style=""> 10 </div> <div style=""> 11 </div> <div style=""> 12 </div> <div style=""> 13 </div> <div style=""> 14 </div> <div style=""> 15 </div> <div style=""> 16 </div> <div style=""> 17 </div> <div style=""> 18 </div> <div style=""> 19 </div> <div style=""> 20 </div> <div style=""> 21 </div> <div style=""> 22 </div> <div style=""> 23 </div> <div style=""> 24 </div> <div style=""> 25 </div> <div style=""> 26 </div> <div style=""> 27 </div> <div style=""> 28 </div> <div style=""> 29 </div> <div style=""> 30 </div> <div style=""> 31 </div> <div style=""> 32 </div> <div style=""> 33 </div> <div style=""> 34 </div> <div style=""> 35 </div> <div style=""> 36 </div> <div style=""> 37 </div> <div style=""> 38 </div> <div style=""> 39 </div> <div style=""> 40 </div> <div style=""> 41 </div> <div style=""> 42 </div> <div style=""> 43 </div> <div style=""> 44 </div> <div style=""> 45 </div> <div style=""> 46 </div> <div style=""> 47 </div> <div style=""> 48 </div> </td> <td style=""> <div style=""> <div style=""> <code style="">//Blinn-Phong reflection model wiath attenuation; Fragment Shader</code> </div> <div style=""> <code style="">//To keep it simple didn't add ambient and emissive lights;</code> </div> <div style=""> <code style="">//only diffuse and specular with white intensity</code> </div> <div style=""> <code style="">#version 330</code> </div> <div style=""> <code style="">layout(location = 0) out vec4 out_color;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform vec3 light_position;</code> </div> <div style=""> <code style="">uniform vec3 eye_position;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform </code> <code style="">int</code> <code style=""> material_shininess;</code> </div> <div style=""> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> material_kd;</code> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> material_ks;</code> </div> <div style=""> </div> <div style=""> <code style="">//attenuation coefficients</code> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> att_kC;</code> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> att_kL;</code> </div> <div style=""> <code style="">uniform </code> <code style="">float</code> <code style=""> att_kQ;</code> </div> <div style=""> </div> <div style=""> <code style="">in vec3 world_pos;</code> </div> <div style=""> <code style="">in vec3 world_normal;</code> </div> <div style=""> </div> <div style=""> <code style="">void</code> <code style="">main(){ </code> </div> <div style=""> </div> <div style=""> </div> <div style=""> <code style="">vec3 L = normalize( light_position - world_pos);</code> <code style="">//light direction</code> </div> <div style=""> <code style="">vec3 V = normalize( eye_position - world_pos);</code> <code style="">//view direction</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">LdotN = max(0, dot(L,world_normal));</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">diffuse = material_kd * LdotN;</code> </div> <div style=""> </div> <div style=""> <code style="">//attenuation</code> </div> <div style=""> <code style="">float</code> <code style="">d = distance(light_position, world_pos);</code> </div> <div style=""> <code style="">float</code> <code style="">att = 1.0 / (att_kC + d * att_kL + d*d*att_kQ);</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">specular = 0;</code> </div> <div style=""> </div> <div style=""> <code style="">if</code> <code style="">(LdotN > 0.0)</code> </div> <div style=""> <code style="">{ </code> </div> <div style=""> <code style="">vec3 H = normalize(L + V );</code> <code style="">//Halfway(Blinn-Phong)</code> </div> <div style=""> <code style="">specular = material_kd * </code> <code style="">pow</code> <code style="">(max(0, dot(H, world_normal)), material_shininess);</code> </div> <div style=""> <code style="">}</code> </div> <div style=""> </div> <div style=""> <code style="">float</code> <code style="">light = att * diffuse + att * specular;</code> </div> <div style=""> </div> <div style=""> <code style="">out_color = vec4(light,light, light,1);</code> </div> <div style=""> <code style="">}</code> </div> </div> </td> </tr> </tbody> </table> * Last thing to discuss is gamma correction. Human eye doesn’t perceive lights in a linear way. Old CRT monitors and also new ones(LCD) are engineerd to have non linear response to pixel intensity. For example if a pixel has 25% brightness, at 50% it should be twice as bright, but is about 4.6 times brighter. Final color of the monitor can pe approximated by the following function: [![Gamma Corection][]][Gamma Corection] The standard gamma for monitors is 2.2 but may vary depending on the manufacturer. To undestand how gamma correction works here is a well-known diagram that shows how it’s done: [![Gamma Correction Diagram][]][Gamma Correction Diagram] [Source][] In this diagram, the bottom curve is the monitor response, the above curve is the gamma correction and the dotted middle line is the linear color space. Let’s say that you calculated a RGB value of 0.5 but because of monitor gamma, the final color will be 0.218. In order to see the correct result you have to apply gamma correction which will add brightness to final color. [![Nvidia GPU Gems 3][Nvidia GPU Gems 3 1]][Nvidia GPU Gems 3 1] [Nvidia GPU Gems 3][Nvidia GPU Gems 3 2]: a) With gamma correction b) Without gamma correction Gamma correction is very easy to implement in our fragment shader: <table style=""> <tbody style=""> <tr style=""> <td style=""> <div style=""> 1 </div> <div style=""> 2 </div> <div style=""> 3 </div> <div style=""> 4 </div> <div style=""> 5 </div> <div style=""> 6 </div> <div style=""> 7 </div> </td> <td style=""> <div style=""> <div style=""> <code style="">//fragment shader</code> </div> <div style=""> <code style="">//remeber that we have the same value on all RGB channels</code> </div> <div style=""> <code style="">//...</code> </div> <div style=""> <code style="">float</code> <code style="">gamma = 1/2.2;</code> </div> <div style=""> <code style="">float</code> <code style="">final_light = </code> <code style="">pow</code> <code style="">(light,gamma);</p></code> </div> <div style=""> <code style="">out_color = vec4(final_light,final_light, final_light,1);</code> </div> <div style=""> <code style="">}</code> </div> </div> </td> </tr> </tbody> </table> You have to be careful not to apply gamma correction twice. For example, textures can already have gamma correction and if you make another gamma correction the restult would be brighter. Here we didn’t applied any textures on the sphere but if you have textures and you want to keep gamma correction in shader you can load the image changing the internalFormat of the texture when you load it. Just change GL\_RGB to GL\_SRGB argument in glTexImage2D function. ##### [Source Code][] (VS 2013 OpengGL with C++ framework is based on one of my school projects) ##### Other resources: [http://people.csail.mit.edu/wojciech/BRDFValidation/ExperimentalValidation-talk.pdf][http_people.csail.mit.edu_wojciech_BRDFValidation_ExperimentalValidation-talk.pdf] [http://http.developer.nvidia.com/GPUGems3/gpugems3\_ch24.html][Nvidia GPU Gems 3 2] [https://developer.valvesoftware.com/wiki/Constant-Linear-Quadratic\_Falloff][https_developer.valvesoftware.com_wiki_Constant-Linear-Quadratic_Falloff] [http://www.farbrausch.de/~fg/stuff/phong.pdf][http_www.farbrausch.de_fg_stuff_phong.pdf] [June 19_ 2014]: http://in2gpu.com/2014/06/19/lighting-vertex-fragment-shader/ [Game Development]: http://in2gpu.com/category/game-development/ [OpenGL]: http://in2gpu.com/category/game-development/opengl/ [Sergiu Craitoiu]: http://in2gpu.com/author/sergiu-craitoiu/ [Leave a reply]: http://in2gpu.com/2014/06/19/lighting-vertex-fragment-shader/#respond [Nvidia GPU Gems 3]: /images/20220731/b1a9457a31f9478da86e822bce6c4960.png [JShareFacebook.jpg]: http://in2gpu.com/wp-content/themes/GameNews/images/JShare/JShareFacebook.jpg [JShareFacebook.jpg 1]: https://www.facebook.com/sharer/sharer.php?u=http://in2gpu.com/2014/06/19/lighting-vertex-fragment-shader/ [Jshareflipboard.jpg]: http://in2gpu.com/wp-content/themes/GameNews/images/JShare/Jshareflipboard.jpg [Jshareflipboard.jpg 1]: https://share.flipboard.com/flipit/load?v=1.0&url=http://in2gpu.com/2014/06/19/lighting-vertex-fragment-shader/ [JShareGooglePlus.jpg]: /images/20220731/7352110e2a6a4d55a50559aa5a11c3db.png [JShareGooglePlus.jpg 1]: https://plus.google.com/share?url=http://in2gpu.com/2014/06/19/lighting-vertex-fragment-shader/ [post]: http://iloveshaders.blogspot.ro/2011/04/how-lighting-works.html [Gouraud only diffuse and specular]: /images/20220731/68eacd69e5dc4861a51b5cce2b31c0d5.png [Phong Model]: /images/20220731/57d8fcc139684557ad24bf408ffac4f9.png [Model Lighting in2gpu]: /images/20220731/7981a36fc4014db98f82c41cc91c3952.png [Compute reflection vector]: /images/20220731/ab4c72177cbd432c92d6bb807e94c6d5.png [Reflected Ray Equation]: /images/20220731/ea204d0591b84d808763bb84be21ac6b.png [reflect]: https://www.opengl.org/sdk/docs/man/html/reflect.xhtml [Diffuse light aspects]: /images/20220731/ae9e6baaa4dc4453a157820e786644bd.png [shininess variation]: /images/20220731/f80f79c8e00d456bae2a6136ac3fef78.png [Shininess variation_original image_.]: http://www.siggraph.org/education/materials/HyperGraph/illumin/specular_highlights/phong_model_specular_reflection.htm [material coefficients]: /images/20220731/f96e915b7f654dd1acff8596e873b6f1.png [Material coefficients_original site]: http://devernay.free.fr/cours/opengl/materials.html [Blinn Phong model]: /images/20220731/2f3acf3eba9841b6b850eaa54181211e.png [Halfway Vector]: /images/20220731/7c95f6237ab5439d89998459bc50651f.png [Gouraud vs Flat Shading]: /images/20220731/3fefa6205d354878b357f885db7ad947.png [Gouraud model vs Flat Shading]: http://en.wikipedia.org/wiki/Gouraud_shading [Lighting equation for more tahn one source]: /images/20220731/c9c8930cd2aa4b199ffc7818cab45478.png [Attenuation Equation]: /images/20220731/3b0f8f66de1f45268eadd47070a04a49.png [Gamma Corection]: /images/20220731/8436a1315b2048a4912e0daab027df6b.png [Gamma Correction Diagram]: /images/20220731/31a929051b01490fb619bd802486e735.png [Source]: http://en.wikipedia.org/wiki/Gamma_correction [Nvidia GPU Gems 3 1]: /images/20220731/f34a1af2104b482db930d6364ee63f36.png [Nvidia GPU Gems 3 2]: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch24.html [Source Code]: http://in2gpu.com/wp-content/uploads/2014/06/BasicLighting.rar [http_people.csail.mit.edu_wojciech_BRDFValidation_ExperimentalValidation-talk.pdf]: http://people.csail.mit.edu/wojciech/BRDFValidation/ExperimentalValidation-talk.pdf [https_developer.valvesoftware.com_wiki_Constant-Linear-Quadratic_Falloff]: https://developer.valvesoftware.com/wiki/Constant-Linear-Quadratic_Falloff [http_www.farbrausch.de_fg_stuff_phong.pdf]: http://www.farbrausch.de/~fg/stuff/phong.pdf
相关 LIGHTING IN VERTEX AND FRAGMENT SHADER [June 19, 2014][June 19_ 2014] Category: [Game Development][], [OpenGL][] r囧r小猫/ 2022年08月20日 05:16/ 0 赞/ 20 阅读
还没有评论,来说两句吧...