Basics of lighting in OpenGL. Lighting in opengl es - game development for android OS How lighting works

OpenGL uses the Phong lighting model, in which the color of a point is determined by several factors: material and texture properties, the magnitude of the normal at that point, and the position of the light source and observer. To correctly calculate the illumination at a point, it is necessary to use single normals, however, commands like glScale..() can change the length of the normals. To take this into account, the already mentioned normalization mode is used, which is enabled by calling the glEnable(GL_NORMALIZE) command.

OpenGL provides for setting three parameters that determine the general laws for applying the lighting model. These parameters are passed to the glLightModel() function and some of its modifications. To set global lighting parameters, use the following commands:

void glLightModel(GLenum pname, GLenum param)

void glLightModelv(GLenum pname, const GLtype *params)

The pname argument specifies which lighting model parameter will be adjusted and can take the following values:

GL_LIGHT_MODEL_LOCAL_VIEWER - whether the viewpoint is local or remote. OpenGL calculates specular reflections using the "intermediate vector" h=s+v described earlier. The true directions s and v are different for each mesh vertex. If the light source is directional, then the s-magnitude vector is constant, but v still varies from vertex to vertex. Rendering speed increases if you make the vector v constant for all vertices. By default, OpenGL uses v=(0,0,1), with the vector pointing toward the positive z-axis in camera coordinates. At the same time, you can force the graphics pipeline to calculate the true value of the vector v for each vertex by executing the statement:

GlLightModel(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);

The param parameter must be a boolean and specifies the position of the observer. If it is FALSE, then the viewing direction is considered parallel to the z-axis, regardless of the position in view coordinates. If it is TRUE, then the observer is at the origin of the view coordinate system. This can improve the quality of lighting, but makes it more difficult to calculate. Default value: FALSE.;

GL_LIGHT_MODEL_TWO_SIDE - whether both sides of the polygon are painted correctly. The param parameter must be a boolean and controls the illumination calculation mode for both front and back faces. If it is FALSE, then the illumination is calculated only for the front faces. If it is TRUE, the calculation is carried out for the reverse faces as well. Default value: FALSE. Each polygonal face of the model has two sides. When modeling, you can consider the inside and outside. It is customary to list these vertices counterclockwise when viewed from the outside of the object. Most wireframe objects represent solid bodies that enclose some space, so that the concepts of outside and inside are clearly defined. For such objects, the camera can only observe the outer surface of each face (unless of course the camera is inside the object). With proper removal of invisible surfaces, the inner surface of each face is hidden from view by some closer face.

OpenGL has no concept of "inside" and "outside", it can only distinguish between "front faces" and "non-face faces". A face is front face if its vertices are listed counterclockwise, in the order that the eye sees them. You can reverse this order using the glFrontFace(GL_CW) function, which specifies that a face is front only if its vertices are listed in clockwise order. For an object that encloses some space, all the edges that the eye sees are front faces, and OpenGL draws and shades them correctly. Non-face faces are also drawn in OpenGL, but they end up being hidden behind the closer face faces. You can speed up the processor by disabling OpenGL rendering of non-face faces. The following code is used:

glCullFace(GL_BACK);

glEnable(GL_CULL_FACE);.

The situation is different in Error: Reference source not found, b, where a parallelepiped with one face removed is shown. As before, the arrows show the order in which the vertices of each face are sent to the graphics pipeline. Three of the visible faces are non-facing. By default, OpenGL cannot shade edges correctly. To properly paint non-face faces, you need to instruct OpenGL using the glLightModel (GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE) statement. When this command is executed, OpenGL changes the direction of the normals of all non-face faces so that they point towards the observer, after which shading occurs correctly. Changing the value GL_TRUE to GL_FALSE disables this option. Edges drawn with OpenGL cast no shadows, so all non-face faces receive the same light from the source, even if there is another face between them and the light source;

GL_LIGHT_MODEL_AMBIENT - global background light color. The params parameter must contain four integers or real numbers that specify the color of the background lighting even in the absence of certain light sources. For any given scene, you can set a global background light that is independent of any specific source. To create such lighting, set its color using the following commands:

