2022年12月27日火曜日

BlenderからExportしたFBXファイルについて

今のところBlenderからExportしたFBXファイルをAssimpで読み込んで使っている。

マテリアルの値を適当に取得はしているが、使っているのはAI_MATKEY_TEXTURE_DIFFUSEのみ。
DirectX12の魔導書に書いてある通り、Diffuse、Specular、Toonのテクスチャはマテリアルにあろうが、無かろうが用意して、シェーダは常にそれらをサンプリングしている。
この形がいいのかよくわからないけど、よくよく調べてみるとあらゆる項目に対してテクスチャを用意できるみたいなので、項目を増やすとこの実装はまずい気がする。

そもそも適当に決めた読み込むパラメータの見直しと、読み込んだパラメータをシェーダに反映させるように作り直したい。


読み込むパラメータの見直し


現状読み込んでいるのは、テクスチャが以下。
AI_MATKEY_TEXTURE_DIFFUSE
AI_MATKEY_TEXTURE_SPECULAR

各種色、パラメータが以下。
AI_MATKEY_COLOR_AMBIENT
AI_MATKEY_COLOR_DIFFUSE
AI_MATKEY_COLOR_SPECULAR

パラメータにはこの他に下記が定義されてた。
AI_MATKEY_SHININESS_STRENGTH
AI_MATKEY_SHININESS
AI_MATKEY_COLOR_EMISSIVE
AI_MATKEY_COLOR_TRANSPARENT
AI_MATKEY_COLOR_REFLECTIVE
AI_MATKEY_OPACITY
AI_MATKEY_REFLECTIVITY
AI_MATKEY_REFRACTI

Blenderで定義を変えてExportして、どこと紐づくのかを調べてみた。

Blenderのマテリアル

AI_MATKEY_COLOR_DIFFUSE


Blenderのラベルは「ベースカラー」
Blender側は色指定で、その値がそのまま渡る。
テクスチャを設定した場合は、AI_MATKEY_TEXTURE_DIFFUSEにファイルが設定され、カラーは0.8がRGBに返る。


AI_MATKEY_COLOR_SPECULAR


Blenderのラベルは「スペキュラー」
Blender側はスカラー指定で、受け取りはカラー。
各要素はDIFFUSEのRGB×スペキュラー値×0.5になっていた。
スペキュラー値が0なら0、0.5なら1/4、1なら1/2、2ならDIFFUSEと同じ値が返る。
テクスチャを設定した場合は、AI_MATKEY_TEXTURE_SPECULARにファイルが設定され、カラーは0.2がRGBに返る。


AI_MATKEY_SHININESS_STRENGTH
AI_MATKEY_SHININESS


Blenderのラベルは「粗さ」
どうやら、AI_MATKEY_SHININESS_STRENGTHとAI_MATKEY_SHININESSは同じ値が設定されているようだ。
Blender側はスカラー指定で、受け取りもスカラー。
設定値とは別の値が返る。

粗さとShininessの関係
横軸がBlenderの粗さで、縦軸がAssimpのShininessの値。
基本的にはBlenderで0~1の範囲で設定して、Assimpでは100~0の値が受け取れるので、0.01を掛けて1~0に変換して使う。

AI_MATKEY_COLOR_EMISSIVE


Blenderのラベルは「放射」と「放射の強さ」
Blender側はカラーとスカラー指定で、受け取りはカラー。
単純に放射の色に、放射の強さを掛けた値が返る。
テクスチャを設定した場合は、AI_MATKEY_TEXTURE_EMISSIVEにファイルが設定され、カラーは未設定になる。

AI_MATKEY_OPACITY


Blenderのラベルは「アルファ」
Blender側はスカラー指定で、受け取りはスカラー。
ちなみにテクスチャを指定してもAI_MATKEY_TEXTURE_OPACITYには設定されていなかった。

