From: Bruce S. <bas...@un...> - 2003-02-11 20:23:46
|
From: "John Keck" <joh...@ho...> > Bruce, thanks for your reply about implementing new shapes. I can't > understand the difficulty in implementing opacity for shapes. Wouldn't you > just change the color value under the one you're plotting, instead of > replacing it? Comments from David Scherer: 2000 Nov. 3: OpenGL implements alpha rendering, but transparency places severe restrictions on the rendering pipeline. In particular objects need to be drawn in back-to-front order, which is not necessary for opaque objects thanks to Z buffering. Implementing transparency in an environment as unrestrictive as Visual without exposing the additional complexity to the user is not (quite) trivial. 2001 Feb. 27: > >Alpha is harder, because to render translucent surfaces accurately, you > need > >to draw them from back to front. At present, Visual doesn't need to sort > >most primitives (because they are drawn opaquely, and can be zbuffered). > If > >you want to attack this, I can give you some pointers - but it will take > >some effort. > I've been having a little fun playing with adding an "opacity" > attribute to > visual objects and have noticed that I need to control the order in which > objects are drawn. > > David, would you please explain what needs to be done to get the ordering > right? I might want to tackle this. Because Visual is a very general renderer, this is challenging to get exactly right. I can't give you a full specification right now, but I can discuss some of the issues. First of all, the reason that render order matters for translucent objects: Cs = RGB color on screen (framebuffer) Co = RGB color of object a = alpha of object Rendering one object: Cs = Co*a + Ci*(1-a) Rendering two objects: Cs = Co2*a2 + ( Co1*a1 + Ci*(1-a1) )*(1-a2) = Co2*a2 + Co1*a1*(1-a2) + Ci*(1-a1)*(1-a2) Substituting Co1 for Co2 and a1 for a2 in this equation yields a different result, so alpha rendering is order dependent. The correct order is back-to-front, as intuition would suggest. Distant objects are drawn, and nearby objects are drawn over them (transparently). So, the rendering process looks like: 1. Draw all opaque objects, in any order 2. Draw all transparent objects, from most distant to least distant. More precisely, when each pixel is drawn to the screen, it must overwrite only more distant objects. How to accomplish (2)? The first thing that jumps to your mind is something like: transparent = [] for obj in objects: if obj.opacity==1: draw(obj) else: transparent.append( (Z_value_of(obj), obj) ) transparent.sort() transparent.reverse() for obj in transparent: draw(obj) The first question that comes up is how to choose a Z value for an object that isn't a point: the nearest point? The farthest? The center? Here is a case where none of these will work: B 5 A/ 4 file://C 3 /// 2 / / Z=1 / ^ CAMERA The correct ordering is ABC. Nearest, farthest, and middle Z orderings all give BAC! Worse, consider that the objects might be intersecting: \ / X / \ ^ CAMERA And even nonintersecting triangles may not have an ordering: http://www.bath.ac.uk/~ensab/G_mod/FYGM/Gif/ren1f3.gif These problems can be solved for triangles, but the solution involves things like clipping. Solving it for entire Visual primitives seems impractical, so we would have to do something like: 1. Render all opaque objects 2. Break all transparent objects into triangles, and store the triangles 3. Find any pairs of triangles not separated by a plane and split them 4. Sort the triangles (using separating planes) 5. Render the triangles If you want to do some research on the topic, you will usually see it referred to as "Painter's algorithm" or "depth sorting". |