PDA

View Full Version : True transparency



devdept
07-16-2009, 05:29 AM
Hi All,


We have always believed that true transparency was an hard thing to code. Yesterdeay a coworker suggested the following trick:


Actually, in OpenGL rendering both opaque (alpha=1) and transparent
(alpha<1) objects in the same scene is quite easy: First you draw all the
opaque objects, with depth buffer in normal operation. Then you toggle the
depth buffer read-only (by glDepthMask(GL_FALSE)), draw the transparent
objects and make the depth buffer writable again afterwards
(glDepthMask(GL_TRUE)). There is should be no need for sorting objects by
their viewpoint distances.


What do you think?


Thanks,

Alberto

ZbuffeR
07-16-2009, 05:54 AM
This "trick" is very old and used by a lot of people.
But it does not solve the order problems that can happen *between* translucent faces (between 2 convex objects or within 1 concave object).
That is where you need sorting. Or use order independent transparency, such as additive blending or darken etc.

devdept
07-16-2009, 06:30 AM
Hi ZbuffeR,

As always, thanks for your help.

Can you give me more info (or point me to some resources) about additive blending, darken, etc.

Our customers are striving for a more realistic transparency.

Thanks so much again,

Alberto

devdept
07-16-2009, 02:00 PM
ZbuffeR,

I want to be more clear, suppose to have a more complex scenario like the following:

http://users.rcn.com/wgknestrick/itb%20transparent.jpg

Is it possible that the only solution is to skip objects' display lists and to sort triangles at each frame before drawing them? It looks so slow...

Can you please list all the OpenGL transparency approaches sorted from easy to complex to implement?

We need something more realistic but we are scared from the complexity that always turns out.


Thanks again,

Alberto

Jan
07-16-2009, 02:38 PM
Transparency is a bitch.

To get it working, you can sort all triangles from back to front (for example using a BSP-Tree). That is computationally expensive and not fun to implement. I can't advise you to do so, though, with complex scenes this won't run fast enough.

Another solution is to to use "depth-peeling". However that method requires modern hardware and will still be quite slow, but at least you don't need to sort anything. However, from your other posts i suspect, that you need to support older hardware, so that's not really an option, either.

A third solution, is to only sort by "object" (e.g. group of triangles) and render them roughly from back to front. That's an approach taken very often, because it works well in many situations and isn't difficult to implement (usually). But there will always be situations where it doesn't work properly.

Looking at your screenshot, i find that your results look quite nice already. If you are not doing it already, you could add sorting by object, and leave it at that.


There are not really many options, when it comes to transparency. All completely correct solutions are complex and slow.

Jan.

dorbie
07-16-2009, 03:33 PM
You still need to depth sort the transparent objects.

As has been said it's an old trick, however it is flawed because transparent objects can occlude other transparent objects and can self-occlude.

You have a nice solution BUT transparency blend results are not order invariant.

If you have two 75% transparent objects and one occludes the other or vice versa the result will be highly dependent on drawing order. For it to be correct it needs to be sorted back to front.

Transparency occluding opaque objects in a zbuffered scene has never been a problem except for inexperienced graphics developers.

Sorting isn't a huge problem either although it can increase state changes etc, however the real problem is that object level sorting is not always sufficient to get it correct.

Picture two transparent interlocking tori (two chain links).

Which order do you draw them in as objects to get the correct result? There is no correct order in this scenario.

A simple object level sort is sufficient for most applications. Rather than a depth sort, try to insert a plane between them and decide which side of the plane the eye is on. Use this mechanism to sort for best object level results.

dorbie
07-16-2009, 03:36 PM
There are not really many options, when it comes to transparency. All completely correct solutions are complex and slow.


Yes. Although some graphics hardware with deferred shading internals can handle it automatically (not avilable on mainstream platforms). At the application level there's a need to compromise for good performance.

LangFox
07-16-2009, 06:34 PM
Alpha-to-Coverage with MSAA can do the trick.

devdept
07-16-2009, 11:37 PM
Hi Guys,


Thanks a lot for your thoughts, just a little clarification on the image: this was taken on the internet, it's from SolidWorks CAD application, it doesn't belong to us...

We already implemented object based sorting (using distances from centroid) but simply putting a semi-transparent box inside another semi-transparent box - with the same centroid - will give an incorrect result.

Can we say that all modern 3D applications are using "depth-peeling" and require high end hardware? I mean 3D Studio Max, LightWave3D, Maya, etc.


Where can we find very clear instructions on "depth-peeling"?


Thanks again,

Alberto

LangFox
07-17-2009, 05:05 AM
depth-peeling can be found in nVidia SDK, GPU Gems and ShaderX series.

devdept
07-17-2009, 05:20 AM
Does this mean that on ATI hardwares "depth peeling" does not work?

What about this additional trick to my original post:


generally this is true, but one uses the GL_FUNC_ADD blending function and the GL_SRC_COLOR and GL_DST_COLOR blending factors (which I guess you do or which I would use) the order of two translucent faces does not matter, because one just gets an addition of colors

Thanks,

Alberto

Dark Photon
07-20-2009, 06:20 PM
Does this mean that on ATI hardwares "depth peeling" does not work?
That came out of nowhere. Why would you say that?