AI_MATKEY_COLOR_AMBIENT
AI_MATKEY_COLOR_TRANSPARENT
AI_MATKEY_COLOR_REFLECTIVE
AI_MATKEY_REFLECTIVITY
AI_MATKEY_REFRACTI

これらの値は紐づけがわからず。
Ambientは値自体は取得できて、常に0のカラーが返る。
ほかは設定されていない。

使ってるBlenderのバージョンは3.2、Assimpのバージョンは4.1で、最新のAssimpのヘッダを見るとかなり項目が増えていた。
Blenderのラベルと同じもの(メタリック、シーン、クリアコートなど)も用意されている。
Assimpのバージョンを上げると取れる項目は増えるのだろうか?


PBR


HLSLの魔導書に物理ベースレンダリングについて書かれていて、それを取り入れたいと思っているんだけど、この本のサンプルを見ても結果が不自然。
仕方がないのでネットで探してみると、Unityのシェーダが見つかったのでそれを参考に作ってみた。

マテリアルについてなんとなくわかってきたので、Blenderでパラメータかテクスチャを設定する方法を用意するつもりだけど、シェーダに指定するテクスチャの数を抑えるため1テクスチャにマージして、metalic(R)、roughness(G)、emissive(B)、未定(A)のようにする。

パラメータを使う場合は下記。

metallic

 blender:スペキュラー
 assimp:AI_MATKEY_COLOR_SPECULARでRGBの最大値。

roughness

 blender:粗さ
 assimp:AI_MATKEY_COLOR_SHININESS。

emissive

 blender:放射と放射の強さ
 assimp:AI_MATKEY_COLOR_EMISSIVEでRGBの最大値。

「スペキュラー」も「放射」もBlender上、色を設定するパラメータだけど、テクスチャで指定する方との互換性でスカラー値にする。スペキュラーは計算上メタリック扱いで、放射はアルベドカラーをそのまま光らせる方針。


テクスチャのマージ

モノクロのテクスチャをそれぞれ用意して、metalic(R)、roughness(G)、emissive(B)、未定(A)に割り当てて出力する。

metallic

emissive

出力結果


Emissiveなし

Emissiveあり

右の列がMetallicが高いオブジェクトで、上段と下段はパラメータで全体に指定、中段はテクスチャで枠だけ指定。
中央の列がMetallicが低いオブジェクトで、上段と下段はベースカラーに赤を指定、中段はテクスチャを指定。
左の列はEmissiveが指定してあるオブジェクトで、上段と下段はパラメータで全体に指定、中段はテクスチャで前面のみ光るように指定。

2022年12月16日金曜日

Bloom

今回はBloomについて。

DirectX12の魔導書に続き、HLSLシェーダーの魔導書も購入した。

前書の方では結果に欠陥があって自分で解決しろというスタイルだったので試してもなかったが、今作ってるレンダリングエンジンの機能に加えるため作ってみることにした。


処理は2つに分かれていて、1つ目が高輝度部分抽出で、2つ目が高輝度部分のブラー処理。
最後に元の画像と、ぼかした画像を加算合成するという流れ。


高輝度部分抽出


まず、HDRレンダリングを行うためにDXGI_FORMAT_R32G32B32A32_FLOATの中間レンダーターゲットを用意する。
元になる画像をこの中間レンダーターゲットにコピーする際、
dot( color.rgb, float3( 0.2125f, 0.7154f, 0.0721f )) ;
この内積の結果が1以上の場合出力するとなっているが、真っ黒な絵しか出力されなかった。
ライトを強めにするとか書いてあるが、コピー部分にはライトが関係なさそうでよくわからない。
ネットで調べてみたところ、同じように出来上がった画像の高輝度部分を抽出する場合、
color.rgb = saturate( color.rgb - 0.9f ) * 10.0f ;
こんな感じになっていた。
実際にこんな方法で抽出した場所を光らせても、求めてるものと違うような気がするがとりあえずはこれでやってみることにする。


ブラー処理 