GLfloat amb = (0.2, 0.3, 0.1, 1.0);

glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);

This code gives the background light source a color of (0.2, 0.3, 0.1). The default value is (0.2, 0.2, 0.2, 0.1), so the background light is always present unless you deliberately change it. Setting the background source to a non-zero value ensures that objects in the scene are visible even if you have not activated any lighting functions;

GL_LIGHT_MODEL_COLOR_CONTROL separation of the specular component of the color. For conventional illumination calculations, the background, diffuse, specular and emissive components are calculated and simply added together. By default, texture mapping is applied after lighting, so specular highlights may appear muted or texturing will look different. The next call to glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR) OpenGL separates the specular color calculation from the application. The lighting then generates two colors for each vertex: an initial color consisting of the non-reflected illuminance components, and a second color that is the sum of the specular illuminance components. When rendering textures, only the first color is combined with the texture colors. After the texturing operation is completed, the second color is added to the final combination of the first and texture color components. Objects that are lit and textured with specular color separation are typically more visible and have more noticeable specular highlights. To return to the default settings, you need to call glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR). After this, again the original color will consist of all the components of color: diffuse, diffuse, emissive and specular. Lighting components are not added after texturing.

Illumination of a space is a process through which this space is filled with light and all objects in it are made visible.
Lighting of any object depends on two factors:

  • The first is the material from which the object is made.
  • The second is the light with which it is illuminated.

Depending on the OpenGL implementation, there may be eight or more lights in the scene. Lighting is disabled by default. You can enable the null light source with the command:

  • glEnable(GL_LIGHT0);

The rest are enabled in a similar way, where GL_LIGHTi is specified instead of GL_LIGHT0. After the source is enabled, you need to set its parameters. If your monotonous body is evenly illuminated, then you cannot see its relief. Therefore we need to use light sources.
There are three types of light sources in OpenGL:

  • directional light source: located at infinity and has a dedicated lighting direction.
  • point light source: located at a specific point in space and shines evenly in all directions. You can set the effect of light fading with distance
  • spotlight: is a special case of a point source, but the light from it propagates only within the bounding cone, and not in all directions.

To control the properties of a light source, use the glLight* commands:

  • glLightf(GLenum light, GLenum pname, GLfloat param);
    glLightfv(GLenum light, GLenum pname, const GLfloat *param);

The light parameter tells OpenGL which light source to set the parameters for. The glLightf command is used to set scalar parameters, and glLightfv is used to set the vector characteristics of light sources.

First, let's look at the function that sets the basic settings. Once you have enabled lighting, you can already set the background lighting. By default, the background light value is (0.2, 0.2, 0.2, 1). Create new project, copy the template file there and turn off the lighting. You will have difficulty making out the sphere on the screen. With the glLightModel function you can set the background lighting. If you raise it to (1,1,1,1), i.e. to the maximum, then you do not need to turn on the light sources. You simply won’t notice their actions, because... the object is already maximally illuminated. And it turns out that you kind of turned off the lighting. Basically, add a call to the following function in main:

  • float ambient = (0.5, 0.5, 0.5, 1);
    ...
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);

Try changing the settings and see the result.

Material
The material can scatter, reflect and emit light. Material properties are set using the function

  • glMaterialfv(GLenum face, GLenum pname, GLtype* params)

The first parameter specifies the face for which properties are set. It can take one of the following values:

  • GL_BACK back face
    GL_FONT front face
    GL_FRONT_AND_BACK both faces

The second parameter of the glMaterialfv function specifies the material property to be set and can take the following values.

  • GL_AMBIENT ambient light
    GL_DIFFUSE is also diffuse light
    GL_SPECULAR reflected light
    GL_EMISSION emitted light
    GL_SHININESS degree of reflected light
    GL_AMBIENT_AND_DIFFUSE both ambient lights

