PDA

View Full Version : Blending not yielding the results as expected, trying to make images overlap...



pandoragami
02-11-2018, 06:10 PM
Basically I'm trying to avoid using depth sorting by using blending and I've tried the familiar


glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

but no luck.

The goal I'm trying to get to is something I managed to solve in Irrlicht using the opengl driver so I know this should work. Here's the thread and the final image with blending enabled. http://irrlicht.sourceforge.net/forum/viewtopic.php?f=4&t=52173&sid=9069f5a6bca0de950feb86385ff21b57

https://i.imgur.com/0llqcRn.png

Here's the source code for the GL version using GLUT and SOIL for image loading, I'm using Xubuntu ( not sure it matters).



#include <GL/glut.h>
#include <GL/glu.h>
#include <cmath>
#include <iostream>
#include <string>
#include "SOIL.h"
// angle of rotation for the camera direction
float angle=0.0;
// actual vector representing the camera's direction
float lx=0.0f,lz=-1.0f;
// XZ position of the camera
float x=0.0f,z=35.0f;
// all variables initialized to 1.0, meaning
// the triangle will initially be white
float red=1.0f, blue=1.0f, green=1.0f;

GLuint TextureID = 0;
GLuint GetTexture(std::string Filename)
{
GLuint tex_ID;

tex_ID = SOIL_load_OGL_texture
(
Filename.c_str(),
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_MIPMAPS |
SOIL_FLAG_INVERT_Y |
SOIL_FLAG_NTSC_SAFE_RGB |
SOIL_FLAG_COMPRESS_TO_DXT
);

if( tex_ID > 0 )
{
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, tex_ID );
std::cout<<"texture loaded!"<<std::endl;

return tex_ID;
}
else
return 0;
}
void processNormalKeys(unsigned char key, int x, int y)
{
if (key == 27)
exit(0);
}
void changeSize(int w, int h)
{
// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if (h == 0)
h = 1;
float ratio = w * 1.0 / h;

// Use the Projection Matrix
glMatrixMode(GL_PROJECTION);

// Reset Matrix
glLoadIdentity();

// Set the viewport to be the entire window
glViewport(0, 0, w, h);

// Set the correct perspective.
gluPerspective(45.0f, ratio, 0.1f, 100.0f);

// Get Back to the Modelview
glMatrixMode(GL_MODELVIEW);
}
void renderScene(void)
{
// Clear Color and Depth Buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset transformations
glLoadIdentity();
// Set the camera
gluLookAt( x, 1.0f, z,
x+lx, 1.0f, z+lz,
0.0f, 1.0f, 0.0f);

glEnable(GL_BLEND);

//tried a whole bunch of other stuff
//glBlendFunc(GL_ONE, GL_ONE);
//glEnable(GL_BLEND_COLOR);
//glEnable(GL_DEPTH_TEST);
//glBlendEquation( GL_FUNC_ADD);
//glBlendFunc(GL_DST_ALPHA, GL_ZERO);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, TextureID);
glColor3f(0.9f, 0.9f, 0.9f);
glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0);
glVertex3f(-5.0f, -5.0f, 0.0f);
glTexCoord2d(1.0,0.0);
glVertex3f(-5.0f, 5.0f, 0.0f );
glTexCoord2d(1.0,1.0);
glVertex3f( 5.0f, 5.0f, 0.0f);
glTexCoord2d(0.0,1.0);
glVertex3f( 5.0f, -5.0f, 0.0f );
glEnd();

glColor3f(0.9f, 0.9f, 0.9f);
glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0);
glVertex3f(-10.0f, -5.0f, 0.0f);
glTexCoord2d(1.0,0.0);
glVertex3f(-10.0f, 5.0f, 0.0f );
glTexCoord2d(1.0,1.0);
glVertex3f( 5.0f, 5.0f, 0.0f);
glTexCoord2d(0.0,1.0);
glVertex3f( 5.0f, -5.0f, 0.0f );
glEnd();
glDisable(GL_TEXTURE_2D);

glDisable(GL_BLEND);

