OpenGL is a new generation of graphics card that provides developers with a small program, in order to allow developers to customize the lighting, coordinate conversion, and pixel processing. OpenGL has a specialized language: GLSL. Currently, GLSL should be fully switched to Shader Model5, beginners like me still need to spend a longer time learning to get to know the basics of OpenGL coloring er.
The following two figures show the changes in OpenGL from a Fixed rendering pipeline to a programmable rendering pipeline.
We can easily see that OpenGL's vertex shader replaces the transformation, illumination, texture coordinate generation and conversion of Fixed rendering pipelines; the part coloring tool replaces texture, color summation, and fog operations. Added the GeometryShader concept to OpenGL3.2 and added Tessellation Control and Tessellation Evaluation in OpenGL4.0, in the latest OpenGL version 4.3, the Compute Shader is added ). It seems that the OpenGL pasters are becoming more and more complex and important.
The following describes how to implement the illumination model in the vertex shader. All the content can be found in OpenGL (version 4.
Diffuse Reflection is a simple illumination model, which only considers diffuse reflection. Its formula is:
N is the unit normal of the vertex, and L is the direction of the unit vector from the vertex to the light source. Cmat is the color of the surface material, Cli is the color of light, and Cdiff is the final color of scattering. Note that N and L must be unitized before being passed in. If we use the vertex coloring tool for implementation, it is:
Uniform vec3 lightPos [1]; void main (void) {// MVP transformation of the normal gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; vec3 N = normalize (gl_NormalMatrix * gl_Normal ); vec4 V = gl_ModelViewMatrix * gl_Vertex; vec3 L = normalize (lightPos [0]-V. xyz); // float NdotL = dot (N, L); gl_FrontColor = gl_Color * vec4 (max (0.0, NdotL ));}
Note: Here, lightPos is a variable marked as uniform, which means that you can change the behavior of the shader by importing a value to lightPos at runtime.
The following figure shows the running result of the diffuse reflection illumination model:
Only the diffuse reflection, and a beautiful model will lose its luster. We must find a way to display the model's highlights. In this case, we should use the mirror reflection illumination model. The formula for the mirror reflection illumination model is:
H indicates the direction in the center of the angle between the light vector and the view vector (which can be converted through the view matrix. It is called a halfwidth vector. Sexp is the final mirror color. The values of N, L, Cmat, and Cli are the same as those of the scattering light equation. The following code is implemented using a colorator:
Uniform vec3 lightPos [1]; void main (void) {// normal transformation gl_Position = callback * gl_Vertex; vec3 N = normalize (gl_NormalMatrix * gl_Normal); vec4 V = gl_ModelViewMatrix * gl_Vertex; vec3 L = normalize (lightPos [0]-V. xyz); vec3 H = normalize (L + vec3 (0.0, 0.0, 1.0); const float specularExp = 128.0; // calculate the scattering light float NdotL = max (0.0, dot (N, L); vec4 diffuse = gl_Color * vec4 (NdotL); // calculate the float NdotH = max (0.0, dot (N, H )); vec4 specular = vec4 (0.0); if (NdotL> 0.0) specular = vec4 (pow (NdotH, specularExp )); // calculate the sum of the scattering and mirror components. gl_FrontColor = diffuse + specular ;}
The following is the rendering:
This rendering mode is not ideal, because it is just a simple interpolation, And the illumination on a few sides of the body is very ugly, there are two solutions. One is to use Secondary colors (Secondary Color) to separate the mirror reflection Color from the diffuse Color. The second method is to use a one-dimensional texture to attach a highlighted "texture" to the ry ". The following is a vertex coloring tool that uses the color separation method:
Uniform vec3 lightPos [1]; void main (void) {// normal transformation gl_Position = callback * gl_Vertex; vec3 N = normalize (gl_NormalMatrix * gl_Normal); vec4 V = gl_ModelViewMatrix * gl_Vertex; vec3 L = normalize (lightPos [0]-V. xyz); vec3 H = normalize (L + vec3 (0.0, 0.0, 1.0); const float specularExp = 128.0; // place the scattering color in the main color float NdotL = max (0.0, dot (N, L); gl_FrontColor = gl_Colo R * vec4 (NdotL); // place the mirror color in the secondary color float NdotH = max (0.0, dot (N, H); gl_FrontSecondaryColor = (NdotL> 0.0 )? Vec4 (pow (NdotH, specularExp): vec4 (0.0 );}
Below is:
It is troublesome to use one-dimensional textures. First, create a one-dimensional texture during initialization. The Code is as follows:
Bool OpenGLView: SetupTextureSpecular (void ){...... // Use the texture 0 to set the texture, and enable glGetIntegerv (watermark, & maxTexSize); glActiveTexture (GL_TEXTURE0); glGenTextures (1, & texID); glBindTexture (GL_TEXTURE_1D, texID); // create a one-dimensional texture and set it to GLfloat texture [512*4]; GLint texSize = (maxTexSize> 512 )? 512: maxTexSize; float r = 1.0f, g = 1.0f, B = 1.0f; for (int x = 0; x <512; ++ x) {// Incoming N. H has been scaled by 8 and biased by-7 to take better // advantage of the texture space. otherwise, the texture will be // entirely zeros ~ 7/8 of the way into it. this way, we expand // the useful 1/8 of the range and get better precision. texture [x * 4 + 0] = r * (float) pow (double) x/(double) (texSize-1) * 0.125f + 0.875f, 128.0 ); texture [x * 4 + 1] = g * (float) pow (double) x/(double) (texSize-1) * 0.125f + 0.875f, 128.0 ); texture [x * 4 + 2] = B * (float) pow (double) x/(double) (texSize-1) * 0.125f + 0.875f, 128.0 ); texture [x * 4 + 3] = 1.0f;} // Make sure the first texel is exactly zero. most // incoming texcoords will clamp to this texel. // texture [0] = texture [1] = texture [2] = 0.0f; glTexImage1D (GL_TEXTURE_1D, 0, GL_RGBA16, texSize, 0, GL_RGBA, GL_FLOAT, texture ); return true ;}
Then set some statuses:
glEnable( GL_TEXTURE_1D );glActiveTexture( GL_TEXTURE0 );glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );glBindTexture( GL_TEXTURE_1D, texID );
Finally, let's look at how the vertex shader is written:
Uniform vec3 lightPos [1]; void main (void) {// normal transformation gl_Position = callback * gl_Vertex; vec3 N = normalize (gl_NormalMatrix * gl_Normal); vec4 V = gl_ModelViewMatrix * gl_Vertex; vec3 L = normalize (lightPos [0]-V. xyz); vec3 H = normalize (L + vec3 (0.0, 0.0, 1.0); const float specularExp = 128.0; // place the scattering color in the main color float NdotL = max (0.0, dot (N, L); gl_FrontColor = gl_Color * vec4 (NdotL ); // place the mirror color in the secondary color float NdotH = 0.0; if (NdotL> 0.0) NdotH = max (0.0, dot (N, H) * 8.0-7.0 ); gl_TexCoord [0] = vec4 (NdotH, 0.0, 0.0, 1.0 );}
For example, if the intensity of the highlights is significantly smaller than the preceding two, the illumination accuracy is high. Finally, I seem to be unable to fully understand these effects on Intel's dashboard, so we should try to use high-performance dashboard for rendering.
Reference: OpenGL (version 4)