これは以前作った処理を呼び出せば良いと思ったんだけど、少し問題があった。
静止画の場合は問題なさそうだけど、画面が動くとぼかしの品質が悪くてぼやぼやする感じになった。
ブラーを掛ける前のリソースはミップマップテクスチャでないと品質的に耐えられなさそうなのでミップマップ化する処理を間に追加し、そのミップマップテクスチャでブラーをかけることにした。


最終的な処理の流れ


処理フロー図


1.元画像準備


ブルーム対象の画像。
高輝度のものだけを出力した画像が渡された場合は、次の処理をスキップできるようにした。


2.高輝度部分抽出


今回は色の各成分が0.9以上の箇所を抽出するようにしてみたが、実際には使えないと思ってる。
モデルのEmissiveが値を持っている箇所のみをレンダリングした画像を元画像として出力する仕組みを作ってみる予定。


3.高輝度画像ミップマップ化


ファイル指定のテクスチャをミップマップ付きで用意する仕組みはあったけど、動的なリソースに対してミップマップを作る仕組みがなかった。
なので任意のSRVを指定してミップマップテクスチャを作成する仕組みを用意した。


4.ブラー処理


ミップマップテクスチャを元にブラー処理をかける。


5.元画像とぼかし画像の加算合成


最後は元画像と、ブラー画像を加算合成する。
ブラー画像に対する重みパラメータと、合成後の掛け目のパラメータを用意した。


出力結果


通常レンダリング結果

このレンダリング結果に対してブルーム処理をかけても、高輝度部分が抽出できなかった。

鏡面反射

スペキュラの計算を付け加えて全体をテカテカにして、これに対してブルーム処理をかけてみる。

ブルーム結果

それっぽい結果になった。

ブルーム結果2

パラメータを変えて、ブラー画像を2倍にして、合成結果に0.5かけたもの。


HDRレンダリングってなんだ?


高輝度抽出画像は最初DXGI_FORMAT_R32G32B32A32_FLOATでやっていたが、いつものDXGI_FORMAT_R8G8B8A8_UNORMでも結果が変わらなかったので戻した。
シェーダの結果として1以上の明るさを設定できるんだろうけど、レンダーターゲットはDXGI_FORMAT_R8G8B8A8_UNORMのままなので、1以上は1扱いでそのまま出力されたのか?
レンダーターゲットもDXGI_FORMAT_R32G32B32A32_FLOATで作ればもっと眩しい感じになるのか?
そもそもそれっぽく見せるために、光源をぼかして範囲を広げて周りに光を漏れさせた絵を用意したけど、そんな事せずに光ってる部分の値を1000とか1万とかにすると、ディスプレイ自体がめちゃくちゃ光ってそういうふうに見せてくれないのかな?






2022年12月1日木曜日

CS版軽量なぼかし処理

前々回で、リアルタイムにぼかす処理を作ってみたけど、実際には静止画にぼかしフィルタを掛けているだけ。
ぼかす対象は静止画だったので毎フレーム更新する必要はない。

前に作ったのはリアルタイム用として、今回は1回だけの静止画用をコンピュートシェーダ(CS)で作って見ようと思う。


リアルタイム用は2枚の中間レンダーターゲットを用意して処理していた。
静止画用は空のテクスチャ2枚を用意して、CSで書き込むことになる。
テクスチャに書き込むのにUnorderedAccessView(UAV)をテクスチャに紐づけて、Dispatchする際には、用意したテクスチャではなくUAVの方を指定する。

#define DefRS "RootFlags(DENY_VERTEX_SHADER_ROOT_ACCESS|DENY_HULL_SHADER_ROOT_ACCESS|DENY_DOMAIN_SHADER_ROOT_ACCESS|DENY_GEOMETRY_SHADER_ROOT_ACCESS|DENY_PIXEL_SHADER_ROOT_ACCESS),DescriptorTable( Sampler(s0),visibility=SHADER_VISIBILITY_ALL),DescriptorTable( SRV(t0, flags=DATA_STATIC_WHILE_SET_AT_EXECUTE),visibility=SHADER_VISIBILITY_ALL),DescriptorTable( UAV(u0, flags=DATA_VOLATILE),visibility=SHADER_VISIBILITY_ALL),RootConstants( num32BitConstants=2, b0,visibility=SHADER_VISIBILITY_ALL)"