Does ATI support depth textures? Should work then.

As for how this works, google for details but it's pretty simple. Conceptually you "peel away" one layer of transparency at a time, nearest to the eye first.

In more detail: You render your all alpha objs repeatedly in N passes, for N layers of transparency (i=1..N). Into pass 1 you pass a depth texture of all zero. Into pass i, you pass the depth buffer for pass i-1 as the depth texture. In each pass, you do a fragment shader depth texture lookup, and only render the fragment that's nearest to the eye (normal Z buffering) BUT ALSO further from the eye than the last depth texture value (call frag shader discard if not).

So as you can see, pixel by pixel, we peel away one layer of transparency. When done, blend all those resulting color buffers back-to-front.

Not the cheapest thing in the world, but if you can bound how many levels of transparency you'll have that are important, it works. I'm sure there are other variations. Check whitepapers for details. Google dual depth peeling for how you can generate two passes in one pass.

devdept
07-21-2009, 12:08 AM
Thanks Dark Photon,

Am I asking to much for a working C++ sample? Do you know if there is one somewhere?

One last quick question:
Can we consider that this feature is available only if the hardware supports depth textures?

Thanks,

Alberto

Jan
07-21-2009, 03:05 AM
It is not a feature that you can enable, you have to implement it yourself! And to implement it, you need depth-textures and fragment shaders.

Here is a good source about depth-peeling. (http://lmgtfy.com/?q=depth+peeling)

BTW, that website knows a lot of other stuff, too.

Jan.

Dark Photon
07-21-2009, 04:40 AM
One last quick question:
Can we consider that this feature is available only if the hardware supports depth textures?
That's a little strong. You could do it with hardware that supported floating-point or even fixed-point textures (into which you've encoded floating point values -- e.g. stripe a float across an RGBA8). You just need some way to get floating point depth values from the previous depth buffer into the shader, to an accuracy sufficient for your needs.

devdept
07-21-2009, 05:25 AM
If you take a look to this code (the most serious found on the internet so far) you can see how hard it is this thing to code...

http://developer.download.nvidia.com/SDK/10.5/opengl/samples.html#dual_depth_peeling

What the bigs doing for nice transparency? I mean Autodesk, SolidWorks, etc?


Thanks,

Alberto

Ilian Dinev
07-21-2009, 06:04 AM
Either "Sort by object" or "Sort by polygon" . You can quickly construct a test case to see the artifacts: two intersecting triangles, of different color and opacity.

devdept
07-21-2009, 06:27 AM
Ilian,

How can you sort by object a sphere inside the other? They share the same centroid and the same distance from the viewer...

Thanks,

Alberto

Ilian Dinev
07-21-2009, 06:37 AM
You can't. With sort-by-polygon you can.
It's all a choice for efficiency vs correctness. With sort-by-object, you transform and sort few objects. With sort-by-polygon you transform, average-z sort and stream-upload geometry of many many poly (quite a performance hit).

With depth-peeling you effectively disable ALL acceleration logic from the gpu and avoid-override the established pipeline.

devdept
07-21-2009, 07:01 AM
Ilian,

Please be more clear.

With sort-by-polygon you transform, average-z sort and stream-upload geometry of many many poly
Suppose you have a complex object (like a human body) made of 1,000 triangles in a display list. Now if you want to display it correctly with a transparent material you need to skip the display list and sort each triangle from farther to closer (computing the distance from the eye to the triangle centroid) at each frame (during rotation for example) or is there a more straightforward way to do it?

Thanks,

Alberto

Ilian Dinev
07-21-2009, 08:18 AM
Neither of the two sorting methods can use display-lists. (oh well, there's a trick for sort-by-object, but it'll waste VRAM).

Btw sort-by-object does polygon-sorting of each object, too! But since the material for the object is the same, you only need to re-shuffle the vtx-indices. Thus you can keep a static VBO with the big heavy vtx-data constant; and only stream an IBO, that contains the vtx-indices in a sorted fashion. You transform those triangles on the cpu, and sort by Z again on the cpu, and finally upload the triangles' vtx-indices to a streaming IBO. Same stuff, but much heavier and complex, happens in sort-by-polygon.

Now, in sort-by-polygon you have materials clashing with each-other. It's possible in the z-order to have this arrangement: Mesh7.Triangle99 , Mesh7.Triangle14, Mesh3.Triangle56, Mesh2.Triangle10 . Those Mesh7, Mesh3 and Mesh2 will usually use different textures, different shaders, different shader-uniforms. Ouch :) . In the worst case you will have to switch all those states on every triangle drawn.

