English
FAQSGLプログラミング関連
■  | 進む
FAQ/SGLプログラミング関連

スプライト/ポリゴン



スプライトの描画を一時中断したい。

Q)
一時的にスプライトの描画だけを中断したい。

A)
SGLのシステム変数にはPauseFlagというものが存在します。これをONにすると、 V-Blank内でSGLシステムが行なっているスプライトバッファからのVDP1への 転送が行なわれません。これによって例えばポーズ中は、スプライトを表示 しないと云った効果が可能になります。

PauseFlagに限らずSGLのシステム変数は、extern宣言して使ってください。


スプライトのカラー演算の比率を変えたい。

Q)
スプライト画面のカラー演算比率の設定(例えば半透明)を行うには どのようにすればいいでしょうか。

A)
関数としてslColRate()が用意されています。また、この関数を使ったマクロ

 slColRate*

(例)
slColRateNBG0

があります。
これは SL_DEF.H の中で記述されています。 この関数またはこれらのマクロを使用することでスプライトのカラー演算 の割合を設定することができます。


スプライトの表示にプライオリティを付けたい。

Q)
slPutSpriteで2Dスプライトを表示する際、同じ座標にある2つのスプライトに プライオリティーを付けたいのですが、カメラ位置の方向に座標を変更すると 透過座標に変換された時には、表示位置が違ってしまいます。

slPutSpriteを用いて、同じ座標に表示する場合に任意にプライオリティーを 付ける方法はないのでしょうか。

A)
SGLでは同じZ座標に表示しようとするとZバッファに後に登録されたもの (スプライト、またはポリゴン)の方が優先順位は高く(つまり手前)なります。
ポリゴンであればZの代表値を選択することである程度回避できますが、 スプライトには奥行きという概念がないため、関数の実行順のみがそれを 変更できうる手段ということになります。
もし処理に余裕があり、つけたい優先順位が決まっているなら、位置計算と 表示スケールをユーザ側で行い、slDispSprite()でZ位置を調整してもらうの が最も有効な手段だと思います。


スプライト描画関数で表示位置を別の場所に変更したい。

Q)
slPutSprite、slDispSpriteでは、データの中心点を基準点として扱われますが これを、左上もしくはセンター下などに変更はできないでしょうか。

A)
slPutSpriteもしくはslDispSprite関数では、基本的には描画の基準点を中央 以外には設定できません。
もしこのようなことを行ないたい場合、slSetSprite または、slDispSprite4Pを使って指定することになります。


ポリゴンが消えたり画面に線の様なノイズが走ってしまう。

Q)
SGLでポリゴンが手前に近づくと、クリッピングによって消えてしまったり、 画面に線の様なノイズが走ってしまいます。

A)

  1. ポリゴン設定時ATTR構造体の第二引数(ソートの設定)を変更する。
    SOFTIMAGEのExportでのデフォルトでは、ソートの設定はSORT_CENに なっていますが、これをSORT_MAXにするとZソーティングの基準点から 一番遠い所になりますので若干ポリゴンの欠ける位置が近くなります。

  2. slZdspLevelに与える引数を大きくする。
    slZdspLevelには、0〜7迄の値が入ります。値が大きいほど手前まで 表示されます。

  3. ポリゴンを構成する座標値を小さくする。
    SGL内部では、ポリゴンの座標に対して、Z軸に対してはクリッピングを掛けますがXY成分に関しては、 クリッピング処理を行なっていないため、フレームバッファ空間に対して オーバーフローやアンダーフローを起こし、画面にノイズが 走ってしまうことがあります。これを避けるための処理になります。

  4. 手前と奥でモデルのポリゴン数を変える。
    具体的には、手前に来たポリゴンを分割してしまうということです。
    勿論テクスチャが貼ってあればテクスチャも分割する為アプリケーション側 で、一つのモデルに対して複数のモデルパターンとテクスチャを用意する必要 があります。

補足
SGL Ver 3.0以降のニアクリッピング機能を活用する。
但し、この場合も上の1.4.迄のテクニックをそのまま活用することができます。


