今回は テッセレーションの分割の種類のひとつであるPN-AEN(Crack-Free Point-Normal Triangles using Adjacent Edge Normals)の実装になります。
前回行ったPN Triangles テッセレーションでは、一部のポリゴンの継ぎ目で穴があく「クラック」という現象が起こる欠点がありました。
PN-AENではPN Trianglesを改良し、「クラック」の発生を極力防いだものになります。(完全に防ぐ訳ではないみたいです)
PN-AENを実装するにあたり使用した資料は以下です。
①PN-AEN-Triangles-Whitepaper.pdf
PN-AENはPNの改良版であり、コードはPNで利用したものが殆ど使用出来ます。
違う点は以下の2点になります。
①IndexBufferの内容変更
②Hull Shader(Control Point) コントロールポイント3から12(9)への拡張
※PN-AEN版としては9への拡張なのですが、①IndexBufferの内容変更が
12への拡張なので12としています。違いは殆どありません。
①IndexBufferの内容変更
PNでのIndexBufferは通常描画と同じで「(インデックス x 3) x 面数」でしたが、
PN-AENでは「(インデックス x 3 + 拡張コントロールポイント x 6) x 面数」に拡張されます。
これによってIndexBufferは元のサイズの3倍になります。
手順としてはまず通常の形でIndexBufferを構築し、
何らかの方法でサイズ3倍のIndexBufferに拡張させます。
方法を調査したところ、meshoptimizerというライブラリに
PN-AEN用に拡張してくれるmeshopt_generateTessellationIndexBuffer()関数が
用意されていた為、今回はこれを使用することにしました。
関数の簡単な手順は以下の通りとなります。
1、管理者権限でコマンドプロンプトを実行する。
2、vcpkgのソースコードをダウンロードする。「git clone https://github.com/microsoft/vcpkg.git」を実行
3、vcpkgをインストールする。「bootstrap-vcpkg.bat」を実行
4、vcpkgアプリを立ち上げる。「vcpkg.exe」を実行
5、Visual Studioから利用出来るようにする。「vcpkg integrate install」を実行
6、vcpkgにmeshoptimizerライブラリをインストール「vcpkg install meshoptimizer」を実行
7、ここまでやると後は、普通にVisual Stadioで使用出来ます。
C++ファイルの先頭に「#include "meshoptimizer.h"」と記述し、
「meshopt_generate_tessellation_index_buffer(p_index_buffer_dst, NULL, p_index_buffer_src, 6, vb, 6, 12);」と書けばビルド出来ちゃいます。ちょっと凄い!
「略・・\vcpkg\vcpkg\buildtrees\meshoptimizer\src\v0.18-13698cd784.clean\demo\tests.cpp」の
tessellation()に使用方法があるので参考にしてください。
いくらかテストで動かしましたが問題無く動いています。(エラーが出る場合、十中八九引数の誤りだと思います)
またvcpkgはこのサイトが参考になります。
注意点としてmeshopt_generateTessellationIndexBuffer()で出力されるIndexBufferは
「(インデックス x 3 + 拡張コントロールポイント x 6) x 面数」では無く
「(インデックス x 3 + 拡張コントロールポイント x 6 + 拡張コントロールポイント x 3) x 面数」となります。
そしてIndexBufferは元のサイズの4倍になります。
ただし対するコードの変更は数字の変更のみで殆ど必要ありません。
②Hull Shader(Control Point) コントロールポイント3から12(9)への拡張
Hull Shader(Control Point)のコードをPNからPN-AEN用に切り替えます。
PN用ではコントロールポイントは3つでしたが、PN-AEN用はコントロールポイントは12になります。
これは「PN-AEN-Triangles-Whitepaper.pdf」のサンプルコードそのままで問題ありませんでした。
PN用はHS_PNTriangles()、PN-AEN用はHS_PNAENTriangles()です。
この様にコンパイルで使い分けします。
HullShader g_pmx_object__tessellation__HS_main_PNTriangles = CompileShader(hs_5_0, pmx_object__tessellation__HS_main_PNTriangles());
HullShader g_pmx_object__tessellation__HS_main_PNAENTriangles = CompileShader(hs_5_0, pmx_object__tessellation__HS_main_PNAENTriangles());
PN-AEN用のHS_PNAENTriangles()では引数「InputPatch<HS_RenderSceneInput, 9> I,」
数字をその時の値に書き換えましょう。( 3 or 9 or 12)
CPU側では「D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST」
こちらの数字も同じように書き換えます。( 3 or 9 or 12)
これでうまくいきました。
PN用の画像では右目の上辺りにクラックが発生していますが、
PN-AEN用では発生していないのがわかります。