It's really not straight-forward. Depth-peeling, and its dual- and octo- versions could be really the easiest way to go, if you want extreme robustness. They're currently slow and waste a lot of VRAM, though. Sooo, if fidelity and robustness can be sacrificed in your project, look back at PlayStation1. It has no z-buffer. All geometry onscreen is manually sorted-by-polygon. In modern gpus you can translate that system to one uber-shader, one texture-atlas (or preferably a texture-array), and the OT ("ordering table"). (shader-branch coherency is guaranteed in most cases, so a uber-shader won't be that bad) Or make N passes for the M-sized ordering table, giving N blend/raster-modes and M bins of z-precision. It'll make the count of raster-mode changes limited to NxM, instead of #triangles. Even depth-peeling can't give the robustness of having those N modes (example modes: alpha-blend, additive-blend, refraction-mode). Still, it'll require dynamic creation of streaming VBOs.

devdept
07-22-2009, 12:10 AM
Hi Ilian,

How can you use the VBO/IBO solution with different objects? is you have vertices/triangles of mesh1 and vertices/triangles of mesh2? Normally you call mesh1.Draw() then mesh2.Draw(). How is it possible to sort triangles of the two objects together?

Thinking to the past many famous application do correct transparency with OpenGL since a long time. I believe that during the '90 deepth peeling was not available and probably not even VBO and IBO, how could they do correct transparent triangles intersections with plain OpenGL?


Thanks,

Alberto

ZbuffeR
07-22-2009, 01:14 AM
Thinking to the past many famous application do correct transparency with OpenGL since a long time.
[citation needed] which ones ? In the CAD departement, neither 3dsmax nor blender do this correctly.
Games are often completely wrong as soon as more than one transparency plane are overlaid.

devdept
07-22-2009, 01:42 AM
Mmm... ZBuffer, I've never notices something so bad in these 3D applications. In your opinion what are they doing for such a good compromise of quality/speed?

Thanks,

Alberto

Ilian Dinev
07-22-2009, 01:54 AM
during the '90 deepth peeling was not available and probably not even VBO and IBO, how could they do correct transparent triangles intersections

It has never ever been possible with rasterization. Well, unless they start splitting the intersecting triangles at the intersection line - which is computationally expensive and thus they don't do it.


Normally you call mesh1.Draw() then mesh2.Draw(). Which is only possible thanks to the z-buffer; and nowadays rendering in big batches is the optimal way. But in the past, you would draw triangle by triangle anyway. Transparent objects can't update the z-buffer, so sorting should be done like in the past. Most recent games generally give-up sorting at all, as ZbuffeR noted. Some just sort objects, without sorting the triangles in those objects. Gamers don't notice, and in the cases artifacts in static geometry would be really noticeable, it's the artists' task to simplify the level.

To do transparency as well as in CADs, you have to dynamically merge geometry of mesh1 and mesh2. As I wrote, you may have to do mesh1.numTris+mesh2.numTris number of state-changes in the worst case. That's where the specialized drivers for Quadro and FireGL kick-in, at fast state-changes and better performance in sending many tiny batches via PCIe/AGP.

devdept
07-22-2009, 02:08 AM
Ilian,


To do transparency as well as in CADs, you have to dynamically merge geometry of mesh1 and mesh2. As I wrote, you may have to do mesh1.numTris+mesh2.numTris number of state-changes in the worst case. That's where the specialized drivers for Quadro and FireGL kick-in, at fast state-changes and better performance in sending many tiny batches via PCIe/AGP.

Please, help me with this.

Suppose you have a bulding structure made of columns and floor planes.

Normally we loop over the object array and call Mesh.Draw() for each object (in this case we use a display list).

Now Suppose that all the objects are made transparent.

When transparency come into play we need to collect all the triangles from the mesh objects and put them (at each frame) inside a new array, sort them and draw them from farther to nearer after opaque objects: what do you mean state-changes?

Thanks,

Alberto

Ilian Dinev
07-22-2009, 02:54 AM
State-changes happen when you have to use another texture, another shader, other shader-uniforms, etc.
Thus, every triangle from the merged+sorted list should have info about what state it needs.

Really, really, really, look at PlayStation 1 (aka PSX).
Basics of OT ("Ordering Table"):
http://www.exaflop.org/docs/naifgfx/naifsort.html
Extensive info, incl. types of packets:
http://www.raphnet.net/electronique/psx_adaptor/Playstation.txt
(search for "Packet Descriptions" in that file)

Basic description:
http://psx.rules.org/gpu.txt

devdept
07-22-2009, 03:10 AM
Ilian,

I will give a look to the links you provided thanks. Just one last question. In the introduction below what are the outhor is referring to polygon[loop].z ? Is this the eye to centroid of the triangle distance or something else? Does a more smart way to compute this distance exist rather then doing d = Sqrt((eye.X-centroid.X)^2 + ...) ?


A basic sort algorithm
The simplest and probably slowest routine you could create for your 3d engine would go something
like this:-

do
{
sorted = 1; for ( loop = 0; loop < num_polys_to_sort - 1; loop++ )
{
if ( polygon[ loop + 1 ].z > polygon[ loop ].z )
{
temp_polygon = polygon[ loop ];
polygon[ loop ] = polygon[ loop + 1 ];
polygon[ loop + 1 ] = temp_polygon;
sorted = 0;
}
} } while ( sorted == 0 );

Ilian Dinev
07-22-2009, 03:22 AM
It's the average transformed-to-screenspace Z of the triangle.

vec3 v0 = transform_to_screenspace(triangle[i].vert0);
vec3 v1 = transform_to_screenspace(triangle[i].vert1);
vec3 v2 = transform_to_screenspace(triangle[i].vert2);

float z = (v0.z + v1.z + v2.z)/3;

devdept
07-22-2009, 04:33 AM
Wow, in this case you need also to project each mesh vertex with the glu.Project() at each frame!? It is faster than doing d = Sqrt(...)? Maybe it is possible to get the source of the glu.Project() and remove operation on X & Y that are not useful in this case...

Thanks,

Alberto

dorbie
07-22-2009, 04:42 AM
Alpha-to-Coverage with MSAA can do the trick.

It is useful for cookie cutter alpha to avoid sorting in a zbuffered scene but it does not "do the trick" for alpha blending. The foremost transparency totally occludes any distant transparency, there is no accumulation of blended results. It is certainly useful in many situations, but the levels of transparency are quite limited in addition to the lack of accumulation.

dorbie
07-22-2009, 04:44 AM
It is not a feature that you can enable, you have to implement it yourself! And to implement it, you need depth-textures and fragment shaders.

Here is a good source about depth-peeling. (http://lmgtfy.com/?q=depth+peeling)

BTW, that website knows a lot of other stuff, too.

Jan.

ROFL

dorbie
07-22-2009, 04:58 AM
Wow, in this case you need also to project each mesh vertex with the glu.Project() at each frame!? It is faster than doing d = Sqrt(...)? Maybe it is possible to get the source of the glu.Project() and remove operation on X & Y that are not useful in this case...




That's about right, the rest is down to optimization, e.g. you might do better moving the eye into object space.

Now, the whole idea of somehing like depth peeling is it moves the sort problem into the massively parallel pixel domain problem which simplifies the problem but places the burden on hardware features (and image based data overheads).

Most people get by with some cheesy hack w.r.t. transparency that works in most cases.

Zbuffers are great, they solve a lot of problems and make our live easy. Blended transparency takes that wonderful cruch and beats you with it if you care about truly general purpose blending. Most developers just compromise with an implementation that works 95% of the time or perhaps even 100% of the time with their scenarios. This is not necessarily laziness, just a recognition that the 'correct' solution is often ridiculously slow for marginal benefit.

devdept
07-22-2009, 05:29 AM
Thanks for your clarification Dorbie,


Just to be sure, can you please help me with the correctness of following steps?

1) collect triangles from the scene objects that have a transparent color
2) sort them using the following formula