The color is specified as an array of four elements - RGBA. In the case of GL_SHININESS, params points to a float number, which must be in the range from 0 to 128.
You just need to modify the display function.

  • void CALLBACK display(void)
    {
    GLUquadricObj *quadObj;
    GLfloat front_color = (0,1,0,1);
    GLfloat back_color = (0,0,1,1);
    quadObj = gluNewQuadric();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, front_color);
    glMaterialfv(GL_BACK, GL_DIFFUSE, back_color);
    glPushMatrix();
    glRotated(110, -1,1,0);
    gluCylinder(quadObj, 1, 0.5, 2, 10, 10);
    glPopMatrix();
    gluDeleteQuadric(quadObj);
    auxSwapBuffers();
    }

And you must enable the lighting mode for two faces. By default it is disabled. Add the following line to the main function.

  • glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);

Directional light sources
A light source of this type is located at infinity and the light from it propagates in a given direction. Ideal for creating uniform lighting. A good example of a directional light source is the Sun. For a directional light source, in addition to the radiation components, you can only set the direction.

  • GL_POSITION (0.0, 0.0, 1.0, 0.0) //(x, y, z, w) direction of the directional light source

The first three components (x, y, z) define the direction vector, and the w component is always equal to zero (otherwise the source will turn into a point source).

Decay functions
This is a function of changing the lighting intensity (light intensity does not decrease with distance), used in conjunction with spot lighting

  • GL_POSITION(0.0, 0.0, 1.0, 0.0)//position of the light source (by default the light source is directional)
  • GL_CONSTANT_ATTENUATION 1.0 //constant k_const in the attenuation function f(d)
  • GL_LINEAR_ATTENUATION 0.0 //coefficient k_linear for the linear term in the attenuation function f(d)
  • GL_QUADRATIC_ATTENUATION 0.0 //coefficient k_quadratic with the square of the distance in the attenuation function f(d)

Spotlights
One type of point source is a spotlight. All parameters are applicable to it as for a point source, but in addition, the spotlight allows you to limit the spread of light to a cone. For this cone, you can set the intensity decrease coefficient, depending on the angle between the axis of the cone and the light propagation beam.

  • GL_SPOT_DIRECTION (0.0, 0.0, -1.0) //(x, y, z) - spotlight direction (bounding cone axis)
  • GL_SPOT_CUTOFF 180.0 //angle between the axis and the side of the cone (aka half the angle at the vertex)
  • GL_SPOT_EXPONENT 0.0 //intensity decay exponential

Shadows
Shadows are not directly supported by the OpenGL library, so they need to be handled separately.

Without a light source, the image is not visible. To initialize the source and enable the processor for calculating the impact of the source on objects, simply execute the commands: glEnable(gl_lighting); // enable lighting analysis mode

GlEnable(gl_light0); // include a specific (zero) source in the scene, with its characteristics

To disable a source, use the Disable() function. By default, the light source is located in space with coordinates (0,0,∞). You can create a light source anywhere in image space.

The OpenGl library supports four types of light sources:

  • background lighting (ambient lighting),
  • point sources,
  • spotlights,
  • remote light sources (distant light).
Each light source has its own set of characteristics.
The characteristics of the light source correspond to the parameters of the Phong model.
To set vector parameters, use the glLightfv() function, which has the following format:

glLightfv(source, parameter, pointer_to_array);

There are four vector parameters that determine the position and direction of the source rays and the color composition of its components - background, diffuse and specular.
To set scalar parameters in OpenGL, use the glLightf() function:

glLightf(source, parameter, value);

Let, for example, you want to include in the scene the source GL_LIGHT0, which should be located at the point (1.0, 2.0, 3.0). The source position is saved in the program as a point in uniform coordinates:

GLfloat light0_pos=(1.0, 2.0, 3.0, 1.0);

If the fourth component of this point is zero, then the point source turns into a remote source, for which only the direction of the rays is significant:

GLfloat light0_dir=(1.0, 2.0, 3.0, 0.0);

Next, the color composition of the background, diffusion and specular components of the source is determined. If in the example under consideration the source has a specular component of white color, and the background and diffusion components should be red, then the program fragment that forms the source looks like this:

GLfloat diffise0= (1.0, 0.0, 0.0, 1.0);

GLfloat ambient0=(1.0, 0.0, 0.0, 1.0);