SamplerState Sampler : register(s0) ;
Texture2D TexColor : register(t0) ;        // ぼかし対象画像
RWTexture2D<float4> UAV : register(u0) ;    // 結果画像
struct _Param { 
	float2	Scale ;	// 倍率
} ;
ConstantBuffer<_Param> Param : register(b0) ;

static const int BLUR_SAMPLE_COUNT = 8 ;
static const float2 BLUR_KERNEL[BLUR_SAMPLE_COUNT] = {
	float2(-1.0f, -1.0f),
	float2(-1.0f,  1.0f),
	float2( 1.0f, -1.0f),
	float2( 1.0f,  1.0f),
	float2(-0.5f,  0.0f),
	float2( 0.0f,  0.5f),
	float2( 0.5f,  0.0f),
	float2( 0.0f, -0.5f),
} ;
						
struct CSInput
{
	uint3 ID : SV_DispatchThreadID ;
} ;

[RootSignature(DefRS)] 
[numthreads( 8, 8, 1 )]
void CSMain( CSInput In )
{
	float2 uv = In.ID.xy + 0.5f ;
	float4 color = 0 ;
	for( int j = 0 ; j < BLUR_SAMPLE_COUNT ; j++ ) {
		color += TexColor.Sample( Sampler, ( uv + BLUR_KERNEL[j]) * Param.Scale ) ;
	}
	UAV[ In.ID.xy ] = float4( color.rgb / float( BLUR_SAMPLE_COUNT ), 1.0f ) ;

	return ;
}

シェーダの内容はほとんど変わらない。
ただ1つ重要なポイントがあって、リアルタイム用の時は意識してなかったんだけど渡すテクスチャにミップマップをつけておくこと。
1段階目で一気に縮小するので、その画像をたった8個のサンプリングでは品質が保てなく、実はかなりの部分をミップマップに助けてもらっていた。ミップマップは事前(読み込み時)に1回だけの処理なので、パフォーマンスには影響がない。
だけど、リアルタイムの方ではレンダリング結果にブラーを掛ける場合はミップマップの恩恵は得られない。品質の話はブラー強度を徐々に高めたりして前後を比較して見たときに気になるレベルなので、強度が一定であればミップマップなしでも許容範囲だと思う。


パフォーマンス 


リアルタイムの方は、ぼかし強度によって365~178usだった。
CS版はぼかし強度によって276~14usぐらい。(Dispatch部分のみ)

結構軽そうなので毎フレーム処理するようにしてみたら432~166us。
ぼかし強度が強い場合はリアルタイムでも使ったほうがいい結果になった。

ぼかし強度が弱い場合、そんなにサンプリングしなくても品質が落ちないので試しにBLUR_SAMPLE_COUNTを4にしたら309~163usだった。
ぼかし強度に合わせてサンプル数を調節してやれば、CS版のほうが高速っぽい。

ライブラリにまとめる際、リアルタイム版は結果が中間レンダーターゲット、描画に必要なもう1つの中間レンダーターゲットも常に保持しておく必要があるのに対し、CS版は結果がテクスチャで、描画に必要だったUAV2つと、もう1つのテクスチャは削除できる。

2022年11月28日月曜日

定数バッファ

定数バッファでハマったのでそれについてのメモ。

定数バッファの種類


フレーム依存定数バッファ


最初に自作ライブラリで用意したのはフレーム数に依存した定数バッファ。
ダブルバッファならフレーム数は2で、定数バッファのサイズを256の倍数に補正したサイズをフレーム数倍した領域をCreateCommittedResourceしたもの。