vec3 v0 = transform_to_screenspace(triangle[i].vert0);
vec3 v1 = transform_to_screenspace(triangle[i].vert1);
vec3 v2 = transform_to_screenspace(triangle[i].vert2);
float z = (v0.z + v1.z + v2.z)/3;
3) draw opaque objects
4) draw the sorted list of transparent triangles

And:
Does this approach work with legacy hardware?
Is the only hardware accelerated improvement we can apply the use of IBO/VBO that Ilian mentioned above?
Is this solution what the most of CAD 3D applications doing? (not in raytracing of course)


Thanks,

Alberto

devdept
07-27-2009, 11:14 PM
Hi Ilian,


Ordering Tables really enlightened me, thanks for pointing me there!

There is one thing I still can't understand though. If you do:

vec3 v0 = transform_to_screenspace(triangle[i].vert0);
vec3 v1 = transform_to_screenspace(triangle[i].vert1);
vec3 v2 = transform_to_screenspace(triangle[i].vert2);

float z = (v0.z + v1.z + v2.z)/3;

v0.z and v1.z and v2.z are all something like 0.9994885 and if I use this averaged z value to find a position in a 256 elements ordered table:

int positionInTable = z * 256;

ot[positionInTable] = myTriangle;

I only fill the latest element of the table and never all the others.

What am I doing wrong? I am following the instructions found on this page: http://www.exaflop.org/docs/naifgfx/naifsort.html


Thanks again,

Alberto

Ilian Dinev
07-28-2009, 02:45 AM
myTriangle->pNext = ot[positionInTable];
ot[positionInTable] = myTriangle;

Each element of ot[] is essentially the start of a linked-list. You prepend elements to those linked-lists (prepending speeds-up the code).
There's also the trick (visible in the PSX code tutes) to use a pre-allocated big array to do element-allocation from, instead of using malloc/new.

devdept
07-28-2009, 05:27 AM
Hi Ilian,

I probably didn't explain myself correctly. I was pointing that the z values I got from the gluProject() of my triangles vertices are all close to 1 (as you know depth buffer is not linear) and in this way only the last element in the array is filled ( with a long linked list ).

What am I missing ?

I am converting the depth value to integer simply multiplicating the 0 to 1 depth value by 256 and always getting 255 for all triangles. I can probably resize it to 1.000.000 and get some more element filled but is it the right approach?

Thanks,

Alberto

Ilian Dinev
07-28-2009, 05:35 AM
It's the projection-matrix that gets in the way, I guess. (honestly I'm very forgetful and bad at the matrix-transforms).
I'd inspect matrix values, refresh on maths and find the way to increase the range.

devdept
07-28-2009, 05:53 AM
Ilian,

Are you sure that I don't need to linearize the depth value ?

The article you pointed me to doesn't provide any clue on this...

Thanks,

Alberto