スプライトやポリゴンの表示が1テンポ遅れるような気がする。

Q)
SGL上でスプライトを表示させる場合、 そのフレームで表示関数を実行したス プライト(slDispSprite、slPutPolygon等)は次のフレームで表示される、 と認識 していたのですが、どうもうまく動作しません。

つまり、

slDispSprite(...);
slSynch();
OtherProc();  ←この時点で表示されている筈だが
slSynch();
OtherProc();  ←実際にはここで表示されているように見える

という現象がおきるのです。どおしてでしょう?

A)
VDP1は、VDP2と比べて1処理フレーム遅れますので、御指摘のように、2度 slSynchを実行しないと表示されません。

これは、VDP1がダブルフレームバッファを持っているためで、ユーザーが コマンドバッファに書き込んだ内容は、次のフレームで裏フレームバッファに 書き込みます。
このため、裏バッファの内容を表示するのは、 コマンドバッファに書き込んだ次の次のフレームということになります。
つまり、

slDispSprite(...);
slSynch();  ←この時、裏のフレームバッファにコマンドの内容を反映。
OtherProc();
slSynch();  ←この時点で裏のフレームバッファの内容をVDP2の映像と重ねる。
OtherProc();  ←ここで表示される。

といった流れになります。


システム変数FormTblをかえて新しいテクスチャを定義したい。

Q)
モデルデータやテクスチャデータをゲームに進行に合わせて随時ロードしたい そこで、TEXTURE構造体のテーブルを書き換えたいのですが具体的な方法が 分かりません。

A)
<システム変数FormTblとポリゴン及びスプライトの描画について>  ポリゴンやスプライトの描画リクエスト関数を使った場合、関数内でFormTblを 参照しますが、これらの関数内ではキャッシュの内容を見てコマンドを 発行しています。

 つまり、通常の利用方法ではFormTblの内容は1単位処理内で変更を加えることは 出来ません。

 これを回避するには以下にあげる2つの方法が考えられます。

方法1:FormTblで示されるアドレスそのものを変更
【手順.1】スレーブ側でキャッシュをパージする。
FormTblを再設定する前にスレーブ側からキャッシュをパージし 更新結果を反映させることで上のプログラムの操作が可能になります。 具体的には、まずスレーブの処理が終了していることを確認します。 スレーブの活動状態を把握するには、

ComRdPtr、ComWrPtr

という2つのシステム変数の内容を参考にします。
この2つのシステム変数は、スレーブがslPutPolygon等の処理を 行なっている時に参照されるデータで両者が一致している時、 スレーブは、SGLの処理を行なっていません。

但しスレーブCPUは常にキャッシュ領域を見ていますので、比較する アドレスもキャッシュの中でなくてはなりません。つまり、システム変数

ComWrPtr、ComRdPtr

をそのまま見るのではなく

ComWrPtr + 0x20000000
ComRdPtr + 0x20000000

を見なければなりません。
これらのレジスタは、スレーブがコマンドのリード及びライトを 行っているアドレスを指しておりこれらの値が同じであれば、スレーブは 待機状態であるとみることができますので、まずこの2つのレジスタの 値を比較し同じ値になるのを待ちます。
次にスレーブ側からslCashePurgeを実行しキャッシュをパージします。 これには、slSlaveFunctionを使います。

【手順.2】スレーブ側でキャッシュをパージする。

方法2: FormTblを変更します。
FormTblで示される構造体の内容を変更する。
この方法は、FormTblは一切いじらず、元のデータを変更するという 方法です。

例えば、
slInitStstem( TV_320x224, TEXTURE_TBL, 1 )
のように、FormTblを指定した場合、後の変更を、

TEXTURE_TBL[ i ].Hsize = ....
TEXTURE_TBL[ i ].Vsize = ....
TEXTURE_TBL[ i ].CGadr = ....
TEXTURE_TBL[ i ].HVsize = ....

