Alpha blending between two objects - opengl

I have two objects in my scene , a rectangle and a circle.
rectangle is 1 unit in z axis and circle is 0 units in z axis.
rectangle has opacity of 50 and the circle has opacity of 100
Why is the alpha of rectagle reducing the alpha of the circle even though the circle has opacity of 100.
This is how the alpha looks like.
This is the blend mode i am using.
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

If you want different equation for RGB color and different for Alpha you can use.
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE);

A possible explanation is, that the rectangle is "darker" than the circle.
When alpha blending is set by
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Then the formula for the final color is
color_dest = color_dest * (1-alpha_source) + color_source * alpha_source
Lets assume the color of the circle 1.0. and the alpha channel of the circle is 1.0, too. The circle is drawn first. The content of the target buffer is black (0, 0, 0, 0).
When the circle is drawn then blending is applied:
color_dest = color_dest * (1-alpha_source) + color_source * alpha_source
(1, 1, 1, 1) = (0, 0, 0, 0) * (1 - 1.0) + (1, 1, 1, 1) * 1.0
The rectangle has a color of 0.5 and and an alpha channel of 0.5, too. Again blending is applied:
color_dest = color_dest * (1-alpha_source) + color_source * alpha_source
(0.75, 0.75, 0.75, 0.75) = (1, 1, 1, 1) * (1 - 0.5) + (0.5, 0.5, 0.5, 0.5) * 0.5
So the final color at the fragments where rectangle covers the the circle is (0.75, 0.75, 0.75, 0.75). The "darker" rectangle darkens the circle.

Related

pyopengl gluLookAt() clarity