Ilian Dinev
07-28-2009, 05:58 AM
On the contrary, it's better to quantize into ot[] by 1.0/z , to have more layers near the camera (where gamers can notice artifacts more easily)

devdept
07-28-2009, 06:12 AM
I'll try and let you know.

Thank so much again.

Alberto

devdept
07-28-2009, 06:18 AM
No Ilian,

Unfortunately 1/0.9999232 is always very close to 1.

We are missing something here...

Do you know any other resources on the internet on Ordering Trees?

Thanks,

Alberto

Ilian Dinev
07-28-2009, 09:17 AM
No, it was really hard to find those links, even when I know the stuff and keywords.
In practice, I've done the Z computation+quantization in my own projects in camera-space, not clipspace. So, get the modelview matrix, multiply the triangle-center point with it, and use the resulting Z. (instead of using gluProject).
Still, a quick fix for your current code could be:


float z1; // = 0.9999232 , this is what you already have

int z2 = (1.0f-z1)*10000; // notice your z-far has a say in this
if(z2<0)z=0; else if(z2>=OT_SIZE)z2=OT_SIZE-1;

tri->pNext = ot[z2];
ot[z2]=tri;

devdept
07-29-2009, 12:20 AM
Hi Ilian,


Thank you again for your help.


In practice, I've done the Z computation+quantization in my own projects in camera-space, not clipspace. So, get the modelview matrix, multiply the triangle-center point with it, and use the resulting Z. (instead of using gluProject).

I love this: does it mean that using camera-space the z values are well distribuited between znear/zfar?

I'll try immediately!


Thanks so much again Ilian,

Alberto

devdept
07-29-2009, 02:47 AM
Hi Ilian,

After working all the morning and getting OT working I got this disappointing result:

http://www.devdept.com/one.jpg

The problem is that some long and skinny triangles sorted by their averaged Z depth are sorted wrong no matter how long the OT is:

http://www.devdept.com/two.jpg

In some favorable orientations the result is GREAT:

http://www.devdept.com/three.jpg

PLEASE, tell me that there is a workaround to this issue. What about getting the closer Z depth of each triangle?


Thanks,

Alberto

Ilian Dinev
07-29-2009, 03:09 AM
Hm, similar artifacts are to be expected, but I haven't seen so bad cases :(

Try Z_for_sorting = Zmin + (Zaverage/100);

devdept
07-29-2009, 03:35 AM
No luck, do you think that I am doing something wrong or that this is an OT limitation? In my opinion it fails even on a cube model.

The result with the last formula you provided:
http://www.devdept.com/four.jpg

Thanks again,

Alberto

ZbuffeR
07-29-2009, 06:02 AM
Of course any per-triangle sort will have problems, for perfect solutions I am only aware of bsp trees and zbuffer.

Some things to try :
- disable depth write
- enable backface culling
If you actually need the backfaces, do it in two separate passes : cull frontfaces first, then backfaces (with or without depth write/test)

The screenshot of your 'target' in first pages does not have backfaces.

devdept
07-29-2009, 07:07 AM
Hi ZbuffeR,

Thanks for joining again the discussion.


Some things to try :
- disable depth write
Do you mean glDisable(GL_DEPTH_TEST)?

Just tried, even combined with dual pass:

gl.Enable(gl.CULL_FACE);
gl.FrontFace(gl.CCW);
DrawOT();
gl.FrontFace(gl.CW);
DrawOT();
gl.FrontFace(gl.CCW);

By the way, I have been reading from years "sorting triangles from farther to closer" but this fails in the most trivial case below. The quad behind from the view direction is closer than the other: this invalidates all the sorting algorithms.
http://www.devdept.com/six.gif


The screenshot of your 'target' in first pages does not have backfaces.You are right, I didn't noticed this. They probably have face normal *all outward* that we don't. Here is the resutl we are trying to achieve:
http://www.devdept.com/five.jpg

We feel to be very close to the solution but unfortuantely cannot guess what are we missing.

Any idea would be greatly appreciated.


Thanks,

Alberto

Ilian Dinev
07-29-2009, 08:00 AM
Just an idea: modelers can easily display dynamically-subdivided surfaces, and can handle complex concave poly, maybe they are subdividing flat transparent polygons before sorting?

devdept
07-29-2009, 08:59 AM
Ilian,

Do you mean sorting faces instead of triangles?

Thanks,

Alberto

Ilian Dinev
07-29-2009, 09:11 AM
I mean: you already split faces (polygons) into triangles, maybe further splitting the triangles with long edges into smaller triangles is the next step.
A glintercept to see how other modelers do it may be necessary.

devdept
07-30-2009, 12:38 AM
Mmm, we could subdivide skinny triangles if the face color has an alpha value different from 255...

Can we therefore say in summary that the famous sentence "sorting all the polygons from farther to nearer" is void if triangle sizes are not homogeneous?

Thanks to you all, it was a pleasure to discuss with you about this foundamental 3D graphics concept :).

Alberto

devdept
07-30-2009, 02:55 AM
Look here: even this simple test fail, we are using the following with outwarding normals:

glEnable(gl.CULL_FACE);
glFrontFace(gl.CW);
DrawOT();
glFrontFace(gl.CCW);
DrawOT();
http://www.devdept.com/height.jpg