D3D12_HEAP_TYPE_UPLOADでCreateCommittedResourceしたリソースから、Mapでマッピングしたポインタをリソース破棄まで保持する。
データの書き換えは、このポインタに書き込む。

これは毎フレーム頻繁に値の書き換えがあるような用途で、用意した前半部分と後半部分のメモリをフレームの切り替えで書き込むオフセットを制御する。

読み取り専用定数バッファ


シェーダの内容によってはパラメータとして設定はするんだけど、値自体は最初に設定した以降変わらないというパターンのものもある。
フレーム数に依存した定数バッファでこのパターンのシェーダを使う場合、毎フレームの更新は不必要なため、最初に1フレームと、2フレーム目に同じデータを設定して使うことになる。また、大抵の場合データは書き換えの必要がない。
データの領域がフレーム数倍必要になり、初期化時にフレーム数分書き込む必要がある。

これはかなり無駄なので、このパターンに対応するため次に用意したのは読み取り専用の定数バッファ。フレーム数分定数バッファを用意するのはマイクロソフトのサンプルがそうなっていたからで、常にフレーム数分用意しないといけないと思いこんでいたけど、値を書き換えないなら1つ分でも行けるかなと思い試してみたところ問題なく動作した。

領域は必要な定数バッファサイズを256の倍数に補正したサイズのみ。
作成時にテクスチャと同様、データをGPUに書き込んでしまう。
D3D12_HEAP_TYPE_DEFAULTでCreateCommittedResourceしたリソースに、一時的に作成したD3D12_HEAP_TYPE_UPLOADのリソースを使って、CopyBufferRegionでコピーする。
Uploadでマッピングしたポインタは必要ないのでUnmapする。

32Bit定数バッファ


いろいろなサンプルを見ている中で見つけた定数バッファ。
ルート署名内に「RootConstants( num32BitConstants=1, b0)」と書けば、別途リソースの準備をする必要なく定数バッファを扱える。

テクスチャにミップマップを生成するコンピュートシェーダを用意したとき、別途定数バッファリソースの準備が不要なので使ってみたのがきっかけ。
前回のぼかしのシェーダで、パラメータをこの定数バッファで渡そうとしたものの、エラーがでてうまくいかず、読み取り専用定数バッファでとりあえず済ませた。

その時のエラーがこれ。
D3D12 ERROR: ID3D12CommandList::SetGraphicsRoot32BitConstants: No root signature has been set, so setting root constants doesn't make sense and is invalid. [ EXECUTION ERROR #709: SET_ROOT_CONSTANT_INVALID]

ルート署名に32Bit定数が存在しているのはPIXで確認できる。

PIXのパイプライン情報

このエラー文や32Bit定数バッファにまつわるキーワードで検索しまくったが解決につながる情報は得られなかった。
ネットのサンプルでも普通に使われているし、ミップマップのコンピュートシェーダでは普通に使えている。
コンピュートシェーダで使っているのはSetComputeRoot32BitConstantsで、今回使おうとしているのはSetGraphicsRoot32BitConstants


万策尽きて諦めかけてたとき、ふと思いついた。

BeginRenderという関数を用意して、レンダリング開始時にコマンドアロケータ、コマンドリストをリセットしているが、うまく行ってるミップマップのシェーダでは、このBeginRender後にSetComputeRoot32BitConstantsを呼び出している。対して、うまく行ってないシェーダではBeginRender前に呼び出していた。

コマンドリストのResetから、Closeの間で呼び出す必要があったというのが原因。
定数バッファのリソースは存在せず、シェーダに付属しているイメージなので常に書き込めるわけではないようだ。

