{
Haha, these two lessons have been translated a long time ago, but they haven’t been posted yet. Everyone has been waiting for a long time (is anyone waiting any longer?)
simple transparency
The vast majority of special effects in OpenGL are related to some type of (color) mixing.
Color mixing is defined as combining the color of a certain pixel with the color of its corresponding pixel drawn on the screen.
How the two colors are combined depends on the values of the alpha channel components of the color, and/or the color mixing function used.
Alpha is usually the 4th color component at the end of the color value.
In the previous lessons we used GL_RGB to specify the three components of color.
The corresponding GL_RGBA can specify the value of the alpha component.
Going a step further, we can use glColor4f() instead of glColor3f().
Most people agree that the Alpha component represents the transparency of a material.
This means that an alpha value of 0.0 represents a material that is completely transparent.
An alpha value of 1.0 represents a material that is completely opaque.
color mixing formula
If you're not interested in math and just want to see how to achieve transparency, skip this section.
If you want a deeper understanding of how (color) mixing works, this section should be for you.
『CKER’s addition: It’s actually not difficult^-^. The formula in the original article is as follows, let CKER talk about it again.
In fact, the basic principle of mixing is to separate the color of each pixel and the background color of the image to be separated according to RGB rules.
According to - RGB color component of the image * alpha value + RGB color component of the background * (1-alpha value)
-After mixing with such a simple formula, the RGB components obtained by mixing are finally re-merged. 』
The formula is as follows:
(Rs Sr + Rd Dr, Gs Sg + Gd Dg, Bs Sb + Bd Db, As Sa + Ad Da)
OpenGL calculates the color mixing result of these two pixels according to the above formula.
The lowercase s and r represent source pixels and target pixels respectively. The uppercase S and D are the corresponding color mixing factors.
These determine how you mix colors for those pixels.
In most cases, the alpha mixing values of each color channel are the same.
In this way, we have (As, As, As, As) for the source pixel,
The target pixels are 1, 1, 1, 1) - (As, As, As, As).
The above formula becomes the following:
(Rs As + Rd (1 - As), Gs As + Gd (1 - As), Bs As + Bs (1 - As), As As + Ad (1 - As))
This formula produces a transparent/translucent effect.
Color mixing in OpenGL
The steps to implement color mixing in OpenGL are similar to the OpenGL process we mentioned before.
Then set the formula and turn off the write depth cache when drawing transparent objects.
Because we want to draw the object behind a semi-transparent shape.
This isn't the correct way to mix colors, but most of the time it works fine on simple projects.
Rui Martins' addition: The correct color mixing process should be to draw the entire scene first and then draw the transparent graphics.
And they are drawn in reverse order of the depth buffer (the furthest objects are drawn first).
Consider alpha blending two polygons (1 and 2). Different drawing orders will give different results.
(Here it is assumed that polygon 1 is closest to the observer, then the correct process should draw polygon 2 first, and then draw polygon 1.
As you can see in reality,
The light coming from behind these two <transparent> polygons always passes through polygon 2 first.
Then it passes through polygon 1, and finally reaches the observer's eyes. )
When depth caching is enabled, you should sort transparent graphics by depth,
And draw these transparent objects after all scenes are drawn. Otherwise you will get incorrect results.
I know it's painful to do this some of the time, but it's the right way to do it.
We will use the code from Lesson 7.
Start by adding two new variables at the beginning of the code. I rewrote the entire code for clarity.
}
Var
h_RC: HGLRC; // Rendering Context (shading description table).
h_DC: HDC; // Device Context (device description table)
h_Wnd: HWND; // window handle
h_Instance: HINST; // Program Instance (instance).
keys : Array[0..255] Of Boolean; // Array for keyboard routines
light : Boolean; // light source on/off
blend : Boolean; // Blending OFF/ON? (new)
lp : Boolean; // Is the L key pressed?
fp : Boolean; // Is the F key pressed?
bp : Boolean; // Is the B key pressed? (New)
xrot : GLfloat; // X rotation
yrot : GLfloat; // Y rotation
xspeed : GLfloat; // X rotation speed
yspeed : GLfloat; // Y rotation speed
z : GLfloat = -5.0 f; // Distance deep into the screen
LightAmbient: Array[0..3] Of GLfloat = (0.5, 0.5, 0.5, 1.0); //Ambient light parameters (new)
LightDiffuse: Array[0..3] Of GLfloat = (1.0, 1.0, 1.0, 1.0); // Diffuse light parameters (new)
LightPosition: Array[0..3] Of GLfloat = (0.0, 0.0, 2.0, 1.0); // Light source position (new)
filter : GLuint; // Filter type
texture : Array[0..2] Of GLuint; // Storage space for 3 textures
PRocedure glGenTextures(n: GLsizei; Var textures: GLuint); stdcall; external
opengl32;
Procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external
opengl32;
Function gluBuild2DMipmaps(target: GLenum; components, width, height: GLint;
format, atype: GLenum; data: Pointer): Integer; stdcall; external glu32 name
'gluBuild2DMipmaps';
{
Then move down to LoadGLTextures().
Find if (TextureImage[0]=LoadBMP('Data/Crate.bmp'))
This line. We are now using a tinted glass texture in place of the wooden box texture from the previous lesson.
if (TextureImage[0]=LoadBMP("Data/glass.bmp")); // Load glass bitmap (modified)
}
Function LoadTexture: boolean; //Load the bitmap and convert it into a texture
Var
Status : boolean; // Status indicator
TextureImage : Array[0..1] Of PTAUX_RGBImageRec; // Create texture storage space
Begin
Status := false;
ZeroMemory(@TextureImage, sizeof(TextureImage)); // Set pointer to NULL
TextureImage[0] := LoadBMP('Walls.bmp');
If TextureImage[0] <> Nil Then
Begin
Status := TRUE; // Set Status to TRUE
glGenTextures(1, texture[0]); // Create texture
// Create Nearest filter map
glBindTexture(GL_TEXTURE_2D, texture[0]);
// Generate texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // (new)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // (new)
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
TextureImage[0].data);
glBindTexture(GL_TEXTURE_2D, texture[1]); //Use a typical texture generated from bitmap data
// Generate texture
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
TextureImage[0].data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Linear filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear filtering
//Create MipMapped texture
glBindTexture(GL_TEXTURE_2D, texture[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_NEAREST); // (new)
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0].sizeX,
TextureImage[0].sizey, GL_RGB, GL_UNSIGNED_BYTE,
TextureImage[0].data); //(new) }
End;
If assigned(TextureImage[0]) Then // Whether the texture exists
If assigned(TextureImage[0].data) Then // Whether the texture image exists
TextureImage[0].data := Nil; // Release the memory occupied by the texture image
TextureImage[0] := Nil; // Release the image structure
result := Status; // Return Status
End;
{
Add the following two lines to the glInit() code section.
The first line draws this object at full brightness and gives it 50% alpha blending (semi-transparent).
When the blending option is turned on, this object will be 50% transparent.
The second line sets the type of blending used.
Added by Rui Martins:
An alpha channel value of 0.0 means that the object's material is completely transparent.
1.0 means completely opaque.
}
Procedure glInit(); // Start all settings for OpenGL here
Begin
If (Not LoadTexture) Then // Call the texture loading subroutine
exit; // If failed to load, exit
glEnable(GL_TEXTURE_2D); // Enable texture mapping
glShadeModel(GL_SMOOTH); // Enable shadow smoothing
glClearColor(0.0, 0.0, 0.0, 0.0); // black background
glClearDepth(1.0); //Set the depth buffer
glEnable(GL_DEPTH_TEST); // Enable depth testing
glDepthFunc(GL_LESS); // Type of depth test done
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //Highly optimized perspective projection calculation
glLightfv(GL_LIGHT1, GL_AMBIENT, @LightAmbient[0]); // Set the ambient light
glLightfv(GL_LIGHT1, GL_DIFFUSE, @LightDiffuse[0]); // Set diffuse light
glLightfv(GL_LIGHT1, GL_POSITION, @LightPosition); // Light source position
glEnable(GL_LIGHT1); // Enable light source No. 1
glColor4f(1.0, 1.0, 1.0, 0.5); // Full brightness, 50% Alpha blending (new)
glBlendFunc(GL_SRC_ALPHA, GL_ONE); // Translucent blending function based on the alpha channel value of the source pixel (new)
End;
{Find the following code snippet near the end of Lesson 7.
If keys[VK_LEFT] Then //Is the Left direction key pressed?
yspeed := yspeed - 0.01; //If yes, reduce yspeed
Following the above code, we add the following code.
These lines monitor whether the B key is pressed.
If so, the computer checks to see if the blending option is turned on.
Then set it to the opposite state.
}
If (keys[ord('B')] And Not bp) Then //The B key is pressed and bp is FALSE?
Begin
bp := TRUE; // If yes, bp is set to TRUE
blend := Not blend; // Switch blending options to TRUE / FALSE
If (blend) Then // Is blending on?
Begin
glEnable(GL_BLEND); // Turn on blending
glDisable(GL_DEPTH_TEST); // Turn off depth testing
End
Else // else
Begin
glDisable(GL_BLEND); // Turn off blending
glEnable(GL_DEPTH_TEST); // Turn on depth test
End;
End;
If (Not keys[ord('B')]) Then // Is the B key released?
Begin
bp := FALSE; // If yes, set bp to FALSE
End;
{
But how can you specify the color of the blend when using texture mapping? It's very simple.
When adjusting the texture mode, the color of each pixel of the texture texture is determined by the alpha channel parameter.
Obtained by multiplying the current pixel color.
For example, the drawn color is (0.5, 0.6, 0.4),
We will multiply the colors together to get (0.5, 0.6, 0.4, 0.2)
(When the alpha parameter is not specified, it defaults to zero).
That's it! Implementing Alpha blending in OpenGL is indeed very simple!
}
{
Original note (11/13/99)
My (NeHe) color mixing code was modified to make the displayed objects look more realistic.
Using the alpha parameter to blend the source pixels and destination pixels at the same time will cause the artificial traces of the object to look obvious.
This will make the back of the object appear darker along the sides.
Basically the object will look weird.
The color mixing method I used may not be the best, but it does work.
With lights enabled, objects look realistic.
Thanks to Tom for providing the original code. The color mixing method he used is correct.
But the object doesn't look as attractive as expected :)
The code was modified again due to addressing issues with the glDepthMask() function on some graphics cards.
This command doesn't seem to be very effective when enabling or disabling depth buffer testing on some cards,
So I've converted the code to enable or disable the depth buffer test into old fashioned glEnable and glDisable.
Alpha blending of texture maps
The alpha parameter used for the texture map can be read from the problem map just like the color.
The method is as follows, you need to load the required material and obtain its alpha parameter at the same time.
Then use the color format of GL_RGBA when calling glTexImage2D().
}