OpenGL (advanced tutorial)-glsl lighting (lighting)

Source: Internet
Author: User
Tags acos
Abstract

In the previous article, we introduced simple shading and proposed a lighting model to simulate a light source. However, the story about light is not over yet...

Today I want to learn about directional light, spotlight, per pixel shading, and halfway vector.

For the principle and mathematical description of the light source, see: raytracing Algorithm Theory and Practice (3) Illumination

Direction Light Source

The direction light source has two parameters: Direction and intensity.

It is also a simple ambient + DIFFUSE + spec illumination model. First look at the shader code.

Basic. Vert

#version 400layout (location = 0) in vec3 VertexPosition;  layout (location = 1) in vec3 VertexNormal;  out vec3 LightIntensity;struct LightInfo{vec4 Direction;vec3 Intensity;};struct MaterialInfo{vec3 Ka;vec3 Kd;vec3 Ks;float Shininess;};uniform LightInfo Light;uniformMaterialInfo Material;uniform mat4 ModelViewMatrix;uniform mat3 NormalMatrix;uniform mat4 ProjectionMatrix;uniform mat4 MVP;void getEyeSpace(out vec3 norm, out vec4 position){norm =  normalize(NormalMatrix * VertexNormal);position = ModelViewMatrix * vec4(VertexPosition, 1.0);}vec3 ads(vec4 position, vec3 norm){vec3 s;if(Light.Direction.w == 0.0)s = normalize(vec3(Light.Direction));elses = normalize(vec3(Light.Direction - position));vec3 v = normalize(vec3(-position));vec3 r = reflect(-s, norm);return Light.Intensity * (Material.Ka + Material.Kd*max(dot(s,norm), 0.0) +        Material.Ks * pow(max(dot(r,v),0.0), Material.Shininess));}void main(){vec3 eyeNorm;vec4 eyePosition;getEyeSpace(eyeNorm, eyePosition);LightIntensity = ads(eyePosition, eyeNorm);gl_Position = MVP * vec4( VertexPosition, 1.0);}

In the ads function, we first use the nomal matrix to convert the vertex normal vector to the coordinates of the view. (the nomal matrix is actually a matrix of 3x3 on the left of the Model-View matrix) then, use the Model-View matrix to convert the vertex coordinates to the eye coordinates coordinate system.

The next ads is used to calculate the color of the vertex under the illumination model, calculate the three components respectively, and then add them together.

Basic. Frag

#version 400in vec3 LightIntensity;void main(void){gl_FragColor = vec4(LightIntensity, 1.0);//gl_FragColor = vec4(1.0,1.0,0.1, 1.0);}

This is to assign values to segments based on the color from the vertex shader.

Assign a value to the uniform variable in the setuniform function of CGL. cpp.
void CGL::setUniform(){    mat4 projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);    mat4 mv = view * model;    prog.setUniform("Material.Kd", 0.9f, 0.5f, 0.3f);    prog.setUniform("Material.Ka", 0.9f, 0.5f, 0.3f);    prog.setUniform("Material.Ks", 0.8f, 0.8f, 0.8f);    prog.setUniform("Material.Shininess", 100.0f);    prog.setUniform("Light.Direction", vec4(1.0f, 0.0f, 0.0f, 0.0f));    prog.setUniform("Light.Intensity", 1.0f, 1.0f, 1.0f);    prog.setUniform("ModelViewMatrix", mv);    prog.setUniform("NormalMatrix",mat3( vec3(mv[0]), vec3(mv[1]), vec3(mv[2]) ));    prog.setUniform("MVP", projection * mv);}

The rendering effect is as follows: it is obvious that the light changes from the model to the surface during rotation. Halfway vector Performance Optimization

In the previous illumination model, the formula used to calculate the specular component is as follows:

WhereRIs the direction vector that reflects the light,VIs the vector in the direction of the view, where R is calculated:

This computation process is very time-consuming. We can use a trick to improve it.

DefineH(Halfway vector) vector:

YesHThe positional relationship with other vectors.

The specular component calculation can be converted:

Compared with computingR,HIs relatively simple, andHAndNBetween the angle andVAndRThe angle between them is almost the same! That means we can useH.nTo replaceR.vIn this way, halfway vector can be used to improve the performance. Although the effect may be so small.

This optimization will be used for subsequent lighting computing.

Spotlight

Here we use the simplest spotlight model:

Lighting attributes include position, intensity, direction, attenuation (exponent), and cropping angle.

The implementation is also relatively simple. The Rendering Method of objects in the projection angle is the same as that of the point light source. The vertices outside the projection angle are only ambient during coloring.

We still use the familiar per vertex shading method. Define the spotlight in vert:

