How To Set A Transparent Color In Opengl
Blending
Avant-garde-OpenGL/Blending
Transparent objects tin be completely transparent (letting all colors through) or partially transparent (letting colors through, but too some of its own colors). The amount of transparency of an object is defined by its colour's 1.0
giving the object 0.0
transparency. An alpha value of 0.0
would result in the object having complete transparency. An alpha value of 0.5
tells us the object'south color consist of fifty% of its ain color and 50% of the colors behind the object.
The textures we've used so far all consisted of 3
color components: ruddy, dark-green and bluish, but some textures likewise have an embedded alpha channel that contains an 0.25
at its drinking glass role and an alpha value of 0.0
at its corners. The glass part would ordinarily be completely cherry, simply since it has 75% transparency information technology largely shows the page'southward background through it, making information technology seem a lot less carmine:
We'll soon exist adding this windowed texture to the scene from the depth testing affiliate, but first nosotros'll discuss an easier technique to implement transparency for pixels that are either fully transparent or fully opaque.
Discarding fragments
Some effects exercise non care about partial transparency, but either want to show something or nothing at all based on the color value of a texture. Retrieve of grass; to create something like grass with little effort you generally paste a grass texture onto a second quad and identify that quad into your scene. However, grass isn't exactly shaped similar a 2D square and so you merely desire to brandish some parts of the grass texture and ignore the others.
The post-obit texture is exactly such a texture where it either is full opaque (an alpha value of 1.0
) or information technology is fully transparent (an alpha value of 0.0
) and aught in between. You tin can see that wherever there is no grass, the image shows the page's background colour instead of its ain.
So when adding vegetation to a scene we don't want to see a foursquare image of grass, only rather but show the actual grass and see through the rest of the image. Nosotros desire to
Earlier we get into that we outset need to learn how to load a transparent texture. To load textures with alpha values in that location's not much we demand to change. stb_image
automatically loads an image's alpha channel if information technology's bachelor, simply we practice need to tell OpenGL our texture now uses an alpha channel in the texture generation procedure:
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, width, pinnacle, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
Also brand certain that you retrieve all 4
colour components of the texture in the fragment shader, not but the RGB components:
void chief() { // FragColor = vec4(vec3(texture(texture1, TexCoords)), one.0); FragColor = texture(texture1, TexCoords); }
At present that we know how to load transparent textures information technology'south fourth dimension to put it to the exam by adding several of these leaves of grass throughout the basic scene introduced in the depth testing chapter.
We create a minor vector
array where we add several glm::vec3
vectors to represent the location of the grass leaves:
vector<glm::vec3> vegetation; vegetation.push_back(glm::vec3(-ane.5f, 0.0f, -0.48f)); vegetation.push_back(glm::vec3( 1.5f, 0.0f, 0.51f)); vegetation.push_back(glm::vec3( 0.0f, 0.0f, 0.7f)); vegetation.push_back(glm::vec3(-0.3f, 0.0f, -2.3f)); vegetation.push_back(glm::vec3( 0.5f, 0.0f, -0.6f));
Each of the grass objects is rendered as a single quad with the grass texture fastened to it. It's not a perfect 3D representation of grass, just it'southward a lot more efficient than loading and rendering a large number of complex models. With a few tricks similar adding randomized rotations and scales you can go pretty disarming results with quads.
Considering the grass texture is going to be displayed on a quad object we'll demand to create another VAO once again, make full the VBO, and gear up the advisable vertex attribute pointers. Then later we've rendered the floor and the two cubes we're going to render the grass leaves:
glBindVertexArray (vegetationVAO); glBindTexture (GL_TEXTURE_2D, grassTexture); for(unsigned int i = 0; i < vegetation.size(); i++) { model = glm::mat4(1.0f); model = glm::interpret (model, vegetation[i]); shader.setMat4("model", model); glDrawArrays (GL_TRIANGLES, 0, 6); }
Running the application will now expect a bit like this:
This happens because OpenGL past default does not know what to do with blastoff values, nor when to discard them. We take to manually do this ourselves. Luckily this is quite easy thanks to the employ of shaders. GLSL gives us the discard
control that (once called) ensures the fragment will non exist further candy and thus non finish up into the colour buffer. Thanks to this command we can check whether a fragment has an alpha value beneath a certain threshold and if so, discard the fragment every bit if it had never been processed:
#version 330 core out vec4 FragColor; in vec2 TexCoords; uniform sampler2D texture1; void main() { vec4 texColor = texture(texture1, TexCoords); if(texColor.a < 0.one) discard; FragColor = texColor; }
Here we bank check if the sampled texture color contains an alpha value lower than a threshold of 0.1
and if so, discard the fragment. This fragment shader ensures united states that information technology only renders fragments that are not (almost) completely transparent. Now information technology'll wait like it should:
glTexParameter i( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameter i( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
You can detect the source lawmaking here.
Blending
While discarding fragments is great and all, it doesn't give us the flexibility to render semi-transparent images; nosotros either return the fragment or completely discard it. To return images with different levels of transparency nosotros take to enable
glEnable (GL_BLEND);
At present that we've enabled blending we need to tell OpenGL how information technology should actually blend.
Blending in OpenGL happens with the following equation:
\begin{equation}\bar{C}_{upshot} = \bar{\color{green}C}_{source} * \color{greenish}F_{source} + \bar{\color{cerise}C}_{destination} * \color{red}F_{destination}\end{equation}
- \(\bar{\color{green}C}_{source}\): the source color vector. This is the color output of the fragment shader.
- \(\bar{\color{red}C}_{destination}\): the destination color vector. This is the color vector that is currently stored in the color buffer.
- \(\colour{green}F_{source}\): the source factor value. Sets the bear on of the blastoff value on the source color.
- \(\color{red}F_{destination}\): the destination factor value. Sets the impact of the alpha value on the destination colour.
After the fragment shader has run and all the tests have passed, this
We accept two squares where we want to draw the semi-transparent green square on acme of the reddish square. The carmine square volition be the destination color (and thus should exist starting time in the color buffer) and nosotros are now going to describe the light-green foursquare over the ruby square.
The question so arises: what do we ready the gene values to? Well, nosotros at least desire to multiply the light-green square with its alpha value so nosotros want to set the \(F_{src}\) equal to the alpha value of the source color vector which is 0.6
. Then it makes sense to let the destination square take a contribution equal to the remainder of the alpha value. If the green foursquare contributes lx% to the final color nosotros want the cherry square to contribute 40% of the terminal color e.chiliad. i.0 - 0.six
. So nosotros set \(F_{destination}\) equal to 1 minus the blastoff value of the source colour vector. The equation thus becomes:
\begin{equation}\bar{C}_{effect} = \begin{pmatrix} \color{red}{0.0} \\ \color{green}{i.0} \\ \colour{blue}{0.0} \\ \color{purple}{0.6} \stop{pmatrix} * \colour{green}{0.6} + \begin{pmatrix} \color{carmine}{i.0} \\ \color{green}{0.0} \\ \color{blue}{0.0} \\ \color{regal}{i.0} \stop{pmatrix} * (\color{cherry-red}{1 - 0.6}) \end{equation}
The event is that the combined square fragments contain a color that is 60% green and 40% red:
The resulting colour is then stored in the color buffer, replacing the previous color.
So this is great and all, just how practise nosotros actually tell OpenGL to apply factors similar that? Well information technology merely so happens that at that place is a role for this chosen
The
Pick | Value |
---|---|
GL_ZERO | Cistron is equal to \(0\). |
GL_ONE | Gene is equal to \(one\). |
GL_SRC_COLOR | Factor is equal to the source color vector \(\bar{\color{greenish}C}_{source}\). |
GL_ONE_MINUS_SRC_COLOR | Factor is equal to \(1\) minus the source colour vector: \(1 - \bar{\color{greenish}C}_{source}\). |
GL_DST_COLOR | Gene is equal to the destination color vector \(\bar{\color{red}C}_{destination}\) |
GL_ONE_MINUS_DST_COLOR | Gene is equal to \(1\) minus the destination color vector: \(1 - \bar{\colour{crimson}C}_{destination}\). |
GL_SRC_ALPHA | Gene is equal to the \(alpha\) component of the source color vector \(\bar{\color{greenish}C}_{source}\). |
GL_ONE_MINUS_SRC_ALPHA | Factor is equal to \(1 - alpha\) of the source color vector \(\bar{\color{light-green}C}_{source}\). |
GL_DST_ALPHA | Factor is equal to the \(blastoff\) component of the destination color vector \(\bar{\color{red}C}_{destination}\). |
GL_ONE_MINUS_DST_ALPHA | Factor is equal to \(1 - alpha\) of the destination color vector \(\bar{\color{reddish}C}_{destination}\). |
GL_CONSTANT_COLOR | Factor is equal to the constant colour vector \(\bar{\color{blue}C}_{constant}\). |
GL_ONE_MINUS_CONSTANT_COLOR | Factor is equal to \(ane\) - the constant color vector \(\bar{\color{blueish}C}_{constant}\). |
GL_CONSTANT_ALPHA | Cistron is equal to the \(alpha\) component of the constant colour vector \(\bar{\color{bluish}C}_{constant}\). |
GL_ONE_MINUS_CONSTANT_ALPHA | Factor is equal to \(ane - alpha\) of the constant color vector \(\bar{\color{blue}C}_{constant}\). |
To go the blending outcome of our little two foursquare example, we want to take the \(alpha\) of the source colour vector for the source factor and \(i - alpha\) of the same color vector for the destination factor. This translates to
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
It is also possible to set unlike options for the RGB and alpha channel individually using
glBlendFunc Divide (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
This function sets the RGB components as nosotros've set them previously, simply only lets the resulting alpha component be influenced by the source's alpha value.
OpenGL gives us even more flexibility by allowing us to alter the operator between the source and destination function of the equation. Right now, the source and destination components are added together, simply nosotros could besides decrease them if we desire.
-
GL_FUNC_ADD
: the default, adds both colors to each other: \(\bar{C}_{issue} = \color{dark-green}{Src} + \color{red}{Dst}\). -
GL_FUNC_SUBTRACT
: subtracts both colors from each other: \(\bar{C}_{issue} = \color{green}{Src} - \colour{ruby-red}{Dst}\). -
GL_FUNC_REVERSE_SUBTRACT
: subtracts both colors, but reverses social club: \(\bar{C}_{consequence} = \color{red}{Dst} - \color{green}{Src}\). -
GL_MIN
: takes the component-wise minimum of both colors: \(\bar{C}_{result} = min(\color{red}{Dst}, \color{dark-green}{Src})\). -
GL_MAX
: takes the component-wise maximum of both colors: \(\bar{C}_{effect} = max(\color{carmine}{Dst}, \color{green}{Src})\).
Commonly we can only omit a telephone call to
Rendering semi-transparent textures
Now that we know how OpenGL works with regards to blending it's time to put our knowledge to the test by adding several semi-transparent windows. We'll exist using the same scene every bit in the start of this chapter, merely instead of rendering a grass texture nosotros're at present going to use the transparent window texture from the starting time of this chapter.
First, during initialization nosotros enable blending and set the advisable blending office:
glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Since we enabled blending there is no need to discard fragments so we'll reset the fragment shader to its original version:
#version 330 core out vec4 FragColor; in vec2 TexCoords; uniform sampler2D texture1; void main() { FragColor = texture(texture1, TexCoords); }
This fourth dimension (whenever OpenGL renders a fragment) information technology combines the electric current fragment's colour with the fragment color currently in the color buffer based on the alpha value of FragColor. Since the glass part of the window texture is semi-transparent we should be able to see the rest of the scene by looking through this window.
If you lot take a closer look yet, you lot may notice something is off. The transparent parts of the front end window are occluding the windows in the background. Why is this happening?
The reason for this is that depth testing works a bit tricky combined with blending. When writing to the depth buffer, the depth test does not care if the fragment has transparency or not, so the transparent parts are written to the depth buffer every bit whatsoever other value. The issue is that the background windows are tested on depth as any other opaque object would exist, ignoring transparency. Fifty-fifty though the transparent part should show the windows behind information technology, the depth examination discards them.
So nosotros cannot merely render the windows even so we want and expect the depth buffer to solve all our issues for usa; this is also where blending gets a piddling nasty. To make certain the windows show the windows backside them, we have to depict the windows in the background commencement. This means we have to manually sort the windows from furthest to nearest and draw them accordingly ourselves.
Don't intermission the lodge
To make blending work for multiple objects we have to draw the virtually distant object first and the closest object terminal. The normal non-blended objects tin can still be drawn every bit normal using the depth buffer so they don't take to be sorted. We do have to make certain they are drawn first before drawing the (sorted) transparent objects. When cartoon a scene with non-transparent and transparent objects the general outline is usually as follows:
- Draw all opaque objects offset.
- Sort all the transparent objects.
- Draw all the transparent objects in sorted order.
One way of sorting the transparent objects is to retrieve the distance of an object from the viewer'due south perspective. This can exist accomplished past taking the distance between the photographic camera'south position vector and the object's position vector. We then store this distance together with the corresponding position vector in a
std::map<float, glm::vec3> sorted; for (unsigned int i = 0; i < windows.size(); i++) { float distance = glm::length(camera.Position - windows[i]); sorted[distance] = windows[i]; }
The result is a sorted container object that stores each of the window positions based on their altitude cardinal value from lowest to highest altitude.
Then, this time when rendering, we take each of the map'south values in contrary social club (from uttermost to nearest) and then draw the corresponding windows in correct order:
for(std::map<float,glm::vec3>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); ++it) { model = glm::mat4(1.0f); model = glm::interpret (model, it->2d); shader.setMat4("model", model); glDrawArrays (GL_TRIANGLES, 0, 6); }
We take a reverse iterator from the
You tin observe the complete source code with sorting hither.
While this approach of sorting the objects past their altitude works well for this specific scenario, information technology doesn't take rotations, scaling or any other transformation into business relationship and weirdly shaped objects need a different metric than simply a position vector.
Sorting objects in your scene is a difficult feat that depends greatly on the blazon of scene yous have, let lone the extra processing ability information technology costs. Completely rendering a scene with solid and transparent objects isn't all that easy. In that location are more advanced techniques like
Source: https://learnopengl.com/Advanced-OpenGL/Blending
Posted by: drennonowereve.blogspot.com
0 Response to "How To Set A Transparent Color In Opengl"
Post a Comment