GLfloat specular0=(1.0, 1.0, 1.0, 1.0);

GlEnable(GL_LIGHTING);

GlEnable(GL_LIGHT0);

GlLightfv(GL_LIGHT0, GL_POSITION, light0_pos);

GlLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);

GlLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);

GlLightfv(GL_LIGHT0, GL_SPECULAR, specular0);

You can also include global background lighting in your scene, which is not associated with any individual light source. If, for example, you want to dimly highlight all objects in the scene with white, you should include the following piece of code in the program:

GLfloat global_ambient=(0.1, 0.1, 0.1, 1.0);

GlLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);

In the lighting model, the term that takes into account the distance to the source has the form:

K= 1/(a+ b*d+ c*d^2)

And constant, linear and quadratic components. The corresponding coefficients for each source are set individually using the scalar parameter setting function, for example:

GlLightf(GL_LIGHT0, GL_CONSTANT_ATTENATION, a);

To convert a point source into a spotlight, you need to specify the direction of the spotlight beam (GL_SPOT_DIRECTION), the indicator of the intensity distribution function (GL_SPOT_EXPONENT) and the beam scattering angle (GL_SPOT_CUTTOF). These parameters are set using the glLightf() and glLightfv() functions.

The default parameters for light sources are shown in Table 3.

Default settings for lights

Table 3

Parameter name Default value Content
GL_AMBIENT (0.0, 0.0, 0.0, 1.0) ambient RGBA intensity of light
GL_DIFFUSE (1.0, 1.0, 1.0, 1.0) diffuse RGBA intensity of light
GL_SPECULAR (1.0, 1.0, 1.0, 1.0) specular RGBA intensity of light
GL_POSITION (0.0, 0.0, 1.0, 0.0) (x, y, z, w) position of light
GL_SPOT_DIRECTION (0.0, 0.0, -1.0) (x, y, z) direction of spotlight
GL_SPOT_EXPONENT 0.0 spotlight exponent
GL_SPOT_CUTOFF 180.0 spotlight cutoff angle
GL_CONSTANT_ATTENUATION 1.0 constant attenuation factor
GL_LINEAR_ATTENUATION 0.0 linear attenuation factor
GL_QUADRATIC_ATTENUATION 0.0 quadratic attenuation factor

To create realistic images, it is necessary to determine both the properties of the object itself and the properties of the environment in which it is located. The first group of properties includes parameters of the material from which the object is made, methods of applying texture to its surface, and the degree of transparency of the object. The second group includes the number and properties of light sources, the level of transparency of the environment. All of these properties can be set using the appropriate OpenGL commands.

Material properties

To set the parameters of the current material, use the commands

void glMaterial(GLenum face, GLenum pname, GLtype param)
void glMaterialv(GLenum face, GLenum pname, GLtype *params)

With their help, you can determine the scattered, diffuse and specular colors of the material, as well as the color, the degree of specular reflection and the intensity of light emission if the object should glow. Which parameter will be determined by the value of param depends on the value of pname:

GL_AMBIENT The params parameter must contain four integer or real RGBA color values ​​that define the diffuse color of the material (the color of the material in the shadow).

Default value: (0.2, 0.2, 0.2, 1.0).

GL_DIFFUSE The params parameter must contain four integer or real RGBA color values ​​that specify the diffuse reflection color of the material.

Default value:(0.8, 0.8, 0.8, 1.0).

GL_SPECULAR The params parameter must contain four integer or real RGBA color values ​​that specify the material's specular color.

GL_SHININESS The params parameter must contain a single integer or real value in the range from 0 to 128, which determines the degree of specular reflection of the material.

Default value: 0.

GL_EMISSION The params parameter must contain four integer or real RGBA color values ​​that define the intensity of the material's emitted light.

Default value: (0.0, 0.0, 0.0, 1.0).

GL_AMBIENT_AND_DIFFUSE is equivalent to two calls to the glMaterial...() command with pname GL_AMBIENT and GL_DIFFUSE and the same params values.

It follows that the glMaterial() command can only be called to set the degree of specular reflection of the material. Most models take into account diffuse and specular reflected light; the first determines the natural color of the object, and the second determines the size and shape of the highlights on its surface.