という風に変更するやり方です。この方法を採った場合、スレーブの状態を 把握しておく必要はなくなりますが、最初にslInitSystemに引き渡す段階で 充分なTEXTURE構造体配列のスペース(つまり表示スプライトのMAX)を 用意しておく必要があります。

※尚、キャラクタデータの転送タイミングによっては、表示するキャラクタが 化けることがあります。これは、VDP1がキャラクタデータをフレームバッファ に転送時、(まだ使用しているにも関わらず)VRAMのデータがキャラクタデータ 転送によって書き変えられている為と思われます。

そのようなことを避ける為にもキャラクタデータやルックアップテーブルデータ グーローデータの転送などは、slIntFunctionで指定する関数内で行なうか、 VDP1の描画終了を待って転送するなどしてください。

VDP1の描画終了を知るには、VDP1の転送終了状態レジスタ (VDP1ユーザーズマニュアル・4.6 転送終了状態レジスタを参照) を見ることで判断できます。


スプライト描画関数に与えるZポジションって何?

Q)
Q8 ) スプライト描画関数で使用するZポジションとは何に使われているのでしょうか?

A)
A8 ) Zポジションはスプライト同士のプライオリティ判断にのみ使われています。 Zポジションを変更した場合にスケールの変化はありません。

フレームバッファの内容を保存したい。

Q)
Q9 ) SGLを用いて、VDP1のフレームバッファに以前の内容を残しつつ その上に(消去をせずに)スプライトを上書きしたいのですが、どのような 設定を行えばよろしいでしょうか。

A)
A9 ) ご希望の処理とは少し異なるかもしれませんがslGetFrameDataという関数が あります。この関数でフレームバッファのデータを保存しておき次のフレーム で使用できます。但しメモリには制限がありますし、VDP2の内容は反映 されませんので、使用する際には、画面一杯に対して使うというのはほぼ 出来ないと考えるべきでしょう。

パレットやカラールックアップの時UseLightオプションは使えるのでしょうか?

Q)
Q10 ) SGLで、テクスチャーを指定したポリゴン(マニュアルでは単にテクスチャーと 呼んでいた)に対し、光源計算処理を指定した場合、実際に描画される際に、 その結果が正しく反映されるのでしょうか?

A)
A10 ) 基本的にはSGLのポリゴンでUSE_LIGHTオプションが機能するのはテクスチャが RGBモードで書かれている場合に限られます。これはVDP1の仕様ですので、 SGLに限った話ではありません。しかしながら、パレット形式でも、パレットを 直接いじるなどの方法で、実現する方法はあります。

slSetSprite関数の使い方を教えて。

Q)
Q11 ) slSetSprite関数の使い方がよく分かりません。

A)
A11 ) slSetSpriteは、VDP1のコマンドテーブルのデータを直接操作するための関数で、 その詳細は、VDP1のコマンドに一致します。どういう風に使っているのかを 知りたい場合、もしCinepakをお使いになられているようであれば、Cinepakの サンプルプログラムをご参照ください。 また、付属のサンプルプログラムも併せてご覧ください。

スプライト毎にスクロールとのプライオリティを付けたい。

Q)
SGL環境でスプライトに優先順位を指定する方法がわかりません。
slPriority(scnSPR0,7)などとやった際に、各スプライトに対して、これはSPR0 である、これはSPR1である、というのはどこで(どうやって)設定するので しょうか?
SGLを用いてBG画面を挟む様にスプライトを表示することはできないのでしょうか。

A)
--- スプライトタイプとプライオリティについて --- スプライトデータは、VDP2に渡ると、その種類によってハイレゾ、ローレゾ各 8つのタイプのデータとして認識されます。それぞれのタイプに応じてVDP2は、 スクロールとスプライトのプライオリティを設定します。8つのタイプが どのスクロールとどういうプライオリティの関係になっているかを設定することで スプライトとスクロールを順位をつけて表示することができます。

また、スプライトとスクロールのプライオリティ以外にも、両者間のシャドウや カラー演算等も設定することができます。
この、スプライトの種類のことをVDP2でスプライトタイプと呼びます。