Are we doing something wrong or are these OrderingTable limitations? (none of the boxes touch the other)


Thanks,

Alberto

Ilian Dinev
07-30-2009, 03:18 AM
Could you upload those two meshes as .obj/.mtl , so I can try toying with them?

I inspected how a modeler draws some simple meshes, it was simply doing a qsort() , no subdivision, nothing fancy.

Ah, here's a test:

http://img441.imageshack.us/img441/1355/broken.png

devdept
07-30-2009, 03:38 AM
Hi Ilian,

Here they are:

http://www.devdept.com/random_bars.zip
http://www.devdept.com/extrusion.zip

What is the difference between Modeler and Layout in your image?

Thanks,

Alberto

Ilian Dinev
07-30-2009, 04:01 AM
Exactly the same object. In Modeler, no lights are/can_be specified; in Layout, there's one directional light - that's why the darker shading.

The Modeler version looks perfect, but look at this:
http://img508.imageshack.us/img508/685/broken2.png

devdept
07-30-2009, 05:59 AM
Rhino3D does the job, perfect in any orientation... How?

http://devdept.com/nine.jpg

I don't believe they are splitting OBJ triangles...

What modeler are you using?

Thanks,

Alberto

devdept
07-30-2009, 06:03 AM
What about treating planar faces as a single entity? Placing all the triangles in the same OT row ? Could this improve the result?

Only non planar faces need a different treatment, what do you think?

Thanks,

Alberto

GeLeTo
08-04-2009, 01:50 AM
The easiest way (that I know of) to sort the polygons perfectly is by using a BSP tree. There's no way to avoid artifacts when sorting polygons on a z-value.
You only have to regenerate the BSP tree when the polygons change and you can use the bounding box of the changed polys to update only part of the tree. The sorting is very simple and fast.
Still IMO depth peeling is the way to do it.

Heiko
08-04-2009, 03:13 AM
I think this is a very interesting topic, something I have been thinking about myself a lot. But never implemented something so far. Some thoughts I came up with, but I have no idea whether they would be plausible to implement:

- Would it be possible to do a combined approach? Sorting triangles, but use depth peeling only on triangles that intersect.

- What about using the geometry shader to split up intersecting triangles so that perfect transparency can be obtained by sorting triangles and let the geometry shader take care of the last problem of intersecting triangles. I have never used geometry shaders, but would it for example be possible to do a depth texture lookup (from a pre z-pass) when drawing a triangle and using this texture lookup to split up a triangle if not every vertex of the triangle is equal to the value in the z buffer?

Any thoughts on this? (again: they are just wild ideas I just came up with)

devdept
08-04-2009, 04:49 AM
Hi Ilian,

I want to try also using the midpoint of longest triangles edge (see picture B below), most of the issue are related to skinny triangles centroid too close to the short side:
http://www.devdept.com/ten.gif
What do you think?

Thanks,

Alberto

Ilian Dinev
08-04-2009, 06:29 AM
I'm almost sure those midpoints will also suffer from artifacting on other POV, but it's worth a try.
OTs are for games, some modelers like Lightwave do qsort (I inspected with glIntercept), Rhyno3D possibly uses the forementioned BSP (splitting a big scene may not be quick). Depth-peeling is nice, but can make you run out of VRAM...

I've only been interested in graphics for gamedev and stuff where I manually sort in layers, so OTs have been the solution for me; didn't need to research further.

devdept
08-04-2009, 06:58 AM
Ilian,


some modelers like Lightwave do qsort (I inspected with glIntercept)
Isn't qsort a simple sorting algorithm? In my opinion if you compute zDepth averaging triangle vertices depths you will face the same problem... I can use an OT large enough to have one triangle per cell (in this case I have the same result of a qsort) but the artifacts are still there.

What do you think?

Alberto

Ilian Dinev
08-04-2009, 07:30 AM
Yes, those problems were visible on the Modeler and Layout screenshots I posted. A qsort is better at sorting - it's just that it's not suitable for games, whereas OT is.

Really, do glIntercept on Rhyno3D to see if/how the primitives are split and ordered.

devdept
08-05-2009, 04:11 AM
Hi Ilian,

After many test this morning I discovered that there is no way for good transparency if you have skinny triangles. Either with OT or qsort.

The next time I will try to decompose long triangles on the fly to see if we can get better results.

I really can't understand how you can inspect what other products are doing seeing only OpenGL commands with glIntercept.

Thanks again for your precious suggestions.

Alberto

Ilian Dinev
08-05-2009, 04:27 AM
With glintercept capture a frame, find the draw-calls, count the primitives drawn and compare with expected number, copy/paste in a small app of yours, see how the object looks (might assign diff colors to each tri)

GeLeTo
08-05-2009, 06:12 AM
...Depth-peeling is nice, but can make you run out of VRAM...
This is unlikely, if the scene is too complex you may need too many passes but the used VRAM will be the same. You need two depth/color buffers instead of one. On current hardware it makes sense to use even more buffers (via MRT):
http://research.microsoft.com/apps/pubs/default.aspx?id=70307