The face parameter determines the type of faces for which this material is specified and can take the values ​​GL_FRONT, GL_BACK or GL_FRONT_AND_BACK.

If the object materials in the scene differ in only one parameter, it is recommended to first set the desired mode by calling glEnable() with the GL_COLOR_MATERIAL parameter, and then use the command

void glColorMaterial(GLenum face, GLenum pname)

where the face parameter has a similar meaning, and the pname parameter can take all of the listed values. The value of the pname-selected material property for a particular object (or vertex) is then set by calling glColor...(), avoiding calls to the more resource-intensive glMaterial...() command and increasing program efficiency.

You can add a light source to the scene using the commands

void glLight(GLenum light, GLenum pname, GLfloat param)
void glLight(GLenum light, GLenum pname, GLfloat *params)

The light parameter uniquely identifies the source and is selected from a set of special symbolic names like GL_LIGHTi, where i must be in the range from 0 to GL_MAX_LIGHT, which does not exceed eight.

The remaining two parameters have the same meaning as in the glMaterial...() command. Let's look at their purpose (first the parameters for the first command are described, then for the second):

GL_SPOT_EXPONENT the param parameter must contain an integer or real number from 0 to 128 that specifies the light intensity distribution. This parameter describes the level of focus of the light source.

Default value: 0 (diffused light).

GL_SPOT_CUTOFF param must contain an integer or real number between 0 and 90 or equal to 180, which defines the maximum light spread angle. The value of this parameter is half the angle at the vertex of the cone-shaped light flux created by the source.

Default value: 180 (diffused light).

GL_AMBIENT The params parameter must contain four integer or real RGBA color values ​​that specify the color of the background lighting.

Default value: (0.0, 0.0, 0.0, 1.0).

GL_DIFFUSE The params parameter must contain four integer or real RGBA color values ​​that specify the color of the diffuse lighting.

GL_SPECULAR The params parameter must contain four integer or real RGBA color values ​​that specify the color of the specular reflection.

Default value: (1.0, 1.0, 1.0, 1.0) for LIGHT0 and (0.0, 0.0, 0.0, 1.0) for others.

GL_POSITION the params parameter must contain four integers or reals that define the position of the light source. If the value of the w component is 0.0, then the source is considered to be infinitely distant and when calculating the illumination, only the direction to the point (x,y,z) is taken into account, otherwise the source is considered to be located at the point (x,y,z,w).

Default value: (0.0, 0.0, 1.0, 0.0).

GL_SPOT_DIRECTION The params parameter must contain four integers or real numbers that specify the direction of the light.

Default value: (0.0, 0.0, -1.0, 1.0).

When changing the position of the light source, the following facts should be taken into account: if the position is specified with the glLight...() command before determining the gaze orientation (with the glLookAt() command), then the source will be considered to be at the observation point. If the position is set between specifying the orientation and the view matrix transformations, then it is fixed and does not depend on the view transformations. In the latter case, when the position is specified after the orientation and the view matrix, its position can be changed by setting both a new orientation of the observer and changing the view matrix.

To use lighting, you first need to set the appropriate mode by calling the glEnable (GL_LIGHTNING) command, and then enable the desired source with the glEnable(GL_LIGHTn) command.

Lighting model

OpenGL uses the Phong lighting model, in which the color of a point is determined by several factors: material and texture properties, the magnitude of the normal at that point, and the position of the light source and observer. To correctly calculate the illumination at a point, it is necessary to use single normals, however, commands like glScale...() can change the length of the normals. To take this into account, the already mentioned normalization mode is used, which is enabled by calling the glEnable(GL_NORMALIZE) command.

To set global lighting parameters, use the commands

void glLightModel(GLenum pname, GLenum param)
void glLightModelv(GLenum pname, const GLtype *params)

The pname argument specifies which lighting model parameter will be adjusted and can take the following values:

GL_LIGHT_MODEL_LOCAL_VIEWER param must be a boolean and specifies the position of the observer. If it is FALSE, then the viewing direction is considered parallel to the -z axis, regardless of the position in view coordinates. If it is TRUE, then the observer is at the origin of the view coordinate system. This can improve the quality of lighting, but makes it more difficult to calculate.

Default value: FALSE.

GL_LIGHT_MODEL_TWO_SIDE The param parameter must be a boolean and controls the illumination calculation mode for both front and back faces. If it is FALSE, then the illumination is calculated only for the front faces. If it is TRUE, the calculation is carried out for the reverse faces as well. Default value: FALSE.

GL_LIGHT_MODEL_AMBIENT The params parameter must contain four integers or real numbers that specify the color of the background lighting even in the absence of certain light sources.

Default value:(0.2, 0.2, 0.2,1.0).

As you can see, we have introduced an additional normal matrix, it is necessary in order to transfer the object’s normals from the object’s local coordinate system to the world one, this is necessary to calculate lighting in the world coordinate system.

It is worth noting that when using FFP OpenGL, lighting was calculated not in the world coordinate system, but in the view coordinate system. In my opinion, this is not very convenient, because... The view coordinate system is connected to the camera, and it is convenient to set the lighting sources in the world coordinate system and it is there that the entire calculation is carried out.

Lighting calculation

The lighting calculations in this tutorial use the Phong shading model. The main idea of ​​the model is that the final illumination of an object consists of three components:

  • Background light (ambient)
  • Scattered light (diffuse)
  • Specular light

In addition to these parameters, we will add our own glow of the material (emission), this parameter allows you to highlight an object even if it is not illuminated by any light source.

Accordingly, each of the components is calculated taking into account the parameters of the light source and the material of the object. You can get more detailed information on this lighting model in this article.

Lighting calculations can be either per-vertex lighting or per-pixel lighting. In this lesson we will look at pixel-by-pixel lighting; it allows you to smooth out the insufficient detail of polygonal models and more accurately calculate the illumination at each point of the object. The main calculation of per-pixel lighting occurs in the fragment shader.

Before you start calculating lighting, you need to calculate and transfer some vertex parameters from the vertex shader to the fragment shader:

  • Normal to the surface of an object at a vertex (normal)
  • Direction of incident light, from vertex to light source (light direction)
  • View direction, from vertex to observer (view direction)
  • Distance from a point light source to the vertex (distance)

The normal to the surface of the object and the direction of the incident light are used to calculate diffuse and specular light, however, to calculate reflected light, you also need to additionally know the direction of the observer's view. The distance from the vertex to the light source is necessary to calculate the overall attenuation coefficient. The vertex shader will look like this:

#version 330 core #define VERT_POSITION 0 #define VERT_TEXCOORD 1 #define VERT_NORMAL 2 layout(location = VERT_POSITION) in vec3 position; layout(location = VERT_TEXCOORD) in vec2 texcoord; layout(location = VERT_NORMAL) in vec3 normal; // transformation parameters uniform struct Transform ( mat4 model; mat4 viewProjection; mat3 normal; vec3 viewPosition; ) transform; // parameters of a point light source uniform struct PointLight ( vec4 position; vec4 ambient; vec4 diffuse; vec4 specular; vec3 attenuation; ) light; // parameters for the fragment shader out Vertex ( vec2 texcoord; vec3 normal; vec3 lightDir; vec3 viewDir; float distance; ) Vert; void main(void) ( // convert the coordinates of the vertex to the world coordinate system vec4 vertex = transform.model * vec4(position, 1 .0 ) ; // direction from the vertex to the light source in the world coordinate system vec4 lightDir = light.position - vertex; // pass some parameters to the fragment shader // pass texture coordinates Vert.texcoord = texcoord; // pass the normal in the world coordinate system Vert.normal = transform.normal * normal; // pass the direction to the light source Vert.lightDir = vec3(lightDir) ; // transmit the direction from the vertex to the observer in the world coordinate system Vert.viewDir = transform.viewPosition - vec3(vertex) ; // transmit the distance from the vertex to the light source Vert.distance = length(lightDir) ; // convert the coordinates of the vertex to homogeneous ones gl_Position = transform.viewProjection * vertex; )

Share with friends or save for yourself:

Loading...