35.Dx12版サンプルをDx11版に合わせて追加する(4)

今回は2つのDx12版サンプルをGitHubにアップしましたSimpleSample011,012です。
ドキュメントは申し訳ないですが、まだ記述してません。少しサンプルがたまった段階でアップします。

この記事は、
コミットSimplaSample009,010(Dx12版)追加後の修正。
から、
コミットSimplaSample011,012(Dx12版)追加。
の間の作業です。
GitHubサイト

https://github.com/WiZFramework/BaseCross

を参照して下さい。

今回はこれまでDx11版のみだったサンプルに、Dx12版を追加したものです。
ですので実行イメージは、Dx11版の同じサンプル番号と同じになります。
今回はライブラリの変更はありません。(コミット上はありますが、改行などです)

今回アップしたサンプルのポイントは3D透明です。

SimplaSample011について

SimplaSample01は立方体です。実行イメージは以下になります。

2016082701

左側はライティングがフラットになっています。テクスチャを張り付けるとフラットと通常の表現が見分けがつきにくいですが、陰影がフラットのほうはカーブを描いているのがわかります。

SimplaSample012について

このサンプルはです。球はフラットな法線のみになります。
実行イメージは以下の通りです。

2016082702

3Dの透明処理について

3D空間における透明処理は、いくつかのポイントがあります。
違うオブジェクト同士の透明処理1つのオブジェクト内での透明処理です。

違うオブジェクト同士の透明処理
違うオブジェクト同士は基本的にカメラから離れているものから順番に描画するということで表現します。
3D空間の場合、カメラから見て重なっているオブジェクトは深度バッファを有効にすることで奥のオブジェクト手前のオブジェクトに隠されます。

これは描画順に関係なく自動的に行われるので、透明なもの以外ならいいのですが、隠されてはまずいのが透明なのです。
つまり、手前のオブジェクトが先に描画された場合、それが、透明処理すべきオブジェクトだった場合、そのあと奥のオブジェクトを描画した時に、手前のオブジェクトの透けている部分には、奥のオブジェクトはまだ描画されていないので透けないのです。
それで、透明処理を実装するためには、やはり奥のオブジェクトから手前に向かって描画する必要があります。

1つのオブジェクト内の透明処理
あるオブジェクトが透明なものであれば、テクスチャは、透き通るオブジェクトに張ったシールのようなものになります。
とすれば、透明なオブジェクトは、オブジェクトの裏側が見えなければ変です。
そのため透明なオブジェクトの描画裏面を描画して表面を描画するといった形で、2回描画すると、それっぽくなります。もちろんシールの裏側は白くするといった場合は裏面描画のときのテクスチャを白いテクスチャに設定しなければなりませんが、サンプルでは同じテクスチャを使ってます。

フルバージョンにおける透明処理
このように、いろいろ考えなければならないのですが、BaseCross(もしくはDxBase2015、2016)のフルバージョンでは、以下の手順で透明処理します。(毎ターンごとの処理です)。
シンプルバージョンで透明処理を実装する場合の参考になればと思います。


1、描画の前に透明なものと、透明でないものを分ける
2、透明でない者は、そのままオブジェクトの配列順に描画
3、透明なものは、カメラから見た位置でソートする
4、ソートした透明オブジェクトを奥から手前に向かって描画

このように、毎ターンごとに描画順番を変えています。
これは、結構異論もあると思います。多くの場合描画順番を変えずにできないか、というものです。
たしかに描画順番を変えるというのは、そのぶん処理が重くなります。しかし、では代替えとしてよく紹介されているのがステンシルバッファを使うというものです。
オブジェクトをステンシルバッファに書き込んでおいて、あとで、比較しながら描画します。
それもいいかもしれません。ただ、その場合、透明なものと透明ではないものの設計が、大幅に変更しなければなりません(透明でないものに、余分な負担も必要ないので)
その辺の関係で、僕は描画順番を変えるでよいのではないかと思っています。

以上で基本的にはいいのですが、まだ問題があります。カメラからみて奥から手前にソートするのですが、同じ場所にあった場合はどうするのか、ということです。
たとえば、プレイヤーがシャボン玉にとらわれたとします。すると、シャボン玉は透明ですから、中のプレイヤーは透けなければなりません。プレイヤーが透明なものでなければ、上記1で、シャボン玉とプレイヤーは分離できますのでいいのですが、プレイヤーも透明だった場合、シャボン玉とプレイヤーは同じ位置を持つことになります。
この場合の対応としてフルバージョン描画レイヤーというものをもってます。
描画レイヤー絶対的な描画順であり、透明だろうが透明でなかろうが、まずその順番に描画されます。
描画レイヤーは実体は単純なint型の値です。すべてのオブジェクトが描画レイヤーの値を持ち、通常は0で初期化されます。描画レイヤー値の低いものから順番に描画されます。
描画レイヤーを実装した後の描画アルゴリズムは以下になります。


A、描画レイヤー順(昇順)に分ける。以下、描画レイヤーごとにループ
{
	1、描画の前に透明なものと、透明でないものを分ける
	2、透明でない者は、そのままオブジェクトの配列順に描画
	3、透明なものは、カメラから見た位置でソートする
	4、ソートした透明オブジェクトを奥から手前に向かって描画
}

このようにすれば、例えば上記のシャボン玉描画レイヤー例えば5にしておきます。昇順に描画されるので、ほかのオブジェクトがすべて4以下であれば、全部描画終わったときに、さいごにシャボン玉が描画されるので、どんなものも透けるシャボン玉を表現できます。

もちろん、これで完全ではないかもしれません。オブジェクトが、ステージ上に長く斜めに配置されていたりする場合は、そのオブジェクトは奥のほうは先に、手前は後にのような、オブジェクト描画内でのやりくりが必要になります。
そのようなオブジェクトは特別なオブジェクトとして、ステンシルバッファを使えばいいのかと思います。

Dx12版ライブラリの問題点

今回の実装でも、やはりDx12版ライブラリに問題点が出てきました。
透明処理をする場合、1つのオブジェクト内の透明処理で説明したように、裏側と表側2回描画と述べましたが、今回のサンプルでは、それを実装するためにVSPSDrawContextのインスタンスを2つずつ持っています。
Dx11ではDraw命令をラスタライザステートを変更して2回描画すれば済むのですが、それがDx12の場合はコマンドリストを分けなければいけないのです。
ここにも現時点でのVSPSDrawContextの実装での問題が出てきました。
そろそろVSPSDrawContextの抜本的な改修が必要か、もしくは別の描画クラスを作成して、そのような連続したDraw命令に対応できるようなクラスを作成する必要があります。

このブログでは、ライブラリ作成中の問題点や課題をなるべく記述しようと思っています。
現時点で、どのように解決したらいいのかアイディアもありませんが、これまでもいくつか問題も出てきてるので、そろそろ、本格的に改修しないと、今後出てくる予定の、もっとハードなサンプルに耐えられないかな、と思っています。

次回は、そのあたりをスッキリさせて、発表できればいいなと思っています。
それでは、今回はこの辺で。

そんなわけで、次回アップは少し時間がかかるかもしれません。

カテゴリー

ピックアップ記事

  1. 2016092201
    今回は前回のサンプルを少し機能を追加しまして、いろんなオブジェクトを追加しています。FullTuto…
  2. 2016092001
    前回更新から時間がたってしまいましたが、今回はフルバージョンチュートリアル003をアップしました。内…
  3. eyecatch
    前回更新から時間がたってしまいましたが、今回はフルバージョンチュートリアル002で懸案となっていまし…
PAGE TOP