Introduction
There are three types of light in OpenGL: directional, point, and spotlight ). In this tutorial, we will first use glsl to imitate the light in OpenGL.
We will gradually add ambient light, scattered light, and highlights to the shader.
In the subsequent tutorials, we will use pixel-by-pixel illumination for better results.
Next we will implement pixel-by-pixel light and concentration. These contents are similar to those in the direction, and most of the Code is generic.
In the cartoon coloring tutorial, we learned how to access the section about the light source in the OpenGL state in glsl, which describes the parameters of each light source.
struct gl_LightSourceParameters{ vec4 ambient; vec4 diffuse; vec4 specular; vec4 position; vec4 halfVector; vec3 spotDirection; float spotExponent; float spotCutoff; // (range: [0.0,90.0], 180.0) float spotCosCutoff; // (range: [1.0,0.0],-1.0) float constantAttenuation; float linearAttenuation; float quadraticAttenuation;};uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];struct gl_LightModelParameters{ vec4 ambient;};uniform gl_LightModelParameters gl_LightModel;
You can also access the material parameters in glsl:
struct gl_MaterialParameters{ vec4 emission; vec4 ambient; vec4 diffuse; vec4 specular; float shininess;};uniform gl_MaterialParameters gl_FrontMaterial;uniform gl_MaterialParameters gl_BackMaterial;
In OpenGL, most of these parameters are similar in use, regardless of the light source or material. We will use these parameters to implement our own direction light.
Direction light I
The formula in this section comes from the "mathematical knowledge related to illumination" section in the OpenGL programming guide.
We will start from the scattered light. In OpenGL, it is assumed that the obtained scattered light intensity is always the same regardless of the observer's angle. The intensity of the scattered light is related to the scattered light composition in the light source and the reflection coefficient of the scattered light in the material. It is also related to the angle between the incident light angle and the object surface normal.
OpenGL uses the following formula to calculate the scattering light composition:
I is the intensity of reflected light, LD is the scattering component of the light source (gl_lightsource [0]. Diffuse), MD is the scattering coefficient of the material (gl_frontmaterial.diffuse ).
This formula is the lambert diffuse reflection model. The cosine law of Lambert describes the brightness of the plane scattered light, which is proportional to the cosine of the plane normal and the angle of the clip of the incident light. This theory has been proposed more than 200 years ago.
To implement this formula in vertex shader, the direction and scattering component strength in the light source parameters must be used, and the scattering score in the material must also be used. Therefore, when using this shader, you need to set the light source in OpenGL as usual. Note: As there is no fixed function assembly line, you do not need to call glenable for the light source.
To calculate the cosine value, first make sure that the gl_lightsource [0]. Position and the normal vector are normalized, and then you can use the dot product to obtain the cosine value. Note: when the other side is directed to the light source, the direction saved in OpenGL is directed from the vertex to the light source, which is opposite to the one shown in the preceding figure.
OpenGL stores the direction of the light source in the coordinate system of the viewpoint space, so we need to change the normal to the viewpoint space. You can use the pre-defined consistent variable gl_normalmatrix to complete this transformation. This matrix is the transpose of the inverse matrix of the 3×3 sub-matrix on the top left of the transformation matrix of the model view.
The following is the vertex shader code of the above content:
void main(){ vec3 normal, lightDir; vec4 diffuse; float NdotL; /* first transform the normal into eye space and normalize the result */ normal = normalize(gl_NormalMatrix * gl_Normal); /* now normalize the light's direction. Note that according to the OpenGL specification, the light is stored in eye space. Also since we're talking about a directional light, the position field is actually direction */ lightDir = normalize(vec3(gl_LightSource[0].position)); /* compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. */ NdotL = max(dot(normal, lightDir), 0.0); /* Compute the diffuse term */ diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse; gl_FrontColor = NdotL * diffuse; gl_Position = ftransform();}
In the segment shader, you must use the variable gl_color to set the color.
void main(){ gl_FragColor = gl_Color;}
Displays the effect of applying the shader to the teapot. Note that the bottom of the teapot is very black because no ambient light is used.
It is easy to add ambient light. You only need to use a global ambient light parameter and the ambient light parameter of the light source. The formula is as follows:
The preceding vertex shader needs to add several statements to complete environment light computing:
void main(){ vec3 normal, lightDir; vec4 diffuse, ambient, globalAmbient; float NdotL; normal = normalize(gl_NormalMatrix * gl_Normal); lightDir = normalize(vec3(gl_LightSource[0].position)); NdotL = max(dot(normal, lightDir), 0.0); diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse; /* Compute the ambient and globalAmbient terms */ ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient; globalAmbient = gl_FrontMaterial.ambient * gl_LightModel.ambient; gl_FrontColor = NdotL * diffuse + globalAmbient + ambient; gl_Position = ftransform();}
The final result is displayed. After ambient light is added, the entire image is brightened. However, compared with the global illumination model that applies the reflected light effect, this computing environment light method can only be used as a cheap solution.
Direction light II
The following section describes the mirror reflection in OpenGL. We use a lighting model called the Blin-phong model, which is a simplified version of the phong model. Before that, we need to take a look at the Phong Model to better understand the Blin-Phong Model.
In the phong model, the mirror reflection component is related to the cosine of the angle between the reflected light and the line of sight, for example:
L indicates the incident light. N indicates the line of sight. Eye indicates the line of sight pointing from the vertex to the observation point. r is the result of mirror reflection. The mirror reflection component is related to the cosine of the Alpha angle.
If the line of sight is exactly the same as the reflected light, we will receive the maximum reflection intensity. When the line of sight is separated from the reflected light, the reflection intensity decreases accordingly. The descent rate can be controlled by a factor called shininess. The larger the value of shininess, the faster the descent rate. That is to say, the larger the shininess, the smaller the bright spots produced by the mirror reflection. In OpenGL, the value range is 0 to 128.
Formula for Calculating the reflected light vector:
In OpenGL, The phong model is used to calculate the mirror reflection component formula:
In formula, the index S is the shininess factor, LS is the mirror reflection strength in the light source, and MS is the mirror reflection coefficient in the material.
BlinN proposes a simplified model, namely, BlinN-Phong. It is based on half-vector, that is, a vector in the direction between the observation vector and the light vector:
Now we can use the cosine of the angle between the half vector and the normal to calculate the mirror reflection component. The formula for calculating the mirror reflection using the BlinN-phong model used by OpenGL is as follows:
This method is the same as that used in the fixed assembly line of the video card. Because we need to simulate the direction light in OpenGL, this formula is also used in shader. Fortunately, OpenGL helps us calculate the half vector. We only need to use the following code:
/* compute the specular term if NdotL is larger than zero */if (NdotL > 0.0){ // normalize the half-vector, and then compute the // cosine (dot product) with the normal NdotHV = max(dot(normal, gl_LightSource[0].halfVector.xyz),0.0); specular = gl_FrontMaterial.specular * gl_LightSource[0].specular * pow(NdotHV,gl_FrontMaterial.shininess);}
Download the complete shader designer project:
Http://lighthouse3d.com/wptest/wp-content/uploads/2011/03/ogldirsd.zip