glutSwapBuffers();
}
void processSpecialKeys(int key, int xx, int yy)
{
float fraction = 0.1f;

switch (key)
{
case GLUT_KEY_LEFT :
angle -= 0.01f;
lx = sin(angle);
lz = -cos(angle);
break;
case GLUT_KEY_RIGHT :
angle += 0.01f;
lx = sin(angle);
lz = -cos(angle);
break;
case GLUT_KEY_UP :
x += lx * fraction;
z += lz * fraction;
break;
case GLUT_KEY_DOWN :
x -= lx * fraction;
z -= lz * fraction;
break;
}
}
int main(int argc, char **argv)
{
// init GLUT and create window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize( 640, 640);
glutCreateWindow("SOIL image Test");

// register callbacks
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutIdleFunc(renderScene);
glutKeyboardFunc(processNormalKeys);
glutSpecialFunc(processSpecialKeys);

// OpenGL init

glEnable(GL_DEPTH_TEST);
TextureID = GetTexture( "../../../textures/particlewhite.png");
// enter GLUT event processing cycle
glutMainLoop();

return 1;
}



and the png image 2666

GClements
02-11-2018, 06:25 PM
Basically I'm trying to avoid using depth sorting by using blending and I've tried the familiar


glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


but no luck.

You need to render from back to front with that function.

If the images represent light sources, you might try additive blending, e.g.:


glBlendFunc(GL_SRC_ALPHA, GL_ONE);


or, if the image uses pre-multiplied alpha:



glBlendFunc(GL_ONE, GL_ONE);


More generally: if the destination factor uses the source alpha or the source factor uses the destination alpha, the function will be non-commutative, i.e. the order in which overlapping primitives are rendered matters.

pandoragami
02-11-2018, 06:39 PM
Thanks for the reply. I intend to use these for billboards to render particles, so it's not about light sources. Basically the code I included is pretty much what it's supposed "to do" meaning that I want two polygon quads overlapping each other to sort of blend with each other and the background. I'm starting to realize though that if other objects are around these so called particles then I would have to blend these textures with other objects somehow?

What do you mean by "You need to render from back to front with that function."?

Do you mean depth sorting?

Is there another way to blend polygons in the camera perspective regardless of distance ordering in which opengl somehow magically blends all visible textures into a blurry mess; in order to avoid depth sorting?

Right now I'm wonder how irrlicht managed to run that code I had, basically I enabled blending with the material I used like so...


material.BlendOperation = irr::video::EBO_ADD;

which I'm guessing is equivalent to


glBlendEquation( GL_FUNC_ADD);

and it worked in Irrlicht but not in GL. I don't think there was any depth sorting required, or at least I'm not aware of implicitly called any function to do such a thing.
Maybe Irrlicht does depth sorting in these cases? Any suggestions please thanks!

GClements
02-11-2018, 09:43 PM
What do you mean by "You need to render from back to front with that function."?

Do you mean depth sorting?

Yes.



Is there another way to blend polygons in the camera perspective regardless of distance ordering in which opengl somehow magically blends all visible textures into a blurry mess; in order to avoid depth sorting?

Additive blending. Addition is commutative: A+B=B+A, so the order doesn't matter.

With linear blending, if you blend two translucent colours <c1,a1> and <c2,a2> over an opaque background cb, you get either
a1*c1+(1-a1)*(a2*c2+(1-a2)*cb) = a1*c1+(1-a1)*a2*c2+(1-a1)*(1-a2)*cb
or
a2*c2+(1-a2)*(a1*c1+(1-a1)*cb) = a1*(1-a2)*c1+a2*c2+(1-a1)*(1-a2)*cb

depending upon the order in which the two textures are rendered. Their relative depth doesn't have any effect. Visually, the first texture rendered will appear to be behind the second texture rendered, so you need to order them accordingly.

If you change the destination factor to GL_ONE (additive blending), the 1-a1 and 1-a2 terms disappear, giving
a1*c1+a2*c2+cb
regardless of the rendering order. This is appropriate for light sources, which add to the light coming from behind without occluding it. For translucent surfaces which both occlude light from behind and reflect light from in front, you have to depth-sort somehow. You can either depth-sort the primitives, or use techniques such as "depth peeling" to sort the fragments. Neither are entirely straightforward.



Right now I'm wonder how irrlicht managed to run that code I had, basically I enabled blending with the material I used like so...


material.BlendOperation = irr::video::EBO_ADD;

which I'm guessing is equivalent to


glBlendEquation( GL_FUNC_ADD);

GL_FUNC_ADD is the default. Prior to OpenGL 2.0, it was the only option.

Additive blending refers to using the default blend equation (add) with either of


glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glBlendFunc(GL_ONE, GL_ONE);

depending upon whether the textures use pre-multiplied alpha. I.e. the colours from the various overlapping primitives are simply added together (the destination factor is always one; the source factor weights the colour by the alpha value if it isn't already so weighted, i.e. pre-multiplied alpha).