Depth Determination in 3D Flash

Creating appropriate depths for 3D objects is not easy when you're own your own and working from scratch. There are plenty of barriers and complications that get in your way and laugh in your face. The good news is that for full 3D shapes made completely of convex polygons, as long as you are implementing backface culling, you won;t have to worry about determining the depths of any polygon whatsoever. The reason for this is because there will never be an instance where two visible polygons will ever be overlapping. That being the case, specific determination of the order in which each polygon is created or regulation of their drawn depth in z is completely superfluous.

When I say convex polygons, I mean polygons whose sides make up angles that never angle out away from the center or who's corners always point out and not in. Consider the following 2 polygons. Both have 5 sides but the second polygon has a corner which points inward making the polygon not convex, but concave.

Given a concave polygon, when used in combination with other polygons to create a solid, you have a shape which could be positioned in a manner which would allow 2 visible faces of that shape to overlap each other in some way or another. A shape made of convex polygons will never have this problem. Consider the polygons from the previous example extruded into 3D shapes. At this view, you can see that the concave polygon has some overlapping faces and the convex does not.

So you can see how much easier convex polygonal shapes can be to render as they require no z-depth determination on their own. A concave polygonal shape, however, will need that extra effort to z-sort the rendering of individual faces to properly allow for such an overlapping.

Z-sorting, however, isn't as easy as you might hope it would be. You come across complications of depth approximation and relations. Consider the following 3 polygons. Each are flat triangles positioned within 3D space. As you can see, the one on the left is behind them all, the middle is above the one on the left but below the one on the right which itself is above them all. With this view, it would be logical to assume that the left is furthest back followed by the middle and then the rightmost being the closest.

However, upon closer inspection, if the view is altered to be above the triangles, you see their true relation. The leftmost triangle is actually the closest followed by the center and then the rightmost which is actually the one furthest away - all due to the rotation and relation of the triangles in the view.

How would such a determination be figured in Flash? Not easily and not reasonably. It's obvious here, taking the average approach (finding the center point of the points making up the poly to determine a general average depth) would not suffice as the left triangle would still appear on top. In fact, there is only one point in the middle triangle that is any closer to the view than any of the other points in the left triangle. In fact, its that point alone that makes it so the middle triangle is in front of the left. You can't logically be expected to reference every point within one polygon with the points of every other polygon though. And here, you are also approaching polygon clipping (intersection) which definitely isn't happening in Flash unless you intend to dynamically break apart your polygons into smaller polygons to handle that. It just isn't worth it.

What to do? Well, simply put, avoid the circumstances which would allow such a situation to occur! Do this by using simple convex polygonal shapes as much as possible. Obviously, that's not always a solution since you aren't always going to want to have shapes which are restricted to convex polygons. However, you can ease the pain by, though still keeping your more complex shapes simple (being that you're doing this in Flash, you don't want to over do it anyway), constructing your complex concave shapes out of a couple of simple convex shapes. For example, given the original concave shape, you can use 2 combined convex shapes to make it up. Then, the only depth determination needed is between 2 whole shapes - just two, no z-sorting for individual polygons at all.

Granted, there still lies the possibility that the situation of the 3 triangles will arise, but in doing this, you've greatly reduced that threat and have greater overall control over objects as you are dealing with sorting only a select few.

At this point you would consider using the average location (though with shapes with a large number of points you may just want to average a select few that would represent a center) or use an extraneous point within the shapes points - one that is not used for drawing, but rather one which is used to represent its center location in 3D space. Getting the z of that point would represent the z of the object as a whole.

Now, in certain circumstances, tricks and workarounds can be used to help you z-sort in 3D. A lot of this revolves around circumstance though and won't always work. Since it's you who are developing your 3D scene, you are best aware of its circumstances and can best assume what kind of tricks may best suite it, however, circumstances are hardly ever the same so no certain trick and be the definite trick for any or all of the circumstances which may exist. Here is one example though.

Consider a single extruded complex concave shape.

It has 2 end polygons and a series of connecting polygons defining the extrude.

For this 'trick' to work however, you'd need to be able to have a center point within the original polygonal shape that can reach each corner with a straight line without extending beyond the polygon itself... so this will work on a complex concave polygon, but only to an extent. You can see here that there lies a center point where lines can reach each corner of the polygon. This point will be needed in the calculation as well.

As you can see in the 3D extruded view, there exists a lot of overlapping with this. However, the overlapping is confined to the polygons making the extrude. If either of the caps are visible (the actual ends of the shape), and only one would be at a time, it would be above all other polygons. That makes that polygon easy to handle; if visible, draw it on top of all others, otherwise don't draw at all. All that remains are the remaining extrude polygons.

These extruded side polygons are what make up the perimeter. As the perimeter, they each have two neighbors and in following neighbors on one side of a polygon, you'd eventually end up back around to the initial polygon. This being the case, you can conceive these polygons as straightforward array or list of consecutive polygons starting from one side wrapping around until reaching the first polygon again

sides = [polyside1, polyside2, polyside3, ... polysiden];

where polyside n is a neighbor of polyside1 (as is polyside2).

Now, this trick relies on selecting the polygon side which is closest to the view building out and down (in z) from that polygon to the remaining neighbors on each side. With that, the sides array depicted above would be shifted so that the closest poly would be centralized with consecutive neighboring sides to the left and right in the array (before and after respectively) where all the polygons on the left side of the closest polygon are situated before the closest in the array and those on the right side are situated after. Then, starting from the closest you spread out from that center going down the line of sides to the left and right of that which is closer. The closest poly would be on all top of all others and each neighbor would then be on top of its neighbor going down the line. The trick to finding this closest side is using that center point and finding which side is directly between the view and that point. Here, you can see its the darker side that lies right under the center.

From that side, each consecutive neighbor on the left is below it. Same applies to each consecutive neighbor on the right. Where they meet is the poly at the very back of the shape which would either be the first element in the array or the last. So the final array (conceptual array) would be arranged like the following:

sides = [furthest_left_and_back, right_neightbor_closer_to_front, ... closest_side_left_neighbor, closest_side, closest_side_right_neighbor, ... right_sides_closer_to_back, last_rightmost_side_in_back];

Then, by whatever system which pleases, render out those sides (or z-swap) in the order which satisfies overlapping.

This technique, however, has limited application and only applies to certain circumstances. It also relies on your ability to be able to handle the needed calculations to develop the array relations. Given other circumstances, other workarounds can be found I'm sure. It just may take some creativity. Otherwise, you'd just want to keep it simple and keep it to a few easily arranged simple convex shapes.