もう1つ分かったことは、32Bit定数はフレーム依存定数バッファと同じ使い方ということ。
前回のぼかしのシェーダでは、用途としては読み取り専用定数バッファだったため、ぼかし強度を変更したタイミングで定数バッファを書き換え、毎フレームは書き換えてはいなかった。32Bit定数バッファでも同じように1回だけ書き込んで、次回以降書き込まずにいたら、結果が思い通りにならない。前回書き込んだ値は保持されず、毎フレーム書き込まないといけない模様(GPUによる?)

2023/8/27追記

この頃は定数バッファと同様にバッファが独立してあって、そこに値を設定する関数がSet[Graphics|Compute]Root32BitConstantsだと思っていた。
この関数はコマンドリストに追記する関数なので、当然コマンドリストが記録状態になっていないと使えない。


フレーム毎の書き込み


フレーム依存定数バッファ:不要 ※最初に全フレーム分書き込んだ場合


ダブルバッファの場合、前回、前々回のデータは保持している。
フレーム単位に参照する場所を切り替える関係上、更新を止めるなら全フレームのデータが同じになっていないと動作がおかしくなる。
実質フレーム毎の更新は必要。

読み取り専用定数バッファ:不可


作成時にGPU側にデータをコピーして、仕組み上書き換えできなくしているのでフレーム毎の書き込みはできない。

32Bit定数バッファ:必須


前回の値が保持されないため、毎フレーム書き込む必要がある。


データサイズ


フレーム依存定数バッファ:256byte単位×フレーム数


一定以上のデータ量でフレーム毎に書き換えが必要な場合に選択する。
また、フレーム専用の領域を用意しているので、32Bit定数よりも高速に動作(して欲しい)

読み取り専用定数バッファ:256byte単位


GPU側に書き込んでいるため、大きいデータでも高速に参照ができる。

32Bit定数バッファ:32Bit(4Byte)単位


少量のデータを渡す場合に適している。
コンピュートシェーダの場合は読み取り専用と同じような使い方もできる。

2022年11月27日日曜日

軽量なぼかし処理

以前DoFにチャレンジした際、ぼかし処理にガウシアンブラーを使ってぼかして見たが、思っていたほどボケなかった。
それにもかかわらず結構なGPUパワーを使うので、もっといい方法を探していた。

そこで見つけたのがこのサイト

ガウシアンブラー単体だと、ブラーをかける対象のサイズが大きいと処理の負担も大きい。
DoFでは1/4の縮小画像を作っていきながらブラーをかけて、その画像を拡大して使う。
ほぼそれと同じ発想なんだけど、ブラーの処理が例えば8×8ブラーだと16回サンプリングする必要があるのに対し、8回で済ませる。
あと、縮小画像1/16の画像と、1/64の画像の2段階で処理を行っていた。

最初真似して2段階、その後3段階まで試してみたけど、どうも結果が汚い。どんどん縮小させていって、最後に拡大するとどうしても粗が目立つ。
逆に最初から落としたいレベルまで縮小させてしまってから、縮小画像を4倍に拡大するようにしてみたところ、納得行く感じになった。

処理の流れ


PSシェーダ


#define DefRS "RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | DENY_HULL_SHADER_ROOT_ACCESS | DENY_DOMAIN_SHADER_ROOT_ACCESS | DENY_GEOMETRY_SHADER_ROOT_ACCESS),DescriptorTable( Sampler(s0),visibility=SHADER_VISIBILITY_PIXEL),DescriptorTable( SRV(t0, flags=DATA_STATIC),visibility=SHADER_VISIBILITY_PIXEL),DescriptorTable( CBV(b0, flags=DATA_STATIC),visibility=SHADER_VISIBILITY_PIXEL)"

SamplerState Sampler : register(s0) ;

Texture2D TexColor : register(t0) ;

struct _Param { 
	float2	Scale ;		// 倍率
} ;
ConstantBuffer<_Param> Param : register(b0) ;

