blend_modes.txt
53.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
blend_modes.txt
- Phil Gossett
5/14/95
Overview
-----------
The blend unit performs the first pass of the antialiased z-buffer
algorithm used in the rdp. This algorithm was originally designed for
antialiased, z-buffered opaque surfaces, but has since been extended
to include non-z-buffered, non-antialiased, and neither antialiased
nor z-buffered modes, as well as transparency, decal polys, lines,
"texture edges", and even fake particle systems. In two cycle mode, it
can optionally also do fog.
This document first describes the input muxes used for fog and all the
rendering modes. It then describes the basic opaque suface antialiased
z-buffer rendering mode, together with extensions to transparent and
decal surfaces and lines. It then in detail describes the functioning
of the blend unit for each of the 36 supported rendering modes.
Note that this document only describes the "normal" modes, supported in
the gbi.h macros. There are many possible combinations of the mode bits
not discussed here, some of which might even do something useful...
Blend Mux
------------
The blend mux selects input operands for the blender hardware. The controls
for these muxes are in the SetOtherModes modeword. There are two sets of
mux controls, one for each of the two possible rendering cycles.
The blend equation is of the form:
color = (a*p + b*m) / (a + b)
The reasoning behind this equation will become evident in the discussion of
the anti-aliasing algorithm discussed later in this document.
The four input operands (p, a, m, b) each have four possible sources so two
bits are needed to control each mux. This gives a total of 8 bits per cycle
of blend mux control. The blender will select which of the sets of mux
controls to use depending on the cycle_type mode bit and an internal cycle
counter.
The sources for the 'p' and 'm' muxes are identical:
mux select source
----------- --------------
0 first cycle, pixel RGB
second cycle, blended RGB
1 memory RGB
2 blend (register) RGB
3 fog (register) RGB
For select 0, the cycle select is built into the hardware. The blended RGB
refers to the output of the blend equation on the first cycle. (It's fed
back as an input). Note that this will only work if the 'b' mux is set to
1.0 - 'a', since only the numerator of the blend equation is provided to
the input mux. 'Register' RGBs refer to colors which can be set using
the SetXXXColor RDP commands. Colors set using these commands are stored
in registers within the RDP. Care must be taken to make sure that a PipeSync
command is issued previous to setting these registers. The PipeSync command
inserts a pipeline bubble into the RDP pipe so that a previous primitive is
guaranteed to be finished processing before the register is updated.
It is anticipated that the user will set a group of attributes, process
many primitives, set a new group of attributes, etc. The syncs are exposed
to the user who can more likely determine the minimum number of syncs needed
than would be possible in hardware. (Note that primitive color and primitive
depth (and scissor) are attributes that do not require any syncs.)
The source for the 'a' muxes are:
mux select source
----------- --------------
0 color combiner output alpha
1 fog (register) alpha
2 (stepped) shade alpha
3 zero
The source for the 'b' muxes are:
mux select source
----------- --------------
0 1.0 - 'a' mux output
1 memory alpha
2 1.0
3 zero
In general, the RDP pipeline operates on RGBA pixels with 8 bits per component.
The '1.0' above assumes the alpha is a number between 0.0-1.0. These numbers
are actually fixed point and the output of the 'a' and 'b' alpha muxes have
less resolution (5 bits) than the color components to reduce the hardware cost.
When this alpha is changing slowly across a face, Mach banding can occur due
to the reduced number of dicrete steps in the alpha channel. A special mode
(dither_color_en) can be used to reduce this effect. This mode basically adds
a small amount of randomness (1/2 of an LSB) to the alpha which makes the Mach
banding less noticable. This bit also controls the dithering of RGB from
8 to 5 bits per component (for use in 5/5/5/3 pixel mode).
Note that the dithering of the RGB from 8 bits to 5 bits by adding 3 lsbs of
noise to the original 8 bits (with clamping to prevent wrapping) is enabled
even in 32 bit mode (8/8/8/8), where there is no truncation to be done. Since
this one mode bit controls both RGB dither and alpha dither (which always is
needed, even in 32 bit mode), opaque things should have the dither bit off
in 32 bit mode (so the 3 lsbs don't get stepped on), but transparent things
should have this bit on in 32 bit mode, since the noise from the alpha will
be of the same order as the noise gratuitiously added to the RGB.
In addition, there is one more mux bit (z_source_select), selecting the source
of z for the depth compares used in the z-buffer algorithm. This selects
between primitive z and stepped (shaded) z.
Blend Mux Fog Example
------------------------
Suppose we want to "fog out" from an image to a constant color as a function
(set up in the RSP) of depth. We will assume this is set up (per vertex) in
the stepped alpha of the shaded triangle primitive. We will use the fog
register color as the color to fade too. We will use the stepped shade alpha
as a control to determine how much of the fog color is used. The following
first cycle blend mux selects will achive this effect:
cycle 0, p mux: 0 /* color combiner color */
cycle 0, a mux: 2 /* stepped shade alpha */
cycle 0, m mux: 3 /* fog register color */
cycle 0, b mux: 0 /* 1.0 - stepped shade alpha */
From the blend equation, you can see that these selects perform a linear
interpolation between the fog color and the color combiner output color.
The output of this can then be rendered to the frame buffer in the second
cycle of two cycle mode. This would typically be used only in two cycle
mode, with the second cycle doing the rendering of whatever surface type
in whatever rendering mode. In one cycle mode, only the rendering operation
would be performed. (When you are in one-cycle mode, it is usually best
to make the second cycle controls identical to the first cycle modes.)
Alpha Dither Compare
----------------------
Note that in copy and fill modes, the blender hardware is bypassed
and the fill color or image is written with no opportunity for read/modify
operations. You can achieve a sort of fade effect in copy mode, however,
by using the pixel alpha thresholded with the random dither alpha. Write
enables are generated when the pixel alpha is >= random dither alpha.
By changing the pixel alpha, you can write more or less pixels. The pixel
alpha can come (via the color combiner) from a constant (per poly) such as
primitive_color, or from the stepped (shaded) alpha. This mode is available
in one and two cycle modes as well as in copy mode. While intended mostly
for sprite (2D) applications, it is also used in the "particle system"
modes to produce a "sparkley" effect. alpha_compare_en together with
dither_alpha_en enables this mode. Disabling dither_alpha_en compares
pixel alpha with a constant value (blend_alpha), which if 1 makes color==0
disable writes. This feature (and the one below) is a vestige of indexed
display mode, which is no longer supported.
Blend Mask
-------------
This feature is a vestige of indexed display mode, which is not supported
by the video interface, and hence is pretty useless. Special effects???
Opaque Surface Antialiased Z-buffer Algorithm
--------------------------------------------------
The main goal of this algorithm is to produce an antialiased rendering
of polygonal surfaces without the need for sorting. The key to achieving
this goal is to split the antialiasing problem up into several pieces,
each of which is readily implemented.
There are basically three different kinds of antialiasing. The first
is the antialiasing of textures within polygons. This is accomplished
outside of the blender by the texture hardware, using the industry
standard mipmapping technique. This uses tri-linear interpolation to
produce a correctly sampled texture lookup. (The details of this are
beyond the scope of this document.)
The second kind of antialiasing is the blending of poly fragments within
the pixels they share. The classic example of this is the pinwheel, where
alternating black and white triangles meet at a center vertex. The pixel
within which this vertex lies should be the average of the colors of
all the triangles which share this vertex, weighted by the area of the
pixel at the vertex covered by each of the triangles.
This blending is done in hardware by computing the following:
new color = (a*p + b*m) / (a + b),
where p is the color of the pixel of the new poly, m is the color of the
pixel in the frame buffer memory, a is the coverage value of the new poly,
and b is the sum of the coverage values of all the polys already blended
into that pixel in the frame buffer. Note that no matter what order the
poly fragements come in, they will all average in correctly.
The third kind of antialiasing is the blending of the silhouette of a
foreground object against the background. This is traditionally done at
rendering time in the blend unit. Unfortunately, doing it at this time
has bad consequences for hidden surfacing.
Consider an internal edge of a surface (i.e., an edge shared by two visible
polys not at the silhouette). A priori, when the first of the two polys
is rendered, the blender does not yet know whether it is a silhouette
edge (and hence needs to be blended with the background), or an internal
edge (and hance should not be blended with the background). Note that if
an internal edge does blend with the background, there will be a line
along the edge left when the second poly blends with the first. Once the
blending is done, there is no way to undo it. Also, note that the background
may not even have been rendered yet, unless the rendering of polys is
done in depth-sorted order, which defeats the purpose of z-buffering.
The only way to deal with this is to postpone the blending of silhouette
edges until after the whole scene is rendered. In fact, the final blending
of the silhouette edges is done at display time by the video interface.
While the details of this are beyond the scope of this document, the
main point is that to do this blend on video output, there needs to be
a coverage value left behind in the frame buffer, with which to interpolate
between the foreground (the color of which is in the frame buffer) and
the background (which is assumed to be in one or more of the neighboring
pixels in the frame buffer). This interpolation is as follows:
output color = cvg*foreground + (1-cvg)*background.
Note that for this approach to work, we must be able to distinguish between
internal edges within a surface and silhouette edges between an object and
its background. This is only possible in the context of z-buffering. (If
z-buffering is disabled, the internal edge blending must also be disabled,
since we can no longer distinguish between internal and silhouette edges.)
In order to distinguish between an internal and a silhouette edge, we need
in addition to the normal z buffer containing depth information, some
additional information so that we can tell if two polys sharing a pixel
are within the same surface or not. This added information is the slope
of z (depth) in screen space. This is computed as the sum of the absolute
values of dz/dx and dz/dy. This information is needed for the stepping of
the z values, and so is available for the new poly. The delta for the old
poly is stored in the frame buffer with the z. The rule is then if the
absolute difference in z between the new poly and the frame buffer is less
than the max of the new delta z and the frame buffer delta z, then the
new poly is considered to be part of the same surface as the old poly
already in the frame buffer. If the new z is clearly in front, it overwrites
the frame buffer. If it is clearly behind, it is not written at all.
In fact, while this algorithm works as described above, it has some problems.
First off, we are only representing one fragment per pixel. If there are
multiple silhouettes within one pixel, there will be a slight artifact.
There is some specialized hardware to reduce this effect (the divot circuit)
which is beyond the scope of this document. However, some artifacts remain,
and are simply tolerated. (The effect is usually not too noticable, because
it coincides with a pre-existing discontinuity (the intersection of two
silhouette edges) and is generally dismissed by the eye as "gratuitous
physics" (reflections, defraction, etc.).)
The other, and considerably more visually obvious artifact is "punchthrough",
where part of an object which should have been occluded "punches through"
the object in front of it. This is caused by the z-buffer blending range
being too large, usually due to large delta z's from polys that are very
"edge on" to the viewpoint. There are two different mechanisms to prevent
this artifact.
The first mechanism is to weight the weighting factors in the internal
edge blend by how "edge on" they are. Polys that are more "flat" are
weighted more heavilly than polys that are more "edge on". Thus, the
punching-through poly is attenuated relative the the poly it is punching
through.
The second mechanism to prevent punchthrough is to use the wrapping of
the coverage value to distinguish between contiguous surfaces and a "new"
poly that is not part of that surface. Basically, if the coverage wraps
(i.e., new cvg + old cvg > 1.0), then the new poly must not be part of
the previously rendered surface (or background). In that case, instead of
using the delta z range, the z buffer does a strict compare between the
new and old z, ignoring the deltas, since we know the new poly is not
part of the old surface.
Note that the silhouette antialiasing part of this algorithm depends on
not having shared edges across the silhouette (shared with the backfacing
polys adjacent to the silhouette). Consequently, backfacing polys must
be rejected (culled), or the coverage values at the silhouette edge will
be incorrect for the display-time pass of the antialiasing algorithm. This
is generally desirable in any case, since this saves the rendering time
for the backfacing polys, which should be invisible. Note that this is
only a problem for closed polygonal surfaces (hulls), but not for "open"
surfaces, like flags, which have "external" edges. Since open surfaces
(which aren't "billboarded" to be always facing the viewer, as in trees)
are relatively rare, the microcode always rejects backfacing polys to
conserve time and microcode space. So flag-like objects need to be
represented in the display list twice, once frontfacing and once backfacing.
Transparent Surfaces
-----------------------
In addition to opaque surfaces, we would like to be able to do transparent
surfaces with antialiasing and without the need to sort. There are two
problems with this.
The first problem is avoiding sorting. Strictly speaking, this is impossible.
In order for the colors to be correctly blended from multiple colored
transparent surfaces, the surfaces need to be depth sorted (or carry around
a lot of extra information, more than we have memory for). So we just don't
do the right thing. We do require all the transparent surfaces to be
rendered after the opaque surfaces, but aside from that segregation, there
is no sorting of the transparent (or opaque) surfaces. So multiple colored
transparent surfaces will not be quite right. First off, this case doesn't
come up much (must transparent surfaces are not colored, and it is rare for
multiple transparent surfaces to line up). Secondly, even if it does, most
people have had so little experience with multiple colored transparency that
they don't know what to expect. Generally speaking, rendering the transparent
surfaces in the same order, reguardless of depth, looks just fine.
The second problem with transparency is internal edges. Here, we cannot
do what we did in the opaque surface case. The pixels at an internal edge
of a transparent surface are now blended with the (previously rendered,
opaque) background, as are all the pixels in the interior of the transparent
poly. So if we render one poly sharing an internal edge, and then render
the other poly sharing that same edge, we must be sure not to blend any
pixel twice, or there will be a noticable line on the internal edge as
a consequence of blending twice. So we just don't blend internal edges
of transparent surfaces.
In fact, this is a bit tricker than it seems. We still want the silhouette
of a transparent object to be properly antialiased, so we need to be able
to get the partial coverage values for the silhouette edges, without
double blending the internal edges. This is done with a special mechanism
provided just for transparency.
Under control of a special mode bit (color_on_cvg), we can inhibit the
writing of color (but not coverage) unless the coverage wraps (i.e.,
the sum of the old coverage in the frame buffer and the new coverage of
the currently rendering poly is greater than unity). On an internal edge
of a transparent surface over a fully covered background, the first poly
will write the color, since full coverage plus any non-zero partial coverage
must wrap. The coverage value is always written with the wrapped sum of the
old pixel and new poly coverage, which will be equal to the partial coverage
of the new (first) poly. On the rendering of the second poly, however, the
coverage values will sum to unity on the shared edge, which is not a wrap.
So the second poly will not write over the pixels on the shared edge of the
first poly. Note that this works even if the underlying coverage is not
unity (i.e., the transparent surface is over a pre-rendered silhouette
edge), since still only one of the two transparent polys sharing an internal
edge will get to write (although it could be the second one instead of the
first).
The blender in transparent surface mode uses a different blend equation than
for the opaque surface case. The blend equation for transparency is:
new color = a*p + (1-a)*m
where p is the color of the pixel of the new poly, m is the color of the
pixel in the frame buffer memory, a is the opacity (alpha) of the new poly.
Note that this can be obtained from the opaque surface blend equation by
setting b=(1-a), so the same hardware can be used.
Note that since we never blend across an internal edge, we do not need to
use the deltas to create the z range used to condition blending in the
opaque surface case. Instead, we just compare z directly, since the
transparent surface can only be either clearly in front (in which case it
is written with the transparency-blended color) or clearly behind (in which
case it is not written at all, including coverage).
Note also that unlike opaque surfaces, which modify depth, transparent
surfaces do not modify depth (although they do read it, to test for
occlusion by a previously-rendered opaque object). This is because transparent
surfaces do not want to prevent the writing of other transparent surfaces
which are behind them (but in front of any opaque surfaces).
Decal Surfaces
-----------------
In order to make the creation of models with complex details as simple as
possible, we added a special mode to allow the rendering of "decal" polys
(usually with a texture on them, like a flag or logo) over a previously
rendered opaque surface. Unlike normal rendering, here we only want to
render the decal if it is coplanar with the existing surface. Since we have
the hardware to tell if a surface is (roughly) coplanar from the opaque
surface blend case, we can use that to condition the writes of the decal.
Otherwise the rendering is just like the opaque surface case. Here we rely
on the opaque surface mechanism which conditions blends on the coverage
value not wrapping. This insures that a decal poly written over a fully
covered surface will not blend with that surface, but will instead overwrite
it. Internal edges of a decal will, however, be properly blended (with
each other, but not with the underlying surface).
The coverage values of the decal surface wrap (as do opaque and transparent
surfaces). Note that this only works well if the edge of the decal polys do
not coincide with a silhouette edge of the underlying surface. If this is
the case, it would help to use clamping for coverage since this will result
in simple aliasing. Using wrap in this case fails miserably, since the
coverage values are double what they should be, with some of them wrapping
and some of them not. However, even clamping is wrong. So decals should
never be allowed to exactly coincide with a silhouette edge of the underlying
surface.
Decal surfaces, like transparent surfaces do not modify depth, since they
are supposed to be coplanar with the underlying surface, which already has
the correct depth.
Note that there is also a transparent version of decals, for cases where
some of the underlying surface should blend through. This uses the same
decal z buffering algorithm, but is otherwise like transparent surface mode.
Transparent Lines
--------------------
In this system, there is no explicit line generation hardware. So lines are
rendered as degenerate polys (i.e., a triange two of whose sides are
parallel, and whose third vertex is at infinity) using the normal triangle
hardware. Rendering is very much like the rendering of surfaces. However,
unlike surfaces, lines have no internal edges (since by definition, a line
is an edge). So here, we don't have to worry about incorrecly blending
internal edges at render time. So for lines, all the antialiasing is done
at render time. Note, however, that as with transparent surfaces, lines
must be rendered after any surfaces they may occlude. In fact, lines are
considered intrinsically transparent. Opaque lines are simply transparent
lines with an alpha of unity (or close to it).
The render-time antialising is done by multiplying the new poly (line)
coverage value with the alpha value, and using that as the alpha to do
the transparency blending. This produces the correct result, due to the
absence of internal edges.
The coverage value written into the frame buffer in line mode is the clamped
sum of the old pixel coverage and the new line's coverage times its alpha.
For nearly opaque pixels, the coverage will be clamped to unity, making any
underlying silhouette edge not be modified by the video interface at the
display-time part of the antialiasing algorithm. This prevents the overlying
line from being disturbed by the underlying (and hence hidden) silhouette
edge. However, if the coverage times alpha from the line is nearly zero,
then the silhouette edge is not disturbed, since it should be visible through
the line.
Lines do read depth, and thus can be occluded by opaque objects. However,
lines, like transparent and decal surfaces, do not modify depth. They are
thus blended in display list order, which for thin lines should not matter.
Note that "lines" need not be degenerate triangles. In particular, for
a "ray" coming from somewhere in the foreground to a vanishing point at
infinity, a normal triangle, with two vertices at the source of the ray,
and the third at the vanishing point, produces the desired effect. Also
note that these "rays" can be textured, to produce the effect of a diffuse
particle beam (or "neon glow"), or even "tracer bullets" animated by
changing texture coordinate mapping in the texture unit.
Decal Lines
--------------
This mode also goes by the name "Tron mode", since its main effect is to
exaggerate the polygonalness of an object, making it look more artificial,
and hence more "hi-tech" (at least in the eyes of some artists). Like decal
surfaces, the decal lines are only rendered if they are within the depth
range of the underlying surface, which must be rendered before the decal
line.
Aside from the different z buffer algorithm, the only other difference
between transparent lines and decal lines is the coverage written into
frame buffer memory. For decal lines we do not modify coverage at all. This
is so we do not disturb the antialiasing of the silhouette edges. Note
that the half of the line which is "over the edge" of the silhouette will
not be rendered. Consequently, while the inside edge of the decal line at
the silhouette will be correctly antialiased at render time (as with
transparent lines), the outside edge must still be antialiased at display
time by the video interface. The coverage values at the silhouette are
already correct before the decal lines are rendered. Internal edges are
also already correct, since they are fully covered by the opaque surface
rendering.
Note that the decal line case interacts poorly with one of the features of
the video interface (the divot circuit). In particular, if a decal line is
on the silhouette of an object, the divot circuit can disturb the decal
lines at the silhouette. This can be avoided by not using decal lines
anywhere they could be in the silhouette, or by turning off the divot
circuit (at the loss of some antialiasing quality). Or it can simply be
tolerated as it is. The effect is a thinning and breaking up of the decal
line at the silhouette. In motion, the line doesn't scintillate much,
and so is probably tolerable.
Main Rendering Modes Summary
-------------------------------
color_write_enable: blend_enable: z_write_enable:
opaque surface mode:
(old_depth == MAX_Z) || ((new_depth+delta) >= color_write_enable
(((ncvg+ocvg) <= 7) && old_depth) &&
((new_depth-delta) <= ((ncvg+ocvg) <= 7) &&
old_depth)) || en_antialias
(((ncvg+ocvg) > 7) &&
(new_depth < old_depth))
transparent surface mode:
(old_depth == MAX_Z) || 1 (LERP if wrap cvg, 0 (never write)
(new_depth < old_depth) else save color)
decal surface mode:
(old_depth != MAX_Z) && ((new_depth+delta) >= 0 (never write)
((new_depth-delta) <= old_depth) &&
old_depth) && ((ncvg+ocvg) <= 7) &&
((new_depth+delta) >= en_antialias
old_depth)
transparent line mode:
(old_depth == MAX_Z) || 1 (always LERP) 0 (never write)
(new_depth < old_depth)
decal line mode:
(old_depth != MAX_Z) && 1 (always LERP) 0 (never write)
((new_depth-delta) <=
old_depth) &&
((new_depth+delta) >=
old_depth)
output_cvg: a: b: p: m:
opaque surface mode:
(!blend_enable && ncvg ocvg pixel memory
(ncvg-1)) || color color
(blend_enable &&
(ncvg+ocvg))
transparent surface mode:
(ncvg+ocvg)&7 ((ncvg+ocvg) > 7): alpha 1-a pixel memory
((ncvg+ocvg) <= 7): 0 1-a color color
decal surface mode:
(ncvg+ocvg)&7 ncvg ocvg pixel memory
color color
transparent line mode:
min(FULL_CVG, alpha* 1-a pixel memory
alpha*ncvg + ocvg) ncvg color color
decal line mode:
ocvg alpha* 1-a pixel memory
ncvg color color
Texture Edge Mode
--------------------
Texture edge mode is the first of the special-purpose modes. It is a
variation of opaque surface mode. It is intended mostly for trees.
Trees are usually special-cased to be a textured "billboard", using
alpha values of zero in the texture to define the outline of the tree.
Either two billboards are crossed, or the one billboard moves to always
face the eyepoint, so as to hide the two dimensional nature of the tree.
Frequently, only one bit of alpha (all or nothing) is available in
the highly-packed texture modes usually used for tree textures. Mipmapping
can be used to maintain a properly antialiased tree texture, but at some
point the eye can get close enough to the tree texture to exceed the
highest level of detail.
When a mipmaped texture is rendered beyond its highest level of detail,
one texel may correspond to many screen pixels. Since we do a bilinear
interpolation of the four adjacent texels nearest to the desired pixel,
even a one bit alpha texture will produce a gradient of alphas from
opaque (1.0) to transparent (0.0) over several pixels. This would make
the edges of trees blurry when seen close up, which looks un-natural.
Texture edge mode used to fix this problem by rescaling the alpha, centered
around the 50% point, so that the alpha gradient went from 1.0 to 0.0
over approximately one pixel. The expression for this is as follows:
adjusted alpha = clamp((alpha - 0.5) / L + 0.5),
where the clamp limits the result to between 1.0 and 0.0. Note that
the L used to rescale the alpha gradient is none other than the LOD
used in the normal mipmap process. Note that when L is greater than
1.0, the alpha was not adjusted, and when L is 0.0, this expression amounted
to a threshold around the 50% point. This adjusted alpha was then multiplied
with the coverage value, which would be 1.0 within a texture, with the
edge of the tree being determined by the texture alphas. This coverage
times adjusted alpha was then used as the coverage value for what is
otherwise the normal opaque surface mode.
On further testing, it was discovered that the texture edge mode bit
is in fact both unnecessary and undesirable. Due to the very limited
precision of the hardware implementation of the texture edge circuit,
it seems to do more harm than good, introducing aliasing instead of
eliminating it. However, simply switching this bit off, but otherwise
treating things as texture edge mode, works just fine.
The reason for this is that a "blurryness" in coverage does not produce
a blurryness in the final image, since the backend filter simply ignores
the internal partial coverage bits. So the antialiasing works as it is.
Interpenetration
-------------------
Interpenetration is another special purpose mode, which allows antialiased
interpenetration of polys to a reasonable approximation, at the cost of
some loss of protection against "punchthrough". This mode is intended for
protrusions ("spikes") through a normal opaque surface, and for terrain,
so the placement of objects (like trees) on the surface of the terrain
need not be precise. Note that in the latter case, the terrain should
be the interpenetrating surface, rendered last (after all the other
opaque objects in the foreground). This ordering both prevents unnecessary
punchthrough, as well as rendering more quickly (since the background
terrain does not get written if it is behind an already rendered foreground
object). Interpenetration mode should not be used for articulated joints,
or other purposes where the interpenetration is used to connect what is
supposed to be a contiguous surface. If it is used in this way, unacceptable
punchthrough will result. It is probably better in these cases to use normal
opaque surface mode if this is really necessary. The lines of intersection
will alias, but if the two surfaces are roughly the same color, this may
not be too noticable. Interpenetration mode should not be used gratuitously.
There is both an opaque and transparent version of interpenetration mode.
Interpenetration mode was inspired by texture edge mode (described above).
The idea of scaling a gradient (of alpha in the case of texture edge mode)
by a scaling factor (the LOD in the case of texture edge mode) to rescale
the coverage value used by the normal antialiasing algorithm is carried
over directly. The difference is that a different gradient (of depth in the
case of interpenetration mode) is scaled by a different scaling factor
(the delta z used in the normal opaque surface z-buffer algorithm in the
case of interpenetration mode). The expression for this is:
adjusted cvg = cvg * (oldz - newz) / deltaz,
where oldz is the depth of the pixel already in the frame buffer, newz
is the depth of the pixel from the interpenetrating poly, and deltaz
is the max of the frame buffer delta z and the interpenetrating poly's
delta z, which is the sum of the absolute values of dz/dx and dz/dy.
Conceptually, what this expression is trying to do is estimate in fractions
of a pixel how far away the current pixel is from the sub-pixel point
where the old surface and the interpenetrating new surface will intersect.
What is really needed here is something like the following:
adjusted cvg = cvg * (oldz - newz) /
magnitude of vector difference of delta z's.
In fact, we are using the max of the sums of the absolute values of the two
components of delta z as an estimate for the magnitude of the vector
difference of the delta z's. Furthermore, the delta z in the frame buffer
is highly quantized. In fact, the delta is only accurate to a factor of two.
While this is all horribly inaccurate, it works remarkably well. The reason
is that the while the delta z is very inaccurate, it is consistent throughout
a poly. The error simply moves the line of intersection by a subpixel amount
(which is perceptually not very noticable) while still producing coverage
values consistent with a clean, properly antialiased silhouette edge.
The only down side of this is that interpenetration mode requires using
the wrapping of coverage to select whether to do the coverage adjustment
(if it wraps, and hence is a potentially interpenertating surface) or
not (if it doesn't wrap, and hence is assumed to be part of the same
surface). This can result in unacceptable punchthrough if any previously
rendered objects are behind and either very edge-on or very near the
foreground interpenetration mode surface. This almost never happens for
terrain (where an object is almost never both occluded and near the terrain
surface), and is not terribly noticable in the case of small protrusions
from a normal opaque surface object.
Note that interpentrating polys must be rendered after the surfaces which
they interpenetrate (which need not themselves have been rendered in
interpenetration mode). Other than that, there are no sorting requirements.
"Particle System" Mode
-------------------------
The so-called "particle system" mode is really just a clever use of the
alpha dither compare function described above. This is not a true particle
system, where a large number of discrete particles interact to produce
some interesting effect (fire, explosions, water, etc.). This mode is just
another polygonal rendering mode which can be used to make the surface
of an object resemble the behavior of some kinds of particle systems. Note
that this is much more efficient than a "true" particle system, since by
this method, a large number of particles can be represented by a much
smaller number of polys. The remarkable thing about it is that it produces
properly antialiased silhouettes with correctly rendered internal edges.
This mode is an odd hybrid of the normal 3D opaque surface mode and the
2D alpha dither compare mode. As described above, alpha dither compare is
a way of getting "stipple transparency" by, on a pixel by pixel basis,
allowing a write of the pixel only if its alpha value is greater than the
value of a random number between 0.0 and 1.0. This makes the probability
of a write proportional to the alpha value, which averaging over many frames
produces the effect of transparency. The most obvious use of this effect
is a "transporter", where the object starts out opaque (alpha = 1.0), but
then fades to nothing (alpha = 0.0) in a cloud of sparkles. With some other
effects added in (textures, inverse transparency, etc), this mode can also
be used for explosions, fire, and the like. By animating the alphas with
texture mapping, propagating "waves" of alpha can be produced. Due to the
human visual system's predilection for finding patterns whether they are
there or not (eg., the "canals" on Mars), even though the "particles" are
completely uncorrelated, the waves of alpha will create the perception of
coordinated behavior amoung a large number of interacting particles.
In this mode, the interior of a poly is strictly under the control of the
alpha dither compare. The probability of a write is proportional to the alpha
value. The silhouette edge is handled as for opaque surfaces, at display time
in the video interface. The tricky thing is what to do about the internal
edges of a surface.
Note that in this alpha dither compare case, the density of the neighborhood
is a function of alpha. This means that on a shared internal edge, a blend
will only be likely to occur if the alpha value is quite high. In fact,
the probability of a blend is proportional to the square of the alpha value.
If the blend doesn't happen, then the internal edge is treated like a
silhouette edge, and as long as the neighborhood has enough uncovered pixels,
the display-time antialiasing of these partially covered internal edge
pixels will do the right thing. So the only possible problem is with internal
edges at high alpha values, and here, the weighted average will just merge
the (nearly identically colored) fragments from the two polys with possibly
the wrong weights. But since the two fragments are nearly identical, any
error in weighting doesn't matter.
Note that the thing the alpha dither compare is comparing against the random
dither is the alpha selected by alpha_cvg_select. So this must be set to
select just alpha, since this is what we want to use as the "transparency"
of the "particle system" surface. But this is clearly wrong for the blend of
a shared internal edge. But by the analysis above, it doesn't matter, since
the only place a blend is likely to occur doesn't care what the weightings
actually are. So the internal edges come out fine (as long as the polys
sharing an internal edge are not very differently colored), and the
silhouettes are properly antialiased. As with normal transparent surfaces,
if a color edge is desired within the surface, use texture, not different
colors for the surface characteristics of two groups of polys. This is the
only difference between a particle system surface with an alpha of 1.0 and a
normal opaque surface.
The 36 Supported Rendering Modes
-----------------------------------
antialias_en
| z_compare_en
| | z_update_en
| | | image_read_en
| | | | cvg_dest (0:clamp, 1:wrap, 2:zap, 3:save)
| | | | | color_on_cvg
| | | | | | cvg_times_alpha
| | | | | | | alpha_cvg_select
| | | | | | | | force_blend
| | | | | | | | | z_mode (0:opaque, 1:inter, 2:trans, 3:decal)
| | | | | | | | | | texture_edge_mode
| | | | | | | | | | | alpha_compare_en
| | | | | | | | | | | | dither_alpha_en
mode | | | | | | | | | | | | | p m a b
------------ - - - - - - - - - - - - - ------ ------ ----------- -------
AA ZBUF
opaque surf 1 1 1 1 0 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
trans surf 1 1 0 1 1 1 0 0 1 2 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
decal surf 1 1 0 1 1 0 0 1 0 3 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
trans decal 1 1 0 1 1 1 0 0 1 3 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
interpen 1 1 1 1 0 0 0 1 0 1 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
trans interp 1 1 0 1 1 1 0 0 1 1 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
trans line 1 1 0 1 0 0 1 1 1 2 0 0 0 (0)pix (1)mem (0)pixA*cvg (0)1-a
decal line 1 1 0 1 3 0 1 1 1 3 0 0 0 (0)pix (1)mem (0)pixA*cvg (0)1-a
texture edge 1 1 1 1 0 0 1 1 0 0 0 0 0 (0)pix (1)mem (0)adjA*cvg (1)memcvg
text interp 1 1 1 1 0 0 1 1 0 1 0 0 0 (0)pix (1)mem (0)adjA*cvg (1)memcvg
sub surf 1 1 1 1 2 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
particle 1 1 1 1 0 0 0 0 0 0 0 1 1 (0)pix (1)mem (0)pixA (0)1-a
opaque terr 1 1 1 1 0 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (0)1-a
texture terr 1 1 1 1 0 0 1 1 0 0 0 0 0 (0)pix (1)mem (0)adjA*cvg (0)1-a
sub terr 1 1 1 1 2 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (0)1-a
AA NONZ
opaque surf 1 0 0 1 0 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
trans surf 1 0 0 1 1 1 0 0 1 0 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
trans line 1 0 0 1 0 0 1 1 1 0 0 0 0 (0)pix (1)mem (0)pixA*cvg (0)1-a
decal line 1 0 0 1 2 0 1 1 1 0 0 0 0 (0)pix (1)mem (0)pixA*cvg (0)1-a
texture edge 1 0 0 1 0 0 1 1 0 0 0 0 0 (0)pix (1)mem (0)adjA*cvg (1)memcvg
sub surf 1 0 0 1 2 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
particle 1 0 0 1 0 0 0 0 0 0 0 1 1 (0)pix (1)mem (0)pixA (0)1-a
opaque terr 1 0 0 1 0 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (0)1-a
texture terr 1 0 0 1 0 0 1 1 0 0 0 0 0 (0)pix (1)mem (0)adjA*cvg (0)1-a
sub terr 1 0 0 1 2 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (0)1-a
PT ZBUF
opaque surf 0 1 1 0 2 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
trans surf 0 1 0 1 2 0 0 0 1 2 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
decal surf 0 1 0 0 2 0 0 1 0 3 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
trans decal 0 1 0 1 2 0 0 0 1 3 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
cloud surf 0 1 0 1 3 0 0 0 1 2 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
overlay surf 0 1 0 1 3 0 0 0 1 3 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
particle 0 1 1 0 2 0 0 0 0 0 0 1 1 (0)--- (0)pix (3)zero (2)one
PT NONZ
opaque surf 0 0 0 0 2 0 0 0 1 0 0 0 0 (0)--- (0)pix (3)zero (2)one
trans surf 0 0 0 1 2 0 0 0 1 0 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
cloud surf 0 0 0 1 3 0 0 0 1 0 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
particle 0 0 0 0 2 0 0 0 1 0 0 1 1 (0)--- (0)pix (3)zero (2)one
Mode Bit Descriptions
------------------------
antialias_en: if not force blend, allow blend enable - use cvg bits
z_compare_en: condition color write enable on depth comparison
z_update_en: enable writing of z if color write enabled
image_read_en: enable color/cvg read/modify/write memory access
cvg_dest[1:0]: 0) clamp if blend_en, new if !blend_en
1) wrap always
2) zap (force to full cvg)
3) save (don't overwrite memory cvg)
color_on_cvg: only update color on cvg overflow (transp surf)
cvg_times_alpha: use alpha times cvg for pixel alpha and cvg
alpha_cvg_select: use cvg (or alpha*cvg) for pixel alpha
force_blend: force blend enable
z_mode: 0) opaque
1) interpenetrating
2) transparent
3) decal
texture_edge_mode: enable texture edges (must also use cvg_times_alpha)
Note: This bit is no longer used in texture edge mode!
alpha_compare_en: condition color write enable on alpha compare
dither_alpha_en: compare alpha with pseudo-random noise (dithering)
Notes:
(1) Interpenetration is only meaningful in antialiased zbuffered mode.
(2) Texture_edge_mode is only meaningful in antialiased modes. In
point sampled modes, alpha_compare_enable with 128 should be used
instead, with the mode bits set for an opaque surface.
(3) Always zap coverage in point sampled modes.
(4) If color_on_cvg, must also force_blend.
(5) If not cvg_times_alpha and alpha_cvg_select, must not force_blend.
(6) Always force_blend on non-zbuffered modes.
(7) If texture_edge_mode, must also cvg_times_alpha and alpha_cvg_select.
(8) In opaque surface mode, clamp/new cvg_dest mode works better on the
edges of a decalled surface which closely corresponds to the edge of
the underlying surface. Otherwise, use the wrap cvg_dest mode.
(9) To place new color regardless of other conditions, use force blend
with p=don't care; m=pixel_color; a=zero; b=one; and don't enable
z compare.
The Antialiased Z-Buffered Rendering Modes
---------------------------------------------
antialias_en
| z_compare_en
| | z_update_en
| | | image_read_en
| | | | cvg_dest (0:clamp, 1:wrap, 2:zap, 3:save)
| | | | | color_on_cvg
| | | | | | cvg_times_alpha
| | | | | | | alpha_cvg_select
| | | | | | | | force_blend
| | | | | | | | | z_mode (0:opaque, 1:inter, 2:trans, 3:decal)
| | | | | | | | | | texture_edge_mode
| | | | | | | | | | | alpha_compare_en
| | | | | | | | | | | | dither_alpha_en
mode | | | | | | | | | | | | | p m a b
------------ - - - - - - - - - - - - - ------ ------ ----------- -------
AA ZBUF
opaque surf 1 1 1 1 0 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
trans surf 1 1 0 1 1 1 0 0 1 2 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
decal surf 1 1 0 1 1 0 0 1 0 3 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
trans decal 1 1 0 1 1 1 0 0 1 3 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
interpen 1 1 1 1 0 0 0 1 0 1 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
trans interp 1 1 0 1 1 1 0 0 1 1 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
trans line 1 1 0 1 0 0 1 1 1 2 0 0 0 (0)pix (1)mem (0)pixA*cvg (0)1-a
decal line 1 1 0 1 3 0 1 1 1 3 0 0 0 (0)pix (1)mem (0)pixA*cvg (0)1-a
texture edge 1 1 1 1 0 0 1 1 0 0 0 0 0 (0)pix (1)mem (0)adjA*cvg (1)memcvg
text interp 1 1 1 1 0 0 1 1 0 1 0 0 0 (0)pix (1)mem (0)adjA*cvg (1)memcvg
sub surf 1 1 1 1 2 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
particle 1 1 1 1 0 0 0 0 0 0 0 1 1 (0)pix (1)mem (0)pixA (0)1-a
opaque terr 1 1 1 1 0 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (0)1-a
texture terr 1 1 1 1 0 0 1 1 0 0 0 0 0 (0)pix (1)mem (0)adjA*cvg (0)1-a
sub terr 1 1 1 1 2 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (0)1-a
These are the recommended rendering modes for 3D graphics, discussed above
in some detail. They are what the rendering engine was primarily designed
to do. They produce the best visual quality at near-optimal efficiency.
Sub surface mode is intended to be used as a way to get an opaque object
upon which an antialiased transparent surface can be overlayed. The coverage
values from the transparent surface will fill in the zapped coverage values
from the initial opaque surface.
The terrain modes are to get around the modification of the blending weights
by delta z, which was intended for punchthrough reduction. This cauese
aliasing of internal edges in cases where the object faces are non-coplanar.
These new modes use the normal lerp blender mode, which is free of delta-z
dependence, and hence doesn't alias. Note, however, that these modes do
not handle "pinwheels" correctly, since they assume that only two polys meet
at any pixel, which is generally not true. But in the case of terrains, which
have very large polys, this is more nearly correct.
The Antialiased Non-Z-Buffered Rendering Modes
-------------------------------------------------
antialias_en
| z_compare_en
| | z_update_en
| | | image_read_en
| | | | cvg_dest (0:clamp, 1:wrap, 2:zap, 3:save)
| | | | | color_on_cvg
| | | | | | cvg_times_alpha
| | | | | | | alpha_cvg_select
| | | | | | | | force_blend
| | | | | | | | | z_mode (0:opaque, 1:inter, 2:trans, 3:decal)
| | | | | | | | | | texture_edge_mode
| | | | | | | | | | | alpha_compare_en
| | | | | | | | | | | | dither_alpha_en
mode | | | | | | | | | | | | | p m a b
------------ - - - - - - - - - - - - - ------ ------ ----------- -------
AA NONZ
opaque surf 1 0 0 1 0 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
trans surf 1 0 0 1 1 1 0 0 1 0 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
trans line 1 0 0 1 0 0 1 1 1 0 0 0 0 (0)pix (1)mem (0)pixA*cvg (0)1-a
decal line 1 0 0 1 2 0 1 1 1 0 0 0 0 (0)pix (1)mem (0)pixA*cvg (0)1-a
texture edge 1 0 0 1 0 0 1 1 0 0 0 0 0 (0)pix (1)mem (0)adjA*cvg (1)memcvg
sub surf 1 0 0 1 2 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
particle 1 0 0 1 0 0 0 0 0 0 0 1 1 (0)pix (1)mem (0)pixA (0)1-a
opaque terr 1 0 0 1 0 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (0)1-a
texture terr 1 0 0 1 0 0 1 1 0 0 0 0 0 (0)pix (1)mem (0)adjA*cvg (0)1-a
sub terr 1 0 0 1 2 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (0)1-a
These modes are primarily for situations where the sorting by depth of
a scene is trivial, for example, the terrain for a flight simulator (as
long as it is not too mountainous). Otherwise, the cost of sorting the
polys by depth would be prohibitive. These modes can be mixed and matched
with any of the other rendering modes, z-buffered or not. Note that for
proper antialiasing, polys should be rendered in forward painter's algorithm
order (back to front), NOT inverse order. (This is NOT the "a-buffer"
algorithm, which requires inverse painter's algorithm order.) So in a mixed
rendering mode scene, any non-z-buffered background polys should be rendered
first.
Note that there is no decal surface mode. Since there is no z to condition
the blend, decal surface mode is identical to opaque surface mode. There is
a decal line mode, since it is slightly different in the way it handlees
silhouette edges. Also since there is no z, there are no interpenetration
modes.
The line modes are very similar to the z-buffered line modes, except that
decal line mode zaps coverage to unity. This is because in the non-z case,
both sides of the line are rendered, and are already correctly antialiased
at render time. For the non-line modes, blending is based on coverage wrap,
since there is no z to discriminate between new and contiguous surfaces.
Sub surface mode is intended to be used as a way to get an opaque object
upon which an antialiased transparent surface can be overlayed. The coverage
values from the transparent surface will fill in the zapped coverage values
from the initial opaque surface.
The terrain modes are to get around the modification of the blending weights
by delta z, which was intended for punchthrough reduction. This causes
aliasing of internal edges in cases where the object faces are non-coplanar.
These new modes use the normal lerp blender mode, which is free of delta-z
dependence, and hence doesn't alias. Note, however, that these modes do
not handle "pinwheels" correctly, since they assume that only two polys meet
at any pixel, which is generally not true. But in the case of terrains, which
have very large polys, this is more nearly correct.
The Point-Sampled Z-Buffered Rendering Modes
-----------------------------------------------
antialias_en
| z_compare_en
| | z_update_en
| | | image_read_en
| | | | cvg_dest (0:clamp, 1:wrap, 2:zap, 3:save)
| | | | | color_on_cvg
| | | | | | cvg_times_alpha
| | | | | | | alpha_cvg_select
| | | | | | | | force_blend
| | | | | | | | | z_mode (0:opaque, 1:inter, 2:trans, 3:decal)
| | | | | | | | | | texture_edge_mode
| | | | | | | | | | | alpha_compare_en
| | | | | | | | | | | | dither_alpha_en
mode | | | | | | | | | | | | | p m a b
------------ - - - - - - - - - - - - - ------ ------ ----------- -------
PT ZBUF
opaque surf 0 1 1 0 2 0 0 1 0 0 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
trans surf 0 1 0 1 2 0 0 0 1 2 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
decal surf 0 1 0 0 2 0 0 1 0 3 0 0 0 (0)pix (1)mem (0)pixcvg (1)memcvg
trans decal 0 1 0 1 2 0 0 0 1 3 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
cloud surf 0 1 0 1 3 0 0 0 1 2 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
overlay surf 0 1 0 1 3 0 0 0 1 3 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
partical 0 1 1 0 2 0 0 0 0 0 0 1 1 (0)--- (0)pix (3)zero (2)one
The point-sampled rendering modes are provided for completeness. They have
no significant performance advantage over the antialiased modes. These
modes can be mixed and matched with any of the other rendering modes,
antialiased or not, and so could be used for "special effects" within an
otherwise antialiased scene. Generally speaking, point sampling looks bad,
and should be avoided.
Note that there is no distinction between point-sampled line and surface
modes, since lines and surfaces only differ in the way they are antialiased.
For the same reason there are no point-sampled interpenetration or texture
edge modes.
For the point-sampled modes, coverage is usually zapped to unity to prevent
the video interface from trying to antialias them. Note also that in these
modes, because the coverage always wraps (since it is always fully covered
to begin with), surfaces are never blended, and the delta z range is never
used in the z-buffering.
Cloud and overlay surface modes are versions of transparent surface and
transparent decal surface which do not disturb coverage. These are intended
as overlays, where the silhouette of the poly will have zero opacity, and
hence should not affect the antialiasing of the image. (Note that textures
can still be bilerped, which is the only kind of antialiasing that matters
in this case.
The Point-Sampled Non-Z-Buffered Rendering Modes
---------------------------------------------------
antialias_en
| z_compare_en
| | z_update_en
| | | image_read_en
| | | | cvg_dest (0:clamp, 1:wrap, 2:zap, 3:save)
| | | | | color_on_cvg
| | | | | | cvg_times_alpha
| | | | | | | alpha_cvg_select
| | | | | | | | force_blend
| | | | | | | | | z_mode (0:opaque, 1:inter, 2:trans, 3:decal)
| | | | | | | | | | texture_edge_mode
| | | | | | | | | | | alpha_compare_en
| | | | | | | | | | | | dither_alpha_en
mode | | | | | | | | | | | | | p m a b
------------ - - - - - - - - - - - - - ------ ------ ----------- -------
PT NONZ
opaque surf 0 0 0 0 2 0 0 0 1 0 0 0 0 (0)--- (0)pix (3)zero (2)one
trans surf 0 0 0 1 2 0 0 0 1 0 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
cloud surf 0 0 0 1 3 0 0 0 1 0 0 0 0 (0)pix (1)mem (0)pixA (0)1-a
particle 0 0 0 0 2 0 0 0 1 0 0 1 1 (0)--- (0)pix (3)zero (2)one
The point-sampled, non-z-buffered rendering modes are provided for
completeness. They have no significant performance advantage over the
antialiased modes.
Since there is neither antialiasing nor z-buffering, there is no difference
between lines and surfaces, and no such thing as interpenetration, decals,
or texture edges. Only the transparent surface mode requires the reading of
the frame buffer at render time. The opaque modes simply overwrite the
color and zap the coverage in the frame buffer.
Cloud surface mode is a versions of transparent surface mode which does
not disturb coverage. This is intended as an overlay, where the silhouette
of the poly will have zero opacity, and hence should not affect the
antialiasing of the image. (Note that textures can still be bilerped, which
is the only kind of antialiasing that matters in this case.