Ilian Dinev
08-05-2009, 06:39 AM
Yes, I wrote that exactly because the multi-layer approach seems best.
Though, I was also thinking in terms of MSAA and HDR (11-10-11 is fortunately available), though MSAA might not be necessary for transparent objects.

devdept
08-10-2009, 07:02 AM
Hi Ilian,


Look at this model (a cube with a small cubic cavity close to a corner):

http://www.devdept.com/eleven.jpg

How can you expect proper sorting in this case with all the approaches we discussed? Every triangle's meaningful point is wrong in this case...


Thanks,

Alberto

Ilian Dinev
08-10-2009, 08:37 AM
Yup, that's the pitfall of triangle-sorting; together with its inability to handle intersecting triangles. Those are unfixable (notice we've been looping in circles here ^^ ).

There's possibly a neat modern standard trick, which I forgot to mention: alpha-to-coverage. (it's just that it produces hi-freq noise in the distance)

And the BSP approach could also be great.

devdept
08-10-2009, 11:57 PM
Hi Ilian,

Honestly, thinking again to this model, there is probably no difference between drawing the small cube before or after the big one, what do you think?

BSP is about splitting triangles, isn't it? I don't believe it would be fast enough for real time shading.

I don't know alpha-to-coverage, do you know a tutorial that help with its usage in transparency?


Thanks,

Alberto

Ilian Dinev
08-11-2009, 06:31 AM
There can be difference when the cube-order isn't neat, and colors are different for the cubes.

BSP: only once the geometry is modified, you recreate a BSP. When the user views the model from all POV, there's no need to generate a new BSP. It will be correct from all POV.

For A2C, there are docs, and the nVidia SDK9.5 examples.

devdept
08-12-2009, 12:07 AM
Good morning Ilian,

Yesterday I studied again BSP and I have a question for you:

When you have thousands of triangles cutting them by plane is something very heavy to process, do you believe that deciding if they are in front or back based on their centroid will help a little compared to Ordering Tables or will end with the same result?

Thanks,

Alberto

Jan
08-12-2009, 01:25 AM
BSP-Trees are designed to fully solve all problems regarding sorting. If you don't do it properly, you will have exactly the same problems, as you have right now.

The main problem with BSP-Trees is that generating them is an O(n*n) operation. You can add many tricks to reduce the cost, but for complex geometry it will always take some time (having an object with several thousand triangles can take *seconds*, at least with a naive implementation). But if you can guarantee, that all your transparent objects have less than, say, 5000 polygons, it should be possible to generate a BSP-Tree without a much noticable performance hit.

Jan.

devdept
08-12-2009, 04:57 AM
Thanks Jan,

We have almost decided to go for it. To cut a triangle by plane the only approach is to check for segement->plane intersection on the 3 edges, right?

Thanks,

Alberto

Jan
08-12-2009, 06:36 AM
Yep, that's the way to go.

devdept
09-20-2009, 05:43 AM
Hi Guys,

After studing and implementing BSP I am quite disappointed and sure that I am missing something. I followed the Norman Chin approach of the Graphics Gem V "A walk through BSP trees" p.121.

Now I have BSP working and splitting geometry correctly accorting to all the sample provided in the article above. Even with the most simple geometry - a very simplyfied cylinder - (see below / top view) I can't render the correct transparency result.

http://www.devdept.com/twelve.gif
The result is a completely unbalanced tree that does not sort triangles correctly from E-D to H-A.

Now I am wondering:

1) Am I doing something wrong?
2) Do I need to split the process in two step doing a first pass with back facing only triangles and a second one with front facing ones?
3) Shall I change my GL_DEPTH_TEST settings?


Thanks so much to everybody again for your precious help!

Alberto

devdept
09-20-2009, 01:13 PM
Or maybe I still need to sort from back to front even after the BSP tree construction? I mean computing the distance from the viewer from each triangle.

Thanks,

Alberto

ZbuffeR
09-20-2009, 02:30 PM
as per :
http://www.opengl.org/resources/code/samples/bspfaq/

For each node of the tree, you have to evaluate if camera is on the + or - side, and change the drawing order accordingly.
pseudo code :


void Draw_BSP_Tree (BSP_tree *tree, point eye)
{
real result = tree->partition.Classify_Point (eye);
if (result > 0)
{
Draw_BSP_Tree (tree->back, eye);
tree->polygons.Draw_Polygon_List ();
Draw_BSP_Tree (tree->front, eye);
}
else if (result < 0)
{
Draw_BSP_Tree (tree->front, eye);
tree->polygons.Draw_Polygon_List ();
Draw_BSP_Tree (tree->back, eye);
}
else // result is 0
{
// the eye point is on the partition plane...
Draw_BSP_Tree (tree->front, eye);
Draw_BSP_Tree (tree->back, eye);
}
}

so a tree walk for your cylinder example would be:
A: cam is in + side : walk to - branch
B: + side : walk -
C: - side : draw C, then walk -
D: - side : draw D, then walk -
E: - side : draw E, then walk -
F: - side : draw F, then walk -
G: + side : walk -
H: + side : walk - (nop), draw H, back to parent
G: draw G, back to parent
F: back to parent
F: back to parent
E: back to parent
D: back to parent
C: back to parent
B: draw B, back to parent
A: draw A, back to parent
exit depth-first walk.

