blending

Hi! i have a problem with blending… my code should blend a valume made of 3 “slices” and read the blended value… From what I’ve read, the function GL_ONE_MINUS_SRC_ALPHA should calculate the blended value(for 3 “slices” like in my code), resolving this expression:
((µ1α1)(1-α2)+ µ2α2)(1-α3)+(µ3*α3)

where µ1 is the value of the first “slice” and α1 is the alpha value of the first slice ( and so on…)

so… the result is 2 ( that is a reasonable result). but the result of the program is always half of the expected value. f.e. with 3 slices and the values µ1=1,µ2=2,µ3=3 the result is 1 (instead of 2), if the result should be 40, the program give 20 and so on… so i think that the program is correct because it is wrong in a “correct way”. maybe there’s something that i don’t know about the method, or maybe i’m not considerating all… please help!!!

#include <cstdio>
#include <cstdlib>
using namespace std;

#include <gl\glew.h>
#include <gl\glut.h>
#include <gl\gl.h>
#include <gl\glu.h>

#include <windows.h>

//trasforms alpha from double to char and from 0 and 255
char DoubleToChar(double alpha){
return (char)(alpha*255.0);
}

int main(int argc, char **argv) {

//Volume values: it represents a 1x1x3 volume ( 3 slices along z)
unsigned char Volumevalues[12]={1,0,0,1,2,0,0,0,3,0,0,0};
Volumevalues [3]=DoubleToChar(1.0);
Volumevalues [7]=DoubleToChar(1.0/2.0);
Volumevalues [11]=DoubleToChar(1.0/3.0);
unsigned char result [16]; //array for the result

//initialize glut
glutInit (&argc, argv);
glutCreateWindow(“radiographic simulation”);
glewInit();

// create the texture
GLuint tex;
glGenTextures (1, &tex);
glBindTexture(GL_TEXTURE_3D,tex);

// sets texture’s parameters
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);

//allocate the texture
glTexImage3D(GL_TEXTURE_3D,0,GL_RGBA,1,1,4,0,GL_RGBA,GL_UNSIGNED_BYTE, Volumevalues);

//viewport transform for 1:1 pixel=texel=data mapping
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,1,0.0,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0,0,1,1);

glPushMatrix();

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

float a= ((float)0.5)/3.0;
float b =((float)1.5)/3.0;
float c= ((float)2.5)/3.0;

glBegin(GL_QUADS);
glTexCoord3f(0.0,0.0,a); glVertex2f(0,0);
glTexCoord3f(0.0,1.0,a); glVertex2f(0,1);
glTexCoord3f(1.0,1.0,a); glVertex2f(1,1);
glTexCoord3f(1.0,0.0,a); glVertex2f(1,0);

glTexCoord3f(0.0,0.0,b); glVertex2f(0,0);
glTexCoord3f(0.0,1.0,b); glVertex2f(0,1);
glTexCoord3f(1.0,1.0,b); glVertex2f(1,1);
glTexCoord3f(1.0,0.0,b); glVertex2f(1,0);

glTexCoord3f(0.0,0.0,c); glVertex2f(0,0);
glTexCoord3f(0.0,1.0,c); glVertex2f(0,1);
glTexCoord3f(1.0,1.0,c); glVertex2f(1,1);
glTexCoord3f(1.0,0.0,c); glVertex2f(1,0);

glEnd();
glPopMatrix();

glutSwapBuffers();

//reads datas from the frame buffer and write them into the array result
glReadBuffer(GL_FRONT);
glReadPixels(0,0,1,1,GL_RGBA,GL_BYTE,result);