参照
VDP1ユーザーズマニュアル6.4 CMDCOLR カラーバンク
VDP2ユーザーズマニュアル9.1 スプライトデータ

スプライトタイプはVDP1の設定時に各スプライト単位に与えることができます。 SGLでは、この設定をカラーパレットの設定の際行なうことができます。
以下に例を示しましょう。

まず、使用するスプライトタイプを選択します。
デフォルトでは、スプライトタイプ3です。変更するには、 slSpriteType()関数に引数にスプライトタイプを入れて呼び出します。

次に

#define PrioNo0 (0<<12)
#define PrioNo1 (1<<12)
#define PrioNo2 (2<<12)
#define PrioNo3 (3<<12)
#define PrioNo4 (4<<12)
#define PrioNo5 (5<<12)
#define PrioNo6 (6<<12)
#define PrioNo7 (7<<12)

が定義されていたとします。

・ポリゴンの場合

ATTRIBUTE( Single_Plane, SORT_CEN, tex1, PrioNo4|0x0010, No_Gouraud,..
ここでポリゴンのプライオリティナンバを4に設定しています。 つまりパレット番号にORを取る形で、プライオリティナンバ0〜7迄を設定 できます。

・slPutSprite、slDispSprite*の場合

SPR_ATTRIBUTE( 0, SprType6|0x0000, No_Gouraud, CL256Bnk, sprNofilp );

これも同様にパレットの指定の際にスプライトタイプ6を使うことを 指定しています。

以上いずれの場合も、ATTR、SPR_ATTR構造体のcolnoメンバに指定します。

・slSetSpriteの場合

SPRITE spr;
spr.CTRL = FUNC_Sprite;
spr.PMOD = MSBOn | WindowIn | MESHoff | ECenb;
spr.COLR = PrioNo2 | 0x0020;
                  :
                  :
というように、VDP1のコマンドテーブルのカラー制御ワードにパレットと 一緒に(これもORで)プライオリティナンバ(この場合2)を指定します。

また、各スプライトタイプに関するプライオリティの設定は、slPriorityまたは、 slPrioritySpr?関数を使います。(slPrioritySpr?はマクロ。)
用例としては、

slPriority( scnSPR6, 5 );

或は、

slPrioritySpr6( 5 );

とします。
スクロール側は、slPriorityNBG?やslPriorityRBG0などの関数を使います。


スプライトを回転させると1ドットずれる。

Q)
slPutSpriteやslDispSpirte、slSetSpriteなどのスプライト描画関数を使って、 スプライトを回転すると、スプライトが1ドットずれて表示されてしまうんですが どうしたら直るんでしょうか?

A)
スプライトの回転をする際に回転の中心点が中央になっています。
セガサターンでは、スプライトの横方向のドット数は8の倍数を基準にしていますので ドット単位で見れば、正確に中央となるドットは存在しません。したがっで、 スプライトを回転させる際どうしても1ドットずれてしまいます。

このこと自体はセガサターンの仕様ですのでどうしようもありませんが、ドットが ずれるのを回避するには、プログラムで回転に合わせて表示位置を変えるか、 スプライトデザインを設計する際に、回転によってドットがずれることを 予め考慮した図形を書くかして対応してください。


スプライトを表示した時1ドット大きく見える。

Q)
slDispSpriteでスプライトを表示すると、指定した大きさよりも1ドット大きな 絵が表示されました。何が原因なのでしょうか。

A)
slDispSprite関数 でスケールに 1.00を指定した場合、元絵よりも1ドット 大きく表示されます。

これはハードウェアが指定した表示サイズよりも1ドット大きく表示してしまう ためで、これを避けたい場合には スケールに 0.99999 を指定してください。 この値は、SL_DEF.H で ORIGINAL というマクロにより定義されています。


■  | 進む
FAQSGLプログラミング関連
Copyright SEGA ENTERPRISES, LTD,. 1997