It does work :)

devdept
09-20-2009, 10:54 PM
Hi ZbuffeR,

I am very sorry but the picture I provided was wrong. Please consider this one:

http://www.devdept.com/thirteen.gif

What we get is:

TREE CONSTRUCTION

Selected plane is face [A]
Added face [A] to same dir
Added face [B] to neg dir
Added face [C] to neg dir
Added face [D] to neg dir
Added face [E] to neg dir
Added face [F] to neg dir
Added face [G] to neg dir
Added face [H] to neg dir
Selected plane is face [H]
Added face [H] to same dir
Added face [G] to neg dir
Added face [F] to neg dir
Added face [E] to neg dir
Added face [D] to neg dir
Added face [C] to neg dir
Added face [B] to neg dir
Selected plane is face [B]
Added face [B] to same dir
Added face [C] to neg dir
Added face [D] to neg dir
Added face [E] to neg dir
Added face [F] to neg dir
Added face [G] to neg dir
Selected plane is face [G]
Added face [G] to same dir
Added face [F] to neg dir
Added face [E] to neg dir
Added face [D] to neg dir
Added face [C] to neg dir
Selected plane is face [C]
Added face [C] to same dir
Added face [D] to neg dir
Added face [E] to neg dir
Added face [F] to neg dir
Selected plane is face [F]
Added face [F] to same dir
Added face [E] to neg dir
Added face [D] to neg dir
Selected plane is face [D]
Added face [D] to same dir
Added face [E] to neg dir
Selected plane is face [E]
Added face [E] to same dir


TREE TRAVERSING AND RENDERING

The viewer is on the negative side face [A]
Draw: A

The viewer is on the POSitive side face [H]
The viewer is on the negative side face [B]
Draw: B

The viewer is on the POSitive side face [G]
The viewer is on the negative side face [C]
Draw: C

The viewer is on the POSitive side face [F]
The viewer is on the negative side face [D]
Draw: D
Draw: E
Draw: F
Draw: G
Draw: H

That is completely wrong.

Do you confirm that BSP alone can do the job of sorting from back to front the triangles for transparency purpose? If yes, at least I know we need to find a bug in it.

Thanks again,

Alberto

Heiko
09-20-2009, 11:00 PM
Hi ZbuffeR,

I am very sorry but the picture I provided was wrong. Please consider this one:

http://www.devdept.com/thirteen.gif

What we get is:

TREE CONSTRUCTION

Selected plane is face [A]
Added face [A] to same dir
Added face [B] to neg dir
Added face [C] to neg dir
Added face [D] to neg dir
Added face [E] to neg dir
Added face [F] to neg dir
Added face [G] to neg dir
Added face [H] to neg dir
Selected plane is face [H]
Added face [H] to same dir
Added face [G] to neg dir
Added face [F] to neg dir
Added face [E] to neg dir
Added face [D] to neg dir
Added face [C] to neg dir
Added face [B] to neg dir
Selected plane is face [B]
Added face [B] to same dir
Added face [C] to neg dir
Added face [D] to neg dir
Added face [E] to neg dir
Added face [F] to neg dir
Added face [G] to neg dir
Selected plane is face [G]
Added face [G] to same dir
Added face [F] to neg dir
Added face [E] to neg dir
Added face [D] to neg dir
Added face [C] to neg dir
Selected plane is face [C]
Added face [C] to same dir
Added face [D] to neg dir
Added face [E] to neg dir
Added face [F] to neg dir
Selected plane is face [F]
Added face [F] to same dir
Added face [E] to neg dir
Added face [D] to neg dir
Selected plane is face [D]
Added face [D] to same dir
Added face [E] to neg dir
Selected plane is face [E]
Added face [E] to same dir


TREE TRAVERSING AND RENDERING

The viewer is on the negative side face [A]
Draw: A

The viewer is on the POSitive side face [H]
The viewer is on the negative side face [B]
Draw: B

The viewer is on the POSitive side face [G]
The viewer is on the negative side face [C]
Draw: C

The viewer is on the POSitive side face [F]
The viewer is on the negative side face [D]
Draw: D
Draw: E
Draw: F
Draw: G
Draw: H

That is completely wrong.

Do you confirm that BSP alone can do the job of sorting from back to front the triangles for transparency purpose? If yes, at least I know we need to find a bug in it.

Thanks again,

Alberto

Is it me, or does it look right? I mean `abcdefgh' is a correct order to render from the viewers point of view. Further, the viewer is indeed on facing the backside of A, B, C and D.

devdept
09-21-2009, 12:11 AM
You'll see? I am going completely crazy on this transparency :)

Yes, in effect the cylinder is fine as you can see below. But as soon as the geometry complexity increases the "dark shades" remind me that somewhere the problem exists. We provide some images for "OpenGL gurus" to guess where the problem is. Inside BSP or not? There is one thing that make me even more confused the same "dark shades" turn out in the sphere with all the normals outwarded and in the bottle that has faces with normal turned on each quarter (longitudinally).

Thanks for all the help you can provide!

http://www.devdept.com/fourteen.gif