README.jp
93.1 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
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
-------------------------------------------------------------------------------
===============================================================================
Z Sort マイクロコードドキュメント
Release 0.34
Aug 4, 1998.
Copyright by Nintendo, Co., Ltd. 1997-1998
任天堂株式会社開発第 3 部 安本吉孝
===============================================================================
-------------------------------------------------------------------------------
目次
1. ZSort マイクロコードとは
2. ZSort マイクロコードの機能
2.1 ZSort による描画処理の流れ
2.2 描画処理と算術演算処理
3. 描画処理
3.1 描画可能な図形(ZObject)
3.2 ZObject リストの処理
3.3 Z ソート処理
3.4 ZObject のデータ形式
3.4.1 zShTri 構造体
3.4.2 zShQuad 構造体
3.4.3 zTxTri 構造体
3.4.4 zTxQuad 構造体
3.4.5 zNull 構造体
3.5 RDPcmd パラメータによる RDP コマンドの制御
3.6 画面クリアおよびその他の描画処理
4. 算術演算処理
4.1 表示物体と算術演算
4.2 DMEM 内の演算用ワークエリア
4.3 GBI 一覧
4.4 GBI の機能解説
5. その他の処理
5.1 GBI 一覧
5.2 GBI の機能解説
6. 他のマイクロコードとの互換性
6.1 GBI について
6.2 共通 GBI
7. CPU のサポートライブラリ
8. TASK マネージメント
8.1 RSP 処理の実装手法
8.2 2 タスク処理
8.3 2 パス並列処理
9. 使用上の注意
9.1 RSP から RDP へのコマンドの受け渡し
9.2 自己ロード機能
10. ZSort パッケージのインストール
11. サンプルプログラム
12. 変更履歴
===============================================================================
1. ZSort マイクロコードとは.
===============================================================================
ZSort マイクロコードは, Nintendo64 (以下 N64) ハードウェア上で Z ソー
トによる隠面消去処理を行なうために開発されたものです. 画面上に表示する
べき図形の全てを画面の深さ順に整列させ, 奥のものから順に描画していくと
いう手法で画面を作成します.
N64 には Z-Buffer 処理による隠面処理がハードウェアによってサポートさ
れています. Z-Buffer 法による隠面処理では 1 Pixel 毎に可視かどうかを判
定するので Z ソートと比べて描画される図形の前後関係を正確に表現できる
という利点がありますが, その反面 RAM のアクセスが増加してしまいます. Z
ソートでは, Z-Buffer 程の前後関係の処理は出来ませんが 1 図形あたりの
RAM へのアクセス量が減るため, 単位時間内に画面へ表示できる図形の量は
Z-Buffer 法と比べて多くなります.
この ZSort 法による利点は, RAM の帯域が改善されるため RDP の処理が軽
くなることです. 多くのアプリケーションでは RDP の処理にかかる時間がネッ
クとなり表示する図形の量に制限がかかっているのが現状であるため, このこ
とは朗報といえるでしょう.
ただし, ここで注意するべきことは RSP の処理はそれほど変わらないとい
うことです. RDP の処理は塗り潰す領域のサイズに応じて変化し, 特に小さな
領域の描画では, RSP の処理よりも RDP の処理の方が早く終わります. これ
は, 小さな描画領域がたくさんあって RSP の処理が終わるのを RDP が常に待っ
ているような状態では Z-Buffer でも ZSort でも, 処理能力は変わらないこ
とを意味します. ただし描画領域がある程度大きい場合には ZSort 法が有利
になります. ZSort マイクロコードは万能ではありません. 描画したい画面を
よくご考慮の上ご選択ください.
===============================================================================
2. ZSort マイクロコードの機能
===============================================================================
--------------------------------
2.1 ZSort による描画処理の流れ
ZSort マイクロコードでは描画領域として 3 角形領域と 4 角形領域の他に
RDP コマンドによる Texture Rectangle や Fill Rectangle をサポートして
います. こうして RDP によって描画される領域それぞれのことを本マニュア
ル上では ZObject と呼びます.
ZSort マイクロコードでは 1 つの ZObject に対し, その描画領域を代表す
る 1 つの画面深度値を求めます. そして各 ZObject をその画面深度でソート
し, 画面の奥にある ZObject から順に描画することで隠面処理を行ないます.
ZObject の描画のための処理の流れは以下のようになります.
| モデル行列と透視変換行列等の乗算
| モデル頂点の座標変換/透視変換/画面深度計算
| 頂点が画面内にあるかどうかの判定
| クリッピング/裏面判定
| ZObject データの構築
| ZObject リスト作成
V ZObject リストの順に描画を行なう(描画処理)
ここで ZObject を描画するためには ZObject をどのように描画するかとい
う情報をデータとして用意してやらなければなりません. 従来の Fast3D マイ
クロコードでは 3 角形の描画に Vertex 命令と Tri 命令を組み合わせていま
したが, ZSort マイクロコードでは ZObject 構造体を作ることで描画を行な
うの点が異なります.
これらの全ての処理が ZSort マイクロコードで実装されているわけではあ
りません. ZSort マイクロコードが他のグラフィックマイクロコードと大きく
異なる点は, ZSort マイクロコードはそれだけでは動作しないという点で
す. CPU が描画に関する処理の一部を行なう必要があります.
例えば, ZObject を画面の深さ順にソートする機能はマイクロコードとして
は実装されていません. ソート処理は CPU が行ないその結果を RSP に渡す必
要があるのです.
最低でも, 以下の処理は CPU で行なう必要があります.
- クリッピング/裏面判定
- ZObject データの構築
- ZObject リスト作成
現在, ZSort マイクロコードで実装されている主な機能を以下にあげます.
これらの各処理は 1 つあるいは複数の GBI コマンドからなる Display List
によって制御されます.
+ モデル行列と透視変換行列等の乗算.
+ モデル頂点の座標変換/透視変換/画面深度計算
+ 頂点が画面内にあるかどうかのフラグ作成
+ ZObject リストの順に描画を行なう(描画処理)
当然ながら行列の乗算や座標変換などの処理(ここでは, 算術演算処理と呼
ぶ)については, CPU で処理することも可能です. プロセッサの空き状態に応
じて使い分けるのが良いでしょう. ただし, 以降では算術演算処理を RSP で
行なうことを前提にした説明を行ないます. CPU で算術処理を行なわれる場合
は, 後程説明する算術演算処理は参考資料としてお読み下さい.
----------------------------
2.2 描画処理と算術演算処理
RSP で算術演算を行なう場合は通常, ZSort マイクロコードの処理は 2 パ
スの形になります. これは, 最後の ZObject の座標変換が終了しないと, Z
ソートの完全な結果を得ることができないからです. このことは他のマイクロ
コードと異なりパイプライン的にデータを流していくことができないことを意
味します. 全ての ZObject の情報を一時的に保持する必要があるからです.
ここでは座標変換にかかわる次の機能を算術演算処理と呼び, 第 1 パスで
処理します. これらの処理はあくまで *頂点の* 座標の変換です. ここでは
ZObject の面としてのデータの作成は行ないません. 実際の ZObject の面デー
タは頂点座標変換結果から CPU が構成します. ご注意下さい.
+ モデル行列と透視変換行列等の乗算.
+ モデル頂点の座標変換/透視変換/画面深度計算
+ 頂点が画面内にあるかどうかの判定
次に ZSort 後の以下の処理を描画処理と呼び, 第 2 パスで処理します.
+ ZObject リストの順に描画を行なう
この ZObject リストとは, ZObject のデータを画面奥のものから順にリスト形式
によって連結した以下のようなチェーン状のデータ列のことです. Zobj 3 の
X は終端を意味します.
GBI ZObj 1 ZObj 2 ZObj 3
+-+ +------+-+ +------+-+ +------+-+
|o----->| Data |o----->| Data |o----->| Data |X|
+-+ +------+-+ +------+-+ +------+-+
この ZObject リストは CPU が作成する必要があります. ZSort マイクロコー
ドでは, このリスト形式の ZObject リストをサポートしているため, ソート
処理に伴うデータの入れ替えコストを最小に抑えることができます. ソーティ
ング処理のアルゴリズムは, どのようなものを使用しても問題はありませ
ん. ちなみに本マイクロコードのサンプルプログラムでは, こうした ZObject
リストを複数個, 作成することで Far 平面と Near 平面の間を 1024 段階に
分割したバケットソートを行なっています.
以上をまとめると次のような処理の流れとなります.
[CPU] 算術演算用 DisplayList 作成
|
V
[RSP] 算術演算処理
|
V
[CPU] ZObject データ作成
ZObject リスト(=描画用 DisplayList)作成(ZSort)
|
V
[RSP/RDP] 描画処理
===============================================================================
3. 描画処理
===============================================================================
-----------------------------
3.1 描画可能な図形(ZObject)
前章でも述べたように ZSort マイクロコードでは, ZObject という描画
領域ごとに描画を行ないます. ZObject の種類として以下があり, それぞれに
対応した構造体によってその描画パラメータが定義されます.
zShTri - スムースシェーディングされた 3 角形
zShQuad - スムースシェーディングされた 4 角形
zTxTri - テクスチャ付のスムースシェーディングされた 3 角形
zTxQuad - テクスチャ付のスムースシェーディングされた 4 角形
zNull - RDP コマンドを使用したその他の描画領域
(FillRectangle や TextureRectangle に使用)
フラットシェーディングされた 3 角形 / 4 角形を描画する ZObject は用
意されていません. こうした図形を描画したい場合は, 全ての頂点に同じ色を
指定し描画してください. これは, マイクロコードのサイズの制限から全ての
図形をサポートできなかったからです. ご了承ください.
マイクロコードではこのような単純な型の図形しかサポートしていませんが
CPU 側のライブラリを工夫することで様々な型の図形を描画できます. 詳しく
はサンプルプログラムを参照してください.
--------------------------
3.2 ZObject リストの処理
ZObject はリスト形式を取ることが出来るようにするため, その構造体の先
頭部に次の ZObject へのポインタデータおよび次の ZObject の種別 ID が格
納されています. 全ての ZObject 構造体の先頭 4bytes の領域はヘッダ領域
として予約されており, この 4bytes の値によって ZObject をリスト形式に
することができます.
GBI コマンド
+-+-+
|o|X| g[s]SPZObject
+|+-+
|
V
+------+-+ +------+-+ +------+-+
|ZObj 1|o----->|ZObj 2|o----->|ZObj 3|X|
+------+-+ +------+-+ +------+-+
GBI コマンド g[s]SPZObject でこのリストの先頭 ZObject (上図の場合は
ZObj 1) へのポインタおよび ZObject 種別 ID を指定すれば, RSP はこのリ
ストを辿って順に描画処理を行ないます.
GBI コマンド g[s]SPZObject には 0,1,2 個のリストを処理できます. すな
わち以下の 2 つの ZObject リスト A,B が 1 つの GBI で描画できるのです.
GBI コマンド
+-+-+
|o|o| g[s]SPZObject
+|+|+
| |
| V
| +------+-+ +------+-+
| |ZObj 4|o----->|ZObj 5|X| ZObject リスト B
| +------+-+ +------+-+
V
+------+-+ +------+-+ +------+-+
|ZObj 1|o----->|ZObj 2|o----->|ZObj 3|X| ZObject リスト A
+------+-+ +------+-+ +------+-+
これは GBI コマンドのサイズは最低でも 8 bytes であり, これは 4 bytes
であるポインタデータの 2 つ分に相当するからです. もし, 2 個未満の処理
リストを描画するときは, 空きの部分には終端値(=G_ZOBJ_NONE)を書き込んで
ください.
この GBI コマンド g[s]SPZObject のデータフォーマットは, 以下の通りです.
前半部と後半部が同じ形になっています.
------------------------------------------------------------------------------
* gSPZObject(Gfx *gp, u32 listA, u32 listB)
listA ZObject リンク A のリンクパラメータ =ZHDR(ListA, ZidA)
listB ZObject リンク B のリンクパラメータ =ZHDR(ListB, ZidB)
31 3 2 0
+----------------+----+
| ListA |ZidA|
+----------------+----+
| ListB |ZidB|
+----------------+----+
ListA/ListB ZObject リストへのポインタの bit31 から bit3 までの値
先頭 8 bits は 0x80 でなければならない. (通常は 0x80)
ZidA/ZidB ZObject リストの先頭の ZObject の種別 ID
このデータ(32bit分) を設定するためのマクロとして,
ZHDR(pointer,type) が用意されています. 以下のように使用できます.
gSPZObject(gfx, ZHDR(ptr_listA, ZH_SHTRI), ZHDR(ptr_listB, ZH_TXTRI));
または, 処理リンク A または 処理リンク B のみを変更するために, 以下
のように直接値を代入しても構いません.
*((u32 *)gfx) = ZHDR(ptr_listA, ZH_SHTRI);
ここで ZH_xxxxx は ZObject の種別 ID で, 以下の 5 つの値を取ります.
ZH_SHTRI - スムースシェーディングされた 3 角形
ZH_SHQUAD - スムースシェーディングされた 4 角形
ZH_TXTRI - テクスチャマップおよびスムースシェーディングされた 3 角形
ZH_TXQUAD - テクスチャマップおよびスムースシェーディングされた 4 角形
ZH_NULL - RDP コマンドを使用したその他の描画領域
************************************************************************
ここでは, gSPZObject のみの説明をしましたが, gsSPZObject も存在します.
以降の章にも GBI コマンドの説明が出てきますが, この GBI と同様に
gsSPZ*** の解説は省略します.
************************************************************************
------------------
3.3 Z ソート処理
GBI コマンド g[s]SPZObject は ZObject の ZObject リストへのポインタ
と種別 ID を並べただけの構造なので, このコマンドを複数並べ配列とするこ
とで, 簡単に 3 つ以上の ZObject リストを処理することができます. 各
ZObject リストに対し, 画面の深度のほぼ等しい ZObject をまとめて
ZObject リストを作成し, 画面奥の ZObject リストから順に g[s]SPZObject
によって並べることで, パケットソートを簡単に行なうことが可能です.
処理手順は以下の通りになります. ここでの例は, 各 ZObject の画面深度を
1024 段階に分け処理を行ないます.
(1) gSPZObject 用の配列の用意.
画面深度の 1 段階につき ZObject リスト 1 つを用意するため,
gSPZObject の配列サイズとして 512 (=1024/2) コマンド必要となります.
この配列がそのまま, DL の一部となり, RSP に直接処理されるため,
gSPZObject 配列の最後尾に gSPEndDisplayList を追加します. よって,
必要なサイズは 513(=512+1)コマンド分となります.
|
| Gfx zarray[1024/2+1];
|
(2) 配列の初期化.
配列の全ての要素に終端値 (G_ZOBJ_NONE = 0x80000000) を代入し, 配
列を初期化します. 最後尾に EndDL を書き込みます. 以下図参照.
|
| int i;
| for (i = 0; i < 512; i ++){
| gSPZObject(zarray+i, G_ZOBJ_NONE, G_ZOBJ_NONE);
| }
| gSPEndDisplayList(zarray+512);
|
0 1 2 3 ..... 510 511 512
+-----+-----+-----+-----+--/ /--+-----+-----+-----+
zarray |X |X |X |X |X |X |X |X | / /|X |X |X |X |X |EndDL|
+-----+-----+-----+-----+/ /----+-----+-----+-----+
X: 終端値 (=G_ZOBJ_NONE)
(3) 各 ZObject の画面深度に応じた配列への登録.
ZObject ごとに画面深度の計算を行ないます. RSP で各頂点における画
面深度の値は計算できますが, ZObject においてどの値を画面深度として
使用するかの決定はユーザー側に任されています. 画面深度として使用す
る値の例として以下のような値があります.
3 角形の ZObject における画面深度の例:
+ 3 頂点の視点からの距離の最小値.
+ 3 頂点の視点からの距離の最大値.
+ 3 頂点の視点からの距離の平均値.
+ 3 頂点の視点からの距離の最大値と最小値の中間値.
* また視点からの距離の逆数を使用することもできます. サンプルプロ
グラムでは逆数値の平均を使用しています.
この値を 0 〜 1023 に正規化し, 登録する配列要素の番号にします.
該当する配列の要素にもともと保存してあるポインタおよび ZObject 種別
ID を登録する ZObject のヘッダ内に保管し, 該当する配列の要素へは
ZObject 構造体データへのポインタおよび ZObject 種別 ID を書き込みま
す.
|
| s32 zid; /* 登録する配列要素の番号 */
| zHeader *zhptr; /* ZObject へのポインタ */
| u32 ztype; /* ZObject の種別 ID */
| u32 *uzarray = (u32 *)zarray;
|
| for ( each ZObject ){
| 画面深度から zid を計算する;
| if (zid < 0) zid = 0; /* zid のクランプ */
| if (zid > 1023) zid = 1023;
| zhptr->t.header = *(uzarray+zid); /* 次の Node の設定 */
| *(uzarray+zid) = ZHDR(zhptr, ztype); /* zarray への登録 */
| }
|
0 1 2 3 ..... 510 511 512
+-----+-----+-----+-----+--/ /--+-----+-----+-----+
zarray |X |X |X |X |o |X |X |X | / /|X |X |X |X |X |EndDL|
+-----+-----+|----+-----+/ /----+-----+-----+-----+
|
V
+------+-+
|ZObj 1|X|
+------+-+
この処理を全 ZObject に対して行ない, 出来た配列を gSPDisplayList
で呼び出せば描画処理が出来ます.
gSPDisplayList(o)
|
+-------+
|
V 0 1 2 3 ..... 510 511 512
+-----+-----+-----+-----+--/ /--+-----+-----+-----+
zarray |X |o |X |X |o |X |X |X | / /|X |X |o |X |X |EndDL|
+---|-+-----+|----+-----+/ /----+---|-+-----+-----+
| | |
| V V
| +------+-+ +------+-+
| |ZObj 5|o| |ZObj 6|o|
| +------+|+ +------+|+
| | |
V V V
+------+-+ +------+-+ +------+-+
|ZObj 3|X| |ZObj 4|o| |ZObj 2|X|
+------+-+ +------+|+ +------+-+
|
V
+------+-+
|ZObj 1|X|
+------+-+
上の例の場合, ZObj 3 -> ZObj 5 -> ZObj 4 -> ZObj 1 -> ZObj 6 -> ZObj 2
の順で描画処理が行なわれます.
--------------------------
3.4 ZObject のデータ形式
Z Sort マイクロコードがサポートする ZObject は 5 種類あり, それぞれ
を描画するための必要なデータは異なります. 以降では, それぞれの ZObject
のデータを格納するための 5 種類の構造体について説明します.
---------------------
3.4.1 zShTri 構造体
zShTri 構造体は, テクスチャなしのスムースシェード処理された 3 角形を
描画するためのデータ構造体です. その形状を指定するために以下のような
zShVtx 型の頂点データを 3 組必要とします.
-----------------------------------------------------------
typedef struct {
s16 x, y; /* 頂点のスクリーン座標 (s10.2) */
u8 r, g, b, a; /* 頂点におけるカラー 各 0..255 */
} zShVtx;
-----------------------------------------------------------
zShTri 構造体は以下のようなデータ形式をとります.
+0 +4 +7
+-----------+-----------+
| Hdr | RDP cmd |
+-----+-----+--+--+--+--+
V0 | X | Y |R |G |B |A |
+-----+-----+--+--+--+--+
V1 | X | Y |R |G |B |A |
+-----+-----+--+--+--+--+
V2 | X | Y |R |G |B |A |
+-----+-----+--+--+--+--+
-------------------------------------------------------------
typedef struct {
zHeader *header; /* 次の ZObject の情報 */
Gfx *rdpcmd1; /* 前処理 DP コマンド */
zShVtx v[3]; /* 頂点データ */
} zShTri_t;
typedef struct { /* ワードアクセス用構造体 */
zHeader *header;
Gfx *rdpcmd1;
u32 xy0, clr0;
u32 xy1, clr1;
u32 xy2, clr2;
} zShTri_w;
typedef union {
zShTri_t t;
zShTri_w w;
u64 force_structure_alignment;
} zShTri;
-------------------------------------------------------------
この構造体で指定された 3 頂点から成る 3 角形が描画されます. この際に
は 3 角形の裏表は考慮されません. 裏を向いていようが表を向いていようが
描画されてしまいます. 裏側を向いている 3 角形の描画をしたくない場合は,
ZObject データ作成時にCPU が裏表の判定をして, 表側を向いている ZObject
のみを描画するようにしてください. この裏表の判定については他の多角形
ZObject についても同様です.
メンバー変数 header は ZObject がリスト構造で連なるときに, 次の
ZObject へのポインタ等を保持します.
メンバー変数 rdpcmd1 は現在の RDP の処理モードを変更するために使用し
ます. ZObject を描画する前に RDP へ送られる RDP コマンド DL 列をここへ
指定します. rdpcmd1 についての詳細は 3.5 項で説明します.
----------------------
3.4.2 zShQuad 構造体
zShQuad 構造体は, テクスチャなしのスムースシェード処理された 4 角形
を描画するためのデータ構造体です. その形状を指定するために前項で説明し
た zShVtx 型の頂点データを 4 組必要とします.
zShQuad では 3 角形 V0-V1-V2 と V1-V2-V3 の 2 つの 3 角形を描画する
ことで, 4 角形の描画を行ないます.
V0+--------+V1
| /|
| / |
| / |
|/ |
V2+--------+V3
zShQuad 構造体は以下のようなデータ形式をとります.
+0 +4 +7
+-----------+-----------+
| Hdr | RDP cmd |
+-----+-----+--+--+--+--+
V0 | X | Y |R |G |B |A |
+-----+-----+--+--+--+--+
V1 | X | Y |R |G |B |A |
+-----+-----+--+--+--+--+
V2 | X | Y |R |G |B |A |
+-----+-----+--+--+--+--+
V3 | X | Y |R |G |B |A |
+-----+-----+--+--+--+--+
-------------------------------------------------------------
typedef struct {
zHeader *header; /* 次の ZObject の情報 */
Gfx *rdpcmd1; /* 前処理 DP コマンド */
zShVtx v[4]; /* 頂点データ */
} zShQuad_t;
typedef struct { /* ワードアクセス用構造体 */
zHeader *header;
Gfx *rdpcmd1;
u32 xy0, clr0;
u32 xy1, clr1;
u32 xy2, clr2;
u32 xy3, clr3;
} zShQuad_w;
typedef union {
zShQuad_t t;
zShQuad_w w;
u64 force_structure_alignment;
} zShQuad;
-------------------------------------------------------------
同じ 4 角形を 1 つの zShQuad で描画する場合と 2 つの zShTri で描画す
る場合では必要なメモリに差があり, zShQuad の方が使用するメモリが少なく
て済むことが zShQuad を使用する大きなメリットでしょう.
更に RDP での描画で有利になるように 4 角形の分割線を CPU で動的に変
更してやることで RDP の描画パフォーマンスが向上します. 具体的には, 対
角線 V0-V3 の Y 座標の差の絶対値 ABS(Y0-Y3) と V1-V2 の Y 座標の差の絶
対値 ABS(Y1-Y2) を比較し, 絶対値の小さい方の対角線に沿って 4 角形を 2
つの 3 角形に分割描画するように ZObject のデータを入れ替えれば良いです.
以下のアルゴリズムを参考にしてください.
|
| zShQuad *zquad;
|
| if (ABS(Y0-Y3) > ABS(Y1-Y2)){
| /* 対角線 V1-V2 で分割し, V0-V1-V2 と V1-V2-V3 に分割 */
| zquad->t.v[0] = V0; zquad->t.v[1] = V1;
| zquad->t.v[2] = V2; zquad->t.v[3] = V3;
| } else {
| /* 対角線 V0-V3 で分割し, V1-V0-V3 と V0-V3-V2 に分割 */
| zquad->t.v[0] = V1; zquad->t.v[1] = V0;
| zquad->t.v[2] = V3; zquad->t.v[3] = V2;
| }
|
ただしこのときは, どちらの対角線が分割線として選択されるか分からない
ので, どちらの対角線で分割されても問題が無いように, 指定された 4 頂点
は同一平面上になければなりません. またテクスチャ使用時あるいはスムース
シェード時には, テクスチャ座標値(s,t) あるいは カラー値(r,g,b,a) に矛
盾が生じないように値を設定する必要があります. (サンプルプログラム
cubes-1 は良くない見本も含まれています ;-).)
テクスチャマップ使用時について具体的に説明すると,
v0(x0,y0,z0,s0,t0), v1(x1,y1,z1,s1,t1), v2(x2,y2,z2,s2,t2),
v3(x3,y3,z3,s3,t3) において, ベクトル V1,V2,V3 を
V1 = (v1 - v0), V2 = (v2 - v0), V3 = (v3 - v0)
と定義したときに,
V2 = a * V1 + b * V3
を満たす実係数 a, b が存在する必要があります. 幾何学的には s, t を含め
た 5 次元座標空間上において 4 頂点が同一平面上にあることが必要となりま
す.
同様に smooth shading や lighting を使用する際には, カラー値(r,g,b)
または法線ベクトル(nx,ny,nz)について上記の関係を満たさなけばなりません.
例えば以下の onetri における頂点データは Quadrangle には不向きです.
onetri/static.c:
static Vtx shade_vtx[] = {
{ -64, 64, -5, 0, 0, 0, 0, 0xff, 0, 0xff },
{ 64, 64, -5, 0, 0, 0, 0, 0, 0, 0xff },
{ 64, -64, -5, 0, 0, 0, 0, 0, 0xff, 0xff },
{ -64, -64, -5, 0, 0, 0, 0xff, 0, 0, 0xff },
}; ^^^^^^^^^^^^^^^^
この部分
これが以下であれば問題はありません.
static Vtx shade_vtx[] = {
{ -64, 64, -5, 0, 0, 0, 0, 0xff, 0, 0xff },
{ 64, 64, -5, 0, 0, 0, 0, 0, 0, 0xff },
{ 64, -64, -5, 0, 0, 0, 0, 0, 0xff, 0xff },
{ -64, -64, -5, 0, 0, 0, 0, 0xff, 0xff, 0xff },
}; ^^^^^^^^^^^^^^^^
すなわち, 頂点間において値が連続的に変化する場合に注意を払う必要があ
るということです. このため頂点間においてカラー値が変化しない Flat
Shading については問題にはなりません.
zShQuad でも他の ZObject と同様に 4 角形の裏表によるカリング処理は行
ないません. CPU が ZObject データを作成するときにこの判定をしてくださ
い.
メンバー変数 header は ZObject がリスト構造で連なるときに, 次の
ZObject へのポインタ等を保持します. もし次の ZObject が無い場合は,
G_ZOBJ_NONE を代入してください.
メンバー変数 rdpcmd1 は現在の RDP の処理モードを変更するために使用し
ます. ZObject を描画する前に RDP へ送られる RDP コマンド列をここに指定
します. rdpcmd1 についての詳細は 3.5 項で説明します.
---------------------
3.4.3 zTxTri 構造体
zTxTri 構造体は, テクスチャ付のスムースシェード処理された 3 角形を
描画するためのデータ構造体です. その形状を指定するために以下のような
zTxVtx 型の頂点データを 3 組必要とします.
----------------------------------------------------------------
typedef struct {
s16 x, y; /* 頂点のスクリーン座標 (s10.2) */
u8 r, g, b, a; /* 頂点におけるカラー 各 0..255 */
s16 s, t; /* 頂点におけるテクスチャ座標 (s10.5) */
s32 invw; /* テクスチャパースペクティブ補正処理
パラメータ 1/W (s15.16)
(視点からの距離の逆数に比例) */
} zTxVtx;
----------------------------------------------------------------
メンバー変数 invw は, 各頂点の座標値 (x,y,z,1) に MP 行列を乗じた後
の座標値 (X,Y,Z,W) の W から以下のように求めます. ただし perspNorm は
guPerspective 関数で取得できる透視変換正規化パラメータです.
invw = (1<<30)/(perspNorm * W);
RDP はこの値を使用して, テクスチャのパースペクティブ補正を行ないます.
マイクロコードの算術演算処理 GBI ではこの値を透視変換と同時に求めるこ
とができます.
zTxVtx 構造体は以下のようなデータ形式をとります.
+0 +4 +8 +c +f
+-----------+-----------+-----------+-----------+
| Hdr | RDP cmd 1 | RDP cmd 2 | RDP cmd 3 |
+-----+-----+--+--+--+--+-----+-----+-----------+
V0 | X | Y |R |G |B |A | S | T | invW |
+-----+-----+--+--+--+--+-----+-----+-----------+
V1 | X | Y |R |G |B |A | S | T | invW |
+-----+-----+--+--+--+--+-----+-----+-----------+
V2 | X | Y |R |G |B |A | S | T | invW |
+-----+-----+--+--+--+--+-----+-----+-----------+
-------------------------------------------------------------
typedef struct {
zHeader *header; /* 次の ZObject の情報 */
Gfx *rdpcmd1; /* 前処理 DP コマンド 1 */
Gfx *rdpcmd2; /* 前処理 DP コマンド 2 */
Gfx *rdpcmd3; /* 前処理 DP コマンド 3 */
zTxVtx v[3]; /* 頂点データ */
} zTxTri_t;
typedef struct { /* ワードアクセス用構造体 */
zHeader *header;
Gfx *rdpcmd1;
Gfx *rdpcmd2;
Gfx *rdpcmd3;
u32 xy0, clr0, st0, invw0;
u32 xy1, clr1, st1, invw1;
u32 xy2, clr2, st2, invw2;
} zTxTri_w;
typedef union {
zTxTri_t t;
zTxTri_w w;
u64 force_structure_alignment;
} zTxTri;
-------------------------------------------------------------
zTxTri でも他の ZObject と同様に 3 角形の裏表によるカリング処理は行
ないません. CPU が ZObject データを作成するときにこの判定をしてくださ
い.
メンバー変数 header は ZObject がリスト構造で連なるときに, 次の
ZObject へのポインタ等を保持します. もし次の ZObject が無い場合は,
G_ZOBJ_NONE を代入してください.
メンバー変数 rdpcmd1,2,3 は現在の RDP の処理モードを変更したり, テク
スチャをロードするために使用します. ZObject を描画する前に RDP へ送ら
れる RDP コマンド DL 列 3 組をここに指定します. rdpcmd1,2,3 についての
詳細は 3.5 項で説明します.
----------------------
3.4.4 zTxQuad 構造体
zTrQuad 構造体は, テクスチャ付のスムースシェード処理された 4 角形
を描画するためのデータ構造体です. その形状を指定するために前項で説明し
た zTxVtx 型の頂点データを 4 組必要とします.
zTxQuad では 3 角形 V0-V1-V2 と V1-V2-V3 の 2 つの 3 角形を描画する
ことで, 4 角形の描画を行ないます.
V0+--------+V1
| /|
| / |
| / |
|/ |
V2+--------+V3
zTxVtx 構造体は以下のようなデータ形式をとります.
+0 +4 +8 +c +f
+-----------+-----------+-----------+-----------+
| Hdr | RDP cmd 1 | RDP cmd 2 | RDP cmd 3 |
+-----+-----+--+--+--+--+-----+-----+-----------+
V0 | X | Y |R |G |B |A | S | T | invW |
+-----+-----+--+--+--+--+-----+-----+-----------+
V1 | X | Y |R |G |B |A | S | T | invW |
+-----+-----+--+--+--+--+-----+-----+-----------+
V2 | X | Y |R |G |B |A | S | T | invW |
+-----+-----+--+--+--+--+-----+-----+-----------+
V3 | X | Y |R |G |B |A | S | T | invW |
+-----+-----+--+--+--+--+-----+-----+-----------+
-------------------------------------------------------------
typedef struct {
zHeader *header; /* 次の ZObject の情報 */
Gfx *rdpcmd1; /* 前処理 DP コマンド 1 */
Gfx *rdpcmd2; /* 前処理 DP コマンド 2 */
Gfx *rdpcmd3; /* 前処理 DP コマンド 3 */
zTxVtx v[4]; /* 頂点データ */
} zTrQuad_t;
typedef struct { /* ワードアクセス用構造体 */
zHeader *header;
Gfx *rdpcmd1;
Gfx *rdpcmd2;
Gfx *rdpcmd3;
u32 xy0, clr0, st0, invw0;
u32 xy1, clr1, st1, invw1;
u32 xy2, clr2, st2, invw2;
u32 xy3, clr3, st3, invw3;
} zTrQuad_w;
typedef union {
zTrQuad_t t;
zTrQuad_w w;
u64 force_structure_alignment;
} zTrQuad;
-------------------------------------------------------------
zTxQuad を使用するメリットおよび, パフォーマンスを引き出すための技法
については zShQuad についての説明を参考にしてください.
zTxQuad でも他の ZObject と同様に 4 角形の裏表によるカリング処理は行
ないません. CPU が ZObject データを作成するときにこの判定をしてくださ
い.
メンバー変数 header は ZObject がリスト構造で連なるときに, 次の
ZObject へのポインタ等を保持します. もし次の ZObject が無い場合は,
G_ZOBJ_NONE を代入してください.
メンバー変数 rdpcmd1,2,3 は現在の RDP の処理モードを変更したり, テク
スチャをロードするために使用します. ZObject を描画する前に RDP へ送ら
れる RDP コマンド DL 列 3 組をここに指定します. rdpcmd1,2,3 についての
詳細は 3.5 項で説明します.
--------------------
3.4.5 zNull 構造体
zNull 構造体は, 3 角形や 4 角形というような, いわゆるポリゴンと呼ば
れる形状の描画を行なうためのものではなく, RDP に対し直接コマンドを送る
ことで描画される矩形領域 (FillRectangle, TextureRectangle) の描画のた
めに用意されたものです.
実際は, 矩形領域を描画するためのコマンドだけでなく, どのような RDP
コマンドでも設定可能です. よって Fog カラーや Primitive カラーを変更す
るだけで何も描画しないという ZObject も作成できます.
+0 +4 +8 +c +f
+-----------+-----------+-----------+-----------+
| Hdr | RDP cmd 1 | RDP cmd 2 | RDP cmd 3 |
+-----------+-----------+-----------+-----------+
-------------------------------------------------------------
typedef struct {
zHeader *header;
Gfx *rdpcmd1;
Gfx *rdpcmd2;
Gfx *rdpcmd3;
} zNull_t;
typedef union {
zNull_t t;
u64 force_structure_alignment;
} zNull;
-------------------------------------------------------------
メンバー変数 header は ZObject がリスト構造で連なるときに, 次の
ZObject へのポインタ等を保持します. もし次の ZObject が無い場合は,
G_ZOBJ_NONE を代入してください.
メンバー変数 rdpcmd1,2,3 に RDP へ送る RDP コマンド列へのポインタを
指定します. これについての説明は, 3.5 項で説明します.
------------------------------------------------
3.5 RDPcmd パラメータによる RDP コマンドの制御
ZObject の各構造体には, 1 つまたは 3 つの RDP Cmd 領域があります.
このメンバー変数で ZObject 描画中の RDP の状態を変更することができます.
RDP の状態を変更するためには, GBI コマンドを羅列した専用の DL を使い
ます. このことを RDP コマンド列と呼びます.
RDP コマンド列には主に RDP の状態を制御するためのコマンドしか含むこ
とができません. すなわち, RDP コマンド列として使用可能な GBI には制限
があるのです. この RDP コマンド列と使用可能な GBI を以下に示します.
以下の表の GBI コマンドの動作は Fast3D 互換マイクロコードと同じです.
表記以外の GBI コマンドを RDP コマンド列として使用したときの動作は保証
しません.
---------------------------------------------------------
RDP コマンド列に使用可能な GBI コマンド
---------------------------------------------------------
gSPNoOp gDPNoOp
gSPEndDisplayList
gDPFillRectangle
gSPTextureRectangle gSPTextureRectangleFlip
gDPSetColorImage gDPSetDepthImage
gDPSetTextureImage gDPSetScissor
gDPSetFillColor gDPSetEnvColor
gDPSetFogColor gDPSetBlendColor
gDPSetPrimColor gDPSetPrimDepth
gDPSetCombineMode gDPSetConvert
gDPSetKeyR gDPSetKeyGB
gDPSetOtherMode
gDPPipelineMode(*) gDPSetCycleType(*)
gSPSetTexturePersp(*) gDPSetTextureDetail(*)
gDPSetTextureLOD(*) gDPSetTextureLUT(*)
gDPSetTextureFilter(*) gDPSetTextureConvert(*)
gDPSetCombineKey(*) gDPSetColorDither(*)
gDPSetAlphaDither(*) gDPSetAlphaCompare(*)
gDPSetDepthSource(*) gDPSetRenderMode(*)
gDPSetTile gDPSetTileSize
gDPLoadBlock
gDPLoadTextureBlock gDPLoadTextureBlockS
gDPLoadTextureBlock_4b gDPLoadTextureBlock_4bS
gDPLoadTextureBlockYuv gDPLoadTextureBlockYuvS
gDPLoadMultiBlock gDPLoadMultiBlockS
gDPLoadMultiBlock_4b gDPLoadMultiBlock_4bS
gDPLoadTile
gDPLoadTextureTile gDPLoadTextureTile_4b
gDPLoadMultiTile gDPLoadMultiTile_4b
gDPLoadTLUT
gDPLoadTLUT_pal16 gDPLoadTLUT_pal256
gDPLoadSync gDPPipeSync
gDPTileSync gDPFullSync
---------------------------------------------------------
大きな注意点として, gSPSegment が使用できないことに注意してください.
gDPSetColorImage などにセグメントアドレスを使用することはできますが,
その値の設定は RDP コマンド列ではできません. また gSPBranchDL や
gSPDisplayList も使用できませんのでご注意ください.
rdpcmd1, rdpcmd2, rdpcmd3 の 3 つの RDP Cmd 領域は以下のように使われ
ることを想定しています.
rdpcmd1: RDP のレンダリングモードの設定用.
rdpcmd2: TMEM へのロード用 (主に TMEM 全体/ TMEM 前半部へのロード)
rdpcmd3: TMEM へのロード補助用 (主に TLUT / TMEM 後半部へのロード)
こうした想定のため, テクスチャなしの図形 (zShTri, zShQuad) の描画で
は rdpcmd1 だけを使用し, テクスチャありの図形 (zTxTri, zTxQuad) は, 3
つ全てを指定できるようになっています.
Z Sort マイクロコードの場合, Z Buffer 機能を使用したマイクロコードと
異なり, 画面深度順で描画されることになるため, 同じテクスチャを持つポリ
ゴンのみを連続して描画できません. このため, Z Sort マイクロコードでは,
各 ZObject にテクスチャ情報を与える必要があります. ただし既に TMEM へ
ロードされているテクスチャと同じテクスチャをロードするという無駄を小さ
くするための機構を用意しています.
これは直前に処理した RDP コマンド列へのポインタを記憶しておき, それ
と今回の ZObject で処理する RDP コマンド列へのポインタを比較し, 異なっ
ているときのみ RDP へ送るという処理です.
マイクロコードは rdpcmd1,rdpcmd2,rdpcmd3 のそれぞれに対応した RDP コ
マンドポインタの記憶領域 (ここでは仮に rdpcmd1_save, rdpcmd2_save,
rdpcmd3_saveと呼びます) を DMEM 内に用意しています. 以下はそれぞれの処
理のアルゴリズムを C 言語風に記述したものです.
------------------------------------------------
o zShTri, zShQuad の場合 (RDP Cmd 領域が 1 つ)
|
| if (rdpcmd1 != rdpcmd1_save){
| rdpcmd1 で示される RDP コマンド列の処理;
| rdpcmd1_save = rdpcmd1;
| }
| ZObject の描画;
|
rdpcmd1 には通常, RenderMode の切り替え用の RDP コマンド列を設定
します. 以下は rdpcmd1 に指定する RDP コマンド列のサンプルです.
gsDPSetOtherMode は幾つかの DP モードの設定を一度に行なうための
GBI です. 沢山の RDP コマンドを 1 命令で処理することができるのでな
るべくこのコマンドを使用する方が処理速度に関して有利です. 上記の
RDP コマンド列に使用できる GBI の表において (*) の印が付いているコ
マンドは gDPSetOtherMode でまとめて処理可能です.
|
|#define OTHERMODE_A(cyc) (G_CYC_##cyc##|G_PM_1PRIMITIVE|G_TP_PERSP|\
| G_TD_CLAMP|G_TL_TILE|G_TT_NONE|G_TF_BILERP|\
| G_TC_FILT|G_CK_NONE|G_CD_DISABLE|G_AD_DISABLE)
|#define OTHERMODE_B(rm) (G_AC_NONE|G_ZS_PRIM|G_RM_##rm##|G_RM_##rm##2)
|
|/*------ Shade Triangle モード切り替え ------*/
|Gfx modeShTri[] = {
| gsDPPipeSync(),
| gsDPSetOtherMode(OTHERMODE_A(1CYCLE), OTHERMODE_B(RA_OPA_SURF)),
| gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE),
| gsSPEndDisplayList(),
|};
|
------------------------------------------------
o zTxTri, zTxQuad の場合 (RDP Cmd 領域が 3 つ)
|
| if (rdpcmd1 != rdpcmd1_save){
| rdpcmd1_save = rdpcmd1;
| rdpcmd1 で示される RDP コマンド列の処理;
| }
| if (rdpcmd2 != rdpcmd2_save){
| rdpcmd2_save = rdpcmd2;
| rdpcmd2 で示される RDP コマンド列の処理;
| }
| if (rdpcmd3 != rdpcmd3_save){
| rdpcmd3_save = rdpcmd3;
| if (rdpcmd3 != NULL){
| rdpcmd3 で示される RDP コマンド列の処理;
| }
| }
|
rdpcmd1 には, zShTri, zShQuad と同様に, RenderMode の切り替え用
の RDP コマンド列を設定します. 以下は rdpcmd1 に指定する RDP コマ
ンド列のサンプルです. 4b CI テクスチャにおけるパレットの切り替え等
もここに含めると良いでしょう.
|
|/*------ Textured Triangle モード切り替え ------*/
|Gfx modeTxTri1[] = {
| gsDPPipeSync(),
| gsDPSetOtherMode(OTHERMODE_A(1CYCLE), OTHERMODE_B(RA_OPA_SURF)),
| gsDPSetCombineMode(G_CC_MODULATERGB, G_CC_MODULATERGB),
| gsSPEndDisplayList(),
|};
|
rdpcmd2 にはテクスチャロード用の RDP コマンドを設定します.
以下は rdpcmd2 に指定する RDP コマンド列のサンプルです.
|
|Gfx modeTxTri2[] = {
| gsDPPipeSync(),
| gsDPLoadTextureBlock(brick, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, 0,
| G_TX_WRAP | G_TX_MIRROR, G_TX_WRAP | G_TX_MIRROR,
| 5, 5, G_TX_NOLOD, G_TX_NOLOD),
| gsSPEndDisplayList(),
|};
|
rdpcmd3 も rdpcmd2 と同様に設定します. rdpcmd3 は TLUT のロード
用として使用することを想定していますが, テクスチャのロード用として
も使用できます.
もし rdpcmd3 が必要ないならNULL(=0x00000000) を代入します.
このとき, rdpcmd3_save は NULL で *クリア* されますが, rdpcmd3 で
示される RDP コマンドの処理は行ないません.
--------------------------------------
o zNull の場合 (RDP Cmd 領域が 3 つ)
|
| if (rdpcmd1 != NULL && rdpcmd1 != rdpcmd1_save){
| rdpcmd1_save = rdpcmd1;
| rdpcmd1 で示される RDP コマンド列の処理;
| }
| if (rdpcmd2 != NULL && rdpcmd2 != rdpcmd2_save){
| rdpcmd2_save = rdpcmd2;
| rdpcmd2 で示される RDP コマンド列の処理;
| }
| if (rdpcmd3 != NULL && rdpcmd3 != rdpcmd3_save){
| rdpcmd3_save = rdpcmd3;
| rdpcmd3 で示される RDP コマンド列の処理;
| }
|
zNull に関しては特に想定していることはありません. ご自由にお使い
下さい. 上記のアルゴリズムを見て判るように, rdpcmd に対して NULL
(=0x00000000) を設定するとその RDP コマンドの処理をしません. この
とき対応する rdpcmd_save の値は *保存* されます. (NULL 指定時に
*保存* されることが, zTxTri, zTxQuad の rdpcmd3 の処理 (クリアされ
る)と異なるのでご注意ください.)
--------------------------------------
3.6 画面クリアおよびその他の描画処理
ZSort マイクロコードを使用する上で注意しなければならない点の 1 つに,
通常の DisplayList に直接 RDP コマンドを書き込むことができないことが挙
げられます. これは, SP のコマンドの処理と DP のコマンドの処理とが内部
的に分れていることによります. これによりマイクロコードの命令数と処理速
度を稼いでいます.
通常, 画面クリアなどの背景を塗り潰すような処理は, 全ての ZObject の
描画処理前に行なう必要があり, Fast3D 互換マイクロコードでは通常そうし
た GBI 列を static な領域に作成しておき, DisplayList 側から呼び出して
います.
ZSort マイクロコードでは, 前述した画面クリアなどの DP の動作を制御す
るための RDP コマンド列を通常の DisplayList から呼び出すため, 以下の
GBI コマンドが用意されています. この RDP コマンド列に使用可能な GBI コ
マンドには, ZObject の描画中に使用されるものと同じ制限があります. 前出
の表を参考にしてください. 具体的な使用例は, サンプルプログラム cubes-1
を参照してください.
------------------------------------------------------------------------------
* gSPZRdpCmd(Gfx *gp, Gfx *rdpcmd)
rdpcmd RDP コマンド列へのポインタ
RDP コマンド列を処理する. ただし呼び出される RDP コマンドには
制限がある. (3.5 項 RDP コマンド列に使用可能な GBI コマンドの表を参照)
===============================================================================
4. 算術演算処理
===============================================================================
-----------------------
4.1 表示物体と算術演算
ZSort マイクロコードで描画可能な多角形は zShTri, zShQuad, zTxTri,
zTxQuad の 4 種類であることは前章で述べた通りです. 一見すると少ないよ
うに見えますが, これと算術演算を組み合わせると様々な描画方法ができるよ
うになります. 本マイクロコードで処理可能な演算の主なものは以下の 3 つ
です.
----------------------------------------------------------------
(演算 A) --- gSPZMultMPMtx ---
モデル座標頂点データ +
MxP マトリクス ==> スクリーン座標頂点データ
----------------------------------------------------------------
(演算 B) --- gSPZLight / gSPZLightMaterial ---
法線ベクトルデータ +
マテリアルデータ +
ライトデータ +
ModelView マトリクス ==> カラーデータ
----------------------------------------------------------------
(演算 C) --- gSPZLight / gSPZLightMaterial ---
法線ベクトルデータ +
視線(LookAt)データ +
ModelView マトリクス ==> テクスチャ座標(環境マップ)データ
----------------------------------------------------------------
全ての多角形 ZObject において (演算 A) を行なってスクリーン座標頂点
データを求める必要があります. また, ライト処理を行なう場合には (演算 B)
を, 環境マップ処理を行なう場合には (演算 C) を行なう必要があります.
ただし, 上記の演算 A,B,C を行なう各 GBI (gSPZMultMPMtx, gSPZLight /
gSPZLightMaterial) はそれだけでは機能しません. 実際に演算を行なう GBI
の前には頂点のデータと変換パラメータ(行列など)を用意して RSP の DMEM
にロードする処理を行なう必要があり, また演算の後には演算結果を DMEM か
ら DRAM へ書き戻す必要があります.
--------------------------------
4.2 DMEM 内の演算用ワークエリア
ZSort マイクロコードには, RSP によって 3 次元モデル座標のスクリーン
座標系への変換処理やライティング計算やマトリクス演算を行なうために特化
された算術演算専用の GBI が用意されています.
この演算処理を *複数個組み合わせる* ことで ZObject をスクリーンに描
画するために必要な座標値やカラー値などの値を取得することになります.
例えば, モデル座標をスクリーン座標に変換するには以下のような GBI コ
マンドを組み合わせて処理します.
(1) gSPZViewport VIEWPORT の設定をする.
(2) gSPZPerspNormalize パース正規化係数を設定する.
(3) gSPZSetMtx PROJECTION 行列を DMEM 内のワークエリアにロード.
(4) gSPZSetMtx MODELVIEW 行列を DMEM 内のワークエリアにロード.
(5) gSPZMtxCat MODELVIEW 行列と PROJECTION 行列を乗算.
(6) gSPZSetUMem DRAM 内のモデル座標値を DMEM 内のワークエリアにロード.
(7) gSPZMultMPMtx モデル座標値をスクリーン座標値に変換.
(8) gSPZGetUMem スクリーン座標値を DRAM へ出力.
ZSort マイクロコードでは算術演算処理において使用するためのワークエリ
アを DMEM 内に確保しています. ワークエリアにはマトリクス用と汎用の 2
種類あり, それぞれ以下のような大きさとなっています. また汎用ワークエリ
アのことをユーザエリアと呼びます.
------------------------------------------
o 汎用ワークエリア
(ユーザエリア) 計 2048Bytes
------------------------------------------
o マトリクス用のワークエリア 計 192Bytes
(内訳) ModelView 用 64Bytes
Projection 用 64Bytes
M x P 用 64Bytes
------------------------------------------
ユーザエリアは 0 から 2047 番地まであり, これをどのように使うかは,
アプリケーション作成者が任意に決めることができます.
サンプルプログラム cubes-1 の libzsort では, 以下のようにユーザエリ
アを使っています. 領域が重なっていますが時系列的に異なるので問題ありま
せん. 参考にしてください.
------------------------------------------------------------------
1200-1919: モデル座標値ソース保持用 (120 組保持可能)
0-1919: スクリーン座標値計算結果保持用 (120 組保持可能)
0- 383: 法線ベクトルソース保持用 (128 組保持可能)
512-1023: マテリアルカラーソース保持用 (128 組保持可能)
512-1023: ライティング計算結果保持用 (128 組保持可能)
1024-1535: 環境テクスチャマップ座標計算結果保持用 (128 組保持可能)
1920-2047: ライトデータ保持用
(DEFUSE ライト 3 個 + AMBIENT 1 個 + 環境マップ)
------------------------------------------------------------------
ユーザエリアはユーザが自由に割り振って使用することができますが, マト
リクス用のエリアはマトリクスデータを保持するために用意されたものなので
通常, 他の目的に使用するべきではありません. また番地を指定することで細
かな割り振りが可能なユーザエリアに対して, マトリクス用エリアは基本的に
その領域 ID (GZM_MMTX, GZM_PMTX, GZM_MPMTX) の内の 1 つを指定します.
ただしユーザエリアの先頭の 0〜63 番地 と 64〜127 番地をマトリクス用に
使用することは可能です. よって, マトリクス領域として以下のような 5 つ
を使用することができます. ただし, ModelView/Projection/MxP の各マトリ
クス領域の名称は理解を助けるために仮に名付けたもので, それぞれの領域に
機能上の違いはありません. 混乱を求めるなら, MxP マトリクス領域に
ModelView マトリクスを代入して使用することも可能です.
--------------------------------------------
GZM_MMTX ModelView マトリクス領域
GZM_PMTX Projection マトリクス領域
GZM_MPMTX M x P 用 マトリクス領域
GZM_USER0 ユーザエリア 0〜 63 番地
GZM_USER1 ユーザエリア 64〜127 番地
--------------------------------------------
算術演算用 GBI は Main DL, Sub DL のどちらでも動作しますが, Main DL
と Sub DL 双方でユーザエリアを読み書きするようにしたときには注意が必要
です. Main DL と Sub DL とで並列処理を行なった場合, Main DL の GBI で
計算したデータを Sub DL の GBI が破壊してしまうといったことが起こり得
ます. このため, Main DL, Sub DL の双方でユーザエリアにアクセスすること
はお勧めしません. また, それほどメリットもないので, Main DL と Sub DL
のどちらが算術演算を行なうかを固定する方がよいでしょう.
--------------
4.3 GBI 一覧
算術演算用 GBI の一覧です.
----------------------------------------------------------------
gSPZSetUMem - ユーザエリアへデータを書き込む.
gSPZGetUMem - ユーザエリアのデータを読み出す.
gSPZSetMtx - マトリクスを書き込む.
gSPZGetMtx - マトリクスを読み出す.
gSPZMtxCat - マトリクスを乗ずる.
gSPZMtxTrnsp3x3 - マトリクスの 3x3 要素を転置する.
gSPZViewport - VIEWPORT を設定する.
gSPZMultMPMtx - モデル座標値をスクリーン座標値に変換する.
gSPZSetAmbient - Ambient ライト(環境光)を書き込む.
gSPZSetDefuse - Defuse ライト(拡散光)を書き込む.
gSPZSetLookAt - LookAt 構造体データを書き込む.
gSPZXfmLights - ライトパラメータの前処理を行なう.
gSPZLight - ライト計算を行なう.
gSPZLightMaterial - マテリアルを考慮したライト計算を行なう.
gSPZMixS16 - s16 型の数値の補間を行なう.
gSPZMixS8 - s8 型の数値の補間を行なう.
gSPZMixU8 - u8 型の数値の補間を行なう.
----------------------------------------------------------------
--------------------
4.4 GBI の機能解説
この項では算術演算用 GBI の解説をします.
------------------------------------------------------------------------------
* gSPZSetUMem(Gfx *gp, u32 umem, u32 size, u64 *adrs)
umem 書き込み先のユーザエリアの番地 (0 〜 2040)
size 書き込むサイズ (8 〜 2048)
adrs DRAM 上の書き込み元へのポインタ
ユーザエリアへデータを書き込む. umem, size は 8 の倍数でなけ
ればいけません. また adrs は 8 Bytes 境界になければなりません.
もし, 10 Bytes 分のデータが必要な場合は, 16 Bytes を指定します.
------------------------------------------------------------------------------
* gSPZGetUMem(Gfx *gp, u32 umem, u32 size, u64 *adrs)
umem 読み出し元のユーザエリアの番地 (0 〜 2040)
size 読み出すサイズ (8 〜 2048)
adrs DRAM 上の読み出し先へのポインタ
ユーザエリアからデータを読み出す. umem, size は 8 の倍数でな
ければいけません. また adrs は 8 バイト境界になければなりません.
------------------------------------------------------------------------------
* gSPZSetMtx(Gfx *gp, u32 mid, Mtx *mptr)
mid 書き込み先のマトリクス領域.
mptr DRAM 上の書き込み元へのポインタ.
マトリクス領域へ DRAM 上のマトリクスデータを書き込みます. 一
般的に mid には GZM_MMTX, GZM_PMTX, GZM_MPMTX のうちの 1 つを
指定します. ただし, ユーザエリアの先頭の 128Bytes 分を使用する
ことも可能です. そのときは GZM_USER0, GZM_USER1 を指定します.
これによりユーザエリアの 0 〜 63 番地 と 64 〜 127 番地をマト
リクス領域として使用できます.
------------------------------------------------------------------------------
* gSPZGetMtx(Gfx *gp, u32 mid, Mtx *mptr)
mid 読み出し元のマトリクス領域.
mptr DRAM 上の書き込み元へのポインタ.
マトリクス領域から DRAM 上へマトリクスデータを読み出します. 一
般的に mid には GZM_MMTX, GZM_PMTX, GZM_MPMTX のうちの 1 つを
指定します. ただし, ユーザエリアの先頭の 128Bytes 分を使用するこ
とも可能です. そのときは GZM_USER0, GZM_USER1 を指定します.
これによりユーザエリアの 0 〜 63 番地 と 64 〜 127 番地をマト
リクス領域として使用できます.
------------------------------------------------------------------------------
* gSPZMtxCat(Gfx *gp, u32 mids, u32 midt, u32 midd)
mids マトリクス領域 S.
midt マトリクス領域 T.
midd マトリクス領域 D.
(マトリクス D) = (マトリクス S) x (マトリクス T) を計算します.
mids,midt,midd は一般的に GZM_MMTX, GZM_PMTX, GZM_MPMTX のうち
の 1 つを指定します. ただし, ユーザエリアの先頭の 128Bytes 分
を使用することも可能です. そのときは GZM_USER0, GZM_USER1 を指
定します. これによりユーザエリアの 0 〜 63 番地 と 64 〜 127
番地をマトリクス領域として使用できます.
ただし, マトリクス T の領域と マトリクス D の領域は同じ場合
には正常な動作は保証できません. S と D あるいは S と T は同じ
領域でも問題はありません.
------------------------------------------------------------------------------
* gSPZMtxTrnsp3x3(Gfx *gp, u32 mid)
mid 転置させるマトリクス領域.
マトリクスの (x,y,z) の 3x3 の要素を転置させます.
もし, マトリクスが回転行列である場合, 転置させた結果は元のマト
リクスの逆回転を意味することになります. こうして転置されたマト
リクスは, 主にライトの処理に使われます.
|00 01 02 03| |00 10 20 03|
|10 11 12 13| -> |01 11 21 13|
|20 21 22 23| |02 12 22 23|
|30 31 32 33| |30 31 32 33|
mid には一般的に GZM_MMTX, GZM_PMTX, GZM_MPMTX のうちの 1 つ
を指定します. ただし, ユーザエリアの先頭の 128Bytes 分を使用す
ることも可能です. そのときは GZM_USER0, GZM_USER1 を指定します.
これによりユーザエリアの 0 〜 63 番地 と 64 〜 127 番地をマト
リクス領域として使用できます.
------------------------------------------------------------------------------
* gSPZViewPort(Gfx *gp, Vp *vp)
vp VIEWPORT データへのポインタ.
本 GBI は F3DEX 等における gSPViewPort GBI とほぼ同じで,
VIEWPORT を設定するものですが, VIEWPORT データのパラメータに違
いがあります. ZSort マイクロコードでは Vp 構造体のメンバ変数で
ある vscale, vtrans の vscale[3] と vtrans[3] に Fog を制御す
るためのパラメータを指定します. この指定のために以下のマクロを
用意しています.
vp->vp.vscale[3] = GZ_VIEWPORT_FOG_S(in, out);
vp->vp.vtrans[3] = GZ_VIEWPORT_FOG_T(in, out);
in: Fog 開始距離
out: Fog 終了距離
また, 画面の上方を正の方向にするために vscale[1] の値には,
負の値を設定する必要があります. これにより, 右, 上, 手前が正の
方向となります. (右手系)
具体的には, 視点からの距離 3000 から Fog を開始し, 距離 4000
で背景色と等しくなるという指定をするときは, 以下のように初期化
します.
Vp viewport = {
SCREEN_WD*2, -SCREEN_HT*2, G_MAXZ/2, GZ_VIEWPORT_FOG_S(3000, 4000),
SCREEN_WD*2, SCREEN_HT*2, G_MAXZ/2, GZ_VIEWPORT_FOG_T(3000, 4000),
};
------------------------------------------------------------------------------
* gSPZMultMPMtx(Gfx *gp, u32 mid, u32 src, u32 num, u32 dest)
mid MxP マトリクス.
src 頂点のモデル座標値が格納されているユーザエリアの先頭番地
num 処理する頂点数.
dest 座標変換後の頂点のスクリーン座標値を格納するユーザエリア
の先頭番地
ユーザエリアの src の位置におけるデータを 16bit の x,y,z 値
とみなし mid で指定した 4x4 行列をかけ, その結果の (X,Y,Z,W)
を W=1 で正規化します. その後, 得られた座標に対して ViewPort
変換を行なうことでスクリーン座標値を取得します. またこのとき
FOG パラメータやクリッピング処理用フラグも計算し, それらのデー
タをまとめて dest の位置へ出力します. その後 src に 6 を加算,
dest に 16 を加算し次の頂点へ進みます. num 個の頂点を連続して
処理します.
ここでの入力と出力の座標値のフォーマットは, ヘッダファイル
gzsort.h 内の zVtxSrc 構造体と zVtxDest 構造体で以下のように定
義されています.
-------------------------------------------------------------------
typedef struct {
s16 x, y, z; /* 頂点のモデル座標値 (s10.2) */
} zVtxSrc; /* サイズ 6 Bytes */
typedef struct {
s16 sx, sy; /* 頂点のスクリーン座標値 (s10.2) */
s32 invw; /* テクスチャパースペクティブ補正処理
パラメータ 1/W (s15.16) */
s16 xi, yi; /* 正規化前の X,Y の値 (整数部のみ) */
u8 cc; /* クリップ処理判定用フラグ */
u8 fog; /* FOG 係数 */
s16 wi; /* W の値 (整数部のみ) */
} zVtxDest; /* サイズ合計 16 Bytes */
-------------------------------------------------------------------
zVtxSrc 構造体のサイズは 6Bytes なので gSPZSetUMem による
DMA 転送時には 8Bytes アライメントに対し特に注意しなければなり
ません. 転送サイズが 8 の倍数にならないときには, 8 の倍数に
DMA 転送サイズを切り上げる必要があります.
zVtxDest 構造体のサイズは, 16Bytes なので 2048Bytes のユーザエ
リア内には最大 128 個分の領域しか確保できません. よって num の範
囲は 1 から 128 までです. (実際にはライト処理を行なったりするので
これよりも少なくなることが多いです.) このとき dest の番地から
num*16 Bytes の領域が書換えられますが, num が 3 以下の場合は例
外です. この場合 dest で指定した位置から 64 Bytes 分の領域が上
書きされます. 例えば num が 3 で dest が 0 のときは, 0 〜 47
番地には変換後の正しい値が格納されますが, 48 〜 63 番地には,
意味のないデータが書き込まれます. このとき 48 〜 63 番地の元の
値は破壊されてしまうので充分に注意する必要があります. この仕様
は計算速度の向上のためやむを得ないものです.
この GBI のルーチンは基本的には以下のような手続きになってい
ます. dest の出力によって未処理の src が上書きされないように注
意すれば, src と dest の領域を重複させることが可能です. サンプ
ルプログラムの cubes-1 の libzsort では src = 1200 〜 1919,
dest = 0 〜 1919 として最大 120 個の頂点を処理できるようになっ
ています.
--------------------------------
for (i = 0; i < num; i ++){
*dest = MultMP(*src);
src += 6;
dest += 16;
}
--------------------------------
メンバー変数 invw は, 各頂点の座標値 (x,y,z,1) に MxP 行列を
乗じた後の座標値 (X,Y,Z,W) の W から以下のように求めます. この
式から invW は視点からの距離の逆数に比例することが判ります. た
だし perspNorm は gSPZPerspNormalize で設定した透視変換正規化
パラメータです.
invw = (1<<30)/(perspNorm * W);
invW の値をそのまま ZObject の zTxTri/zTxQuad の設定に使用す
ることができます.
guPerspective, guLookAt などを使用して MP マトリクスを作成し
た場合, wi の値は通常, 視点からの距離を示します. この値を画面
深度として選び Z Sort を行なうことも可能です.
また xi,yi は, 透視変換を行なう前の正規化されていない座標値
です. この値は, 主にクリッピング処理に使われます. ZSort マイク
ロコードではマイクロコードによるクリッピング処理はサポートされ
ていません. ただし CPU プログラムで xi,yi,wi の値を使用してク
リッピングを行なうことが出来ます. 詳しくは後程説明します.
クリップ処理判定用フラグ cc の値を調べることによって, その頂
点が ViewPort (可視領域)内にあるかどうかを簡単に判定することが
出来ます. 下は cc の各フラグの説明です.
---------------------------------------------------------
GZ_CC_LEFT X 座標が可視領域の Left Plane よりも左
GZ_CC_RIGHT X 座標が可視領域の Right Plane よりも右
GZ_CC_TOP Y 座標が可視領域の Top Plane よりも上
GZ_CC_BOTTOM Y 座標が可視領域の Bottom Plane よりも下
GZ_CC_NEAR Z 座標が可視領域の Near Plane よりも前
GZ_CC_FAR Z 座標が可視領域の Far Plane よりも奥
---------------------------------------------------------
頂点 v0,v1,v2 からなる 3 角形が完全に画面外にあるかどうかを
判定するときには以下のように各頂点の cc 値を AND し, その結果
が 0 であるかどうかを調べます. 結果が 0 で無ければ, その 3 角
形の全領域が 6 つのクリップ面の内の少なくとも 1 つに対して外側
にあることになります. このときの 3 角形は画面外にあることにな
るのでその時点で処理を打ち切ることができます.
-------------------------------------------------
if (v0.cc & v1.cc & v2.cc){
3 角形は画面外にあるので処理を打ち切る;
}
-------------------------------------------------
さらに 3 角形 v0,v1,v2 が Near Plane と交差しているかを判定
したいときは, 3 角形が Near Plane 外にあるかどうかを上記の式で
判定した後に, 以下のように OR 処理をすることで判定します. これ
は, Near Plane でクリッピング処理を行なうかどうかの判定に使わ
れます.
-------------------------------------------------
if ((v0.cc | v1.cc | v2.cc) & GZ_CC_NEAR){
Near クリッピング処理を行なう;
}
-------------------------------------------------
fog は FOG 処理を行なうときに使用します. fog の値を RGBA の A
の値として使用することで FOG 処理が可能です. ZSort マイクロコー
ドでは FOG の調節は ViewPort の Vp 構造体のパラメータで行ない
ます. 詳しくは, サンプルプログラムを参照してください.
本 GBI で取得できる頂点データは実際には以下のように使用され
ます. 実際に ZObject の各構造体に代入される数値は sx, sy, fog,
invw の値ですが, invw あるいは wi の値が Z ソートを行なうため
の画面深度の値として用いられます.
------------------------------------------------------
[ zShTri 構造体の場合 ]
zVtxDest *v0, *v1, *v2;
zShTri *shtri;
/* スクリーン座標の設定 */
shtri->t.v[0].x = v0->sx; shtri->t.v[0].y = v0->sy;
shtri->t.v[1].x = v1->sx; shtri->t.v[1].y = v1->sy;
shtri->t.v[2].x = v2->sx; shtri->t.v[2].y = v2->sy;
/* 以下の設定は Fog を使うときのみ */
shtri->t.v[0].a = v0->fog;
shtri->t.v[1].a = v1->fog;
shtri->t.v[2].a = v2->fog;
------------------------------------------------------
[ zTxTri 構造体の場合 ]
zVtxDest *v0, *v1, *v2;
zTxTri *txtri;
/* スクリーン座標の設定 */
txtri->t.v[0].x = v0->sx; txtri->t.v[0].y = v0->sy;
txtri->t.v[1].x = v1->sx; txtri->t.v[1].y = v1->sy;
txtri->t.v[2].x = v2->sx; txtri->t.v[2].y = v2->sy;
/* テクスチャ補正パラメータの設定 */
txtri->t.v[0].invw = v0->invw;
txtri->t.v[1].invw = v1->invw;
txtri->t.v[2].invw = v2->invw;
/* 以下の設定は Fog を使うときのみ */
txtri->t.v[0].a = v0->fog;
txtri->t.v[1].a = v1->fog;
txtri->t.v[2].a = v2->fog;
------------------------------------------------------
------------------------------------------------------------------------------
* gSPZSetAmbient(Gfx *gp, u32 umem, Ambient *ambient);
* gSPZSetDefuse (Gfx *gp, u32 umem, u32 lid, Light *defuse );
umem ライトデータ保持用領域の先頭番地.
ambient Ambient ライト構造体へのポインタ.
lid Defuse ライトの番号 (0,1,....)
defuse Defuse ライト構造体へのポインタ.
Ambient ライト(環境光)データまたは Defuse ライト(表面拡散光)
データをユーザエリアに書き込みます. ライトデータ領域はユーザエ
リア内に予め確保しておきます. そのサイズは, Defuse ライトの数
および環境マップを行なうかどうかに依存し, 以下の式で計算できま
す.
(ライトデータ領域のサイズ) =
8 + 24 * (Defuse ライトの数) + ((環境マップを行なう)? 48 : 0));
サンプルプログラム cubes-1 の libzsort では Defuse ライトを
3 個と環境マップを使用しますので, ユーザエリア 1920 〜 2047 の
128Bytes をライト用として確保しています.
Ambient 構造体, Defuse 構造体の設定には, Fast3D のマクロを使
用することができます. 以下は Defuse ライトが 2 個のときに
gdSPDefLights2 を使用して, ライトを設定する一例です.
---------------------------------------------------------------
/*--- Light parameter ---*/
static Lights2 scene_light =
gdSPDefLights2( 0x20,0x20,0x20, /* Ambient */
0xe0,0xe0,0xe0, 0, 40,80, /* Defuse 0 */
0x40,0x00,0x00, 0,-80,40 ); /* Defuse 1 */
/*--- Load light parameter ---*/
gSPZSetAmbient(gp++, 1920, &scene_light.a);
gSPZSetDefuse (gp++, 1920, 0, &scene_light.l[0]);
gSPZSetDefuse (gp++, 1920, 1, &scene_light.l[1]);
---------------------------------------------------------------
------------------------------------------------------------------------------
* gSPZSetLookAt(Gfx *gp, u32 umem, u32 lnum, LookAt *lookat)
umem ライトデータ保持用領域の先頭番地.
lnum Defuse ライトの数
lookat LookAt 構造体へのポインタ.
環境マッピングのパラメータである LookAt 構造体データをライト
データ領域に書き込みます. ライトデータ領域はユーザエリア内に予
め確保しておきます. これについては gSPZSetAmbient/Defuse の説
明を参照してください.
ZSort マイクロコードでは環境マップ処理において Fast3D 互換マ
イクロコードであった TEX_GEN と TEX_GEN_LINEAR の処理モードの
内, TEX_GEN_LINEAR はサポートされていません. 常に TEX_GEN の処
理となります.
LookAt 構造体の設定には, OS の gu ライブラリ関数の,
guLookAtReflect, guLookAtHilite 等が利用できますが, ZSort と一
部異なる部分があります. これを修正するためのマクロ
guZFixLookAt が用意されていますので, ライブラリ関数で LookAt
を設定した後に guZFixLookAt で修正してください.
以下は Defuse ライトが 2 個のときに gdSPDefLights2 を使用し
て, ライトを設定し, さらに guLookAtReflect で反射マップを行な
うときのデータの書き込み処理です.
---------------------------------------------------------------
/*--- Light parameter ---*/
static Lights2 scene_light =
gdSPDefLights2( 0x20,0x20,0x20, /* Ambient */
0xe0,0xe0,0xe0, 0, 40,80, /* Defuse 0 */
0x40,0x00,0x00, 0,-80,40 ); /* Defuse 1 */
/*--- Make reflection parameter ---*/
guLookAtReflect(&dynamicp->viewing, &dynamicp->lookat,
0, 0, 1000, 0, 0, 900, 0, 1, 0);
guZFixLookAt(&dynamicp->lookat);
/*--- Load light parameters ---*/
gSPZSetAmbient(gp++, 1920, &scene_light.a);
gSPZSetDefuse (gp++, 1920, 0, &scene_light.l[0]);
gSPZSetDefuse (gp++, 1920, 1, &scene_light.l[1]);
/*--- Load reflection parameters ---*/
gSPZSetLookAt (gp++, 1920, 2, &dynamicp->lookat);
---------------------------------------------------------------
guZFixLookAt は gzsort.h 内で以下のように定義されています.
---------------------------------------------------------------
#define guZFixLookAt(lp) \
{ (lp)->l[1].l.col[1] = (lp)->l[1].l.colc[1] = 0x00; }
---------------------------------------------------------------
これは, 2 つの要素を 0 クリアしているだけです. (gu ライブラ
リでは 0x80 を代入してしまいます.) もしこれを毎回使用する無駄
を無くしたいとお考えなら, libultra のサンプルプログラムのディ
レクトリ下の libultra/gu にある OS の gu ライブラリ関数のソー
スファイル (Partner 版ではライブラリとは別に配布している場合が
あります) を参考に修正しライブラリ関数と置き換えてください.
------------------------------------------------------------------------------
* gSPZXfmLights(gfx *gp, u32 mid, u32 lnum, u32 umem)
mid ModelView マトリクスの左上 3x3 要素を転置したマトリクス.
lnum 処理するライト要素数.
umem ライトデータが保持されているユーザエリアの先頭番地
ライティングの前処理を行ないます. ライトデータあるいは
ModelView マトリクスの一方または両方が変更されてから,
g*SPLight または g*SPLightMaterial が呼び出されるまでの間に本
GBI を呼び出さなければなりません. これによって, ライトデータが
gSPZLight や gSPZLightMaterial によるライティング計算に使用で
きるように前処理されます. 通常ライトデータが 1 シーン内で変更
されることは稀なので, ModelView マトリクスが変更になったときに
この GBI を呼び出せば良いでしょう.
本 GBI の実行には ModelView マトリクスの逆回転マトリクスが必
要となります. 通常, これには ModelView マトリクスの左上 3x3 要
素を転置したマトリクスを適用できます. (ある座標軸のみをスケー
リングさせた場合などに陰影づけが少しおかしくなることがあります
が, あまり気にならないことが多いのです.) この ModelView マトリ
クスの転置は gSPZMtxTrnsp3x3 を使用します.
lnum の数は基本的には Defuse ライトの数となります. Ambient ラ
イトは含みません. また ZSort マイクロコードでは, lnum を 0 に
することはできません. Ambient ライトのみのライティング処理をし
たいときは, 黒色 (RGB=0,0,0) の Defuse ライトを 1 つダミーで指
定してください.
また, 環境マップを行なうときは擬似的に 2 つの Defuse ライトを
使用します. ハイライトの表現やリフレクションの表現を行なう場合
には環境マップ用パラメータをライト用パラメータ領域にロードし,
lnum に (Defuse ライトの数 +2) を設定してください. ライトを使
用せず (Defuse ライトなし)に, 環境マップのみを使用する場合には
前述のダミーの Defuse ライトは必要ありません. lnum に 2 を指定
して本 GBI を呼び出してください.
以下は ModelView マトリクスが変更になったときの処理例です.
ライトデータ領域先頭は 1920 番地で, Defuse ライトが 2 個, 環境
マップありの場合の処理です.
-----------------------------------------------------
/*--- Set ModelView and MxP matrix ---*/
gSPZSetMtx(gp++, GZM_MMTX, &dynamicp->modeling[i]);
gSPZMtxCat(gp++, GZM_MMTX, GZM_PMTX, GZM_MPMTX);
/*--- Xfm light data ---*/
gSPZMtxTrnsp3x3(gp++, GZM_MMTX);
gSPZXfmLight(gp++, GZM_MMTX, 1920, 4);
-----------------------------------------------------
------------------------------------------------------------------------------
* gSPZLight(Gfx *gp, u32 nsrc, u32 num, u32 cdest, u32 tdest)
* gSPZLightMaterial(Gfx *gp,
u32 msrc, u32 nsrc, u32 num, u32 cdest, u32 tdest)
msrc マテリアルカラーデータ(頂点自体の色)が格納されているユー
ザエリアの先頭番地
nsrc 法線ベクトルデータが格納されているユーザエリアの先頭番地
num 処理する法線ベクトルの数 (2 の倍数)
cdest ライト計算後の頂点のカラー値を格納するユーザエリアの先頭番地
tdest 環境マップ計算後の頂点のテクスチャ座標値を格納するユーザ
エリアの先頭番地
ユーザエリアの nsrc 番地からのデータを signed 8bit の法線ベク
トル値 (nx,ny,nz) 値とみなし, それに gSPZXfmLight で指定した
ライトパラメータを用いてライティング計算を行ないます. これによっ
て法線ベクトルに対応するライトカラーを取得でき, このライトカラー
と頂点自体の色であるマテリアルカラーとを各 r,g,b 要素毎に掛け
合わせることで頂点のカラーを取得します. また a 要素はマテリア
ルカラーの a 値がそのまま使用されます. こうして計算されたカラー
値は, ユーザエリアの cdest 番地に格納されます.
gSPZLight の場合, マテリアルカラーとして (r,g,b,a) = (255,255,
255,255) が使われます. これは Fast3D 系マイクロコードと同じ仕様
で, ライトカラーで頂点の色付けを行なうことを意味します. また
gSPZLightMaterial の場合は, ユーザエリアの msrc 番地からのデー
タを unsigned 8bit のカラーデータとして順に (r,g,b,a) として使
います.
また, ライトデータとして LookAt 構造体データが設定してある場
合には, ライティング計算と同時に環境マップ計算が行なわれます.
計算結果として (S,T = 0.00 〜 32.00) までのテクスチャ座標値が
ユーザエリアの tdest 番地に出力されます. もし, LookAt 構造体が
設定してない場合でも tdest へは不定値が出力され, (num * 4) Bytes
分の領域が破壊されますので注意してください.
こうして, cdest と tdest を出力した後, nsrc に 3, msrc,
cdest,tdest に 4 が加算され, 次の頂点へ進みます. num 個の法線
ベクトルを連続して処理しますが, num は偶数でなければいけません.
num が奇数の場合, それを超える偶数(num+1)個のデータが cdest,
tdest へ出力されます. このとき num+1 個目の出力データの位置に
は意味のないデータが出力されます.
本 GBI での入力と出力のデータ値のフォーマットは, ヘッダファ
イル gzsort.h 内の zNorm, zColor, zTxtr 各構造体として以下のよ
うに定義されています.
-----------------------------------------------------
typedef struct { s8 nx,ny,nz; } zNorm;
typedef struct { u8 r, g, b, a; } zColor_t;
typedef union {
zColor_t n;
u32 w;
} zColor;
typedef struct { s16 s, t; } zTxtr_t;
typedef union {
zTxtr_t n;
u32 w;
} zTxtr;
-----------------------------------------------------
また, 各構造体のサイズは 3 または 4Bytes なので gSPZSetUMem
による DMA 転送時には 8Bytes アライメントに対し特に注意しなけ
ればなりません. また転送サイズが 8 の倍数にならないときには, 8
の倍数に DMA 転送サイズを切り上げる必要があります.
この GBI のルーチンは基本的には以下のような手続きになってい
ます. cdest, tdest の出力によって未処理の nsrc, msrc が上書き
されないように注意すれば, これらの領域を重複させることも可能です.
---------------------------------------------------
for (i = 0; i < num; i ++){
(*cdest,*tdest) = CalcLight(*nsrc,*msrc);
nsrc += 3;
msrc += 4;
cdest += 4;
tdest += 4;
}
---------------------------------------------------
------------------------------------------------------------------------------
* gSPZMixS16(Gfx *gp, u32 src1, u32 src2, u32 num, u16 factor)
* gSPZMixS8 (Gfx *gp, u32 src1, u32 src2, u32 num, u16 factor)
* gSPZMixU8 (Gfx *gp, u32 src1, u32 src2, u32 num, u16 factor)
src1 補間されるデータが格納されているユーザエリアの先頭番地 1
および補間結果が出力されるユーザエリアの先頭番地 (共通)
src2 補間されるデータが格納されているユーザエリアの先頭番地 2
num データの数. (8 の倍数)
factor 混ぜ合わせ係数 (u.15 フォーマット 0x0000 〜 0x7fff の値)
以下の数式で 2 つの数の線形補間を行ないます.
それぞれの GBI で s16, s8, u8 型のデータを扱います.
(*src1) = (*src1)*factor + (*src2)*(1.0-factor);
gSPZMixS16 において src1, src2 を 16 Bytes 境界に合わせる必
要があります. また gSPZMixS8,gSPZMixU8 において src1, src2 を
8 Bytes 境界に合わせる必要があります.
num は 8 の倍数である必要があります. もし, 8 の倍数で無い値を
指定した場合, 8 の倍数になるまで意味のないデータが src1 へ出力
されます.
===============================================================================
5. その他の処理
===============================================================================
--------------
5.1 GBI 一覧
その他の GBI の一覧です.
----------------------------------------------------------------
gSPZSegment - セグメントを設定する
gSPZSetSubDL - Sub DL を登録/起動する.
gSPZLinkSubDL - 未処理の Sub DL の処理を行なう.
gSPZSendMessage - CPU にメッセージを送る.
gSPZWaitSignal - CPU からのシグナルを待つ.
----------------------------------------------------------------
--------------------
5.2 GBI の機能解説
この項ではその他の GBI の解説をします.
------------------------------------------------------------------------------
* gSPZSetSubDL(Gfx *gp, Gfx *subdl)
subdl Sub DL の先頭番地
Sub DL を登録します. この GBI は Main DL でしか処理できま
せん. 既に Sub DL が起動しているのに 2 重に登録したときの動作
は保証しません. gSPZLinkSubDL で既に登録している Sub DL の処理
を完了させてから登録してください.
------------------------------------------------------------------------------
* gSPZLinkSubDL(Gfx *gp)
処理の残っている Sub DL の処理を行ないます. この GBI は
Main DL でしか処理できません. もし Sub DL が既に終了していたり,
Sub DL が登録されていないときには何もしません.
------------------------------------------------------------------------------
* gSPZSendMessage(Gfx *gp)
CPU へ SP_BREAK メッセージを送ります. これにより,
DisplayList の実行状況が CPU 側で判るようになりました.
もし DL の実行状況が判らない場合, CPU は処理が完了したかどう
かの判断ができないため, RSP の処理が終了するまで (=RSP のメッ
セージを受けるまで) 待つ必要があります.
DisplayList
| ZObject A の頂点計算
| ZObject B の頂点計算
| ZObject C の頂点計算
V この時点で終了メッセージが CPU へ送られる.
もし本 GBI を使って以下のように DisplayList を用意すると,
CPU は ZObject 毎の頂点計算が終了したかどうかを知ることができ
るため, 直ぐに ZObject の構築処理にかかることができます.
DisplayList
| ZObject A の頂点計算
| gSPZSendMessgae ------> メッセージが CPU へ送られる
| ZObject B の頂点計算
| gSPZSendMessage ------> メッセージが CPU へ送られる
| ZObject C の頂点計算
V gSPZSendMessage ------> メッセージが CPU へ送られる
実際にはメッセージを送る/受けることによるオーバーヘッドもあ
るため, 上記のように ZObject 毎にメッセージを送るよりも複数の
ZObject 毎に送る方が良い場合があります. この調整はユーザ側が行
なってください.
RSP から送られる SP_BREAK メッセージを CPU で受けるには通常
のメッセージの受け渡しと同じように, メッセージキューを用います.
SP_BREAK メッセージ用のメッセージキューを確保して,
osSetEventMesg で OS_EVENT_SP_BREAK と接続してください. また
キューのサイズは DisplayList 中の gSPZSendMessage の数以上にし
ておく方が安全ですが, これは強制ではありません. うまく
SP_BREAK メッセージの数をコントロールできるならそれ以下でも問
題ないでしょう.
従来のマイクロコードでは, この SP_BREAK メッセージは,
rmonThread が使用しています. 元来このメッセージは GameShop
DEBUGGER の使用時において, マイクロコードの BREAK POINT 処理を
行なうために用意されたものです. 現状ではこの機能はそれほど使わ
れていないと判断し, ユーザに解放することにしました. このため,
rmon Thread を使用しないときは何も問題はありませんが, rmon
Thread を起動する場合, SP_BREAK メッセージキューを設定する処理
は, rmonThread の作成/起動処理 (rmon Thread に osStartThread
を行なう) 以降に行なわねばなりません. この点ご注意ください.
------------------------------------------------------------------------------
* gSPZWaitSignal(Gfx *gp, zSignal *sig, u32 param)
sig Signal バッファへのポインタ
param Signal 値. (u32)
CPU の Signal 値が param 値以上になるまで待機します. CPU に
よる Signal 値の更新は RDRAM 上のバッファを介して行なわれるた
め, アプリケーション側でこのバッファを用意する必要があります.
本 GBI 実行中, RSP は CPU がバッファ上の Signal 値を書換えたか
どうかを判定し, 書換えていた場合 RDRAM 上の Signal バッファを
DMEM へ DMA 転送し param と比較します.
CPU の Signal 値の書換え処理用のマクロとして以下を用意してあ
ります.
--------------------------------------------------------
GZ_SENDSIGNAL(zSignal *sig, u32 val)
sig Signal バッファへのポインタ.
val 新しい Signal 値.
Signal 値を val に書換えた後, RSP に書換えが起こった
ことを通知する.
--------------------------------------------------------
Signal 値は unsigned の 32 bit 変数なので, 最小値は 0
となります.
これまでのマイクロコードでは, Display List を完全に作成して
から, それを RSP に渡しました. すなわち, Display List の作成が
完全に終了するまで, RSP は処理ができなかったのです. しかし本
GBI を使用することによって完全な Display List が作成されていな
くても, 作成した分だけを RSP に処理させることができるようにな
ります. すなわち Display List の続きができるまで RSP を待たせ
ておくことができるのです. この gSPZWaitSignal と前出の
gSPZSendMessage とを組合わせると CPU と RSP のプロセス間の単純
な同期をとることができ, Display List の逐次処理に威力を発揮す
ることになるでしょう.
===============================================================================
6. 他のマイクロコードとの互換性
===============================================================================
------------------
6.1 GBI について
Z Sort マイクロコードは他の Fast3D 互換マイクロコードなどとの互換性
はありません. ただし, 今後 F3DEX 系マイクロコードと自己ロードによって
切り替えることができるように一部 GBI を共通化する予定です. 本章では共
通化されるであろう GBI について説明します.
ここで説明されている GBI の名称は基本的に対応する F3DEX の GBI マク
ロの接頭語の gSP を gSPZ と変更したものになっています.
Z Sort マイクロコードの GBI は, F3DEX GBI Level 2 のサブセットを内包
しています. この F3DEX GBI Level 2 とは, F3DEX マイクロコードにおける
RSP の処理速度を上げるために現状の GBI を改造した新しい GBI セットで,
今後のリリースの F3DEX マイクロコードに採用予定のものです. そのため,
F3DEX マイクロコード Ver 1.23 以前で採用されている GBI とバイナリレベ
ルでの互換性はありません. このため F3DEX マイクロコード系のマイクロコー
ドと自己ロードなどの処理を行なうことは難しくなっています.
Z Sort マイクロコードは F3DEX GBI Level 2 を使用するため, Z Sort マ
イクロコードを使用するときは #define 文あるいは, コンパイルオプション -
D で F3DEX_GBI_2 を定義しなければなりません.
(注意: 現状では F3DEX_GBI も定義する必要があります.)
--------------
6.2 共通 GBI
gSPZSegment - セグメントを設定する.
gSPZPerspNormalize - パース補正値を設定する.
------------------------------------------------------------------------------
* gSPZSegment(Gfx *gp, u32 seg, u32 base)
seg セグメント番号 (0 〜 15)
base セグメントベースアドレス.
セグメントの設定を行ないます. Main DL, Sub DL のどちらでも処
理できますが, 同一セグメント番号に対して Main DL と Sub DL と
で書換えを行なった場合, 並列起動したときなどにおいて不都合が起
こることが予想されます. これを防ぐためにも, なるべく Main DL
と Sub DL において使用するセグメントが重ならないように注意する
ことが望まれます.
------------------------------------------------------------------------------
* gSPZPerspNormalize(Gfx *gp, u16 persp)
persp パース補正値
パース補正値を設定します. 本 GBI は F3DEX 等における
gSPPerspNormalize GBI と同じものです.
------------------------------------------------------------------------------
この項未完成
===============================================================================
7. CPU のサポートライブラリ
===============================================================================
Z Sort マイクロコードでは, スクリーン上の頂点データから面データすな
わち ZObject のデータを構築する処理を CPU に依存しています. 算術演算処
理 GBI コマンドで 3D 座標上頂点をスクリーン座標上の頂点へ変換すること
はできますが, それらの頂点を接続して多角形を構成するのは CPU の役目で
す. その他にも CPU 側で行なわねばならない処理が幾つかあり, こうした処
理を行なうための CPU ライブラリを作成する必要があります. ここではライ
ブラリのサンプルとして, サンプルプログラム cubes-1 で使用しているライ
ブラリについて説明します.
| モデル行列と透視変換行列等の乗算
| モデル頂点の座標変換/透視変換/画面深度計算
| 頂点が画面内にあるかどうかの判定
| クリッピング/裏面判定
| ZObject データの構築
| ZObject リスト作成
この項未完成
===============================================================================
8. TASK マネージメント
===============================================================================
------------------------
8.1 RSP 処理の実装手法
RSP の処理が 2 パスに分れることは前項で述べました. ここではその実装
について説明します.
ここでは, 以下の 2 つの実装手法を想定しています.
実装 A) 2 タスク処理
実装 B) 2 パス並列処理
詳細は次項から説明します. A,B それぞれに長所, 短所があるのでそれを充
分に理解した上で実装手法をお選び下さい.
-----------------
8.2 2タスク処理
算術演算処理と描画処理を別タスクに分け, 順に起動するものです. 設定も
他のマイクロコードの起動方法と似ているので理解しやすい手法と言えるでしょ
う. ここでその概念を理解してください.
==== 実装 A ====
最も単純な 2 タスク処理は以下のようになります.
(1) 算術演算用の Display List の作成.
(2) RSP 第 1 タスク(算術演算用の Display List)を起動する.
(3) RSP は演算を行なう, CPU は RSP の終了まで待機.
(4) a. 演算結果を使用した ZObject データの作成.
b. ソーティングによる ZObject の処理リンクの作成.
c. 描画処理用の Display List の作成.
(5) RSP 第 2 タスク(描画処理用の Display List)を起動する.
(6) RSP は描画計算を行なう. CPU は RDP の終了まで待機.
(7) RDP は描画を行なう.
この手法は最も単純であるため理解しやすく, キー入力から画面の反応まで
の時間を短くしたい場合に有効です. また ZObject 用のデータを展開するた
めのバッファがシングルバッファで良いため確保するべきメモリ量も減ります.
またこれは全ての実装手法について言えることですが, (4)a.b.c. の CPU
で行なう ZObject の構成にはかなりの計算コストが必要となります. この部
分の実装の仕方で 1 フレームに描画可能な ZObject の数に差が出ます. もし
可能ならこの部分は C 言語ではなく *アセンブリ言語* で記述されることを
お勧めします.
各処理における CPU と RSP, RDP の動作状態を以下に示します. 括弧内の
数字は上記の箇条書きの番号に対応します.
フレーム フレーム
開始 終了
| |
CPU |==(1)=>|==(2)=>| |==(4)=>|==(5)=>| | |
RSP | | |==(3)=>| | |==(6)=>| |
RDP | | | | | |======(7)====>|
| |
==== 実装 B ====
実装 A の手法の問題の 1 つは, CPU と RSP が並列に動く箇所がないこと
でしょう. このため CPU と RSP の処理にそれぞれ *空き* が出来てしまいま
す. ここでこの空きを少しでも解消するために (3) と (4) の処理をパイプ
ライン的に処理することを考えます. ここでは, あるまとまった数の ZObject
データを作成するのに必要な頂点データが揃った時点で, その分の ZObject
の作成を開始することにします. これをサポートするために ZSort マイクロ
コードでは, CPU へメッセージを送るための GBI コマンドが用意されていま
す. これを算術演算処理 GBI コマンドの途中に入れておけば, RSP はそのコ
マンド処理時に CPU へメッセージを送ります. CPU はそのメッセージを受信
することでそのメッセージ発生コマンド以前の算術演算処理が終了したことを
知ることができます.
また RDP については, (1)-(5) まで何も動作していないことが判ります.
この処理では, RDP の空き時間が大きいため, 描画性能は低くなります.
RDP 処理時間を稼ぐためには, 主に画面クリアなどの RSP の演算処理を必要
としない描画処理を第 1 パス内で行なう方が良いのは言うまでもありません.
あくまで一例ですが, こうした点を改良すると以下のようになるでしょう.
フレーム フレーム
開始 終了
| |
CPU |==(1)=>|==(2)=>| ====(4)=>|==(5)=>| | |
RSP | | |=(3)====> | |==(6)=>| |
RDP | | |=(7)=> | |======(7)====>|
| |
第 3 段において各プロセッサは以下のような処理を行ないます.
CPU: RSP が座標計算処理したデータから ZObject データを作成し, ソート
する. また第 2 パス用の DL を作成する.
RSP: 座標計算を行ない, あるまとまった数の ZObject データを作成するの
に必要な頂点データが揃うごとに CPU へメッセージを送る.
RDP: 主に画面クリアなどの RSP の演算処理を必要としない処理を行なう.
この処理を行なうための処理系の実装は前述の処理系よりも複雑になります.
この処理の複雑さは次項の 2 パス並列処理の複雑さと大差がなく, こうした
(3) と (4) の逐次処理によって得られるパフォーマンスは一般的にそれほど
大きくないため, キー入力の反応速度の遅延や, メモリ量の増加にこだわらな
い場合は他の方式を使用されることをお勧めします.
==== 実装 C ====
キー入力の反応速度の遅延を容認できる場合は, 以下のような実装方法が考
えられます. これは (5),(6),(7) の処理を次フレームに持ち越した形になり
ます.
フレーム フレーム
開始 終了
| |
CPU |==(5)=>|==(1)=>|==(2)=>| |==(4)=>|
RSP | |====(6)======> |==(3)=>| |
RDP | |==============(7)=========>| |
| |
この場合, キー入力に対する画面の反応までの時間が遅くなりますが, RDP
の処理時間を長く取ることが可能となります.
(6) が終了するまで (3),(4) の処理を待つ必要があるため, RSP における
(6) の処理時間と CPU による (4) の処理時間は出来るだけ短くする必要があ
ります. FIFO バッファを大きくすると RDP の描画処理を RSP が待つことが
少なくなるため, 通常 (6) の時間が短くなり, この処理系のパフォーマンス
が上がります. ただし, 小さな ZObject が沢山登場するシーンでは RDP より
RSP の方の処理が長くなり, RDP が RSP を待つようになるため, こうした場
合には FIFO バッファを大きくしてもパフォーマンスは上がりません. この場
合, (4) をアセンブル言語で実装することは前提となるでしょう.
==== 実装 D ====
実装 C において CPU 処理 (1),(2) が (6) よりもかなり早く終了する場合
には (3) の RSP の処理を (6) の終了まで待つ必要があります. この無駄を
無くすために (6) の描画 RSP TASK を yield 処理により停止させ, (3) の
演算 RSP TASK を起動し, (3) の処理終了後に (6) を再開させるという処理
を行なうことができます.
この処理を行なうためには (3) の演算 TASK の flag に OS_TASK_SP_ONLY
を追加する必要があります. OS_TASK_SP_ONLY をセットして起動した ZSort
マイクロコードはコプロセッサモードで動作します. コプロセッサモードで
描画処理 GBI を使用した場合, RDP が正常に動作しませんのでご注意くださ
い.
また (6) を Yield 処理で停止させ, (3) を起動している最中でも AUDIO
TASK による Yield 要求は受け付けられます. これを可能とするためには (3)
と (6) の Yield バッファを別の領域にとる必要があります.
フレーム フレーム
開始 終了
| |
CPU |==(5)=>|=(1)=>|=(2)=>| |==(4)=>| |
RSP | |====(6)=====>|=(3)=>|=(6)=> |
RDP | |==============(7)===========>| |
| |
実装の難易度とパフォーマンスを考えると, 実装 C か 実装 D が 2 タスク
処理の中では最もバランスが取れていると思います.
==== 実装 E ====
もし (3) を RSP ではなく CPU で実装でき充分なパフォーマンスを得るこ
とが可能であるような稀な場合には, 全く問題なく並列に処理することが可能
です. 以下のようになります. ただし, (6) と (4) が重なる場合があるので,
ZObject のデータおよび DL をダブルバッファで処理する必要があります.
開始 終了
| |
CPU |==(5)=>|==(1)=>|==(2)=>|==(3)=>|==(4)=>|
RSP | |====(6)=============>| |
RDP | |==============(7)=========>| |
| |
この実装でパフォーマンスが上がるかどうかは (3) の部分をどれだけ速く
処理できるかに依ります. もし可能なら (4) の部分と同様に (3) の部分のア
センブリ言語による実装を検討されることをお勧めします.
----------------------
8.3 2 パス並列処理
グラフィック処理において RDP の処理時間と RSP の処理時間が一致するこ
とは稀です. この差を埋めるために FIFO バッファが存在します. ここで RDP
の処理時間が RSP の処理時間を上回った場合, FIFO バッファには未処理の
RDP コマンドが貯まっていくことになります. この FIFO バッファのサイズも
有限であるため, この状態が長く続くと FIFO バッファが完全に埋まってしま
うことになります.
通常のマイクロコード (Fast3D,F3DEX系,S2DEX)において, こうした Buffer
FULL の場合, RSP は FIFO バッファに空きができるまで待機します. この状
態で RSP は RDP の処理を待っているだけで, その計算能力は無駄に消費され
ていることになります.
ZSort マイクロコードではこの無駄を無くすために RSP が RDP の処理を待っ
ている間に RDP に関与しない他の DL の処理(主に算術演算処理)を行なうこ
とができるようにしました. これによって擬似的に, 算術演算処理と描画処理
を 1 つのタスクにまとめて, 並列動作させることができます. これを 2 パス
並列処理と呼ぶことにします.
この 2 パス並列処理において RSP の待ち時間内で処理される DL を Sub
Display List (Sub DL) と呼び, これに対して通常のマイクロコードと同様に
普通に処理される DL を Sub DL と区別するために Main DL と呼びます. Sub
DL は Main DL と同様に 18 段の DL スタックを専用に持っています. Sub
DL は RSP が RDP の処理を待っている時に処理されるので, Sub DL で処理で
きる GBI コマンドは限られています. 当然ながら RDP を使用するコマンドは
実行できません. RSP のみを使用するコマンドだけが使用できます. もし RDP
を使用する GBI コマンドを Sub DL に含めると誤動作しますのでご注意下さ
い. 具体的にどの GBI コマンドが Sub DL に使用できるかは後の章で説明し
ます. 算術演算用のコマンドが主に使用できます.
実際の処理では, 常に RDP の処理時間が RSP の処理時間より長いというこ
とはなく, RDP の描画面積が小さければ上記の RSP の無駄な時間は無くなっ
てしまいます. この場合, Sub DL は Main DL で明示的に呼び出されるまで処
理されないことになります.
このマイクロコードの仕様では都合の悪い場合があることが予想されま
す. RDP の描画面積は描画するシーンによって変動するため, Sub DL を処理
できる RSP の待機時間は一定しません. CPU の ZObject 作成時間を確保する
ためにもある時間内に, RSP の算術演算を終わらせる必要があります. この
ため, RSP の待機時間中以外にも, Sub DL の処理が行なわれることが望まし
いわけです.
以上の理由から, RSP の待機時間以外にも, ある程度の ZObject を処理す
るたびに Sub DL 内の GBI コマンドを 1 つずつ起動するようなマイクロコー
ド gspZSort.pl.fifo.o (以下 ZSort.pl ucode と表記) を用意しました. こ
の Sub DL のコマンドが呼び出されるタイミングは, 描画している ZObject
の種類によって異なりますが, 多角形の ZObject の場合, 2 個から 4 個の
ZObject を描画するごとに 1 つの Sub DL コマンドが必ず処理されます.
ZSort.pl に対して RSP の待機中のみ Sub DL の処理を行なう仕様のマイク
ロコードが gspZSort.fifo.o マイクロコード(以下 ZSort ucode と表記)です.
ZSort.pl ucode では, こうした追加処理を行なうため, ZSort ucode より
オーバーヘッドが大きくなり, そのため ZSort ucode の方が ZSort.pl ucode
よりも RDP による描画処理性能は僅かながらも勝ります. この 2 種類のマイ
クロコードは, Sub DL の呼び出し割合の違いとそれに伴うオーバーヘッドが
生じる以外は同じものです. 状況に応じてお選びください.
この 2 パス並列処理の実装は, 以下のようになるでしょう.
ここでは (3) と (6) が並列に処理されています.
==== 実装 F ====
フレーム フレーム
開始 終了
| |
CPU ....|==(5)=>|=(1)=>|=(2)=>| |==(4)===>| |
RSP Main| |============(6)===========>| |
Sub| | | |=(3)=>| | |
RDP ....| |==============(7)================>|
| |
===============================================================================
9. 使用上の注意
===============================================================================
-----------------------------------------
9.1 RSP から RDP へのコマンドの受け渡し
この項未完成
--------------------
9.2 自己ロード機能
この項未完成
===============================================================================
10. ZSort パッケージのインストール
===============================================================================
------------------------------------------------------------------------
本章の記述は, ZSort マイクロコードが別パッケージで配布されている場合
に関するもので, 既に N64 開発環境に本パッケージが含まれている場合はこ
こに記載されている作業は必要ありません.
------------------------------------------------------------------------
+ インストール済みパッケージの確認
本マイクロコードは, N64 開発環境 2.0I で動きます. 以下のパッケージが
インストールされているかご確認下さい.
もしインストールされていない場合は先にインストールしてください.
---------------------------------------------------------------------------
ultra - Ultra 64 Development Environment, 2.0I
---------------------------------------------------------------------------
+ IRIX 5.3 の場合
Z Sort マイクロコードのパッケージは以下のような形式となっています.
---------------------------------------------------------------------------
patchNuZST_mmddyy (mmddyy はリリース日付)
---------------------------------------------------------------------------
これを Software Manager または inst コマンドでインストールしてください.
このパッチによって以下のファイルがインストールされます.
---------------------------------------------------------------------------
/usr/src/PR/doc/gfxucode.ZSort/README.jp 本ファイル
/usr/lib/PR/gspZSort.fifo.o ZSort マイクロコード
/usr/lib/PR/gspZSort.pl.fifo.o ZSort マイクロコード(算術演算処理強化版)
/usr/include/PR/gzsort.h ZSort 用インクルードファイル
/usr/src/PR/demos/gzsort/* ZSort サンプルプログラム
---------------------------------------------------------------------------
+ PC Partner (Windows95/NT 版) の場合
Z Sort マイクロコードのパッケージは以下のような形式となっています.
---------------------------------------------------------------------------
ZSORTxxx.EXE (xxx はリリース番号)
---------------------------------------------------------------------------
このファイルは自己解凍形式になっています. 実行しますと, インストー
ル先の入力を求めてきますので, ultra64 開発環境の ROOT ディレクトリを
入力してください. Default は c:\ultra となっています. ここで指定した
ディレクトリ下へ IRIX 版同様にファイルが展開されます.
===============================================================================
11. サンプルプログラム
===============================================================================
サンプルプログラムは /usr/src/PR/gzsort/ 以下のディレクトリにインストー
ルされています.
o zonetri/
4 角形を一枚表示するものです. 最も単純な ZSort のアプリケーショ
ンです.
o cubes-1/
ZSort マイクロコードを用いていろいろな種類のポリゴンを描画す
るものです. 汎用の libzsort ライブラリを作成し, そこへデータを
渡して描画しています. Near Clipping などの処理もライブラリ内で
行なっています. 2 Pass 処理なのでパフォーマンスはあまりよくあ
りません.
libzsort ライブラリのソースは, アセンブル言語で実装されるこ
とを前提としているため, 若干 C 言語らしくない表記をしている部
分があります.
===============================================================================
12. 変更履歴
===============================================================================
10/09/97:
Release 0.30 (beta 1)
* 初版作成.
10/13/97:
Release 0.31 (beta 1+)
* サンプルプログラム zonetri を追加.
* PC 版 (Windows95/NT) のサポート.
11/25/97:
Release 0.32 (beta 2)
* ドキュメントの修正.
* gSPZWaitSignal/gSPZSendMessage GBI マクロの修正.
* OS_TASK_SP_ONLY フラグを追加.
01/06/98:
Release 0.33 (beta 2 for 2.0I)
* N64 開発環境 2.0I 用に再パッケージしたもので機能的には 0.32
と全く同じです.
08/04/98:
Release 0.34
* F3DEX2 等で使用されている最新の gbi.h ヘッダファイルと共に使う
とうまく動かないことの対処.
-------------------------------------------------------------------------------