Am I blending this correctly?

Started by
5 comments, last by Bozebo 14 years, 1 month ago
I am in the process of learning OpenGL. I have been using various resources (including the outdated NeHe tutorials - which are a good way to start otherwise I would not know how things used to work from the correct perspective) to figure everything out. At the moment I have a basic understanding of texturing, vertex manipulation and a few other vital techniques. My next step is to get to grips with blending: So, I took a look at the particles example which is nice looking and I understand what it is doing, but my problem is that it only blends properly with a black background. So, I took a look at the next tutorial which shows off masking. Now I have essentially got a circular gradiented disk which I can have blended infront of a textured/coloured opaque surface correctly, good. But to do so I need 2 textures and have to do a double pass as NeHe's masking tutorial does. Now, is that not bad practice? Shouldn't I be looking at other blending methods to get the job done, and if so can somebody point me in the right direction? I have had a play with the different values for glBlendFunc but I can't get it to appear correctly without a double pass like NeHe did. I am aware I could modify my texture loading routine to create a mask for the image, which would solve the problem of 2 source bitmaps but I want to understand fully what is going on so I can learn at a more stable rate and get to grips with things before I delve into the world of fragment shaders and other more complicated operations. Take a look at my current source (devcpp project, but it shouldn't be hard to get it working fine in something else). Tanks for your time so far.
Advertisement
Try using glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA). I think NeHe uses GL_ONE for destination blending, as otherwise you can get artifacts when particles aren't drawn in front to back order. It also depends on what effect you want to achieve. Explosions etc. often look good with additive blending (GL_ONE), as everything gets brighter where particle density is higher.
I am not trying to freeload code off people or anything, but this is my frame's drawing code.

I tried a few adjustments and couldn't get any results I was happy with.

I tried having single pass with various different blending methods, none of them ended up looking correct while over the opaque background geometry, though a few had nice effects when over the black background. With double pass I tend to end up with bad looking blending unless I stick to GL_DST_COLOR,GL_ZERO for the mask and

      //start of frame      //object step code etc      //enter the drawing phase      //clear the screen and z-buffer      GL_clear();            //draw events      glLoadIdentity();            //camera       //glTranslatef(0,-16,-128); (this is the same as -camera.x etc, just added a class to it below for ease)      //not working with the frustum yet, I will leave that for another time      glTranslatef(-camera.x,-camera.y,-camera.z); //basic camera implementation      glRotatef(camera.pitch,1,0,0);      glRotatef(camera.yaw,0,1,0);              //floor      glPushMatrix(); //don't really need this do I?        glCallList(ground); //coloured + checkered platform to test blending      glPopMatrix();	          //draw particles      glDepthMask(false); //disable updating the z-buffer      glEnable(GL_BLEND); //enable blending    	      //test particle      glTranslatef(0,partY,0); //positioning (no rotation yet, make it "2d"?)      glBlendFunc(GL_DST_COLOR,GL_ZERO); //blend the mask      glBindTexture(GL_TEXTURE_2D,partOrbMask.texture);      glCallList(part); //draws the quad      //the next bit is sort of what I mean by double pass (the non-single pass bit being the mask above)          glColor4f(1,0,0,0.2); //translucent + red      glBindTexture(GL_TEXTURE_2D,partOrb.texture); //inverted form of the mask      glBlendFunc(GL_ONE,GL_ONE); //blend the particle      glCallList(part); //draws the quad              glDisable(GL_BLEND); //no blending (back to opaque)      glDepthMask(true); //did I need to change this? or is it causing issues?      glColor4f(1,1,1,1); //white,opaque            //end of frame      //get input etc


"orb" particle texture:

(the mask is an inverted form of this, ie: black in the centre radiation in a gradient to a white exterior)

What are your thoughts?

I have added different comments so If you want to say anything about my code it would help me a lot to hear it because most of my work is "blind" as I can't find any proper tutorials that combine effects together in a practical manner (eg, NeHe's particles don't work with something other than black behind them)
Does your texture actually have an alpha channel, or are you using that image as the color?
If it's the color, you could try GL_ONE, GL_ONE_MINUS_SRC_COLOR. Usually you probably want that image to represent the alpha channel, and keep the RGB channel as all white, if you want to colorize it with glColor4f. How do you load your textures?
To use alpha you need a format that supports it, for example PNG. Alpha channels can be saved in BMPs but whether they're actually used depends on how you load the image, as there's no alpha in the BMP specification.
There are no alpha channels, the images are loaded from raw format 24bpp.

So, opengl textures support alpha channels directly?

Here is my texture class:
class texture{  public:  GLuint texture;  int width,height;    bool loadRAW(char* path,int w = 128,int h = 128){    width = w;    height = h;        BYTE * data[width * height * 3]; //3 bytes per pixel    FILE * file;        //open and read texture data    file = fopen(path,"rb"); //attempt to open the file    if(!file) //check the file could be opened      return false;        fread(data, width * height * 3, 1, file); //copy file contents into the buffer    fclose(file); //close the file        //allocate a texture resource    glGenTextures(1,&texture);    /*    if(repeat){ //if it repeats      //set as repeating      glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);      glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);    }        //set filtering    glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,filtering);    */    //set as target    glBindTexture(GL_TEXTURE_2D,texture);    //set texture data    gluBuild2DMipmaps(GL_TEXTURE_2D,3,width,height,GL_RGB,GL_UNSIGNED_BYTE,data);           //free buffer    free(data);        return true;  }};

(I think in some of my other workings I have a version of loadRAW which uses edge size instead of width/height as all the textures are going to be square)

I don't like using that buggy/dated/flawed glut library ^_^ so I opted for raw textures.

Would alpha channels solve my problems?

So where I use glColor4f(1,0,0,0.2);
it would render as the alpha of the pixel in the texture multiplied by 0.2?

So In the end I only need glColor3f? as the alpha is declared more sensibly.

The nature of NeHe's tutorials doesn't exactly help my understanding of other techniques.

Am I looking towards a different use of gluBuild2DMipmaps? Or another function for similar uses? I thought to implement an alpha map you had to use blending, and that was the idea behind the double pass.
Use 4 instead of 3, and GL_RGBA instead of GL_RGB for gluBuild2DMipmaps, and specify a data array with 4 bytes per pixel, where the last will be the alpha.
You could do it in your load function, by setting the alpha channel to the RGB average and setting RGB to 255, or save a RAW with an alpha channel if the program you use supports it.

Quote:So where I use glColor4f(1,0,0,0.2);
it would render as the alpha of the pixel in the texture multiplied by 0.2?

Yes this is correct.
Great thanks for the help!

I think here I will make it form the alpha channel from the same image as the source one (find the "lightness" in an HSL fashion), considering that for particles the effect I want is basically a shape where it is coloured to the magnitude of an alpha.

[Edited by - Bozebo on March 13, 2010 10:18:20 AM]

This topic is closed to new replies.

Advertisement