opengl transparency order algorithm - opengl

Is there a simple algorithm, given a depth vector (ie the one going into the screen) to determine which polygon (or rather, just which triangle) is 'behind' the other one from their coordinates so I can sort them and get their transparency effects to behave appropriately? I was thinking about comparing overlaps of minimum and maximum values but this can fail, particularly when the range of one polygon in the depth direction goes beyond both the minimum and maximum depth direction of the other. Any ideas?

After investigation it would appear NO there is no such way. See opengl.org/wiki/Transparency_Sorting. Basically the problem is ill defined since we are talking about 2d overlaps in 3d space so can get pathological cases where A>B B>C C>A: here there is no possible order which works.
The problem is that the alpha blending function
glBlendEquation(GL_FUNC_ADD);
glBendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
is not commutative: it relies on subtraction. This is why order matters: A-B != B-A. This however is the best way to do transparency which lots of complicated color effects etc. The way round this is either order independent transparency (eg depth peeling which is apprently costly) or brute force eg. divide up your polygons into arbitrary smaller ones until the sort can be done. This could be made more sophisticated by only dividing up your polygons along the lines where they overlap in the x-y dimensions of the view port. But it's still all a bit of a pain.
If on the other hand your transparency is a simple example (ie. when it explicitly doesn't make a difference to the visuals what order the transparencies are in eg. for me all transparent objects were rectangles of the same grey colour ) none of this matters! It's all a red herring: the problems comes from THINKING it does matter. What we need to do is stop providing information to the z-buffer and telling opengl that it needs to consider the order (which then subsequently gets messed up). So in this case we just need to write
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glEnable( GL_BLEND );
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glBegin(GL_TRIANGLES);
// draw here
glEnd();
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
where the glDepthMask(GL_FALSE) is ensuring depth information isn't being written. You can rotate all you want and the transparencies look fine! But this is dependent on being in a situation where the image outcome DOESN'T depend on the order: it's just that with all the documentation you might think your situation does depend on it when it might not.
If it does depend on the order (it would look different from one angle as opposed to another using the above and you don't want it to) and you don't want to do fancy things or complicated sorts you can use a 'lesser' form of transparency by using commutative blending (multiplicative or additive). You still have to disable z writing and you can do things like
Multiplicative
glBlendFunc(GL_ZERO,GL_SRC_COLOR);
glEnable( GL_BLEND );
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glBegin(GL_TRIANGLES);
// draw here
glEnd();
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
Additive
glBlendFunc(GL_ONE,GL_ONE);
glEnable( GL_BLEND );
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glBegin(GL_TRIANGLES);
// draw here
glEnd();
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
and play about with these to see if they look OK. The point is try these 'lesser' approaches to transparency before looking into complicated sorts/order independent approaches because these will have much lower overheads and might work for your situation depending on what you are doing.

Related

Is there any way to make front face of gluCylinder() transparent?

I am using gluCylinder() to create a cylinder in openGL and then plotting points inside the cylinder with Depth Test On .
When i see the front view of the cylinder, the points inside the cylinder are obstructed by front face.
To make front face of the cylinder translucent i am using Blending.
I am using below functions.
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
But whatever coloring or alpha value i assign to the cylinder the front face is not looking transparent due to its back face.
Tell whether it is possible to do with blending only or else i need to introduce lighting for both the faces of Cylinder.Here it clearly visible the change in the color of front face and back face of cylinder. And the points inside the cylinder are not visible due to being obstructed by front face of cylinder.
You should be able to accomplish this by drawing the cylinder twice, while culling the front faces the first time, and culling the back faces the second time. This way, you can draw the front and back parts differently, e.g. by making the front part transparent.
The code sequence could look like this:
// Draw back part of cylinder, opaque.
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
gluCylinder(...);
// Draw points.
// Draw front part of cylinder, transparent.
glCullFace(GL_BACK);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
gluCylinder(...);
glDisable(GL_BLEND);
If I understand you right then no, you can't do it with blending alone.
If the cylinder's normals all point outward then you also won't be able to see the cylinder's internal parts no matter what you do.
I do something similar to show characters behind walls and it goes like this - render your scene normally and save it all to a framebuffer. Then render what you want shown behind with the buffer contents on top, using a custom shader to make a bubble of transparency around the thing you want shown behind.
Not sure if I am explaining it well or not but it unfortunately requires multiple steps to get the results you want.
Your problem is still a bit unclear to me despite the image but I will attempt to answer based on my perception of your issue.
You are drawing a cylinder and have geometry (lines or other models) inside the cylinder. You want the cylinder to look translucent so the inner objects are visible. Here is one way to do it. Assuming your render functions are drawCylinder() and drawPoints().
init()
{
...
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
...
}
drawScene()
{
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
drawCylinder();
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
drawPoints();
}
doing so will make sure that the points are drawn regardless of the cylinder. Try using lower values of alpha for your cylinder color.
Please note this is one way to do it. I suggest using shaders to have more control over blending as well as exploring fragment/pixel discard options.

Display a quad perpendicular to the screen

When drawing a quad, it vanishes when rotation brings in a position perpendicular to the screen. Ideally what I'd like to see is (b) but I get nothing
Is there something wrong with my code ? (warning old openGL code following)
void draw_rect(double vector[4][3], int rgb[3], double transp)
{
GLint is_depth, is_blend, blend_src, blend_dst;
glGetIntegerv(GL_DEPTH_WRITEMASK, &is_depth);
glGetIntegerv(GL_BLEND, &is_blend);
glGetIntegerv(GL_BLEND_SRC, &blend_src);
glGetIntegerv(GL_BLEND_DST, &blend_dst);
glEnable(GL_BLEND);
glDepthMask(0);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// code to set the color ...
glBegin(GL_POLYGON);
glVertex3v(&vector[0][0]);
glVertex3v(&vector[1][0]);
glVertex3v(&vector[2][0]);
glVertex3v(&vector[3][0]);
glEnd();
if (!is_blend){ glDisable(GL_BLEND); }
glDepthMask(is_depth);
glBlendFunc(blend_src, blend_dst);
}
A quad (assuming it is defined by coplanar faces, as in this case) is by definition infinitely thin. It is correct behavior for it to be invisible when perpendicular to the camera.
The "correct" solution is to make a box rather than a single quad.
See Drawing cube 3D using Opengl for an example using a cube. You'll need to tweak the vertex positions to make the cube smaller along one dimension (probably Z), but it'll give you the effect that you're looking for.
Also, stop using the fixed function stuff (glVertex, etc.). It's been deprecated for years. Shaders aren't that difficult, and examples are easy to find via your favorite search engine.
try making it a line of some definite width when the quad is perpendicular to the screen

transparency in opengl (using FLTK)

I'm drawing some 3D structures in a Fl_Gl_Window in FLTK's implementation of opengl. This images are drawn and rotated so the code looks something like
glTranslatef(-xshift,-yshift,-zshift);
glRotatef(ang1,ang2,ang3);
glTranslatef(xshift,yshift,zshift);
glColor4f((120.0/256.0),(120.0/256.0),(120.0/256.0),0.2);
for (int side=0;side<num_sides;side++){
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glEnable( GL_BLEND );
glBegin(GL_TRIANGLES);
//draw shape
glEnd();
glDisable(GL_BLEND);
}
and it almost works apart from at different angles the transparency doesn't work properly. For example, if I draw a cube from one side it will look transparent all the way through without being able to discern the two sides but from the other one side will appear darker as it is supposed to. It's as if it calculates the transparency too 'early' as in before the rotation. Am I doing something wrong? Should I move the rotation to below the transparency effects (i.e. before them in execution) or does the order of the triangles matter?
The order of the triangles matters. To get the desired effect for transparency you need to render the triangles in back to front order because the hardware blending works by reading the color for the fragment in the depth buffer and blending it with the fragment currently being shaded. That's why you are getting different results when you rotate your cube since you are not changing the order of the triangles in the cube. You may also want to look into Order Independent Transparency techniques.
Depending on how many triangles you have sorting them every frame can get really expensive. One approximation technique is to presort the triangles along the x, y, and z axes and then choose the sorted ordered that most closely matches your viewing direction. This only works to a certain extent. One popular type of order independent transparency technique is depth peeling. Here's a tutorial with some code for implementing it: http://mmmovania.blogspot.com/2010/11/order-independent-transparency.html?m=1. You might also want to read the original paper to get a better understanding of the technique: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.18.9286&rep=rep1&type=pdf.

Opengl surface rendering issue

I just started loading some obj files and render it with opengl. When I render these meshes I get this result (see pictures).
I think its some kind of depth problem but i cant figure it out by myself.
Thats the parameters for rendering:
// Dark blue background
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
// Enable depth test
glEnable( GL_DEPTH_TEST );
// Cull triangles which normal is not towards the camera
glEnable(GL_CULL_FACE);
I used this Tutorial code as template. https://code.google.com/p/opengl-tutorial-org/source/browse/#hg%2Ftutorial08_basic_shading
The problem is simple, you are doing FRONT or BACK culling.
And the object file contains CCW(Counter-Clock-Wise) or CW (Clock-Wise) cordinates, so written from left to right or right to left.
Your openGL code is expecting it in the other way round, so it hides the surfaces which you are looking backward on.
To check this solves your problem, just take out the glEnable(GL_CULL_FACE);
As this exactly seems to be producing the problem.
Additionally you can use glCullFace(ENUM); where ENUM has to be GL_FRONT or GL_BACK.
If you don't in at least one of both cases can't see your mesh (means in both cases: GL_FRONT or GL_BACK your just seeing the partial mesh) , thats a problem with your code of interpreting the .obj. or the .obj uses not strict surface vectors. (A mix of CCW and CW)
I am actually unsure what you mean, however glEnable(GL_CULL_FACE); and then GL_CULL_FACE(GL_BACK); will cull out or remove the back face of the object. This greatly reduces the lag while rendering objects, and only makes a difference if you are inside or "behind" the object.
Also, have you tried glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); before your render code?

Why does my colored cube not work with GL_BLEND?

My cube isn't rendering as expected when I use GL_BLEND.
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
I'm also having a similar problem with drawing some semi-opaque vertices in front, which could well be related.
Related: Why do my semi-opaque vertices make background objects brighter in OpenGL?
Here's what it's supposed to look like:
Normal cube http://img408.imageshack.us/img408/2853/normalcube.png
And here's what it actually looks like:
Dark cube http://img7.imageshack.us/img7/7133/darkcube.png
Please see the code used to create the colored cube, and the code used to actually draw the cube.
The cube is being drawn like so:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glLoadIdentity();
// ... do some translation, rotation, etc ...
drawCube();
glPopMatrix();
// ... swap the buffers ...
You could try disabling all lighting before drawing the cube:
glDisable(GL_LIGHTING);
It looks like you have lighting enabled on the second one,
try with a glShadeModel( GL_FLAT ) before drawing,
This has me stomped. What it looks like is that some vertices have some alpha values that are non-opaque. However the code you posted has all 1. for alpha. So... in order to debug more, did you try to change your clear color to something non-black ? Say green ?
From the code, I doubt lighting is turned on, since no normals were specified.
Last comment, offtopic... You should really not use glBegin/glEnd (2 function calls per vertex + 2 per primitive is really not a good usage of the recent developments in OpenGL). Try glDrawElements with QUAD_LIST, or even better, TRIANGLE_LIST. You already have the data nicely laid out for that.