// print out results
printf("Data before roundtrip:
“);
for (int i=0; i<16; i++)
printf(”%d
", Volumevalues [i]);
printf("Data after roundtrip:
“);
for (int i=0; i<4; i++)
printf(”%d
",result[i]);

getchar();

return 0;

}

Are you taking numerical inaccuracies into account?

e.g. in the first pass, if you have a value of 2 (range 0…255) with an alpha of 0.15, the resulting value is 0.30 which is rounded down to 0 when writing to a 32bpp RGBA framebuffer.

If you want to avoid this, use a for-loop in a fragment shader to iterate over the different slices.

N.

From what I’ve read, the function GL_ONE_MINUS_SRC_ALPHA should calculate the blended value(for 3 “slices” like in my code), resolving this expression:
((µ1α1)(1-α2)+ µ2α2)(1-α3)+(µ3*α3)

In order for your equation to be correct, you must ensure that the destination color before doing any rendering is (0, 0, 0, 0). Otherwise, you should use a separate blending equation for the first pass.

And put your code in [ code ] tags.

for Nico: alpha values are trasformed into the range 0-255 (the first fuction in the code), so using a char and not a float ,why there should be numerical inaccuracies? and… what do you mean with your solution? isn’t it enough blend the slices like i do?

for Korval: i tryed to clear the color buffer, but the result is the same…

suggestions???(i am repetitive but, i remind you that the program works… in a “correct” wrong way, and the strange thing is that in the result, alpha value is 127 ( i don’t mind because i need only the color values…) that is half of 255 (half like the color value), maybe there’s a relation…

I don’t know how to be any clearer than in my previous post. Suppose you want to calculate the sum of 3 values in the range 0-255. The range of this sum is 0-3*255 and you are writing the result to a pixel with a range of 0-255 so it’s impossible to get the full resolution of your result, hence the inaccuracies.

PS. If you just want to calculate the mean of three values (sum divided by count) you can use.


glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glBlendColor(1.0/count,1.0/count,1.0/count,1.0/count);
glBlendEquation(GL_CONSTANT_COLOR,GL_ONE);
glEnable(GL_BLEND);

N.

I’ll ask the more obvious question. Why use GL at all?
You aren’t doing graphics. You are doing math and it’s something that could be done in a few clock cycles on the CPU.

IIRC he’s trying to simulate radiography…

for Nico:
1- so i don’t need to use one_minus_src_alpha?
2- the program gives me an error… to many arguments in glBlendequation; i searched and the parameters you wrote aren’t accepted by the function, It must be GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, GL_MIN, GL_MAX, GL_ALPHA_MIN_SGIX, or GL_ALPHA_MAX_SGIX.
are you sure that the name is correct?

2- it is glBlendFunc, and you need the GL_ARB_imaging extension use GL_CONSTANT_COLOR

I checked with a program if my pc supports that extension, and the answer is yes. I’ve changed the code into this:


#include <cstdio>
#include <cstdlib>
using namespace std; 

#include <gl\glew.h>
#include <gl\glut.h>
#include <gl\gl.h>
#include <gl\glu.h>

#include <windows.h>

//trasforms alpha from double to char and from 0 and 255 
char DoubleToChar(double alpha){
return (char)(alpha*255.0);
}

int main(int argc, char **argv) {

//Volume values: it represents a 1x1x3 volume ( 3 slices along z)
unsigned char Volumevalues[12]={1,0,0,1,2,0,0,0,3,0,0,0};
Volumevalues [3]=DoubleToChar(1.0);
Volumevalues [7]=DoubleToChar(1.0/2.0);
Volumevalues [11]=DoubleToChar(1.0/3.0);
unsigned char result [12]; //array for the result

//initialize glut
glutInit (&argc, argv);
glutCreateWindow("radiographic simulation"); 
glewInit();

// create the texture
GLuint tex;
glGenTextures (1, &tex);
glBindTexture(GL_TEXTURE_3D,tex); 

// sets texture’s parameters 
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);

//allocate the texture
glTexImage3D(GL_TEXTURE_3D,0,GL_RGBA,1,1,4,0,GL_RGBA,GL_UNSIGNED_BYTE, Volumevalues); 

//viewport transform for 1:1 pixel=texel=data mapping
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,1,0.0,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0,0,1,1);


glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glBlendColor(1.0/3,1.0/3,1.0/3,1.0/3);
glBlendEquation(GL_CONSTANT_COLOR);
glEnable(GL_BLEND);

glPushMatrix();

glEnable(GL_TEXTURE_3D);


float a= ((float)0.5)/3.0;
float b =((float)1.5)/3.0;
float c= ((float)2.5)/3.0;

glBegin(GL_QUADS);
glTexCoord3f(0.0,0.0,a); glVertex2f(0,0);
glTexCoord3f(0.0,1.0,a); glVertex2f(0,1);
glTexCoord3f(1.0,1.0,a); glVertex2f(1,1);
glTexCoord3f(1.0,0.0,a); glVertex2f(1,0);

glTexCoord3f(0.0,0.0,b); glVertex2f(0,0);
glTexCoord3f(0.0,1.0,b); glVertex2f(0,1);
glTexCoord3f(1.0,1.0,b); glVertex2f(1,1);
glTexCoord3f(1.0,0.0,b); glVertex2f(1,0);

glTexCoord3f(0.0,0.0,c); glVertex2f(0,0);
glTexCoord3f(0.0,1.0,c); glVertex2f(0,1);
glTexCoord3f(1.0,1.0,c); glVertex2f(1,1);
glTexCoord3f(1.0,0.0,c); glVertex2f(1,0);

glEnd(); 
glPopMatrix();


//reads datas from the frame buffer and write them into the array result
glReadBuffer(GL_FRONT);
glReadPixels(0,0,1,1,GL_RGBA,GL_BYTE,result);

// print out results
printf("Data before roundtrip:
");
for (int i=0; i<16; i++)
printf("%d
", Volumevalues [i]);
printf("Data after roundtrip:
");
for (int i=0; i<4; i++)
printf("%d
",result[i]);

getchar();


return 0;

} 

but the result is always the same… 1! not 2! where is the error? i have missed something??

Ow yeah, sorry for providing the wrong function before. Although I’ve used blending lots of times I’m still confused by:

glBlend[b]Equation/b;
glBlend[b]Func/b;

I’ll probably keep on making this mistake till the end of days :wink:

N.

Nico, please… be patient… do you mean this way?:


glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);

glBlendColor(1.0/3,1.0/3,1.0/3,1.0/3);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_CONSTANT_COLOR,GL_ONE);
glEnable(GL_BLEND);

Yep, that’s it.

N.

it doesn’t work! :frowning: always the same thing… 1 and not 2!! could it be my pc?? i repost my code…maybe miracles exists… :frowning:


#include <cstdio>
#include <cstdlib>
using namespace std; 

#include <gl\glew.h>
#include <gl\glut.h>
#include <gl\gl.h>
#include <gl\glu.h>

#include <windows.h>

//trasforms alpha from double to char and from 0 and 255 
char DoubleToChar(double alpha){
return (char)(alpha*255.0);
}

int main(int argc, char **argv) {

//Volume values: it represents a 1x1x3 volume ( 3 slices along z)
unsigned char Volumevalues[12]={1,0,0,1,2,0,0,0,3,0,0,0};
Volumevalues [3]=DoubleToChar(1.0);
Volumevalues [7]=DoubleToChar(1.0/2.0);
Volumevalues [11]=DoubleToChar(1.0/3.0);
unsigned char result [12]; //array for the result

//initialize glut
glutInit (&argc, argv);
glutCreateWindow("radiographic simulation"); 
glewInit();

// create the texture
GLuint tex;
glGenTextures (1, &tex);
glBindTexture(GL_TEXTURE_3D,tex); 

// sets texture’s parameters 
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);

//allocate the texture
glTexImage3D(GL_TEXTURE_3D,0,GL_RGBA,1,1,4,0,GL_RGBA,GL_UNSIGNED_BYTE, Volumevalues); 

//viewport transform for 1:1 pixel=texel=data mapping
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,1,0.0,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0,0,1,1);


glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);