static const int BLUR_SAMPLE_COUNT = 8 ;
static const float2 BLUR_KERNEL[ BLUR_SAMPLE_COUNT ] = {
	float2(-1.0f, -1.0f),
	float2(-1.0f,  1.0f),
	float2( 1.0f, -1.0f),
	float2( 1.0f,  1.0f),
	float2(-0.5f,  0.0f),
	float2( 0.0f,  0.5f),
	float2( 0.5f,  0.0f),
	float2( 0.0f, -0.5f),
} ;

struct PSInput
{
	float4 Pos	: SV_POSITION ;
	float2 UV	: TEXCOORD ;
} ;
struct PSOutput
{
	float4 Col : SV_TARGET ;
} ;
PSOutput PSMain( PSInput In )
{
	PSOutput Out ;

	float4 color = 0 ;
	for( int j = 0 ; j < BLUR_SAMPLE_COUNT ; j++ ) {
		color += TexColor.Sample( Sampler, In.UV + BLUR_KERNEL[j] * Param.Scale ) ;
} Out.Col = float4( color.rgb / float( BLUR_SAMPLE_COUNT ), 1.0f ) ; return Out ; }

Param.Scaleに「1.0f / 元のテクスチャサイズ * ぼかし強度」を指定する。
1/4096の場合は、元のテクスチャ幅、高さそれぞれ64で割ったサイズの画像を用意して、ぼかし強度に64を指定してレンダリングをした後、元のテクスチャ幅、高さそれぞれ32で割ったサイズの画像を用意して、ぼかし強度に32を指定してレンダリングする。


出力結果


無料の写真素材「ぱくたそ」からお借りした画像

この画像をそれぞれの強度でぼかした結果がこれ。

1/16

1/64

1/256

1/1024

1/4096

中間バッファ


1/1024と1/4096の中間バッファはこんな感じ

1/1024の中間バッファ

1/4096の中間バッファ

この時点ではかなりカクカクしているけど、この後それぞれ1/512、1/2048の画像にアップスケーリングして、間をなだらかにするので元のサイズに戻してもあまり違和感がない状態になっている。


パフォーマンス


ガウシアンブラーは4KでGPU使用率が40%ぐらいに対し、今回の方式だと20%で半分になっていた。
PIXで測ってみると、1024×1024のサイズ同士ではガウシアンブラーが646usに対し、1/16縮小が365us、1/4096縮小が178usだった。
ボケの強度を強くするほど中間バッファのサイズが小さくなるので処理が軽くなる。

ガウシアンブラーは期待していたボケ具合にはならず、更に重い処理だったが、今回の方式であればボケ具合を調整できる上に、処理時間も半分以下ので済むので満足。

2022年11月24日木曜日

サンプラー見本

サンプラーはテクスチャを貼り付けるときに必要なリソースで、主にフィルターと、アドレスモードを設定する。(そのほかの値は比較関数以外は固定値で使いこなせてない)

フィルター


D3D12_FILTERのenum値で、定義値を見るとごちゃごちゃしていてよくわからない。
最初に定義されているのが「D3D12_FILTER_MIN_MAG_MIP_POINT」で、D3D12_FILTERの後に、MIN、MAG、MIP、POINTという名前がついている。
MINがテクスチャの縮小時の挙動、MAGがテクスチャの拡大時の挙動、MIPがミップレベルの挙動を指していて、最後のPOINTがその挙動。
挙動にはPOINTとLINERとANISOTROPICがあり、ANISOTROPICはちょっと特殊。
POINTはポイントサンプリング、LINERはサンプリングに線形補間を使用。

改めて「D3D12_FILTER_MIN_MAG_MIP_POINT」を見ると、拡大縮小、ミップレベルですべてポイントサンプリングするということになる。
別の定義「D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR」は、縮小時は線形補間、拡大時はポイントサンプリング、ミップレベルは線形補間を利用する。
ただリファレンスには「拡大または縮小のどちらを行うかの選択があいまいな場合に、未定義の動作が発生します。」とあるので、実質使うのは「D3D12_FILTER_MIN_MAG_MIP_POINT」と「D3D12_FILTER_MIN_MAG_MIP_LINER」だけでいいのではないか?