I'm trying to understand what I'm doing wrong displaying two different cubes with a grid through the x and z axis. I'm using gluLookAt() to view both cubes at the same angle. I'm very confused why the first viewport does not show the grid but the second one does. Here's my code and an example picture of why I'm confused.
def draw(c1, c2):
glClearColor(0.7, 0.7, 0.7, 0)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glBegin(GL_LINES)
for edge in grid_edges:
for vertex in edge:
glColor3fv((0.0, 0.0, 0.0))
glVertex3fv(grid_vertices[vertex])
glEnd()
glViewport(0, 0, WIDTH // 2, HEIGHT)
glLoadIdentity()
gluPerspective(90, (display[0] / display[1]) / 2, 0.1, 50.0)
gluLookAt(c1.center_pos[0], c1.center_pos[1], c1.center_pos[2] + 8, c1.center_pos[0], c1.center_pos[1], c1.center_pos[2], 0, 1, 0)
glPushMatrix()
glTranslatef(c1.center_pos[0], c1.center_pos[1], c1.center_pos[2])
glRotatef(c1.rotation[0], c1.rotation[1], c1.rotation[2], c1.rotation[3])
glTranslatef(-c1.center_pos[0], -c1.center_pos[1], -c1.center_pos[2])
glBegin(GL_LINES)
for edge in c1.edges:
for vertex in edge:
glColor3fv((0, 0, 0))
glVertex3fv(c1.vertices[vertex])
glEnd()
glPopMatrix()
glViewport(WIDTH // 2, 0, WIDTH // 2, HEIGHT)
glLoadIdentity()
gluPerspective(90, (display[0] / display[1]) / 2, 0.1, 50.0)
gluLookAt(c2.center_pos[0], c2.center_pos[1], c2.center_pos[2] + 8, c2.center_pos[0], c2.center_pos[1], c2.center_pos[2], 0, 1, 0)
glPushMatrix()
glTranslatef(c2.center_pos[0], c2.center_pos[1], c2.center_pos[2])
glRotatef(c2.rotation[0], c2.rotation[1], c2.rotation[2], c2.rotation[3])
glTranslatef(-c2.center_pos[0], -c2.center_pos[1], -c2.center_pos[2])
glBegin(GL_LINES)
for edge in c2.edges:
for vertex in edge:
glColor3fv((0, 0, 0))
glVertex3fv(c2.vertices[vertex])
glEnd()
glPopMatrix()
OpenGL is a state machine. Once a state is set, it persists even beyond frames. This means if you change the viewport or set a matrix, that viewport and matrix are the same at the beginning of the next frame. These states are not "reset" from one frame to the next. You need to set the viewport and set the identity matrix at the beginning of draw:
def draw(c1, c2):
glClearColor(0.7, 0.7, 0.7, 0)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glViewport(0, 0, WIDTH, HEIGHT)
glLoadIdentity()
glBegin(GL_LINES)
for edge in grid_edges:
for vertex in edge:
glColor3fv((0.0, 0.0, 0.0))
glVertex3fv(grid_vertices[vertex])
glEnd()
# [...]

how implement own blend function?

I want to implement the following blend function in my program which isn't using OpenGL.
glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
In the OpenGL realtime test Application I was able to blend with this function colors on a white background. The blended result should look like http://postimg.org/image/lwr9ossen/.
I have a white background and want to blend red points over it. a high density of red points should be get opaque / black.
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
for(many many many times)
glColor4f(0.75, 0.0, 0.1, 0.85f);
DrawPoint(..)
I tried something, but I had no success.
Has anyone the equation for this blend function?
The blend function should translate directly to the operations you need if you want to implement the whole thing in your own code.
The first argument specifies a scaling factor for your source color, i.e. the color you're drawing the pixel with.
The second argument specifies a scaling factor for your destination color, i.e. the current color value at the pixel position in the output image.
These two terms are then added, and the result written to the output image.
GL_DST_COLOR corresponds to the color in the destination, which is the output image.
'GL_ONE_MINUS_SRC_ALPHA` is 1.0 minus the alpha component of the pixel you are rendering.
Putting this all together, with (colR, colG, colB, colA) the color of the pixel you are rendering, and (imgR, imgG, imgB) the current color in the output image at the pixel position:
GL_DST_COLOR = (imgR, imgG, imgB)
GL_ONE_MINUS_SRC_ALPHA = (1.0 - colA, 1.0 - colA, 1.0 - colA)
GL_DST_COLOR * (colR, colG, colB) + GL_ONE_MINUS_SRC_ALPHA * (imgR, imgG, imgB)
= (imgR, imgG, imgB) * (colR, colG, colB) +
(1.0 - colA, 1.0 - colA, 1.0 - colA) * (imgR, imgG, imgB)
= (imgR * colR + (1.0 - colA) * imgR,
imgG * colG + (1.0 - colA) * imgG,
imgB * colB + (1.0 - colA) * imgB)
This is the color you write to your image as the result of rendering the pixel.

setting up an opengl perspective projection

I am having an issue setting up the viewing projection. I am drawing a cube with the vertices (0, 0, 0) (0, 0, 1) (0, 1, 1) (0, 1, 0) (1, 0, 0) (1, 1, 0) (1, 1, 1) and (1, 0, 1). This is how I am initializing the view:
void initGL(int x,int y, int w, int h)
{
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH );
glutInitWindowPosition( x, y );
glutInitWindowSize( w, h );
glutCreateWindow( "CSE328 Project 1" );
glutDisplayFunc(draw);
glFrontFace(GL_FRONT_AND_BACK);
glMatrixMode(GL_PROJECTION);
glFrustum(-10.0, 10.0, -10.0, 10.0, 2.0, 40.0);
glMatrixMode(GL_MODELVIEW);
gluLookAt(10, 10, 10, 0.5, 0.5, 0, 0, 1.0, 0);
glutMainLoop();
}
For some reason, the cube is filling the entire screen. I have tried changing the values of the frustum and lookAt methods, and either the cube is not visible at all, or it fills the entire viewport. In glLookAt I assume the 'eye' is positioned at (10, 10, 10) and looking at the point (0.5, 0.5, 0), which is on the surface of the cube. I thought this would give enough distance so the whole cube would be visible. Am i thinking about this in the wrong way? I have also tried moving the cube in the z direction so that it lies from z = 10 to z = 11, and so is in the clipping plane, but it gives similar results.
The cube has length 1, the viewing volume spans 20 units in x and y dimensions. The cube occupies some pixels in the middle even with orthographic projection; unless there is some other transformation applied during drawing.
I suggest making the frustum smaller (e.g. +/- 2.0f) and moving the camera closer; (4.0f, 4.0f, 4.0f).
Moving the eye position further from the cube by changing the first 3 parameters of gluLookAt() should make it smaller.
You could also replace your call to glFrustum() with a call to gluPerspective() which would make it easier to configure the perspective projection to your liking.

Open GL: draw rectangles with borders?

Check the image I produced, but what I want to do is producing those rectangles with borders, and set the background colour to another. How can I do that?
glRectf(top_left_x, top_left_y, bottom_right_x, bottom_right_y)?
if loop==0:
ratio = 0.10
glBegin(GL_QUADS)
while ratio <= 1.0:
width = window_width/2
height = window_height
long_length = width * ratio
short_length = height* (1.0 - ratio)
top_left_x = (width - long_length) / 2.0
top_left_y = (height - window_height * (1.0-ratio)) /2
bottom_right_x = top_left_x + long_length
bottom_right_y = top_left_y + short_length
glColor(1.0,1.0,1.0,0.5)
glVertex3f(top_left_x, top_left_y, 0.0)
glVertex3f(top_left_x + long_length, top_left_y, 0.0)
glVertex3f(bottom_right_x,bottom_right_y, 0.0)
glVertex3f(bottom_right_x-long_length,bottom_right_y, 0.0)
ratio += 0.05
glEnd()
You can draw a rectangle not filled this way:
glBegin(GL_LINES);
glVertex2d(top_left_x, top_left_y);
glVertex2d( top_right_x, top_right_y);
glVertex2d( bottom_right_x,bottom_right_y);
glVertex2d(bottom_left_x,bottom_left_y);
glVertex2d(top_left_x, top_left_y);
glEnd();
OpenGL use a state machine. So for changing the color just put :
glColor3f (R, G, B);
before your drawing primitives.
So, mixing it up, your step should be:
choose fill color
draw fill rect with glRectf
choose border color
draw unfilled rect with the code I posted
These steps repeated for each rectangle you are drawing of course.

Image blending problem when rendering to texture

This is related to my last question. To get this image:
http://img252.imageshack.us/img252/623/picture8z.png
I draw a white background (color = (1, 1, 1, 1)).
I render-to-texture the two upper-left squares with color = (1, 0, 0, .8) and blend function (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), and then draw the texture with color = (1, 1, 1, 1) and blend function (GL_ONE, GL_ONE_MINUS_SRC_ALPHA).
I draw the lower-right square with color = (1, 0, 0, .8) and blend function (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).
By my calculation, the render-to-texture squares should have color
.8 * (1, 0, 0, .8) + (1 - .8) * (0, 0, 0, 0) = (.8, 0, 0, .64)
and so after drawing that texture on the white background, they should have color
(.8, 0, 0, .64) + (1 - .8) * (1, 1, 1, 1) = (1, .2, .2, .84)
and the lower-right square should have color
.8 * (1, 0, 0, .8) + (1 - .8) * (1, 1, 1, 1) = (1, .2, .2, .84)
which should look the same! Is my reasoning wrong? Is my computation wrong?
In any case, my goal is to cache some of my scene. How do I render-to-texture and then draw that texture so that it is equivalent to just drawing the scene inline?
If you want to render blended content to a texture and composite that texture to the screen, the simplest way is to use premultiplied alpha everywhere. It’s relatively simple to show that this works for your case: the color of your semi-transparent squares in premultiplied form is (0.8, 0, 0, 0.8), and blending this over (0, 0, 0, 0) with (GL_ONE, GL_ONE_MINUS_SRC_ALPHA) essentially passes your squares’ color through to the texture. Blending (0.8, 0, 0, 0.8) over opaque white with (GL_ONE, GL_ONE_MINUS_SRC_ALPHA) gives you (1.0, 0.2, 0.2, 1.0). Note that the color channels are the same as your third calculation, but the alpha channel is still 1.0, which is what you would expect for an opaque object covered by a blended object.
Tom Forsyth has a good article about premultiplied alpha. The whole thing is worth reading, but see the “Compositing translucent layers” section for an explanation of why the math works out in the general case.
Whoops, my computation is wrong! the second line should be
(.8, 0, 0, .64) + (1 - .64) * (1, 1, 1, 1) = (1, .36, .36, .84)
which indeed seems to match what I see (when I change the last square to color (1, .2, .2, .8), all three squares appear the same color).
Regarding your last question: Replacing parts of the scene by textures is not trivial. A good starting point is Stefan Jeschke's PhD thesis.