glBlendColor(1.0/3,1.0/3,1.0/3,1.0/3);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_CONSTANT_COLOR,GL_ONE);
glEnable(GL_BLEND);

glPushMatrix();
glEnable(GL_TEXTURE_3D);


float a= ((float)0.5)/3.0;
float b =((float)1.5)/3.0;
float c= ((float)2.5)/3.0;

glBegin(GL_QUADS);
glTexCoord3f(0.0,0.0,a); glVertex2f(0,0);
glTexCoord3f(0.0,1.0,a); glVertex2f(0,1);
glTexCoord3f(1.0,1.0,a); glVertex2f(1,1);
glTexCoord3f(1.0,0.0,a); glVertex2f(1,0);

glTexCoord3f(0.0,0.0,b); glVertex2f(0,0);
glTexCoord3f(0.0,1.0,b); glVertex2f(0,1);
glTexCoord3f(1.0,1.0,b); glVertex2f(1,1);
glTexCoord3f(1.0,0.0,b); glVertex2f(1,0);

glTexCoord3f(0.0,0.0,c); glVertex2f(0,0);
glTexCoord3f(0.0,1.0,c); glVertex2f(0,1);
glTexCoord3f(1.0,1.0,c); glVertex2f(1,1);
glTexCoord3f(1.0,0.0,c); glVertex2f(1,0);

glEnd(); 
glPopMatrix();


//reads datas from the frame buffer and write them into the array result
glReadBuffer(GL_FRONT);
glReadPixels(0,0,1,1,GL_RGBA,GL_BYTE,result);

// print out results
printf("Data before roundtrip:
");
for (int i=0; i<16; i++)
printf("%d
", Volumevalues [i]);
printf("Data after roundtrip:
");
for (int i=0; i<4; i++)
printf("%d
",result[i]);

getchar();

return 0;
}

I posted two replies stating that the problem could be caused by numerical inaccuracies, did you check whether this is the problem yet?

In theory:

start with 0 in the framebuffer.
Then you draw the first quad:
0 + (1/3.0)*1 = 1/3.0
Then you draw the second quad:
1/3.0 + (1/3.0)*2 = 1
Then you draw the third quad:
1 + (1/3.0)*3 = 2

In practice:

start with 0 in the framebuffer.
Then you draw the first quad:
0 + (1/3.0)*1 = 1/3.0 -> 0 //rounded down to 0 when writing to 8 bit channel!
Then you draw the second quad:
0 + (1/3.0)*2 = 2/3.0 -> 0 //rounded down to 0 when writing to 8 bit channel!
Then you draw the third quad:
0 + (1/3.0)*3 = 1 -> 1

N.

so i lose precision during the operations… you suggested to make a for loop to avoid this… where precisely? i’m not so good :frowning: ( i think you’ve noticed it… )

If you want to do this with a for-loop, you’ll first have to learn how to use shaders with e.g. GLSL.

N.

there isn’t another way? i would take weeks to learn glsl or cg :frowning: . don’t you know how to do it?

If your card supports 16 bit floating point blending you can use a 16 bit fp texture and attach it to a framebuffer object. This will solve the innaccuracies. The GLSL approach is better and should work on virtually all graphics cards.

N.

Hi Nico! the problem, was… Solved! i haven’t used f.p. values… but only unsigned byte. In fact the problem wasn’t the code, but the texture type; using byte when the color values are 128 or more, they generete an overflow; it was enough change the data type into unsigned byte and the problem was solved. I would like to really THANK YOU for what you have done, and… don’t worry i’ll be back soon with another problem :slight_smile: