OpenGL tutorial (17) environment light

Source: Internet
Author: User

Original post address: http://ogldev.atspace.co.uk/www/tutorial17/tutorial17.html

In 3D Realistic Graphics, illumination is an important technology. Physically speaking, a beam is composed of many small particles, I .e., "photon", which are transmitted in the air, refraction and reflection on the surface of an object, and finally enters my visual system, it forms the real world we see in our eyes. In programming, we cannot simulate all the actions of photon. Therefore, it is an eternal topic in computer graphics to model illumination and simulate its real effect.

Among various paper algorithms, many kinds of illumination model algorithms have been proposed. With the development of graphics and the improvement of GPU computing capability, more illumination algorithms will emerge. In this tutorial, we will only discuss the most basic illumination model. It is relatively easy to program and its effect applies to all objects in the scenario.

The most basic lighting model is the environment light/diffuse light/highlights (ambient/diffuse/specular) Lighting Model:

Ambient Light refers to the lighting conditions around you without the sun. It simulates the reflection and refraction at different locations after the sunlight shines on the ground, the final light mixed together has no direction and no starting point. It is a uniform illumination effect. Even in the shadow, ambient light exists.

The diffuse reflection light is reflected on the surface of the object, and eventually enters the effect of our eyes, the direction of the diffuse reflection light and the light, and the normal of the object surface. For example, an object has two sides, when the diffuse light only shines on one plane, the plane is bright and the other is dark. Sunlight seems to have no direction, but there are actually some. For example, in a building, when the sun shines on it, its projection direction is the direction of sunlight.

A highlight is a property of an object. When light acts on an object, a part of the object may be particularly bright. This is the highlight, which will change the position as our viewpoint moves. Metal objects generally have such highlights, such as metal balls and automotive surfaces. To calculate a highlight, you must consider the direction of light, the normal direction of the light object, and the line of sight.

In 3D applications, we do not directly set ambient light, diffuse light, and highlights. Instead, we use the concept of a light source, such as the sun, lights, candles, and torch. these light sources are all ambient light, the combination of diffuse light and different highlights.

In the following tutorial, we use several different light sources to study the basic illumination model.

First, let's look at the "direction light". The direction light is a ray of light without a starting point, which means that all the light is parallel. The direction of light can be expressed by a vector, which is used to calculate the illumination effect of all objects in the scenario. In real life, the sun can be regarded as the direction of light, not to say that the light emitted by the sun is parallel, but because the sun is too far away from us, its light can be considered as parallel light.

Another important property of light direction is that its brightness is constant no matter how far it is from the object. In the following tutorial, we will learn the light source, the brightness of the Point Light Source degrades with the distance.

The following figure illustrates the direction of light:

We already know that sunlight includes two parts: ambient light and diffuse light. In this tutorial, we first program the effect of ambient light. In the next tutorial, we will learn about diffuse light.

In the previous tutorial, we learned how to sample the pixel color on a texture. The pixel color has three channels, red, green, and blue (RGB). Each channel is a single byte, that is to say, the color value range of each channel is [0,255]. Different RGB values represent different colors, (255,255,255, 0) indicates black, and () indicates white. We can scale a color RGB value proportionally. We can see that the color remains unchanged, but the brightness is getting lower and lower. ER or darker (depending on the scaling factor ).

When the light is white, the reflected light is only the color of the object, which may be darker or brighter, depending on the intensity of the light source. If the light source is pure red (, 0, 0), then the reflected light is only the red channel of the surface color of the object, because no blue or green part is reflected, if the object is pure blue, at this time, the object looks black because no blue light is reflected.

We will specify the RGB value range of the light source color to [0-1], and then multiply the color of the light source and the surface color of the object to obtain the color of the light reflection, that is, the color of the object we see. The following equation is used to calculate ambient light:

In this tutorial, we can use the and S keys to increase and decrease the intensity of ambient light. Of course, this is only the part of ambient light, and the direction light itself has not been computed, in the next tutorial, we will implement the diffuse light in the future. Now, the four sides of the object pyramid we render have the same illumination.

Environment light is not realistic. It is a human-added illumination factor. After we consider the diffuse reflection and highlights, We will combine them to achieve more realistic 3D object rendering.

The Code is as follows:

In this tutorial, we will make some changes to the program architecture. The main changes are as follows:

  1. The shader management is encapsulated in the technique class, such as shader compilation and links. Our own special effects (effect) classes are derived from technique.
  2. Put the glut initialization and callback function management in the glubackend module for processing. This module registers itself to accept the callback function of glut, and forwards it to the application through the C ++ Interface Class icallbacks.
  3. Move the global functions and variables in the main CPP to a class. This class can be seen as an application class. In the subsequent tutorial, we will expand this class, provides more general functions, which are popular in many engines and frameworks.

Let's take a look at the restructured code:

Glu_backend.h

void GLUTBackendInit(int argc, char** argv);
bool GLUTBackendCreateWindow(unsigned int Width, unsigned int Height, unsigned int bpp, bool isFullScreen, const char* pTitle);

Code related to glut is moved to the "glut backend" module, which makes it easier to initialize glut and create a window.

void GLUTBackendRun(ICallbacks* pCallbacks);

After the glut is initialized and created, we need to execute the glut main loop. The glubackendrun function is used to execute the main loop. The newly added callbacks interface is used to register the glut callback function. Unlike the callback function registered by each application in the previous tutorial, the glut backend module registers itself as a virtual function and then inherits the class, send events to the objects used in this function.

Technique. h

class Technique
{
public:
Technique();
~Technique();
virtual bool Init();
void Enable();
protected:
bool AddShader(GLenum ShaderType, const char* pShaderText);
bool Finalize();
GLint GetUniformLocation(const char* pUniformName);
private:
GLuint m_shaderProg;
typedef std::list<GLuint> ShaderObjList;
ShaderObjList m_shaderObjList;
};

In the previous tutorial, we implemented shader compilation, linking, and other functions in the main program CPP. In this tutorial code, we wrapped these common functions and created the technique class, its Inheritance class will focus mainly on shader special effects.

Each technique must first call the init function for instantiation. The derived class of techniqu must first call the init function of the base class (this function creates an OpenGL program object ), you can also add your own private functions.

After a technique object is created and instantiated, the derived class will call the addshader () function to add a shader and call the finalize () function link object. Before switching technique and calling draw, we must call the enable function because it encapsulates gluseprogram ().

This class tracks intermediate compiled objects and deletes them with gldeleteshader () after they are used, which helps reduce program resource consumption. The program object itself is deleted in the Destructor through gldeleteprogram.

Tutorial17.cpp

class Tutorial17 : public ICallbacks
{
public:
Tutorial17()
{
...
}
~Tutorial17()
{
...
}
bool Init()
{
...
}
void Run()
{
GLUTBackendRun(this);
}
virtual void RenderSceneCB()
{
...
}
virtual void IdleCB()
{
...
}
virtual void SpecialKeyboardCB(int Key, int x, int y)
{
...
}
virtual void KeyboardCB(unsigned char Key, int x, int y)
{
...
}
virtual void PassiveMouseCB(int x, int y)
{
...
}
private:
void CreateVertexBuffer()
{
...
}
void CreateIndexBuffer()
{
...
}
GLuint m_VBO;
GLuint m_IBO;
LightingTechnique* m_pEffect;
Texture* m_pTexture;
Camera* m_pGameCamera;
float m_scale;
DirectionalLight m_directionalLight;
};

The above code is the code of the main application class, which encapsulates some other code. Init () is used to create a special effect class, load the texture and create the vertex and index buffer. The run function calls glubackendrun () and passes the object as a parameter.

Lighting_technique.h

struct DirectionalLight
{
Vector3f Color;
float AmbientIntensity;
};

We have defined a direction light structure. Note that only the color of the light and the ambient light are available. In the subsequent tutorial, we will continue to add the diffuse reflection and highlights.

The first parameter is the RGA color of the light source, and the second parameter is the ambient light coefficient. When it is 1.0, it is a very bright ambient light, and when it is 0.1, it is a very dark ambient light.

class LightingTechnique : public Technique
{
public:
LightingTechnique();
virtual bool Init();
void SetWVP(const Matrix4f& WVP);
void SetTextureUnit(unsigned int TextureUnit);
void SetDirectionalLight(const DirectionalLight& Light);
private:
GLuint m_WVPLocation;
GLuint m_samplerLocation;
GLuint m_dirLightColorLocation;
GLuint m_dirLightAmbientIntensityLocation;
};

We will generate a lighting class from the technique class. After this class is created, we must first call the init function.

in vec2 TexCoord0;
out vec4 FragColor;
struct DirectionalLight
{
vec3 Color;
float AmbientIntensity;
};
uniform DirectionalLight gDirectionalLight;
uniform sampler2D gSampler;
void main()
{
FragColor = texture2D(gSampler, TexCoord0.xy) *
vec4(gDirectionalLight.Color, 1.0f) *
gDirectionalLight.AmbientIntensity;
}

Vertex shader code remains unchanged. A direction-light uniform variable is added to the segment-element shader, which is used to pass illumination parameters from the application. The final returned color is multiplied by the result of illumination and texture sampling to obtain the final pixel color.

m_WVPLocation = GetUniformLocation("gWVP");
m_samplerLocation = GetUniformLocation("gSampler");
m_dirLightColorLocation = GetUniformLocation("gDirectionalLight.Color");
m_dirLightAmbientIntensityLocation = GetUniformLocation("gDirectionalLight.AmbientIntensity");

In order to access the uniform variable directionallight, we added the above Code. Note that we need to specify the member variables in the structure separately.

After the program runs, the interface is as follows. We can use the and S keys to adjust the ambient brightness.

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.