2024年8月4日日曜日

文字列を描画する仕組みをレンダリングエンジンに組み込む

文字列を描画する仕組みは作ったけど、レンダリングエンジンへの組み込みが中途半端になっていたので、きちんと組み込んでみた。


文字列の属性


最初はFPSなどを描画する為に毎フレーム更新する前提のものを用意していたけど、ラベルのように設定したら更新されないものにも対応したいと思っていた。

SetText(一時的なテキスト設定)


毎フレーム更新される前提で、Update内で毎回設定する。
前回のテキストはクリアされ設定しなければ描画されない。

SetLabel(ラベルテキスト設定)


毎フレームは変更されず、更新のあった場合だけ再描画する。
利用側は毎フレーム書き込んでもいいし、書き込まなくてもよい。
管理側でID別に文字列を管理し、関数が呼び出される度に値を比較し変更があった場合だけ描画する。


出力先の設定


今までレンダーターゲットにのみ書き込んでいた。
SetTextは直接レンダーターゲットに書き込み、毎フレーム必要な文字列を描画する。
SetLabelは中間レンダーターゲットをキャッシュに利用できるようにする。
専用の単一中間レンダーターゲットに対して書き込み、変更がなければそのまま維持される。(ダブルバッファで用意してないのは前回の書き込みを利用するため)
描画完了後、別途テクスチャにコピーする。実際の画面への描画はこのテクスチャを貼り付ける。


出力方法


SetTextの場合は、主にレンダーターゲットを想定しており全体がクリアされたところに描画する。
SetLabelの場合は、状況により全体クリアと部分クリアを切り替える。
 

部分クリア


最初に描画位置を設定して文字列を描画する。
この時の描画範囲を記憶しておく。
次回描画時に前回記憶してある範囲だけをクリアして、新しい文字を書き込む。
大量のラベルを貼り付けても、実際に描画するのは最初と書き換えたときのみ。書き換えた場合もその書き換えた文字列のみの描画だけで済む。
ただし制限として文字列同士が重なり合うような場合は強制的に全体を描画し直す必要がある。

全体クリア


前述の通り初回の書き込み時と、文字列が重なるような状況の場合は強制的に全体クリアを行う。文字列が重なる場合、各ラベルの描画範囲を確認して重なる対象のラベルだけ部分クリアも可能だけど、ライブラリ内では重くなるから行わない。
利用側が重ならないように使うか、重なる状況の場合は強制クリア、もしくはSetTextでの描画を選択してもらう。


ハマりポイント



ClearRenderTargetView


部分クリアはこの関数の引数に渡す複数の矩形で行っている。
動作させてみると落ちる。
設定した矩形の数が61個で呼び出していた模様。
これを試しに1つに変更したら動いた。いままで0でしか動かしたことがなかった。
10、20、30と増やしても動き、50にしたらだめだった。
予想は32個で、31、32、33と試したら33で落ちた。
制限についてネットで調べてみても出てこない。
似たようなので見つけたのはClearUnorderedAccessViewUint関数の指定できる矩形の数が127だったという記事。環境に依存するのか、DirectXの仕様として決まっているのかもわからない。とりあえず数が多い場合は32ずつ処理するように修正した。



0 件のコメント:

コメントを投稿