残りのANISOTROPICは異方性補完という方法で、視線も考慮した補完方法らしい。
線形補間よりも品質は良くなるがパフォーマンスも落ちるので、今のところは未使用。
定義も、「D3D12_FILTER_ANISOTROPIC」で、拡大縮小、ミップレベルの補完をいい具合にしてくれるみたい。

アドレスモード


D3D12_TEXTURE_ADDRESS_MODEのenum値で全部で5種類ある。

D3D12_TEXTURE_ADDRESS_MODE_WRAP

並べて表示

D3D12_TEXTURE_ADDRESS_MODE_MIRROR

反転して表示

D3D12_TEXTURE_ADDRESS_MODE_CLAMP

範囲外は端の色が続く

D3D12_TEXTURE_ADDRESS_MODE_BORDER

範囲外はD3D12_SAMPLER_DESCの色で塗りつぶされる
アルファを0にすると、範囲外は何も描かれなくなる

D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE

1回だけ反転して、それ以降はCLAMPの動作


アドレスモードはD3D12_SAMPLER_DESCに3つ指定することになる。
1つ目は横方向、2つ目は縦方向、3つ目はよくわからない。


横と縦に同じアドレスモードを指定した見本


貼り付けるテクスチャ画像はこれ。
テクスチャ画像

このテクスチャを5×5で表示(UVの値は-2~2を指定)

WRAP/LINER

ドットがしっかりした画像の場合は、線形補間するとぼやけてしまう。
以降はポイントサンプリング。

WRAP/POINT

MIRROR/POINT

CLAMP/POINT

BORDER/POINT

MIRROR ONE/POINT



横と縦に別のアドレスモードを指定した見本


横にWRAPを指定


WRAP/MIRROR/POINT

WRAP/CLAMP/POINT

WRAP/BORDER/POINT

WRAP/MIRROR ONE/POINT


横にMIRRORを指定


MIRROR/WRAP/POINT

MIRROR/CLAMP/POINT

MIRROR/BORDER/POINT

MIRROR/MIRROR ONE/POINT


横にCLAMPを指定


CLAMP/WRAP/POINT

CLAMP/MIRROR/POINT

CLAMP/BORDER/POINT

CLAMP/MIRROR ONE/POINT


横にBORDERを指定



BORDER/WRAP/POINT

BORDER/MIRROR/POINT

BORDER/CLAMP/POINT

BORDER/MIRROR ONE/POINT


横にMIRROR ONEを指定


MIRROR ONE/WRAP/POINT

MIRROR ONE/CLAMP/POINT

MIRROR ONE/BORDER/POINT

MIRROR ONE/MIRROR/POINT


2022年10月30日日曜日

Android ワイヤレスデバッグ

携帯側の設定



[設定]-[システム]-<詳細設定>-[開発者向けオプション]を開く。

開発者向けオプション

デバッグの項目に「ワイヤレスデバッグ」という項目があるのでチェックをOnにする。

デバイスとのペア設定

「ワイヤレスデバッグ」を選択すると詳細画面が開くので、「ペア設定コードによるデバイスペア設定」を選択する。
ペアリングするための「IPアドレスとポート」と、「Wi-Fiペア設定コード」が表示される。

ワイヤレスデバッグ

「ワイヤレスデバッグ」では接続するための「IPアドレスとポート」が表示される。

 

接続コマンド



ペアリング

adb pair ペアリング用IPアドレス:ポート番号 Wi-Fiペア設定コード
「デバイスとのペア設定」に表示されているIPアドレスとポート番号を入力する。
「ワイヤレスデバッグ」に表示されているIPアドレスとポート番号ではない。

接続

adb connect 接続用IPアドレス:ポート番号
「ワイヤレスデバッグ」に表示されているIPアドレスとポート番号を入力する。

接続確認

adb devices
接続されているデバイスの一覧が表示される。