{"id":275,"date":"2023-07-18T16:11:36","date_gmt":"2023-07-18T16:11:36","guid":{"rendered":"https:\/\/www.infodreams.it\/main\/?page_id=275"},"modified":"2023-07-19T08:17:15","modified_gmt":"2023-07-19T08:17:15","slug":"dev-132-using-opengl-part-4-of-4","status":"publish","type":"page","link":"https:\/\/www.infodreams.it\/main\/publications\/dev-magazine\/dev-132-using-opengl-part-4-of-4\/","title":{"rendered":"Dev 132 \u2013 Using OpenGL \u2013 part 4 of 4"},"content":{"rendered":"<p><img decoding=\"async\" src=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/01_copertina.png?w=800&#038;ssl=1\" data-recalc-dims=\"1\" \/><\/p>\n<div class=\"entry-content\">\n<blockquote class=\"has-medium-font-size\"><p>\nThis is the last step of our journey: knowing the technical aspects of lighting sources and apply them to 2D objects to achieve a more realistic look.\n<\/p><\/blockquote>\n<h2><span id=\"Introduction\" class=\"ez-toc-section\"><\/span>Introduction<\/h2>\n<p class=\"has-medium-font-size\">The more advanced features of OpenGL are concerned, for the most part, the simulation of natural phenomena like light and materials. In this way, through the continuous development, an attempt to provide the library of characteristics such as to realize scenes increasingly close to reality.<\/p>\n<h2><span id=\"Let%E2%80%99s_turn_some_light_on\" class=\"ez-toc-section\"><\/span>Let\u2019s turn some light on<\/h2>\n<p class=\"has-medium-font-size\">When drawing primitives or creating solid objects, up to this moment, we are able to associate them a given RGB color. In the real world, however, we simply do not see things according to their absolute color. People knows that color is nothing more than an interpretation by our visual organs of a particular range of radiation, ie, the light. Usually that arises from a well-defined source and the color of objects varies depending on the position with respect to it. OpenGL can approximate the conditions of the real world through the use of three types of illumination:<\/p>\n<ol class=\"has-medium-font-size\">\n<li>The \u2018<strong>ambient light<\/strong>\u2018, which has a brightness that but don\u2019t comes from a specific direction, although having a source. When creating an \u2018ambient light\u2019 all the polygons of a scene are illuminated in the same manner.<\/li>\n<li>The \u2018<strong>scattered light<\/strong>\u2018. It represents that kind of light that is reflected in a uniform manner. In this way a surface becomes brighter when the rays emitted by the source strikes it perpendicularly.<\/li>\n<li>The \u2018<strong>specular light<\/strong>\u2018. It is similar to the previous unless the fact that, in this case, the rays from the source are reflected back to a particular direction. This effect generates, usually a bright spot on the reflecting surface as can the sunlight on the bodywork of a car.<\/li>\n<\/ol>\n<p class=\"has-medium-font-size\">The light, however, represents only a component of the equation. Indeed, we know that color and brightness of an object are also dependent on the material that constitutes it, and how this it reacts to light radiation.<\/p>\n<p class=\"has-medium-font-size\">Using the illumination we will not discuss any more about the color of a polygon in terms of RGB levels, but regarding the manner in which it reflects or absorbs certain wavelengths. We could create a blue ball or a metallic-looking cube or more similar to plastic one, simply by setting the properties of their constituent materials. Let\u2019s see how join it all together. To enable the use of light is sufficient the OpenGL call<\/p>\n<pre class=\"wp-block-code\"><code>glEnable(GL_LIGHTING)<\/code><\/pre>\n<p class=\"has-medium-font-size\">which enables the color calculation of each vertex according to the material and the type and position of the light source. Obviously, in the absence of the latter the scene would remain dark. First you need to set the three types of lighting via the function<\/p>\n<pre class=\"wp-block-code\"><code>void glLightfv(GLenum light, GLenum pname, const GLfloat * param)<\/code><\/pre>\n<p class=\"has-medium-font-size\">The first parameter of the function identifies the light source to which apply the settings. OpenGL provides a maximum of 8 light sources: from GL_LIGHT0 to GL_LIGHT7. The second parameter asks you to specify one of three types of light, ie<\/p>\n<ol class=\"has-medium-font-size\">\n<li><strong>GL_AMBIENT<\/strong> to set the values \u200b\u200bof ambient light<\/li>\n<li><strong>GL_DIFFUSE<\/strong> to set the values \u200b\u200bof the diffused light<\/li>\n<li><strong>GL_SPECULAR<\/strong> to set the values \u200b\u200bof the specular highlight<\/li>\n<li><strong>GL_POSITION<\/strong> to set the position of the light<\/li>\n<\/ol>\n<p class=\"has-medium-font-size\">Finally, the function, takes an array of 4 float which contains the settings of the source where the first three variables represent the intensity of the components between 0.0f and 1.0f. The value 1.0f to the fourth causes the light rays from spreading in all directions, while if it will be 0.0f as coming from an infinite distance. In the latter way the rays are processed as they are parallel to each other. In order to use the source must be set to activate it by calling<\/p>\n<pre class=\"wp-block-code\"><code>glEnable(GL_LIGHT0)<\/code><\/pre>\n<p class=\"has-medium-font-size\">Now it is necessary to make sure that the polygons has a material for reacting to the lighting. We enable the management of materials by<\/p>\n<pre class=\"wp-block-code\"><code>glEnable(GL_COLOR_MATERIAL)<\/code><\/pre>\n<p class=\"has-medium-font-size\">then we inform OpenGL about the properties of the polygons\u2019s faces with the function<\/p>\n<pre class=\"wp-block-code\"><code>void glColorMaterial(GLenum face, GLenum mode)<\/code><\/pre>\n<p class=\"has-medium-font-size\">The first parameter indicates to which face we want to apply that setting. The possible values \u200b\u200bare GL_FRONT, GL_BACK for front and back faces, while GL_FRONT_AND_BACK does it on both. The second parameter takes the values \u200b\u200bGL_EMISSION, GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_AMBIENT_AND_DIFFUSE. It say that the material must react accordingly to the color settings of the indicated light type. After that we just have to make the material with the mirror function between<\/p>\n<pre class=\"wp-block-code\"><code>void glMaterialfv(GLenum face, GLenum pname, const GLfloat * params)<\/code><\/pre>\n<p class=\"has-medium-font-size\">we make the call in this form<\/p>\n<pre class=\"wp-block-code\"><code>GLfloat reflectivity[] = {1.0f, 1.0f, 1.0f, 1.0f};\r\n...\r\nglMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, reflectivity);<\/code><\/pre>\n<p class=\"has-medium-font-size\">and set its level of reflectivity with<\/p>\n<pre class=\"wp-block-code\"><code>glMateriali(GL_FRONT, GL_SHINIESS, 128)<\/code><\/pre>\n<p class=\"has-medium-font-size\">The more the last parameter value is high \u2013 it can take up to 128 \u2013 the more mirror effect appears \u201cfocused\u201d, ie, the point generated is more defined and focused. Let\u2019s see a practical example, following listing shows a possible initialization GL_LIGHT0 light source and the material is a generic program.<\/p>\n<pre class=\"wp-block-code\"><code>\/\/ Array for the lights settings\r\nGLfloat ambientLight[] = {0.1f, 0.1f, 0.1f, 1.0f};\r\nGLfloat diffuseLight[] = {0.45f, 0.2f, 0.4f, 1.0f};\r\nGLfloat specularLight[] = {1.0f, 1.0f, 0.4f, 1.0f};\r\nGLfloat light0Position[] = {0.0f, 0.0f, 0.0f, 1.0f};\r\n\r\n\/\/ Array for reflectivity settings\r\nGLfloat reflectivity[] = {1.0f, 1.0f, 1.0f, 1.0f};\r\n\r\nvoid SetupRC()\r\n{\r\n    glClearColor(0.0f,0.0f,0.0f,1.0f);\r\n    glEnable(GL_DEPTH_TEST);\r\n    glShadeModel(GL_SMOOTH);\r\n\r\n    \/\/ Activates lighting \r\n    glEnable(GL_LIGHTING);\r\n\r\n    \/\/ Sets LIGHT0 components\r\n    glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);\r\n    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);\r\n    glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);\r\n    glLightfv(GL_LIGHT0, GL_POSITION, light0Position);\r\n\r\n    \/\/ Activates LIGHT0\r\n    glEnable(GL_LIGHT0);\r\n\r\n    \/\/ Enables materials\r\n    glEnable(GL_COLOR_MATERIAL);\r\n\r\n    \/\/ Sets materials reactivity to the \r\n    \/\/ and scattered light\r\n    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);\r\n\r\n    \/\/ Sets the reflectivity values\r\n    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, reflectivity);\r\n\r\n    \/\/ Sets the reflectivity level\r\n    glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 32);\r\n}<\/code><\/pre>\n<p class=\"has-medium-font-size\">The sample programs <strong>Luci.exe<\/strong> describes in practice the application of rules learned so far, <strong>Figure 1<\/strong> is an image taken from the example. Now everything is ready and OpenGL is able to properly manage the light source, but we have not put any object in the scene. Even if we had done the result was not what was intended, and this is because it was not introduced an additional concept: the normals.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" class=\"wp-image-4637\" src=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/Figura1_4.png?w=800&#038;ssl=1\" sizes=\"(max-width: 408px) 100vw, 408px\" alt=\"\" data-recalc-dims=\"1\" \/><figcaption>Figure 1 \u2013 Example of lighting on an object<\/figcaption><\/figure>\n<\/div>\n<p class=\"has-medium-font-size\">A normal is nothing but the vector perpendicular to the plane where a polygon is placed, so it is used to determine the angle of inclination between it and a light source. It is clear that if this angle is equal to zero the light is placed perpendicularly to the figure so the polygon will be better illuminated. Otherwise, when the angle increases, the quantity of reflected light decreases.<\/p>\n<p class=\"has-medium-font-size\">There are no specific functions for calculating the normal of a polygon and, without dwelling too much on the subject, I recommend you use the library \u2018gltools\u2019 that you will find on the FTP site. This provides the function<\/p>\n<pre class=\"wp-block-code\"><code>gltGetNormalVector(GLTVector VP1, GLTVector VP2, GLTVector VP3, GLTVector vNormal)<\/code><\/pre>\n<p class=\"has-medium-font-size\">The variable GLTVector is an array of three floats containing the coordinates of one vertex of the polygon. The parameter vNormal is the result of the calculation and should be passed to the function<\/p>\n<pre class=\"wp-block-code\"><code>glNormal3fv(const GLfloat * v)<\/code><\/pre>\n<p class=\"has-medium-font-size\">which accepts an array of float in place of the vector representing the normal. Look following listing for a clearer idea of \u200b\u200bhow to implement proper handling of normals.<\/p>\n<pre class=\"wp-block-code\"><code>\/\/ Create the walls by storing them in a list\r\nvoid drawWalls()\r\n{\r\n    GLint i, j;\r\n\r\n    \/\/ Creates a new list \r\n    glNewList(1, GL_COMPILE);\r\n\r\n    \/\/ Set the color for bottom wall\r\n    glColor3f(1.0f, 1.0f, 1.0f);\r\n\r\n    \/\/ Bottom wall\r\n    glBegin(GL_QUADS);\r\n\r\n    for (i = -HALF_WALL_SIZE; i &lt; HALF_WALL_SIZE - STEP; i+=STEP)\r\n    {\r\n        for (j = -HALF_WALL_SIZE; j &lt; HALF_WALL_SIZE - STEP; j += STEP)\r\n        {\r\n            \/\/ Creates a vector array containing\r\n            \/\/ the coordinates of wall's vertices\r\n            GLTVector3 points[4] = {{j, 0, i+STEP}, {j+STEP, 0, i+STEP}, {j+STEP, 0, i}, {j, 0, i}};\r\n\r\n            \/\/ Calculation of the normal of three points\r\n            gltGetNormalVector(points[0], points[1], points[2], vNormal);\r\n\r\n            \/\/ Sets the normal\r\n            glNormal3fv(vNormal);\r\n\r\n            \/\/ Sets vertex values\r\n            glVertex3fv(points[0]);\r\n            glVertex3fv(points[1]);\r\n            glVertex3fv(points[2]);\r\n            glVertex3fv(points[3]);\r\n        }\r\n    }\r\n\r\n    glEnd();\r\n\r\n    \/\/ Right lateral\r\n    glBegin(GL_QUADS);\r\n\r\n    for (i = 0; i &lt; WALL_SIZE; i+=STEP)\r\n    {\r\n        for (j = -HALF_WALL_SIZE; j &lt; HALF_WALL_SIZE - STEP; j += STEP)\r\n        {\r\n            \/\/ Creates a vector array containing\r\n            \/\/ the coordinates of wall's vertices\r\n            GLTVector3 points[4] = {{j, i, -HALF_WALL_SIZE}, {j+STEP, i, -HALF_WALL_SIZE}, {j+STEP, i+STEP, -HALF_WALL_SIZE}, {j, i+STEP, -HALF_WALL_SIZE}};\r\n\r\n            \/\/ Calculation of the normal of three points\r\n            gltGetNormalVector(points[0], points[1], points[2], vNormal);\r\n\r\n            \/\/ Sets the normal\r\n            glNormal3fv(vNormal);\r\n\r\n            \/\/ Sets vertex values\r\n            glVertex3fv(points[0]);\r\n            glVertex3fv(points[1]);\r\n            glVertex3fv(points[2]);\r\n            glVertex3fv(points[3]);\r\n        }\r\n    }\r\n\r\n    glEnd();\r\n\r\n    \/\/ Left lateral\r\n    glBegin(GL_QUADS);\r\n\r\n    for (i = 0; i &lt; WALL_SIZE; i+=STEP)\r\n    {\r\n        for (j = -HALF_WALL_SIZE; j &lt; HALF_WALL_SIZE - STEP; j += STEP)\r\n        {\r\n            \/\/ Creates a vector array containing\r\n            \/\/ the coordinates of wall's vertices\r\n            GLTVector3 points[4] = {{HALF_WALL_SIZE-STEP, i, j+STEP}, {HALF_WALL_SIZE-STEP, i+STEP, j+STEP}, {HALF_WALL_SIZE-STEP, i+STEP, j}, {HALF_WALL_SIZE-STEP, i, j}};\r\n\r\n            \/\/ Calculation of the normal of three points\r\n            gltGetNormalVector(points[0], points[1], points[2], vNormal);\r\n\r\n            \/\/ Sets the normal\r\n            glNormal3fv(vNormal);\r\n\r\n            \/\/ Sets vertex values\r\n            glVertex3fv(points[0]);\r\n            glVertex3fv(points[1]);\r\n            glVertex3fv(points[2]);\r\n            glVertex3fv(points[3]);\r\n        }\r\n    }\r\n\r\n    glEnd();\r\n\r\n    \/\/ Closes the list\r\n    glEndList();\r\n}<\/code><\/pre>\n<p class=\"has-medium-font-size\">You\u2019ll also notice the function<\/p>\n<pre class=\"wp-block-code\"><code>glNewList(1, GL_COMPILE)<\/code><\/pre>\n<p class=\"has-medium-font-size\">This instruction causes the OpenGL compiles all commands that meets for fast execution the next call<\/p>\n<pre class=\"wp-block-code\"><code>glEndList()<\/code><\/pre>\n<p class=\"has-medium-font-size\">Whenever you need to list just call the function<\/p>\n<pre class=\"wp-block-code\"><code>glCallList(1)<\/code><\/pre>\n<h2><span id=\"Textures\" class=\"ez-toc-section\"><\/span>Textures<\/h2>\n<p class=\"has-medium-font-size\">Filling a polygon through a simple color often is not sufficient to meet our requirements. An important feature that each 3D graphics library provides is the possibility of using an image to fill the polygons. This technique is called \u2018texture mapping\u2019. We can create very convincing scenes providing to objects a near-real appearance. We have already seen, in the first article, an example of texture mapping.<\/p>\n<p class=\"has-medium-font-size\">The first thing we must do to use textures in a program is to load the images. To this end we will use the function<\/p>\n<pre class=\"wp-block-code\"><code>void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid * data)<\/code><\/pre>\n<p class=\"has-medium-font-size\">That enormous amount of parameters have to provide all the information needed to correctly interpret the data pointed by \u2018data\u2019 array. Let\u2019s look at the meaning of each one<\/p>\n<ul class=\"has-medium-font-size\">\n<li><strong>target<\/strong> must be set to GL_TEXTURE_2D[(\/li)] and represents the type of texture, but we will not cover this topic.<\/li>\n<li><strong>level<\/strong> when set to 0 specifies the level of mipmap. We will not cover this topic.<\/li>\n<li><strong>internalformat<\/strong> specifies the format to use for organizing data in memory when they are loaded. It can be set to GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA. Usually, this parameter is set to GL_RGB and GL_RGBA.<\/li>\n<li><strong>width<\/strong>, <strong>height<\/strong> represents the dimensions of the image. It is very important to know that the image can have the following measures following powers of 2 ie 4\u00d72, 64\u00d7128, 4096\u00d71024 and so on \u2026<\/li>\n<li><strong>border<\/strong> serves to create a border for the image. Set it to 0.<\/li>\n<li><strong>format<\/strong> indicates the the format of provided image data. There are many values \u200b\u200bthat this parameter can assume, but the most common are GL_RGB and GL_RGBA.<\/li>\n<li><strong>type<\/strong> is the data type used for express image data. For images at 24 or 32-bit the correct setting is GL_UNSIGNED_BYTE<\/li>\n<li><strong>data<\/strong> is the array containing the image<\/li>\n<\/ul>\n<p class=\"has-medium-font-size\">As was obvious to expect, OpenGL has no function to load image from files. We use the function contained in the file LoadTGA.c.<\/p>\n<p class=\"has-medium-font-size\">Before using a texture we must set other parameters. First we must define what happens when it is resized, ie, when the distance of the object to the observer changes:<\/p>\n<pre class=\"wp-block-code\"><code>glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\r\nglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);<\/code><\/pre>\n<p class=\"has-medium-font-size\">In short we will ensure that OpenGL will use a filter that blurs the edges slightly on enlarged pixel, or when the objects go far away, avoiding the unsightly jagged. Even the texture management must be enabled<\/p>\n<pre class=\"wp-block-code\"><code>glEnable(GL_TEXTURE_2D)<\/code><\/pre>\n<p class=\"has-medium-font-size\">Once the image have been loaded we have to map it on the target polygon. This must be done during the vertices specification phase calling<\/p>\n<pre class=\"wp-block-code\"><code>glTexCoord2f(GLfloat s, GLfloat t)<\/code><\/pre>\n<p class=\"has-medium-font-size\">Each coordinate is associated with the following vertex and can vary between 0.0 and 1.0 regardless of the size of the image. The following code associates a generic image of a triangle<\/p>\n<pre class=\"wp-block-code\"><code>glBegin(GL_TRIANGLE);\r\n    glTexCoord2f(0.0f, 0.0f);\r\n    glVertex3f(0.0f, 0.0f, 0.0f);\r\n    glTexCoord2f(0.5f, 1.0f);\r\n    glVertex3f(5.0f, 10.0f, 0.0f);\r\n    glTexCoord2f(1.0f, 0.0f);\r\n    glVertex3f(10.0f, 0.0f, 0.0f);\r\nglEnd();<\/code><\/pre>\n<p class=\"has-medium-font-size\">In <strong>Figure 2<\/strong> you can see the output of the program Texture.exe. By now you should become familiar with our programs, so studying the code should not be so difficult an undertaking.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" class=\"wp-image-4643\" src=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/Figura2_4.png?w=800&#038;ssl=1\" sizes=\"(max-width: 408px) 100vw, 408px\" alt=\"\" data-recalc-dims=\"1\" \/><figcaption>Figure 2 \u2013 On the scene there are two objects, the teapot and the horizontal plane, each associated with its own texture<\/figcaption><\/figure>\n<\/div>\n<h2><span id=\"The_fog_effect\" class=\"ez-toc-section\"><\/span>The fog effect<\/h2>\n<p class=\"has-medium-font-size\">A very simple to use with OpenGL is fogging which is applied at the end of all operations related to the color. It determines how to mix the color, of the geometry present in the scene, with that choosen for the mist. It is also possible to vary the density values \u200b\u200band the equations that generate a different effect on distant of objects, from the point of observation. To use the effect, simply follow these steps<\/p>\n<pre class=\"wp-block-code\"><code>\/\/ Initialize an array of four GLfloat\r\n\/\/ containing the fog color\r\nGLfloat fogColor[] = {0.7f, 0.7f, 0.7f, 1.0f};\r\n\r\n\/\/ Enable the effect\r\nglEnable(GL_FOG);\r\n\r\n\/\/ Sets the fog color\r\nglFogfv(GL_FOG_COLOR, fogColor);\r\n\r\n\/\/ Sets the distance from the observer, the\r\n\/\/ start of the fog bank\r\nglFogf(GL_FOG_START, 5.0f);\r\n\r\n\/\/ Sets the distance where this ends\r\nglFogf(GL_FOG_END, 30.0f);\r\n\r\n\/\/ Indicates the equation of fog densification\r\nglFogi(GL_FOG_MODE, GL_LINEAR);\r\n\r\n\/\/ Sets the density of the fog\r\nglFogf(GL_FOG_DENSITY, 0.5f);<\/code><\/pre>\n<p class=\"has-medium-font-size\">This is it. The only observation that can be made in the last statement is that OpenGL allows you to change the method that fog thickening is calculated, as a function of the distance from the observer. Indeed, we can specify additional parameters in addition to GL_LINEAR as GL_EXP and GL_EXP2. Choosing such equations we get an exponential thickening effect more pronounced only at big distances.<\/p>\n<h2><span id=\"Blending\" class=\"ez-toc-section\"><\/span>Blending<\/h2>\n<p class=\"has-medium-font-size\">We know by now that images are drawn in the color buffer by overlaping values. We may be interested to enable the blending<\/p>\n<pre class=\"wp-block-code\"><code>glEnable(GL_BLEND)<\/code><\/pre>\n<p class=\"has-medium-font-size\">so that the new figures in the process of being drawn inside the color buffer will be combined with the existing ones.<br \/>\nThere are several ways to combine the color of two images and each one can generate a particular effect, such as, for example, the transparency.<\/p>\n<p class=\"has-medium-font-size\">To proceed, you must know the terminology commonly used. The existing color in the color buffer is called the target, while the one that is being written is the source. To determine how the two colors will be combined we have to use the following equation<\/p>\n<pre class=\"wp-block-code\"><code>Cf = (Cs * S) + (Cd * D)<\/code><\/pre>\n<p class=\"has-medium-font-size\">where: Cf is the final color, Cs is the source and CD the destination. S and D are the factors to scale source and destination colors. These factors are required by<\/p>\n<pre class=\"wp-block-code\"><code>glBlendFunc(GLenum S, GLenum D)<\/code><\/pre>\n<p class=\"has-medium-font-size\">Below the possible values \u200b\u200bfor these parameters<\/p>\n<table class=\"wp-block-table aligncenter is-style-stripes\">\n<tbody>\n<tr>\n<td><strong>Function<\/strong><\/td>\n<td><strong>RGB Blend Factor<\/strong><\/td>\n<td><strong>Alpha Blend Factor<\/strong><\/td>\n<\/tr>\n<tr>\n<td>GL_ZERO<\/td>\n<td>(0, 0, 0)<\/td>\n<td>0<\/td>\n<\/tr>\n<tr>\n<td>GL_ONE<\/td>\n<td>(1, 1, 1)<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>GL_SRC_COLOR<\/td>\n<td>(Rs, Gs, Bs)<\/td>\n<td>As<\/td>\n<\/tr>\n<tr>\n<td>GL_ONE_MINUS_SRC_COLOR<\/td>\n<td>(1, 1, 1) \u2013 (Rs, Gs, Bs)<\/td>\n<td>1 \u2013 As<\/td>\n<\/tr>\n<tr>\n<td>GL_DST_COLOR<\/td>\n<td>(Rd, Gd, Bd)<\/td>\n<td>Ad<\/td>\n<\/tr>\n<tr>\n<td>GL_ONE_MINUS_DST_COLOR<\/td>\n<td>(1, 1, 1) \u2013 (Rd, Gd, Bd)<\/td>\n<td>1 \u2013 Ad<\/td>\n<\/tr>\n<tr>\n<td>GL_SRC_ALPHA<\/td>\n<td>(As, As, As)<\/td>\n<td>As<\/td>\n<\/tr>\n<tr>\n<td>GL_ONE_MINUS_SRC_ALPHA<\/td>\n<td>(1, 1, 1) \u2013 (As, As, As)<\/td>\n<td>1 \u2013 As<\/td>\n<\/tr>\n<tr>\n<td>GL_DST_ALPHA<\/td>\n<td>(Ad, Ad, Ad)<\/td>\n<td>Ad<\/td>\n<\/tr>\n<tr>\n<td>GL_ONE_MINUS_DST_ALPHA<\/td>\n<td>(1, 1, 1) \u2013 (Ad, Ad, Ad)<\/td>\n<td>1 \u2013 Ad<\/td>\n<\/tr>\n<tr>\n<td>GL_CONSTANT_COLOR<\/td>\n<td>(Rc, Gc, Bc)<\/td>\n<td>Ac<\/td>\n<\/tr>\n<tr>\n<td>GL_ONE_MINUS_CONSTANT_COLOR<\/td>\n<td>(1, 1, 1) \u2013 (Rc, Gc, Bc)<\/td>\n<td>1 \u2013 Ac<\/td>\n<\/tr>\n<tr>\n<td>GL_CONSTANT_ALPHA<\/td>\n<td>(Ac, Ac, Ac)<\/td>\n<td>Ac<\/td>\n<\/tr>\n<tr>\n<td>GL_ONE_MINUS_CONSTANT_ALPHA<\/td>\n<td>(1, 1, 1) \u2013 (Ac, Ac, Ac)<\/td>\n<td>1 \u2013 Ac<\/td>\n<\/tr>\n<tr>\n<td>GL_SRC_ALPHA_SATURATE<\/td>\n<td>(f, f, f)<\/td>\n<td>1<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"has-medium-font-size\">We see now a classic example. This is the most common approach to generate a transparency effect<\/p>\n<pre class=\"wp-block-code\"><code>glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)<\/code><\/pre>\n<p class=\"has-medium-font-size\">Here\u2019s what happens if the buffer is red-colored {1.0f, 0.0f, 0.0f, 0.0f}, while the color to be drawn is blue with an alpha value set to 0.5f {0.0f, 0.0f, 1.0f, 0.5f}. We have that<\/p>\n<pre class=\"wp-block-code\"><code>Cd = {1.0f, 0.0f, 0.0f, 1.0f}\r\nCs = {0.0f, 0.0f, 1.0f, 0.5f}\r\nS = source level of alpha = 0.5f\r\nD = 1 - 0.5f = 0.5f<\/code><\/pre>\n<p class=\"has-medium-font-size\">The equation takes the form<\/p>\n<pre class=\"wp-block-code\"><code>Cf = (Cs * 0.5f) + (Cd * 0.5f) = {0.5, 0.0f, 0.0f, 0.0f} + {0.0f, 0.0f, 0.5f, 0.5f} = {0.5f, 0.0f, 0.5f, 0.5f}<\/code><\/pre>\n<p class=\"has-medium-font-size\">generating a dark purple.<\/p>\n<h2><span id=\"Conclusions\" class=\"ez-toc-section\"><\/span>Conclusions<\/h2>\n<p class=\"has-medium-font-size\">I hope I was clear enough and comprehensive because facing a complex subject does not suffice an entire book. It is very important, therefore, that you refer to the official OpenGL specifications (which can be found inside the Demo package) to learn more about the functions and parameters that shall be accepted.<\/p>\n<p class=\"has-medium-font-size\">There are many features, in fact, I have not had a chance to show for obvious reasons. Perhaps I will return to discuss issues related to OpenGL programming, but it also depends on you. Write and participate with questions and suggestions. Let us know if our work is useful for you or, in some way, interesting.<\/p>\n<h2><span id=\"Bibliography\" class=\"ez-toc-section\"><\/span>Bibliography<\/h2>\n<ol class=\"has-medium-font-size\">\n<li>Richard S.Wright jr. and Benjamin Lipchak, \u201cOpenGL SuperBible \u2013 Third Edition\u201d, SAMS, 2005, ISBN 0-672-32601-9<\/li>\n<\/ol>\n<h2><span id=\"Original_article\" class=\"ez-toc-section\"><\/span>Original article<\/h2>\n<ul class=\"wp-block-gallery columns-3 is-cropped\">\n<li class=\"blocks-gallery-item\">\n<figure><a href=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/01_copertina.png?ssl=1\"><img decoding=\"async\" class=\"wp-image-4581\" src=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/01_copertina.png?w=800&#038;ssl=1\" alt=\"\" data-id=\"4581\" data-recalc-dims=\"1\" data-recalc-dims=\"1\" \/><\/a><\/figure>\n<\/li>\n<li class=\"blocks-gallery-item\">\n<figure><a href=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/02_editoriale.png?ssl=1\"><img decoding=\"async\" class=\"wp-image-4583\" src=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/02_editoriale.png?w=800&#038;ssl=1\" sizes=\"(max-width: 684px) 100vw, 684px\" alt=\"\" data-id=\"4583\" data-recalc-dims=\"1\" data-recalc-dims=\"1\" \/><\/a><\/figure>\n<\/li>\n<li class=\"blocks-gallery-item\">\n<figure><a href=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/03_indice.png?ssl=1\"><img decoding=\"async\" class=\"wp-image-4585\" src=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/03_indice.png?w=800&#038;ssl=1\" sizes=\"(max-width: 684px) 100vw, 684px\" alt=\"\" data-id=\"4585\" data-recalc-dims=\"1\" data-recalc-dims=\"1\" \/><\/a><\/figure>\n<\/li>\n<li class=\"blocks-gallery-item\">\n<figure><a href=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/04_indice_2.png?ssl=1\"><img decoding=\"async\" class=\"wp-image-4587\" src=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/04_indice_2.png?w=800&#038;ssl=1\" sizes=\"(max-width: 684px) 100vw, 684px\" alt=\"\" data-id=\"4587\" data-recalc-dims=\"1\" data-recalc-dims=\"1\" \/><\/a><\/figure>\n<\/li>\n<li class=\"blocks-gallery-item\">\n<figure><a href=https:\/\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/20_articolo_pg16.png\"><img decoding=\"async\" class=\"wp-image-4619\" src=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/20_articolo_pg16.png?w=800&#038;ssl=1\" sizes=\"(max-width: 683px) 100vw, 683px\" alt=\"\" data-id=\"4619\" data-recalc-dims=\"1\" data-recalc-dims=\"1\" \/><\/a><\/figure>\n<\/li>\n<li class=\"blocks-gallery-item\">\n<figure><a href=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/21_articolo_pg17.png?ssl=1\"><img decoding=\"async\" class=\"wp-image-4621\" src=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/21_articolo_pg17.png?w=800&#038;ssl=1\" sizes=\"(max-width: 683px) 100vw, 683px\" alt=\"\" data-id=\"4621\" data-recalc-dims=\"1\" data-recalc-dims=\"1\" \/><\/a><\/figure>\n<\/li>\n<li class=\"blocks-gallery-item\">\n<figure><a href=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/22_articolo_pg18.png?ssl=1\"><img decoding=\"async\" class=\"wp-image-4623\" src=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/22_articolo_pg18.png?w=800&#038;ssl=1\" sizes=\"(max-width: 683px) 100vw, 683px\" alt=\"\" data-id=\"4623\" data-recalc-dims=\"1\" data-recalc-dims=\"1\" \/><\/a><\/figure>\n<\/li>\n<li class=\"blocks-gallery-item\">\n<figure><a href=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/23_articolo_pg19.png?ssl=1\"><img decoding=\"async\" class=\"wp-image-4625\" src=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/23_articolo_pg19.png?w=800&#038;ssl=1\" sizes=\"(max-width: 683px) 100vw, 683px\" alt=\"\" data-id=\"4625\" data-recalc-dims=\"1\" data-recalc-dims=\"1\" \/><\/a><\/figure>\n<\/li>\n<li class=\"blocks-gallery-item\">\n<figure><a href=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/24_articolo_pg20.png?ssl=1\"><img decoding=\"async\" class=\"wp-image-4627\" src=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/24_articolo_pg20.png?w=800&#038;ssl=1\" sizes=\"(max-width: 683px) 100vw, 683px\" alt=\"\" data-id=\"4627\" data-recalc-dims=\"1\" data-recalc-dims=\"1\" \/><\/a><\/figure>\n<\/li>\n<li class=\"blocks-gallery-item\">\n<figure><a href=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/25_articolo_pg21.png?ssl=1\"><img decoding=\"async\" class=\"wp-image-4629\" src=\"https:\/\/i0.wp.com\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/25_articolo_pg21.png?w=800&#038;ssl=1\" sizes=\"(max-width: 683px) 100vw, 683px\" alt=\"\" data-id=\"4629\" data-recalc-dims=\"1\" data-recalc-dims=\"1\" \/><\/a><\/figure>\n<\/li>\n<\/ul>\n<h2><span id=\"Downloads\" class=\"ez-toc-section\"><\/span>Downloads<\/h2>\n<div class=\"wp-block-file\"><a href=\"https:\/\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/132_demo.zip\">132_demo<\/a><a class=\"wp-block-file__button\" href=\"https:\/\/www.infodreams.it\/Assets\/pubblicazioni\/dev\/132\/132_demo.zip\" download=\"\">Download<\/a><\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>This is the last step of our journey: knowing the technical aspects of lighting sources and apply them to 2D objects to achieve a more realistic look. Introduction The more &#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":33,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-275","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.infodreams.it\/main\/wp-json\/wp\/v2\/pages\/275","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.infodreams.it\/main\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.infodreams.it\/main\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.infodreams.it\/main\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.infodreams.it\/main\/wp-json\/wp\/v2\/comments?post=275"}],"version-history":[{"count":10,"href":"https:\/\/www.infodreams.it\/main\/wp-json\/wp\/v2\/pages\/275\/revisions"}],"predecessor-version":[{"id":279,"href":"https:\/\/www.infodreams.it\/main\/wp-json\/wp\/v2\/pages\/275\/revisions\/279"}],"up":[{"embeddable":true,"href":"https:\/\/www.infodreams.it\/main\/wp-json\/wp\/v2\/pages\/33"}],"wp:attachment":[{"href":"https:\/\/www.infodreams.it\/main\/wp-json\/wp\/v2\/media?parent=275"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}