//baisc.vert#version 400layout (location = 0) in vec3 VertexPosition;  layout (location = 1) in vec3 VertexNormal;  out vec3 LightIntensity;struct SpotLightInfo{vec4 position;vec3 direction;vec3 intensity;float exponent;float cutoff;};struct MaterialInfo{vec3 Ka;vec3 Kd;vec3 Ks;float Shininess;};uniform SpotLightInfo Spot;uniformMaterialInfo Material;uniform mat4 ModelViewMatrix;uniform mat3 NormalMatrix;uniform mat4 ProjectionMatrix;uniform mat4 MVP;void getEyeSpace(out vec3 norm, out vec4 position){norm =  normalize(NormalMatrix * VertexNormal);position = ModelViewMatrix * vec4(VertexPosition, 1.0);}vec3 adsSpotLight(vec4 position, vec3 norm){vec3 s = normalize(vec3(Spot.position - position));float angle = acos(dot(-s, normalize(Spot.direction)));float cutoff = radians(clamp(Spot.cutoff, 0.0, 90.0));vec3 ambient = Spot.intensity * Material.Ka;if(angle < cutoff){float spotFactor = pow(dot(-s, normalize(Spot.direction)), Spot.exponent);vec3 v = normalize(vec3(-position));vec3 h = normalize(v + s);return ambient + spotFactor * Spot.intensity * (Material.Kd * max(dot(s, norm),0.0)      + Material.Ks * pow(max(dot(h,norm), 0.0),Material.Shininess)); }else{return ambient; }       }void main(){vec3 eyeNorm;vec4 eyePosition;getEyeSpace(eyeNorm, eyePosition);LightIntensity = adsSpotLight(eyePosition, eyeNorm);gl_Position = MVP * vec4( VertexPosition, 1.0);}

Several built-in functions in glsl are described here.

Gentype clamp (gentype X, gentype minval, gentype maxval );

Obtain the second largest of the three numbers.

Gentype radians (gentype degrees );

Converts degrees to radians.

Adsspotlight is the main function. First, calculate the angle between the vertex and the light source direction, determine whether the vertex is in the irradiation area, and then obtain the final color respectively.

The segment shader is still like this:

#version 400in vec3 LightIntensity;void main(void){gl_FragColor = vec4(LightIntensity, 1.0);}

Assignment of the uniform variable:

void CGL::setUniform(){    //model = glm::rotate(this->model, 10.0f, vec3(0.0f,1.0f,0.0f));    mat4 projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);    mat4 mv = view * model;    mat3 normalMatrix = mat3( vec3(view[0]), vec3(view[1]), vec3(view[2]) );    prog.setUniform("Material.Kd", 0.9f, 0.5f, 0.3f);    prog.setUniform("Material.Ka", 0.9f, 0.5f, 0.3f);    prog.setUniform("Material.Ks", 0.8f, 0.8f, 0.8f);    prog.setUniform("Material.Shininess", 100.0f);    vec4 lightPos = vec4(1.0f, 5.0f, 20.0f, 1.0f);   // prog.setUniform("Spot.position", lightPos);    prog.setUniform("Spot.position", view * lightPos);    prog.setUniform("Spot.direction", normalMatrix * vec3(-10.0,0.0,-40.0) );    //prog.setUniform("Spot.direction", vec3(10.9f,10.9f,10.9f)  );    prog.setUniform("Spot.intensity", vec3(0.9f,0.9f,0.9f) );    prog.setUniform("Spot.exponent", 30.0f );    prog.setUniform("Spot.cutoff", 15.0f );    prog.setUniform("ModelViewMatrix", mv);    prog.setUniform("NormalMatrix",normalMatrix);    prog.setUniform("MVP", projection * mv);}

Here we give spot. position assignment is not performed by Prog. setuniform ("spot. position ", lightpos); It is prog. setuniform ("spot. position ", view * lightpos), because the calculation in the shader is carried out under the viewport coordinates, this is done to unify the coordinates. The assignment of spot. direction is the same. You can also place the coordinate transformation step in the shader.

The final result is as follows:

Per pixel Shading

Compared with the previous steps of putting the main computing work in the vertex shader's per vertex shading, per pixel shading refers to placing the computation in the segment shader, which can bring a more realistic rendering effect.

Basic2.vert

#version 400layout (location = 0) in vec3 VertexPosition;  layout (location = 1) in vec3 VertexNormal;  out vec4 Position;out vec3 Normal;uniform mat4 ModelViewMatrix;uniform mat3 NormalMatrix;uniform mat4 ProjectionMatrix;uniform mat4 MVP;void getEyeSpace(out vec3 norm, out vec4 position){norm =  normalize(NormalMatrix * VertexNormal);position = ModelViewMatrix * vec4(VertexPosition, 1.0);}void main(){getEyeSpace(Normal, Position);gl_Position = MVP * vec4( VertexPosition, 1.0);}

Basic2.frag

#version 400in vec4 Position;in vec3 Normal;struct SpotLightInfo{vec4 position;vec3 direction;vec3 intensity;float exponent;float cutoff;};struct MaterialInfo{vec3 Ka;vec3 Kd;vec3 Ks;float Shininess;};uniform SpotLightInfo Spot;uniformMaterialInfo Material;vec3 adsSpotLight(vec4 position, vec3 norm){vec3 s = normalize(vec3(Spot.position - position));float angle = acos(dot(-s, normalize(Spot.direction)));float cutoff = radians(clamp(Spot.cutoff, 0.0, 90.0));vec3 ambient = Spot.intensity * Material.Ka;if(angle < cutoff){float spotFactor = pow(dot(-s, normalize(Spot.direction)), Spot.exponent);vec3 v = normalize(vec3(-position));vec3 h = normalize(v + s);return ambient + spotFactor * Spot.intensity * (Material.Kd * max(dot(s, norm),0.0)      + Material.Ks * pow(max(dot(h,norm), 0.0),Material.Shininess)); }else{return ambient; }       }void main(void){gl_FragColor = vec4(adsSpotLight(Position, Normal), 1.0);//gl_FragColor = vec4(1.0,1.0,0.5, 1.0);}

Let's take a look at the rendering effect:

There are still some differences in the final effect, especially at the junction of light.

Code download

Openglpro13

Reference

OpenGL 4.0 shading language cookbook

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.