Glass figures have their own appeal, but they are seldom suitable for depicting real figures. Since most figures are not transparent, even computer illustrations must be careful not to show invisible back surfaces. The problem with concealing back surfaces is one of the most complex ideas in three-dimensional presentations. It's not just a matter of drawing only certain surfaces rather than other surfaces. To some extent, surfaces overlap each other requiring that both be drawn -- but in the correct order. We will talk about both concealment and sorting in this section.
There are many ways to hide invisible surfaces. Invisible surfaces usually form an angle between the surfaces and the line of vision (line extending from the eye to the corresponding surface). This angle determines whether the viewer is looking at the front or the back of the surface. The surface must be concealed if the viewer is looking at the back of the surface.
Although the method we will describe is based on a similar idea, it assumes that all surfaces are defined in a counterclockwise sense (mathematically positive). Therefore, the surface is independent of its position in space. If it turns itself around so the viewer sees its back surface, it appears mirror reversed and is drawn "forwards".
Now, it is easily checked with hline when the horizontal lines are drawn, if their ending point (corresponding to the definition of the surface algorithm) is to
the right of the starting point. If this is not the case, you'll be looking at its back surface, which must be hidden. The program checks for this in the procedure Fillpol of the POLY.ASM module at label right_increased:
right_increased: push ax push cx
cmp cx,ax ;correct sequence ? jae direct_ok ;then ok, otherwise: cmp w sf_shift,0 ;suppress surface shift ? je draw ;no, then draw anyway pop cx
pop ax
jmp finished ;polygon will not be drawn draw:
xchg ax,cx ;coordinates in correct sequence direct_ok:
The AX and CX registers contain the x-coordinates of the starting and ending points. With a mathematically positive defined surface, CX must be larger than AX. If this is the case, it is drawn directly (label
direct_ok), otherwise, the filling is ended (if fl_backs TRUE, otherwise the position is ignored and drawn anyway after exchanging the coordinates).
This method is adequate for convex figures and figures without "depth" (i.e., cubes) but what about concave figures such as a U-shaped object? Invisible surfaces are sorted out, but the series order is still not correct, leaving some of the surfaces completely visible, while others remain hidden.
If you now sort the surfaces, so the first surface to be drawn is the one with the largest z-coordinate, i.e., the one that is farthest back, and then always work towards the front, the newer surfaces that are in front cover the recently drawn world. Since this method is also used in painting, this is called a "painter's algorithm".
PCPCunderground
The procedure Fillpol is part of the POLY.ASM file on the companion CD-ROM
How do you go about sorting surfaces? Surface corners usually have entirely different z-coordinates. Complex (therefore, slow) algorithms attempt to make the calculations and to find connections between the corners, which makes a clear assignment possible.
Therefore, the mean value for the depth information is given for each surface and used as sorting criteria. This method can be imprecise. Especially with surfaces having a large range in the z direction, you experience very attractive and, above all, very fast results when combined with the concealment of the surface backs.
The most recently mentioned array mean picks up this middle value and saves the corresponding registers for the surfaces. That is why completed z-values are added to the current array position in the macro z2cx. The mean value is then formed in the label polyok, where this total is divided from the number of corners:
polyok:
mov bx,meanptr ;calculate mean value: mov ax,mean[bx] ;get sum
mov cx,polyn dec cx cwd
div cx ;and divide by number of corners mov mean[bx],ax ;write back
If the variable fl_sort is set to TRUE, the procedure
quicksort, which sorts the array mean, is called after calculating all the surfaces. The depth information (in thelower half of a doublewords) serves as a sorting criterion. The surface identification is sorted with it.
public quicksort
quicksort proc pascal down,up:word
;sorts Mean-Array according to Quicksort algorithm
local key:word local left:word push bx
mov bx,down ;find middle add bx,up
shr bx,1
and bx,not 3 ;posit on blocks of 4 mov dx,mean[bx] ;get key
mov key,dx
mov ax,down ;initialize right and left with base values mov si,ax mov left,ax mov ax,up mov di,ax mov dx,key left_nearer:
cmp mean[si],dx ;greater than key -> continue searching jbe left_on
add si,4 ;posit on next one jmp left_nearer ;and check it left_on:
PC PCunderground
The procedure polyok is part of the POLY.ASM file on the companion CD-ROM
PC
PCunderground
The procedure quicksort is part of the 3DASM.ASM file on the companion CD-ROM
cmp mean[di],dx ;less than key -> continue searching jae right_on
sub di,4 ;posit on next one jmp left_on ;and check it right_on:
cmp si,di ;left <= right ? jg end_schl ;no -> subarea sorted
mov eax,dword ptr mean[si] ;exchange mean values and positions xchg eax,dword ptr mean[di]
mov dword ptr mean[si],eax
add si,4 ;continue moving pointer sub di,4
end_schl:
cmp si,di ;left > right, then continue jle left_nearer
mov left,si ;store left, due to recursion cmp down,di ;down < right -> sort left subarea jge right_finished
call quicksort pascal,down,di ;continue sorting recursive halves right_finished:
mov si,left ;up > left -> sort right subarea cmp up,si
jle left_finished
call quicksort pascal,si,up ;continue sorting recursive halves left_finished:
pop bx ret
quicksort endp
The Quicksort algorithm then divides the array into two halves. It continues to exchange elements until only values larger than that in the middle element are in the left half and smaller values on the right half. This part of the array is then sorted recursively in the same manner.
Unlike the 3D_GLASS.PAS program, 3D_SOLID.PAS does not generate a palette. This is why other colors are also defined for the surfaces. 3D_SOLID.PAS also uses the global variables differently. For example,
glass is set to FALSE because glass surfaces are not desired here; besides, both the variables fl_backs
and fl_sort are set to TRUE for the handling of the hidden surfaces. Otherwise, both programs are identical.