Box Blur

4. Box Blur

4.1 基礎知識

Box Blurアルゴリズムも畳み込み演算を用いるが、各位置に同じ重みを持つ畳み込みカーネルを使用し、例えば3*3の畳み込みカーネルは次のように表すことができる。

 

Box Blurの畳み込みカーネルも線形分離可能なので、分離可能なGaussian Blurと同じように、2次元のBox Blur畳み込み演算を2つの1次元Box Blur畳み込み演算に分割することができます。 例として、3×3 Box Blur の畳み込みカーネルが挙げられます。

各位置で同じ重みを持つ畳み込みカーネルは、処理によって得られる各画素点の値が、自身の画素値とフィールド内の他の画素値の平均となることを意味します。この利点は、スライディングウィンドウアルゴリズムを使用せず、より高速な累積アルゴリズムで実装できることです[1]。行列を処理する場合、畳み込みカーネルサイズの最初の要素について、累積和の平均を計算し、出力に書き込みます。その後の新しい要素については、累積和から畳み込みカーネルでカバーされなくなった要素を引き、新しい要素に加え、平均を計算し、出力に書き込みます。このことから、1次元のBox Blur演算では、1つの要素を処理する時間複雑度は、畳み込みカーネルの長さに依存せず、O(1)の定数であることがわかります。

(https://www.intel.com/content/www/us/en/developer/articles/technical/an-investigation-of-fast-real-time-gpu-based-image-blur-algorithms.htmlより)

9×9のBox Blur 畳み込みカーネルを例にとると、横方向の処理は次のように表されます。

(https://www.intel.com/content/www/us/en/developer/articles/technical/an-investigation-of-fast-real-time-gpu-based-image-blur-algorithms.htmlより)

しかし、現代のGPUの実行は高度に並列化され、無秩序であり、アキュムレータを用いて時間複雑性を低減する最適化は、CPUの計算には有効だが、GPUには有効ではありません。そのためには、Computer Shaderを使ってそのような操作を行うことを検討してください。これにより、時間の複雑さが一定になる反面、アルゴリズムの固定費が増加します。

その後の実装によると、以下のような結果が得られました。

Box Blurを一度行った結果の品質は、Gaussian Blur処理を行った結果の品質とはかけ離れていることがよくわかります。これに対して、中心極限定理は、適切な条件下で、多数の互いに独立な確率変数の平均が、適切な正規化後に正規分布に収束することを述べています[2]。つまり、ボックスぼかしを数回かけると、最終的にGaussian Blurに近い品質になるのです。このようにして、アルゴリズムの固定費がさらに増加します。


4.2 Unityの実装

上記のアルゴリズムに基づき、Unityでは、ComputerShaderを利用し、アキュムレータを用いたBox Blurアルゴリズムを実装します。

ComputerShaderを新規に作成し、1024×768の画面に後処理を行います。

まず、水平方向の処理を行い、画像の境界から外れたサンプルは、境界の画素値をサンプリングして補完します。各行のデータを確実に共有するために、各行を1スレッドとし、合計768スレッドとします。

[numthreads(1,768,1)]
void BoxBlurX(uint3 id : SV_DispatchThreadID)
{
	float4 colourSum = InputRT[int2(0, id.y)] * BlurDiameter / 2;
	for (int index = 0; index <= BlurDiameter / 2; index++)
		colourSum += InputRT[int2(index, id.y)];
	for (int index = 0; index < InputRTWidth; index++)
	{
		Result[int2(index,id.y)] = colourSum / BlurDiameter;

		// move window to the next 
		float4 leftBorder = InputRT[int2(max(index - BlurDiameter / 2, 0), id.y)];
		float4 rightBorder = InputRT[int2(min(index + BlurDiameter / 2 + 1, InputRTWidth - 1), id.y)];

		colourSum -= leftBorder;
		colourSum += rightBorder;
	}
}

垂直方向の処理も同様で、合計1024スレッドになります。

[numthreads(1024, 1, 1)]
void BoxBlurY(uint3 id : SV_DispatchThreadID)
{
	float4 colourSum = InputRT[int2(id.x, 0)] * BlurDiameter / 2;
	for (int index = 0; index <= BlurDiameter / 2; index++)
		colourSum += InputRT[int2(id.x, index)];
	for (int index = 0; index < InputRTHeight; index++)
	{
		Result[int2(id.x,index)] = colourSum / BlurDiameter;

		// move window to the next 
		float4 leftBorder = InputRT[int2(id.x, max(index - BlurDiameter / 2, 0))];
		float4 rightBorder = InputRT[int2(id.x, min(index + BlurDiameter / 2 + 1, InputRTHeight - 1))];

		colourSum -= leftBorder;
		colourSum += rightBorder;
	}
}

Csharp側でComputerShaderを呼び出し、BoxBlurの処理を1行で行う。

private void OnRenderImage(RenderTexture input, RenderTexture output)
{
    BoxBlurShader.SetInt("BlurDiameter", BlurDiameter);
    BoxBlurShader.SetInt("InputRTWidth", input.width);
    BoxBlurShader.SetInt("InputRTHeight", input.height);

    BoxBlurShader.SetTexture(kernelHandleX, "InputRT", input);
    BoxBlurShader.SetTexture(kernelHandleX, "Result", tmp0);
    BoxBlurShader.Dispatch(kernelHandleX, 1, 1, 1);

    BoxBlurShader.SetTexture(kernelHandleY, "InputRT", tmp0);
    BoxBlurShader.SetTexture(kernelHandleY, "Result", tmp1);
    BoxBlurShader.Dispatch(kernelHandleY, 1, 1, 1);
    Graphics.Blit(tmp1, output);
}

サイズ36×36の畳み込みカーネルを選び、以下の結果を得ます。

ご覧の通り、非常にはっきりとしたモザイクがかかっているので、さらにBox Blur処理を実行します。

非常に良い結果が出てきました。


4.3まとめ

Box Blurアルゴリズムの大きな利点は、要素の処理にかかる時間的複雑さを定数に減らし、畳み込みカーネルのサイズに関係しなくすることです。しかし、固定費が高いのが難点です。また、Computer Shaderを使用しているため、このアルゴリズムにサッポートしないデバイスもあります。 このアルゴリズムの性能上の利点は、使用する畳み込みコアのサイズがある閾値を超えた場合にのみ発揮してくれます。そのため、一部の特殊なケースにしか適さないと言えます。


参考資料

[1] https://en.wikipedia.org/wiki/Box_blur

[2]https://zh.wikipedia.org/wiki/%E4%B8%AD%E5%BF%83%E6%9E%81%E9%99%90%E5%AE%9A%E7%90%86

 

https://web.archive.org/web/20060718054020/http://www.acm.uiuc.edu/siggraph/workshops/wjarosz_convolution_2001.pdf

https://ams.xyz/dev/FinalDegreeProjectReport-Andr%C3%A9sValencia.pdf

https://cloud.tencent.com/developer/article/1035559

https://en.wikipedia.org/wiki/Box_blur

https://web.archive.org/web/20060718054020/http://www.acm.uiuc.edu/siggraph/workshops/wjarosz_convolution_2001.pdf

http://blog.ivank.net/fastest-gaussian-blur.html

https://medium.com/mobile-app-development-publication/blurring-image-algorithm-example-in-android-cec81911cd5e

http://dev.theomader.com/gaussian-kernel-calculator/

http://genderi.org/frame-buffer-postprocessing-effects-in-double-s-t-e-a-l-wreckl.html

Gaussian Blur

1. Gaussian Blur (一) ―― 基礎アルゴリズムとその実装

 

1.1 基礎知識

ガウシアンぼかし(Gaussian Blur)は、Gaussian Smoothingとも呼ばれ、画像をぼかすための典型的なアルゴリズムです。ガウシアンぼかしは、簡単に言うと、画像全体を加重平均する処理で、各画素値は自身とフィールド内の他の画素値の加重平均で得られます。

ガウシアンぼかしのアルゴリズムに入る前に、畳み込み(Convolution)演算を理解する必要があります。ここでは、行列の畳み込み演算プロセスを簡単に説明します。具体的な畳み込み演算については、関連資料を調べてください。

処理する行列があります。

この行列が3*3の畳み込みカーネルを用いて処理されると仮定すると、このカーネルは次のようになります。

 

まず、畳み込みカーネルを180°反転し、元の畳み込みカーネルと同じ結果を得ます。次に、畳み込みカーネルの中心を処理対象の行列の対応する要素、例えば左上の最初の要素に合わせ、要素のないところには0を加え、対応する要素を掛け合わせて次の結果を得ます。

 

0*0.1+0*0.1+0*0.1+0*0.1+0*0.1+1*0.2+2*0.1+0*0.1+5*0.1+6*0.1=1.5

 

畳み込み演算後の最初の要素の値は1.5です。同様に、行列の他の値も最終結果まで処理します。

 

これは、SWA(Sliding Window Algorithm)の応用で、簡単な行列の畳み込み演算プロセスです。

ガウシアンぼかしはこのような畳み込み演算を利用したもので、畳み込みカーネルの計算がガウシアン分布関数を適用していることから「ガウシアン」ぼかしと呼ばれています。

 

(一次元ガウシアン正規分布の密度関数)

(一次元ガウシアン正規分布の密度関数グラフ)。

 

さらに、2次元のガウシアン分布の式は次のように求められます。

これを正規化すると、次のようになります。

ここで、uは行、vは列を表し、u, v∈{-ω, -ω+1, ………}とします。ω-1, ω}

Sは正規化定数。

概略図は次のようになります。

 

3×3の畳み込みカーネルの場合、その個々の位置の相対座標は次のように表すことができます。

 

式に代入して演算すると、正規化された3*3ガウシアン畳み込みカーネルが得られます。

 

画像に対して、ガウシアン畳み込みカーネルを用いて全画素を畳み込み演算します。 最終的に得られる画像は、画像がぼかされたように見えるので、ガウシアンぼかしと呼ばれています。

出力画像をY、入力画像をXとし、i行j列のデータをX(i,j)、Y(i,j)とすると、サイズが(2ω+1)*(2ω+1)、標準偏差がσのガウシアンカーネルを用いた計算後の結果は、次のようになります。

この式に従って、ガウシアンカーネルの中心を入力画像の位置(i,j)に置き、ガウシアンカーネルの各値と入力画像の対応する位置の値を掛け合わせて、(2ω+1)*(2ω+1)回の乗算計算を行い、(2ω+1)*(2ω+1)-1回の加算計算を行って、時間複雑度はO(ω^2)である。

また、サイズ1024*1024の画像に対して、サイズ33*33の畳み込みカーネルを使って画像全体に1回のぼかし処理を行うには、1024*1024*33*33≒11億4000万回のマッピングリードが必要となり、非常に時間がかかるのは間違いない。

 


1.2 Unityの実装

上記のアルゴリズムを元に、Unityで実装すると以下のようになります。

Shaderを作成し、 2 次元ガウシアンカーネルの計算式を実装します。

float gauss(float x, float y, float sigma)
{
	return  1.0f / (2.0f * PI * sigma * sigma) * exp(-(x * x + y * y) / (2.0f * sigma * sigma));
}

頂点シェーダは UnityCG.cginc に実装された vert_img 関数を選択し、その主な機能は、頂点をモデル空間からクロップ空間へ変換することです。

v2f_img vert_img( appdata_img v )
{
    v2f_img o;
    UNITY_INITIALIZE_OUTPUT(v2f_img, o);
    UNITY_SETUP_INSTANCE_ID(v);
    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
    o.pos = UnityObjectToClipPos (v.vertex);
    o.uv = v.texcoord;
    return o;
}

ガウシアンカーネルのサイズを設定します。

#ifdef MEDIUM_KERNEL
#define KERNEL_SIZE 35
#elif BIG_KERNEL
#define KERNEL_SIZE 127
#else
#define KERNEL_SIZE 7
#endif

各ピクセルとそのフィールドのピクセルに重みをつけるフラグメントシェーダを実装します。重みは上記のgauss関数によって得られます。

float4 frag(v2f_img i) : COLOR
{
	float4 o = 0;
	float sum = 0;
	float2 uvOffset;
	float weight;
	for (int x = -KERNEL_SIZE / 2; x <= KERNEL_SIZE / 2; ++x)
		for (int y = -KERNEL_SIZE / 2; y <= KERNEL_SIZE / 2; ++y)
		{
            //オフセットを計算する
			uvOffset = i.uv;
			uvOffset.x += x * _MainTex_TexelSize.x;
			uvOffset.y += y * _MainTex_TexelSize.y;
            //重みを確認する
			weight = gauss(x, y, _Sigma);
			o += tex2D(_MainTex, uvOffset) * weight;
			sum += weight;
		}
	o *= (1.0f / sum);
	return o;
}

以下のような結果が得られます。

原画像

(7*7のガウシアンカーネルを使用したもの)

 

(35*35のガウシアンカーネルを使用したもの)

DEMOリンク

https://github.com/UWA-MakeItSimple/Course-PostProcessingEffect/blob/main/Assets/Shaders/Blur/GaussianBlur/SecondDimensionGaussianBlur.shader


 

2. Gaussian Blur(二)―― 2段階の1次元演算アルゴリズムとその実装

2.1 基礎知識

2次元ガウシアン関数を用いた畳み込みカーネルによる画像のぼかし処理は,リアルタイム計算を行うゲームに適用するとオーバーヘッドが大きくなります。加速を最適化し、テクスチャ読み取り操作と算術操作の数を減らすために、いくつかの方法を検討する必要があります。最適化は、2次元ガウシアン分布関数の分離可能な性質を利用することによって実行できます。

2次元ガウシアン分布関数の分離可能性とは、2次元ガウシアン関数を同じ1次元ガウシアン関数に分解して2回処理しても、どちらも等価であり、得られる結果は同じだが処理時間が大幅に短縮されることを意味します。数学的な証明式は以下の通りです。

とすると、

 

ガウシアンカーネル行列を、行ベクトルと列ベクトルを掛けた正規化定数として書き直します。

このときの正規化定数Sは、2つの1次元ガウシアンカーネルの正規化係数の逆数乗算に分割できます。

 

したがって、Gを2つのベクトルの積に分割することもできます。

この中には、

したがって、ガウシアンぼかした画像Yは次のように表すこともできます。

 

上記の式は、最初に1次元ガウシアンカーネルと入力画像Xを使用して水平畳み込み演算を実行し、中間結果Zを取得し、次に1次元ガウシアンカーネルと中間結果を使用して垂直畳み込み演算を実行することを示しています。結果Zを使用して、最終結果Yを取得します。

この方法でピクセルのぼかし効果を計算するには、(4ω+ 2)乗算演算と4ω加算演算が必要で、時間計算量はO(ω)であることがわかります。

1024 * 1024サイズの画像の場合、33 * 33の畳み込みカーネルを使用して画像全体にぼかし操作を実行するには、1024 * 1024 *33*2≈6.9kwのテクスチャ読み取りを実行する必要があります。これは2次元ガウシアン畳み込みカーネルを使用した直接処理と比較して大幅に低下します。


2.2 Unityの実装

上記のアルゴリズムに従って、Unityで実装します。

まず、1次元ガウシアンカーネル計算式を実装します。

float gauss(float x, float sigma)
{
	return  1.0f / (sqrt(2.0f * PI) * sigma) * exp(-(x * x) / (2.0f * sigma * sigma));
}

1次元ぼかしアルゴリズムを実装します。

float4 GaussianBlur(pixel_info pinfo, float sigma, float2 dir)
{
	float4 o = 0;
	float sum = 0;
	float2 uvOffset;
	float weight;

	for (int kernelStep = -KERNEL_SIZE / 2; kernelStep <= KERNEL_SIZE / 2; ++kernelStep)
	{
		uvOffset = pinfo.uv;
		uvOffset.x += ((kernelStep)* pinfo.texelSize.x) * dir.x;
		uvOffset.y += ((kernelStep)* pinfo.texelSize.y) * dir.y;
		weight = gauss(kernelStep, sigma);
		o += tex2D(pinfo.tex, uvOffset) * weight;
		sum += weight;
	}
	o *= (1.0f / sum);
	return o;
}

最初のpassでの水平方向の1次元ぼかしを実行する:

struct pixel_info
{
	sampler2D tex;
	float2 uv;
	float4 texelSize;
};

float4 frag_horizontal(v2f_img i) : COLOR
{
	pixel_info pinfo;
	pinfo.tex = _MainTex;
	pinfo.uv = i.uv;
	pinfo.texelSize = _MainTex_TexelSize;
	return GaussianBlur(pinfo, _Sigma, float2(1,0));
}

Pass
{
	CGPROGRAM
	#pragma target 3.0
	#pragma vertex vert_img
	#pragma fragment frag_horizontal
	ENDCG
}

Unityの内蔵関数GrabPass{}を使用して、最初のpassの実行後に画面イメージをキャプチャします。この関数は、デフォルトで_GrabTextureという名前の変数に画像を保存し、次に垂直方向のぼかしを実現します。

float4 frag_vertical(v2f_img i) : COLOR
{
	pixel_info pinfo;
	pinfo.tex = _GrabTexture;
	pinfo.uv = i.uv;
	pinfo.texelSize = _GrabTexture_TexelSize;
	return GaussianBlur(pinfo, _Sigma, float2(0,1));
}
uniform sampler2D _GrabTexture;
uniform float4 _GrabTexture_TexelSize;

GrabPass {}関数によって取得された画像のUV座標は通常の画像と一致しないため、ぼかしアルゴリズム後の結果が反転しないようにUV座標を処理する必要があります。したがって、頂点シェーダーは次のように実装されます。

v2f_img vert_img_grab(appdata_img v)
{
	v2f_img o;
	UNITY_INITIALIZE_OUTPUT(v2f_img, o);
	UNITY_SETUP_INSTANCE_ID(v);
	UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
	o.pos = UnityObjectToClipPos(v.vertex);
	o.uv = half2(v.vertex.x, 1-v.vertex.y);
	return o;
}

垂直ぼかしを実装するpass

GrabPass{}

Pass
{
	CGPROGRAM
	#pragma target 3.0
	#pragma vertex vert_img_grab
	#pragma fragment frag_vertical
	ENDCG

このように、ぼかし処理を行うには、2つのパスを使用する必要があって、結果として2つのDrawCallが必要となり、これはパフォーマンスに影響を与える重要な要素です。

ここでの実装では、比較的に時間がかかるGrabPass{}関数を使用します。OnRenderImage()関数で2つのblitを使用して、それぞれ水平操作と垂直操作を実行することを検討してください。

効果は次のとおりです。

 

(35 * 35のガウシアンカーネルを使用した)



 

3. ガウシアンぼかし(三)-線形サンプリングを使用したアルゴリズムと実装

3.1 基礎知識

ガウシアン分布関数の特性を利用することで、テクスチャの読み取りと算術演算の数を減らすことに成功しました。GPUを活用することで、さらなる高速化が可能です。これまでのアルゴリズムでは、1回のテクスチャ読み取りで1ピクセルの情報しか得られないことを前提としていましたが、GPUの場合は必ずしもそうとは限りません。画像の読み取りにバイリニア補間サンプリング(Bilinear Sampling)が有効になっている場合、GPUは複数のピクセル情報を一度に読み取ることができます。バイリニア補間を使用しても、GPUへ追加の負担をかけません。

バイリニア補間サンプリングについて、簡単に紹介します:

 

(バイリニア補間の概略図)

 

図に示すように、最初にx方向に2つの単線形補間を取得して、2つの一時点R1(x、y1)とR2(x、y2)を取得し、次にy方向に1つの単線形補間を計算してP(x、 y)を得ます。

つまり、テクスチャピクセルを読み取る場合、テクセルの中心にあるテクスチャを読み取らないように選択し、読み取るのに適した位置を選択することで、GPUバイリニア補間によって2つのピクセルの情報を取得できるようになります。

離散サンプリングと同じ効果を維持するには、位置の重みが2つのテクセルの重みの合計に等しくなるように、読み取り座標を調整する必要があります。つまり、簡略化されたガウシアンカーネルの重みと位置は次の要件を満たす必要があります:

 

たとえば、5*5のガウシアンカーネルの場合、2つの1次元ガウシアンカーネルに分割します。ここで、横方向のガウシアンカーネルは次のようになります。

位置:

 

重み:

 

次のように置き換えることができます:

位置:

 

重み:

 

ハードウェア実装による丸め誤差を無視すると、線形サンプリングによって得られた結果は、離散サンプリングによって得られた結果と同じになります。このようにして、(2ω+ 1)*(2ω+ 1)のガウシアンカーネルは(ω+ 1)*(ω+ 1)のガウシアンカーネルに簡略化されます。ピクセルをぼかすには、(2ω+ 2)回の乗算、2ω回の加算、時間計算量はO(ω)になります。

1024 * 1024サイズの画像の場合、33 * 33サイズの畳み込みカーネルを使用して画像全体にぼかし操作を実行する場合は、1024 * 1024 *17*2≈3.56kwのテクスチャ読み取りを実行する必要があります。以前の離散サンプリングより、テクスチャ読み取りの数が大幅に減少しました。


3.2 Unityの実装

上記のアルゴリズムに従って、Unityで実装します。

操作を容易にするために、選択したサンプリングポイントは直接中間点として設定されるため、得られた結果には前の結果と一定の誤差があります。基本的なプロセスは前の方法と同様であり、ぼかしアルゴリズムが実装されています。この時点では、ガウシアンカーネルを1つずつ読み取る必要はなく、ステップサイズを2に変更します。

float4 GaussianBlurLinearSampling(pixel_info pinfo, float sigma, float2 dir)
{
	float4 o = 0;
	float sum = 0;
	float2 uvOffset;
	float weight;

	for (int kernelStep = -KERNEL_SIZE / 2; kernelStep <= KERNEL_SIZE / 2; kernelStep += 2)
	{
		uvOffset = pinfo.uv;
		uvOffset.x += ((kernelStep + 0.5f) * pinfo.texelSize.x) * dir.x;
		uvOffset.y += ((kernelStep + 0.5f) * pinfo.texelSize.y) * dir.y;
		weight = gauss(kernelStep, sigma) + gauss(kernelStep + 1, sigma);
		o += tex2D(pinfo.tex, uvOffset) * weight;
		sum += weight;
	}
	o *= (1.0f / sum);
	return o;
}

効果は次のとおりです。

(35 * 35のガウシアンカーネルを使用)


3.3 まとめ

ガウシアンぼかしアルゴリズムによって実装されたぼかし効果の品質は良好ですが、パフォーマンスの点からみると思いどおりになりません。畳み込みアルゴリズムでは画像のサンプリング回数が多過ぎて、線形サンプリングアルゴリズムでは、2回のパスが必要のためDrawCallの数を2倍にしました。これらはすべて、ガウシアンぼかしアルゴリズムの実際のアプリケーションパフォーマンスに影響します。これにより、開発者はぼかしアルゴリズムを最適化し、ガウシアンぼかし効果の品質を可能な限り達成しながら、実際のニーズを満たすようにパフォーマンスを向上させることができます。次の章では、画像ぼかしアルゴリズムのいくつかの改善されたアルゴリズムを学習します。

DEMOリンク:https://github.com/UWA-MakeItSimple/Course-PostProcessingEffect/blob/main/Assets/Shaders/Blur/GaussianBlur/FirstDimensionGaussianBlur.shader



参考資料:

Gaussian Kernel Calculator:http://dev.theomader.com/gaussian-kernel-calculator/

デモアドレス:https://github.com/VestLee/VestImageEffect

 

https://zhuanlan.zhihu.com/p/110754637

https://zhuanlan.zhihu.com/p/58182228

https://blog.csdn.net/qq_36359022/article/details/80188873

https://zhuanlan.zhihu.com/p/120102048

http://www.ruanyifeng.com/blog/2017/12/image-and-wave-filters.html

https://blog.csdn.net/yangtrees/article/details/8740933

https://www.zhihu.com/question/54918332

https://zhuanlan.zhihu.com/p/106587858

https://yemi.me/2018/04/30/super-fast-blur-gpu/

https://lab.uwa4d.com/lab/5b65e90ad7f10a201ff92a5d

https://lab.uwa4d.com/lab/5b5cfe50d7f10a201fea2686

物理ベースレンダリングーーHDR Tone Mapping

ゲームエンジンのレンダリングパイプラインでは、通常、R、G、Bチャネルの色情報の値の範囲を[0、1](または[0、255])の間に設定します。このうち、0は輝度がないことを表し、1はディスプレイが表示できる最大輝度を表します。この表示法は単純で理解しやすいものですが、真実世界の光の輝度を反映していません。真実世界の照明環境では、光の強度がモニターが表示できる最大輝度を超える場合があります。さらに、人間の目は、実世界の物体を観察するときに、光の強度に応じて調整されます。したがって、より現実的なレンダリング方法は、カラー値を1より大きくすることです。この照明計算方法または環境ライトマップは、ゲームエンジンでよく見られるHDR(High Dynamic Range)照明またはHDR環境マップです。ただし、HDRでレンダリングされた輝度値は、モニターが表示できる最大値を超えます。この時点で、照明結果をHDRからモニターが正しく表示できるLDRに変換する必要があります。このプロセスは通常、Tone Mappingと呼ばれます。次の図は、HDRでレンダリングされた画像に対してTone Mappingを使用した場合と使用しない場合のUnityエンジンの比較結果です。

その中で、上の写真はTone Mappingなしの結果であり、下の写真はTone Mappingありの結果です。トーンマッピングを使用しないレンダリング結果では、多数のピクセルの明るさがディスプレイに表示できる最大値を超えていることがわかります。視覚的には、これらの場所は露出オーバーになります。Tone Mappingを使用したレンダリング結果では、ピクセルの明るさが正常になり、視覚的にもよりリアルになります。

 

本日ご紹介する論文は、2002年のSiggraphカンファレンスで発表された論文「Photographic Tone Reproduction for Digital Images」です。この論文では、この方法で変換された結果を実際のオブジェクトに視覚的に近づける新しいTone Mapping方法を提案します。まず、次の図に示すように、この論文の結果グラフを見てみましょう。

その中で、左の画像は線形スケーリングの結果であり、右の画像は論文のアルゴリズムを使用した変換の結果です。単純な線形スケーリングの結果では、多くの詳細が失われていることがわかりますが、論文のアルゴリズム変換の結果は、画像の詳細を適切に保持しています。次に、論文のアルゴリズム部分を詳しく紹介します。

 

一、初期ライト輝度マッピング

 

まず、記事の著者は、カメラの露出を設定するのと同様に、画像全体の輝度マップを作成します。この操作は、実際には各ピクセルの固定スケーリングです。Tone Mappingに関する以前の研究の結論によると、著者は、輝度の対数平均値が画像のピクセルライト輝度の特性を反映できると考えています。したがって、この値を使用して各ピクセルをスケーリングします。

Lω(x、y)でピクセル(x、y)の輝度を表す場合、対数平均値は次のように表すことができます。

ここで、Nはピクセル数で、δは特異値を回避するために使用される定数です。スケーリングされた輝度L(x、y)は、次の式で表すことができます。

 

その中で、αはKey Valueと呼ばれるスケーリングパラメータであり、次の図に示すように、さまざまなα値がさまざまなスケーリング度に対応します:

 

ただし、単純な線形スケーリングを行うだけでは不十分です。輝度の変化が明らかしてない画像の場合、この方法でピクセルの輝度を特定の範囲に十分に圧縮できますが、ほとんどの写真では、ほとんどのピクセルの輝度が特定の範囲内にあり、ハイライトのピクセルは平均数より高くなるため、光源、鏡面反射などの過度の露出になりがちです。したがって、通常、線形スケーリング後に画像を処理するには、非線形演算子を使用する必要があります。著者は、一般的に使用される演算子を取り上げました。

 

その中で、Ld(x、y)は非線形演算子によって処理されたピクセルを表し、Lwhiteは画像の白の輝度にマッピングされたピクセルの最小値を表します。非線形であるため、明るいピクセルのスケーリングは大きくなります。したがって、この式は、線形スケーリングでは処理できない露出過度の状態を防ぎます。ただし、このような単純な演算子は、多くの場合、詳細が失われる傾向があります。著者は、従来の印刷技術では、印刷結果の品質を向上させるために、通常、dodying-and-burningのアプローチが採用されていることを観察しました。この方法の原理は、印刷内容の違いに応じて、異なる領域の明るさを下げる(ドディ)または上げる(燃える)ことです。この論文の著者は、次の図に示すように、単純な非線形マッピングとdodying-and-burning処理の結果を比較しました。

その中で、上の行の画像の太陽は木の枝で遮られているため、ハイライト領域は含まれていません。下の行の画像には鏡面反射が含まれています。左の列の写真も単純な非線形演算子(Simple Operator)によって拡大縮小されています。観察すると、本の文字が完全にハイライトで覆われていることがわかります。単純な非線形演算子のスケーリングでは、多くの詳細が失われることがわかります。

 

観察とテストの後、論文の著者は、dodging-and-burningの方法に基づいた適応的なdodging-and-burning方法を提案します。これについては、以下で詳しく説明します。

 

二、適応型のdodging-and-burning

 

適応型のdodging-and-burningの特徴は、高コントラストでエッジに囲まれた領域を見つけ、その領域を処理することです。したがって、著者はこれらの領域を見つけるためにガウスカーネル畳み込みを使用することを提案しています。さまざまなスケーリング係数sについて、さまざまなピクセルポイント(x、y)で、ガウスカーネル関数Ri(x、y、s)と画像L(x、y)の畳み込みを計算します。次に、畳み込み結果Vi(x、y、s)は次のように表すことができます。

 

その中で、Ri(x、y、s)は次のように表すことができます。

 

次に、論文の著者は、画像のローカルピクセルの輝度分布を測定するために、さまざまなαiパラメータの畳み込み結果間の差を計算するための誤差関数を定義します。次に、誤差関数Vは次のように表すことができます。

 

さまざまなスケーリングパラメータsを計算して、次の式に準拠するパラメータを見つけます。

 

ここで、ϵはしきい値であり、smは各ピクセルに対して計算されたスケーリングパラメーターです。各ピクセルのスケーリングパラメータを取得した後、ピクセルごとに異なるスケーリング計算を実行します。

 

これにより、最終的なTone Mappingの結果が得られます。次の図は、計算プロセスを示しています。

その中で、左の図はスケーリングパラメータの計算プロセスを示し、Centerは内側の円のガウス計算の範囲を表し、Surroundは外側の円のガウス計算の範囲を表します。右の画像は、さまざまなスケーリングパラメータでスケーリングした後の結果を示しています。観察によって、ズームが小さすぎると画像の細部を効果的に抽出できず、ズームが大きすぎると黒いArtifactsが表示されることがわかります。

 

三、対照実験

 

著者は、dodging-and-burningの計算結果を以前の結果と比較しました。以下に示すように:

その中で、New operatorは論文の実現結果を表しています。

 

四、まとめ

 

論文の著者は、dodging-and-burning印刷技術の観察と分析を通じて、領域ごとに異なるスケーリング係数を採用する新しいTone Mappingアルゴリズムを提案し、適応的なdodging-and-burningの方法を提案します。ハイダイナミック画像をローダイナミック画像に変換する際のハイライトの過度の露出を防ぎ、明るい部分と暗い部分の両方でディテールを維持するという目的を達成できます。

 

五、論文情報

 

著者情報:

ErikReinhardは、有名なコンピュータグラフィックス学者で、現在Technicolor ResearchandInnovationで研究を行っています。

Michael Starkは、ユタ大学で学んだコンピュータグラフィックス研究者。

Peter Shirley、有名なコンピューターグラフィックスの専門家、フォトリアリスティックレンダリングの専門家、ユタ大学の客員教授、NVidiaの主任科学者。

James Ferwerda、有名なコンピュータグラフィックス学者で、ロチェスター工科大学の准教授です。

 

リンク

http://www.cmap.polytechnique.fr/~peyre/cours/x2005signal/hdr_photography.pdf


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com

物理ベースレンダリングーーリアルな環境光で物体を照明する

ゲームエンジンにおいて、物体(オブジェクト)を照らす光源は、平行方向光、点光源、スポットライト、ボリューメトリックライトなどさまざまなものがありますが、いずれも実際の光源を近似したもので、現実の照明の複雑さをうまくシミュレートすることはできていません。照明効果のリアルさを高めるために、イメージベースドライティング(Image-based Lighting)を使用しています。例えば、「Sky Box」は環境光スタンプとして、「Reflection Probe」は反射スタンプ(Reflection Mapping)として働きます。最近流行っている物理ベースレンダリングパイプラインの中に、IBLは不可欠な一部となっています。

 

今日紹介したいのは、1998年にPaul DebevecがSiggraphカンファレンスで発表した論文です。この論文では、HDR(High Dynamic Range)図とグローバルライト照明の技術を使用して、どのように仮想物体を現実の写真に融合させるかという問題を取り上げます。 実現効果と言えば、今でよく言うAR(Augmented Reality)技術に似ています。 仮想物体をレンダリングするとき、HDR画像を環境光スタンプとして使用する方法で照明結果を計算します。この方法は、IBLを照明の計算に用いる最初の実験の一つである。レンダリング結果下図のように示します。

このうち、左図は実に撮った写真で、右図は仮想物体を実の撮った写真に合成した結果です。右図からわかるように、仮想物体の金属材質が周りの環境を反射しハイライトも形成し、前述の方法で実の物体と整合性のある照明結果を作り出すことができることが分かります。

 

この論文では、シーン内の物体を3種類に分類して処理しました。アルゴリズムの枠組みを以下の図に示す。

3種類のシーン内の物体はそれぞれ、「遠景」「近景(局部)」「仮想シーン」です。遠景をレンダリングするとき、実に撮った写真とシンプルなジオメトリでレンダリングします。すべての照明情報は撮影した写真から得ています。また、近景をレンダリングする場合、リアルシーンが仮想シーンに与える影響をシミュレートする必要があるため、著者は物体の材質を近似推定しました。最後に、仮想物体をレンダリングする際、環境照明からの入射光を用いて、照明を計算します。アルゴリズム処理の略図を以下に示す。

まず、実際のシーンを撮影します。次に、反射プローブを用いてシーンの環境光を取得します。環境光スタンプを取得する際、HDR表現を利用します。 それから、取得した環境光スタンプを用いて、遠景をモデル化します。最後に、仮想物体だけでなく、大域照明ソフトウェアで仮想物体と照明効果を持つ近傍の局所物体をレンダリングし、実に撮影した写真に融合させます。

 

次は、この論文のアルゴリズムについて詳しく説明します。

 

一、リアルな環境光で物体を照明する

 

著者は、HDR画像を環境照明のスタンプとして使用しています。HDR画像は普通のLDR画像より実際の照明環境に近いことを説明するために、著者はHDRとLDRの環境光スタンプを別々にレンダリングし、両者の結果を比較したところ、下図のような結果になりました。

1行目はHDR画像でレンダリングした結果、2行目はLDRでレンダリングした結果を示しています。右の3列の結果のうち、LDRのレンダリング結果は、LDRの入射光強度をHDRと同じにできるように、光量を6倍にして計算したものです。しかし、レンダリング結果を見ればわかるように、HDR環境光画像のレンダリング結果はより詳細で、LDRレンダリング結果は平坦に見えてしまうのです。そこで、著者は、次の実験では、完全にHDR画像を環境照明の入射光として使用した。

 

二、無限の遠景

 

遠方の物体をモデル化するために、著者はライトベースモデル(Light Based Model)を提案していました。この方法は、実は現在によく使われているスカイボックスと似ています。下図のように、HDRライトマップを四角い箱にマッピングして遠方の背景にします。

このマップは無限遠のシーンを表示することに使用されるだけでなく、仮想物体への入射光のレンダリングにも使用されます。

 

三、近辺の局部シーン

 

近辺の局部シーンの現実シーンと仮想シーンのライト交互をシミュレートするためには、近辺の局部シーンを幾何モデル化するだけでなく、その材質の情報を取得する必要もあります。材質取得ツールで実景の材質を計測することができるが、この論文の著者は反復的なアプローチで推定します。この方法のプロセスは次のとおりです。

 

1、まず、ローカルのリアルシーンのジオメトリをモデル化し、次に、diffuse、diffuse+specular、あるいはBRDF任意の(空間的にさえ変化する)モデルなど、マテリアルを推定する。

2、推定した材質モデルに対して、初期パラメータを選択する。

3、大域照明アルゴリズムでローカルシーンをレンダリングする。

4、視点を変えて、レンダリング結果と実際の撮影結果を比べてみてください。

5、レンダリング結果が実際の撮影結果と一致しない場合は、モデルパラメータを調整し、ステップ3に戻って反復作業を続ける。

 

四、近辺の仮想シーン

 

近辺の仮想シーンをレンダリングする際、複数の環境光マップを取得し、入射環境光として1つの完全なマップに統合する必要があります。これは、Light Probeを使用して環境光を取り込む場合、Probe球の奥にあるシーンは取り込めないからです。同時に、カメラの方向を向いたシーンでは、球のエッジからの反射が伸びるため、サンプリングレートが低くなり、不完全になりがちです。そこで、プローブ球をさまざまな角度から撮影し、その結果を組み合わせることで、最終的に完全なマッピングを作成することに成功しました。下図は、著者が撮影した3つの環境光マッピングと、仮想シーンのレンダリング結果である。

上の画像はLight Probeを用いて撮影した3枚のマッピング画像で、下の画像は合成された環境光マッピングでレンダリングされた仮想シーンの画像です。レンダリングには、著者が大域照明レンダリングエンジンであるRadianceを使用しました。現在に私たちがゲームエンジンで使用しているリアルタイムアルゴリズムとは異なり、「Radiance」はリアルタイムで計算を行うものではありません。当時のハードウェアの制約から、オフラインレンダリングをサポートしました。

 

五、 融合結果

 

著者は、遠景、近景、仮想のシーンの3つを融合させ、最終的に下図のような結果を得た。

図(a)は実際に撮影した結果です。 図(b)は、Light Probeで撮影した環境光マッピングの設定です。図(c)~(f)は、繰り返しによる局所シーン(床)の推定を示す。著者は、仮想物体と床との間のシャドウオクルージョンや多重反射を示すために、純粋なdiffuseダンボールを用いて床を幾何学的に近似し、第三章の反復アルゴリズムによって床の材質パラメータを推定しました。図(g)は、仮想物体を実景に融合させた結果です。

 

六、 結論

 

本論文では、実写のライティングマッピングを用いて仮想物体をレンダリングし、融合させるアルゴリズムを提供しました。このアルゴリズムは、実際の撮影シーンに仮想物体を融合させるのに有効である主な理由は、仮想物体をレンダリングするための環境光マッピングを実写のHDR画像から取得することで、レンダリングされた仮想物体の照明を実写シーンと一致させることができるからです。また、著者がレンダリング時に仮想物体と相互作用する実景の幾何や材質を推定していることである。さらに、その推定結果に基づいて、大域照明をレンダリングします。最終的には、現実のシーンと仮想物体の間の反射やシャドウオークルジョンを捕捉する効果があります。

 

七、論文情報

 

著者情報

Paul Debevec 南カリフォルニア大学非常勤研究員、GoogleVRプロジェクトの主要メンバー、有名なコンピュータビジョンとグラフィックス研究の学者。Light Stageを用いた人間の顔の反射モデルなどのBSDFの取得や、ハイダイナミックマップを用いた画像ベースのモデリングやレンダリングなどの研究を行っています。 彼の研究は、マトリックス、スパイダーマン2、キングコング、スーパーマンリターンズ、スパイダーマン3、アバターなど多くの有名な映画のレンダリングに使用されています。

 

ダウンロードのリンク

http://www.vis.uni-stuttgart.de/plain/vdl/vdl_upload/103_28_debevec-siggraph98.pdf


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com

物理ベースレンダリングーーHaarウェーブレット基底に基づくグローバルイルミネーション

前回は、球面調和関数(Spherical Hamonies、略してSH)に基づく動的グローバルイルミネーションアルゴリズムを紹介しました。そのアイデアは、オブジェクト間の光の複雑な伝達プロセスを伝達関数と見なすことです。伝達関数は、事前にシミュレートおよび計算され、SH基底関数によって近似されます。同時に、リアルタイム照明計算では、入射環境光はSH基底関数で近似されるため、照明レンダリング結果は、2つのSH基底関数の内積で計算できます。このアルゴリズムは、事前計算シミュレーションによるリアルタイム計算の複雑さを大幅に軽減するため、リアルタイム動的光源のグローバルイルミネーションレンダリングをサポートできます。ただし、このアルゴリズムには欠点があります。つまり、低周波数のレンダリングしか取得できません。したがって、SHベースのPRTは、AO(Ambient Occlusion)と同様のソフトシャドウのみをレンダリングでき、明確な輪郭や境界を持つ実際のシャドウをレンダリングすることはできません。

 

本日紹介したい記事は、2003年のSiggraphカンファレンスでRen Ng他によって発表され、現在400回以上引用されていた『All-Frequency Shadows Using Non-linear Wavelet LightingApproximation』です。この論文では、著者は線形SH変換の代わりに非線形ウェーブレット変換を使用するPRTアルゴリズムを提案します。実験結果により、以前のSH関数と比べ、同じ数のウェーブレット関数を使用した場合は、グローバルイルミネーションの高周波情報をより適切にキャプチャできます。従って、アルゴリズムは、鋭いエッジを持つリアルタイムの影など、よりリアルなGI効果をレンダリングできます。

まず、上記のように、この論文の効果図を見てみましょう。その中で、左図はSHベースのPRTのレンダリング結果で、右図はウェーブレットに基づくPRTのレンダリング結果です。両方の図は同じ数の基底関数項を使用しています。左図では100個のSH基底関数が使用され、右の画像では100個のウェーブレット基底関数が使用されています。中央の6つの正方形のテクスチャは、環境光のスタンプです。左右図のシャドウレンダリング効果を比較すると、右図のシャドウエッジがより鮮明になり、左図がぼやけていることがわかります。したがって、同じ数の基底関数を使用する場合、ウェーブレット変換はSH変換よりも高い周波数の照明情報をキャプチャでき、レンダリング結果は実際の状況に近くなります。次に、本論文のアルゴリズムの主な内容を詳細に紹介します。


 

一、アルゴリズムと実装

 

すべてのレンダリングの問題は、実際にはレンダリング方程式の計算の問題を解決しています。この論文も例外ではないので、レンダリング方程式から始めましょう。オブジェクトの表面上の点xを考え、その法線方向がnである場合、その点からωoの方向に反射された光P(x、ωo)は次のように表すことができます。

 

このうち、Lは入射光強度、Vは可視性関数、frはBRDF関数、nは法線方向、ωは入射光方向です。

論文のアルゴリズムは2つの状況に適用できます:1)視点が変化し、材質がDiffuseに制限されます。2)視点は変更されず、材質は任意です。次に、これら2つのケースのそれぞれのソリューションを紹介します。

 

1.1視点は可変で、材質はDiffuse拡散に制限されてい

材質がDiffuseに制限されている場合、伝達関数は次のように表すことができます。

 

1.2視点は変わらず、材質は任意

材質が任意の場合、伝達関数は次のように表すことができます。

 

その中で、視点が固定されているため、ωoはxにのみ関係します。

 

レンダリング方程式の積分は、入射光の強度Lと、入射光の方向ωに関する他の項の畳み込みとして見ることができます。離散化後、対応する項が乗算されてから合計されます。したがって、各点xiについて、その照明計算は次のように表すことができます。

 

行列とベクトルの形式で表現すると、次のように簡略化できます。P = T・L。その概略図を次の図に示します。

1.3事前計算

事前計算段階では、論文の著者は2つの方法を使用しました。1番目の方法は、伝達行列Tの1列の計算を一度にシミュレートすること、つまり、入射光ベクトルLの各方向ωを計算することです。計算方法はレイトレーシングです。したがって、Tの各列ベクトルは、環境光スタンプの各ピクセルのシーンを照らした結果を表します。この方法は比較的単純で、さまざまなグローバルイルミネーション効果をサポートしますが、固定視点の場合のみをサポートします。

 

2番目の方法は、伝達行列Tの1行の計算をシミュレートすることです。この方法は、直接照明部分のみを計算します。したがって、伝達行列の各行は、次の図に示すように、オブジェクトの表面上の点xの可視性立方体スタンプに、BRDFおよびCosine項の重みを加えたものを表します。

上図は、シーン内のいくつかの頂点の事前計算結果です。その中で、1番目の図はシーンの下部パッチ上の特定の点の事前計算結果であり、2番目の図は植物の下の特定の点の事前計算結果であり、3番目の図は植物の葉の上の特定の点の事前計算結果です。このアプローチは、ラスター化されたグラフィックハードウェアで実装できます。論文の著者は、最初に各点xの高解像度半立方体可視性スタンプをレンダリングします。次に、BRDFおよびCosine項の重み値を計算し、環境スタンプと同じ解像度にダウンサンプリングします。

 

1.4リアルタイムレンダリング

リアルタイムレンダリングでは、論文の著者はまず、2Dハールウェーブレット変換を介して環境光スタンプの対応する係数ベクトルLを計算します。次に、入射光の一部を選択して計算します。その主な目的は、エネルギーが低い入射光を削除することにより、計算量を減らすことです。この論文の著者は、3つのフィルタリング方法を使用しました。 1つ目は、Haarウェーブレット係数のサイズで直接フィルタリングすること、2つ目は、伝達行列の対応する列を使用して重みを計算すること、3つ目は、光源の面積でフィルタリングすることです。次に、LとTの積を計算して、最終的なレンダリング結果を取得します。ウェーブレット変換後の係数ベクトルと行列は非常に大きなスパースベクトルと行列であり、当時のGPUは一般的なスパース行列の乗算演算をサポートできなかったため、計算プロセス全体がCPU側で実行されます。


 

二、効果の比較

 

論文の著者は、SH基底関数とウェーブレット基底関数をそれぞれ使用して環境光スタンプをシミュレートし、異なる数の基底関数を使用した場合の結果と元の環境テクスチャの違いを比較します。次の図のように示します。

その中で、左と右の図は、2つの異なる環境光スタンプのシミュレーション結果です。左と右の図で、左の列はそれぞれ100、4096、10000のSH基底関数項を持つ環境光スタンプのシミュレーション結果であり、右の列の2つの図は100と4096のウェーブレット基底関数を持つ環境光スタンプのシミュレーション結果です。3番目は元の環境光スタンプを示しています。SHとウェーブレットのシミュレーション結果を比較すると、比較的単純な環境光スタンプの場合、ウェーブレット基底関数は高周波情報をキャプチャするために100項しか必要としないのに対し、SHは同様の結果を達成するために4096項を必要とすることがわかります。複雑な環境光スタンプの場合、ウェーブレット基底関数は元のテクスチャを復元するために4096項しか必要としませんが、SHは10000項を使用しても元のテクスチャをうまく復元できません。

 

ウェーブレット変換が非常に少ない項で全周波数照明情報をキャプチャできる理由は、次の図に示すように、ウェーブレット変換後、ほとんどの項の係数がゼロまたはゼロに近くなるためです。

実験を通じて、ウェーブレット変換後の非ゼロ項の割合はわずか0.1%〜1%であることがわかりました。ウェーブレット変換は、完全な周波数情報を圧縮することと同じです。したがって、ウェーブレット変換は、同じ項数でSHよりも多くの照明情報をキャプチャできます。ただし、ウェーブレット変換にも制限があります。 SHの回転不変性がないため、伝達関数では法線方向nは位置変数xの関数として扱われます。これは、ウェーブレット変換に基づくPRTは、オブジェクトを回転させた結果をリアルタイムでレンダリングできないことを意味します。SHにはこの制限はありません。これは、その後の研究でウェーブレット変換に基づくPRTの開発が限られている主な理由の1つでもあります。

 

論文の著者は、次の図に示すように、異なる項数のSH基底関数とウェーブレット基底関数の環境光スタンプに対する近似結果と元の図の間のL2誤差を比較します。

項の数が増えると、SHとウェーブレットの両方の近似誤差が減少することがわかります。ただし、ウェーブレットはより速く収束し、1000では10000項でのSHの誤差よりも小さくなります。


 

三、より多くのレンダリング結果

 

論文の著者は、実験用にさらに多くのシーンをレンダリングします。次の表は、さまざまなシーンでの環境光スタンプのサンプリングの解像度、スパース行列内の非ゼロ項の割合、およびメモリ使用量を示しています。

より多くのレンダリング結果が下の図に示されています。上の行はSHレンダリング結果であり、下の行はHaarウェーブレットレンダリング結果です。左から右にとられる基底関数の項は徐々に増加します。Haarウェーブレットは、同じ数の基底関数項の下でSHによってレンダリングされたシャドウの結果よりも高周波の詳細を持っていることがわかります。


 

四、まとめ

 

論文では、Haarウェーブレット関数をPRTの基底関数として使用し、全周波数情報を保存できるグローバルイルミネーション効果をリアルタイムでレンダリングすることを提案します。球面調和関数の基底関数と比較して、Haarウェーブレットの基底関数も標準的な直交性を持っています。同時に、圧縮率が高いため、非常に少ないパラメーターでレンダリング効果の高周波情報を保持できるため、完全な周波数照明のレンダリング効果を実現できます。Haarウェーブレットは、独自の特性のため、その後のグローバルイルミネーションレンダリングでは広く使用されていませんが、グローバルイルミネーションのリアルタイムレンダリングの研究分野に消えることのない貢献をしています。


 

五、論文情報

 

参考ビデオURL:https://v.qq.com/x/page/n0384trr1va.html

 

著者について:

レン・ン、現在UC Berkeleyに所属

個人のホームページ:https://www2.eecs.berkeley.edu/Faculty/Homepages/yirenng.html

 

有名なコンピュータグラフィックス学者であるRaviRamamoorthiは、現在、UCSDの教授です。コンピュータグラフィックスの大物で、数多くの論文を発表しました

個人のホームページ:https://cseweb.ucsd.edu/~ravir/

 

有名なコンピュータグラフィックス学者であるPat Hanrahanは、現在スタンフォード大学の教授です。コンピューターグラフィックスの大物で、かつてPixarで働いていて、RenderMan Shading Languageの開発者の1人です。

個人のホームページ:https://graphics.stanford.edu/~hanrahan/

 

ダウンロードリンク:

https://graphics.stanford.edu/papers/allfreq/allfreq.pdf


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com

おすすめのAIプラグイン

1)おすすめのAIプラグイン

2)VideoPlayerはAndroidでビデオを再生したら黒画面になる

3)Renderer.GetPropertyBlockの問題

4)RectMask2Dの問題


 

AI

Q:新しいプロジェクトにはいくつかのAIがあり、それを実装するためにいくつかのプラグインを使用したいと思います。推奨するAIプラグインはありますか?私の知る限り、Behavior Designer、Playmaker、Boltなどがあります。いくつかの機能とパフォーマンスが良いものを推奨してくれませんか?

 

A1:NodeCanvasをお勧めします。

優れた点:

  • 3つの完全に切り替え可能なグラフィックモジュールから選択できます。
  • 期待されるすべてのプロフェッショナル機能を備えた、スタイリッシュで直感的なビジュアルノードエディタ。

(すべて元に戻す・やり直し、ズームイン・アウト(拡大・縮小)、ミニマップ、複数選択、コピー、コピー・貼り付け、JSONインポート・エクスポート、グループとコメントなど)

  • 再利用可能でエージェント中心のパラメトリック動作を作成するためのグラフィックス、GameObject、およびグローバル黒板変数。
  • インスタンスまたは静的プロパティとフィールドを持つデータバインド変数。
  • UNETのネットワーク同期変数を使用します。

(UNETは現在廃止されているため、新しいネットワーキングソリューションに置き換えられます)

  • プレハブでオーバーライドできる変数。
  • さまざまな変数データ型の自動変換。
  • すぐに使用できるすべての変数タイプをサポートします。
  • すべての数のエージェント(Agent)にわたる再利用可能な動作グラフ。
  • 3つのグラフィックモジュールすべての間のシームレスなサブグラフィックネスト。

(動作サブツリー、サブステートマシン、サブダイアログツリー)

  • 完全なサブグラフ変数のパラメーター化とスタンプ。
  • モジュラーアクションと条件付きタスクの設計。
  • 条件付き応答動作ツリーの評価。
  • 条件付きおよびスタックベースのFSM遷移。
  • カラフルで有益なランタイムビジュアルデバッグ。
  • 内蔵ドキュメントを検索、お気に入りに登録、および読み取るためのノード/タスクブラウザ。
  • プロジェクトのニーズに応じてタイプ関連のメニューをカスタマイズするための優先タイプコンフィギュレータ。
  • グラフィックを楽に閲覧するためのグラフィカルミニマップ。
  • グラフィカルコンソール。マウスをクリックすることで、障害のあるノードを自動的に見つけることができます。
  • グラフブラウザを使用して、グラフ内のノード、タスク、およびパラメータを検索します。
  • 欠落しているノード、タスク、およびリフレクション参照をバッチで再構築するためのグラフ再構築機能。
  • 設計目標をより素早く完了するためのリアルタイムのランタイム編集。
  • 既存のコードAPIを自動的に統合するために最適化されたリフレクションタスク。
  • グラフィックスでデータを通信および転送するための内蔵イベントシステム。
  • NodeCanvasフレームワークを拡張し、独自のアクション、条件、ノード、さらにはまったく新しいグラフィックモジュールを作成するための明確で十分に文書化されたAPI。
  • あらゆる方法でインスペクターをカスタマイズするためのオブジェクトおよびプロパティペインタ。
  • 多数のサードパーティアセットと統合します。
  • FlowCanvasflowScriptsとのシームレスな統合。
  • ユーザーフレンドリーで軽量、設定は不要です。
  • 安定したパフォーマンス、初期化後のゼロ割り当て、非同期グラフの読み込み。
  • すぐに使用できるすべてのプラットフォームをサポートします。
  • すべてのC#ソースコードが含まれています。

詳細なリンクは次のとおりです。

https://assetstore.unity.com/packages/tools/visual-scripting/nodecanvas-14914

Behaviacも優れていますが、残念ながらTXはあまり維持されていません。

https://github.com/Tencent/behaviac/

A2:Baracudaをお勧めします。

https://github.com/Unity-Technologies/barracuda-release

A3:ゲームAIフレームワークの選択についての投稿を:《What A.I technique is most suited to my game, FSM, BT, GOAP》

AI関連のブログを添付する:AI共有ステーション

http://www.aisharing.com/sitemap

 

A4:Tencentオープンソースプロジェクト:behaviac

behaviacは、ゲームAIの開発フレームワークコンポーネントであり、ゲームプロトタイプの迅速な設計ツールです。すべてのプラットフォームをサポートし、クライアントとサーバーの両方に適しており、ゲームの迅速な反復型開発を支援します。

エディターはPC上で実行でき、操作は便利で直感的で信頼性が高く、リアルタイムおよびオフラインのデバッグをサポートします。エディターはxml、bson、その他の形式をエクスポートでき、C ++、C#ソースコードもエクスポートできて効率が向上します。

ランタイムは、C ++とC#の2つのバージョンを含むすべてのプラットフォームをサポートし、Unityをネイティブにサポートします。


 

Video

Q:この問題はプロジェクトAでのみ発生します。同じビデオとコードを新しいプロジェクトにコピーしてから、ビデオファイルをAddressables Groupに入れ、非圧縮に設定します。携帯電話でビルドすると、通常どおり再生できます。ただし、プロジェクトAでは、ビデオをAddressables Groupに入れ、非圧縮に設定しましたが、それでも再生できず、エラーが報告されます。

 

AndroidVideoMedia::OpenExtractor could not translate archive:/CAB-abafc77eff58910e7bc5f69ce62a4ed7/CAB-abafc77eff58910e7bc5f69ce62a4ed7.resource to local file. Make sure file exists, is on disk (not in memory) and not compressed.

 

このような問題が発生したことがありますか?

A:Addressables Groupで非圧縮と設定していますが、携帯電話でビデオを再生することはできません。したがって、どこでBundleを圧縮したのかと考え、やはりbuild.gradleで見つかりました。次のように、gradleのnoCompressに「.bundle」を追加する必要があります。

aaptOptions {
noCompress ‘.unity3d’, ‘.ress’, ‘.resource’, ‘.obb’, ‘.meta’, ‘.wem’, ‘.bnk’, ‘.txt’, ‘.xml’,’.bundle’ //ADD_NoCompress_TAG
}

 

Rendering

Q:コード印刷ログから、GetPropertyBlockは最初に取得したのは何でしょうか?何の用もないようです:

public MeshRenderer mr;
    [Button]
    void DOTest()
    {
        MaterialPropertyBlock block = new MaterialPropertyBlock();
        mr.GetPropertyBlock(block);
        Debug.Log(block.isEmpty);      //trueをプリントする
        Color baseColor = block.GetColor("_Color");
        Debug.Log(baseColor.ToString());      //オリジナルは白で (0,0,0,0)をプリントしたら何も取得されていない

        block.SetColor("_Color", Color.red);    //色を設定する
        mr.SetPropertyBlock(block);

        mr.GetPropertyBlock(block);        //再取得する
        Debug.Log(block.isEmpty);  // falseをプリントする
        baseColor = block.GetColor("_Color");
        Debug.Log(baseColor.ToString());    //(1,0,0,1)をプリントする

    }

 

もともと、Renderer.GetPropertyBlock(block)を介してRendererのマテリアルプロパティがBlockに格納されたと考え、その後内部の値を変更すると思っていましたが、そうではありません。たとえば、Alphaだけを変更したいと思いますが、元の色を取得できません:

MaterialPropertyBlock block = new MaterialPropertyBlock(); 
meshRenderer.GetPropertyBlock(block); 
Color baseColor = block.GetColor("_Color"); 
block.SetColor("_Color", new Color(baseColor.r, baseColor.g, baseColor.b, alpha)); 
meshRenderer.SetPropertyBlock(block);

 

A1:まず、Propertyにプロパティを追加しなかったため、Emptyであるはずです。つまり、プロパティシートは空のリストです。次に、Setcolorを使用して、プロパティフィールドをプロパティシートに追加してから、リストは空ではなくなります。プリントされたのは白である理由については、これがデフォルト値だと思います。つまり、存在しないプロパティにアクセスしてnullが返されないようにすると、デフォルト値が与えられます(これは推測です)。

元の色を取得するには、メティリアルから直接取得します。

var mat = renderer.material;//renderer.sharedMaterial; Color c = mat.GetColor("_Color"); Debug.Log(c.ToString());

A2:Renderer.HasPropertyBlock()を使用して、RendererがすでにPropertyBlockを持っているかどうかを判断できます。通常、SetPropertyBlockを呼び出す前に、GetPropertyBlockは「null」の結果を取得します。特殊なケースがあります。アニメーションでシェーダーを制御するために使用された後(シェーダーの色を制御するなど)、GetPropertyBlockを使用してMaterialPropertyBlockを取得すると、得られる結果は「空」ではありません。理論的には、アニメーションコントロールシェーダーでは、SetPropertyBlockで色の変更を実現したのです。

 


 

UGUI

 

Q:RectMask2dを使用してScrollviewノードの下にいくつかのアイコンを動的に作成しましたが、ページを開いたときにアイコンが正常に表示されず、スワイプした後にのみ表示されることがわかりました。アイコンオブジェクトが表示されていないときに作成されていることを確認しました。対応するInspectorウィンドウにはDefault UI Shaderというコンポーネンがなくなります。理由を知っている人はいますか?

 

Debugにより、アイコンオブジェクトをRectMask2dのクリッピングHashsetに通常どおり追加できることがわかりました。Frame Debugでアイコンが表示および表示されない場合、Batchが1つ少なくなります。

 

A:動的作成が完了した後、Canvas.ForceUpdateCanvasesを呼び出すことを試して下さい。このインターフェイスは、すべてのUI要素を時間内に更新するためのものです。

https://docs.unity3d.com/ScriptReference/Canvas.ForceUpdateCanvases.html


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com

物理ベースレンダリング-球面調和基底に基づくリアルタイムのグローバルイルミネーション

この記事の主な内容であるPRTを紹介する前に、まずゲームエンジンレンダリングパイプラインでよく見られる一つのステップであるIBLを紹介します。Disneyは、2012 Siggraphカンファレンスで公開されたPBR courseで、レンダリング結果をよりリアルにするためにPBRレンダリングパイプラインにIBL(Image Based Lighting)を追加したと述べました。現在、IBLはPBRレンダリングパイプラインのほぼ不可欠な部分になっています(たとえば、多くのエンジンはSkyBoxを環境光スタンプとして提供するか、シーンの環境光スタンプを取得するためのサンプリングツールを提供し、このスタンプを使用してシーンの物体をレンダリングします。)。

 

IBLとは何ですか?なぜそれを使用する必要がありますか?実際、初期のリアルタイムレンダリングでは、方向光を使用して無限の太陽光をシミュレートし、光源を使用して近くのライトをシミュレートしました。しかし実際には、物体がシーン内にある場合、物体はすべての方向からの入射光によって照らされます。これらの入射光は、光源から取得するだけでなく、物体の表面の拡散反射、鏡面反射、屈折、さらには霧の中の散乱光からも取得できます。四方八方からのリアル的な入射光をシミュレートするために、IBLのアイデアは次のとおりです:シーン内の物理が閉じた立方体に囲まれていると仮定すると、シーン内でそれに当たる光は必ず、立方体6つの面からに違いない。物体の周囲のシーンを6つの面にレンダリングして入射光にすれば、これらの6つのは、光源、物体表面反射、霧の散乱などからのあらゆる種類の光をカバーします。

 

IBLは、実際に撮られた環境光スタンプを入射光として使用するため、実際の環境で物体がどのように照らされるかをより現実的にシミュレートできます。ただし、このアルゴリズムでは、立方体の環境スタンプをサンプリングし、環境スタンプのすべての方向からの入射光から物体の照明情報を計算する必要があります。このプロセスは非常に時間がかかり、GPUの並列処理でさえもリアルタイム完了できません。したがって、入射光と半球表面の材質の畳み込み計算を球面調和関数(Spherical Harmonic Function、SHと略称)の内積に変換して、リアルタイム計算のコストを削減することを提案しました。本日紹介する論文はIBLに基づいており、これに基づいてグローバルイルミネーションを導入し、リアルタイムのグローバルイルミネーションの効果を実現しています。

 

この記事は、2002年のSiggraphカンファレンスでPeter-PikeSloanが発表した論文です。グローバルイルミネーション計算にある不変の事前計算を保存し、リアルタイムレンダリング中に変更された部分を計算するだけでよい事前計算方法を提案します。これにより、リアルタイムレンダリングの時間コストが大幅に削減されます。この論文のアルゴリズムは、リアルタイムのグローバルイルミネーションを実現する最初のレンダリングアルゴリズムであり、その後、有名なPRT(Precomputed Radiance Transfer)である研究が盛んになってきます

 

次の図に示すように、まずこの論文のレンダリング結果を見てみましょう。

 

その中で、左図はグローバルイルミネーションなしの結果であり、右図はグローバルイルミネーションありの結果です。左側と右側を比較すると、右図にAO(AmbientOcclusion)が追加されているため、右側のモデルサーフェスのくぼんだ部分が左側よりも暗いことがわかります。同時に、右の図は、表面の多重反射照明の計算も追加しています。これらの効果はリアルタイムで計算されますが、モンテカルロレイトレーシング、ラジオシティ、マルチパスポイントライトなどの従来のグローバルイルミネーションアルゴリズムでは実現できません。

 

グローバルイルミネーション効果をリアルタイムでレンダリングするには、3つの難点があります。1)複雑なBRDFをシミュレートする必要がある、2)入射光の半球積分を計算する必要がある、3)オクルージョンを計算する必要がある。物体の表面に多重反射がある。

この論文の著者は、これらの複雑な照明計算プロセスを光伝達関数(Transfer Function)と見なし、入射光情報を関数の入力と見なしています。また、球面調和関数、光線伝達の線形性と事前計算を使用して、入射光が物体間での多重反射という複雑な計算を、簡単で高速な内部積計算に変更ます。著者は低次の球面調和関数を使用して表示しているため、低周波の照明情報のみが考慮されます(環境光のスタンプはあまり変化しません)。 PRTアルゴリズムのフローチャートを次の図に示します。

上図はDiffuse材質のフローチャート、下図はGlossy材質のフローチャートです。上図からわかるように、PRTアルゴリズムは最初に環境光スタンプをSHに投影し、SH係数ベクトルを計算します。次に、オフライングローバルイルミネーションアルゴリズムを使用して物体のグローバルイルミネーションをシミュレートし、伝達関数を計算します。また、伝達関数をSHに投影して、係数ベクトルを取得します。最後に、リアルタイム計算では、物体の表面の光は、光のSH係数ベクトルと事前に計算された伝達関数のSH係数ベクトルの内積をとることによって計算できます。Diffuse材質は視線の方向に依存しないため、伝達関数は1つのベクトルだけで表せます。ただし、Glossy材質の場合、異なる視点から物体の表面の同じ点を観察するには、異なる照明を持ちます。したがって、Glossy材質の伝達関数は、異方向の視線次元を増やしてマトリックスにする必要があります。リアルタイム計算では、Diffuseと同じように、光ベクトルに伝達関数行列を掛けて、伝達された入射光ベクトルを取得します。次に、このベクトルを物体材質BRDFと畳み込み、すべての方向の反射光を表すベクトルを取得します。最後に、このベクトルから、視線の方向の反射光線が計算されます。次に、本稿の主な内容をご紹介します。


 

一、球面調和基底関数の紹介

 

PRTアルゴリズムは、重要な数学的ツールである球面調和基底関数を利用します。SHは、フーリエ変換が1次元変数で定義され、SHが2次元球面で定義されることを除いて、フーリエ変換に似ています。レンダリング方程式の積分は2次元球面の方向に定義されるため、SHはレンダリング方程式の計算問題を解決するのに非常に適しています。同様に、2次元球面で定義された関数は、SH基底関数と係数で近似できます。lとmを使用してSHの2つのパラメーターを表す場合、f(s)は球で定義された関数であり、ylmは基底関数である場合、SHでのf(s)の投影係数は次のように表すことができます。

 

f(s)は、おおよそ次のように表すことができます。

 

PRTは、SHの2つの特性、1)回転不変性と2)直交性を利用します。回転不変性により、環境光スタンプをSHに投影した後、物体の表面に対する任意の法線方向を回転してサンプルできます。直交性は、球面で定義された任意の2つの関数について、畳み込み計算を対応するSH係数の内積に変換できることを保証します。


 

二、伝達関数の紹介

 

2.1Diffuse材質

物体の表面での多重反射を考慮せずに、材質がDiffuseである物体Oの場合、その表面上の点p∈Oでのレンダリング方程式は次のように表すことができます。

 

このうち、HNP(s)= max(Np。s、0)は余弦項、Npはp点の法線方向、ρpはp点の色、Lpは入射光、可視性関数Vp(s)→{0,1}、オクルージョンされている場合は0を取り、それ以外の場合は1を取ります。したがって、伝達関数MpDSは次のように表すことができます。

 

その中で、LpとMpはそれぞれSHに投影され、TDSの積分計算はSH係数ベクトルの内積になります。

物体の表面での複数の反射を考慮する場合、点pのレンダリング方程式は次のように表すことができます。

 

ここで、L’P(s)は、s方向から点pに入射する物体Oからの光を表します。TDIの伝達関数MpDIの場合、完全な式で表現することは困難です。ただし、実装では、表面反射を複数回繰り返すことでMpDIを計算できます。

 

2.2 Glossy材質

Diffuse材質と同様に、Glossy材質のレンダリング方程式は次のように表すことができます。

 

ここで、G(s、R、r)は点pでのBRDF、Rは反射光の方向、rはGlossyのパラメータです。Glossy材質は、光の入射方向sだけに関わっているだけではないため、その伝達関数をベクトルだけで表すことはできません。論文の著者によって提案された方法は、入射光LP(s)を伝達後の入射光L’P(s)に変換することです。GがRに関して対称であると仮定すると、最終結果は、L’P(s)をG(s、(0,0,1)、r)で畳み込むことによって計算できます。したがって、LP(s)からL’P(s)への伝達関数は次のように表すことができます。


 

三、事前計算とリアルタイムレンダリング

 

この論文の著者は、複数回シミュレーション方法で伝達関数を事前に計算しています。最初は、物体Oの点pについて、直接照明の結果のみが計算されます。そして、物体によって遮られる光線について、その方向から反射された光線を繰り返し計算し続けます。そして、その後の反復計算では、以前の照明結果がそれに追加されます。各点での伝達関数を計算するとき、論文の著者は10k〜30kの方向をサンプリングします。照明の計算と同時に、オクルージョン情報も計算されます。反復回数の増加に伴い、エネルギーが特定のしきい値に減衰したら、反復を停止して計算を終了します。

 

リアルタイムでレンダリングする場合、次の手順が実行されます。

1)物体Oの入射光Lpを計算します。

2)LpをO法線方向のローカル座標に回転させます。

3)LpベクトルとMpベクトルの内積を行うか、Mp行列を乗算します。

4)Glossy物体の場合、伝達後の入射光L’pをBRDFで畳み込み、R方向の反射光を計算します。

 

異なる物体間で複数の反射光線を計算する必要がある場合は、単一の物体と同じ反復計算が使用されますが、反復中に、それ自体からの反射光だけでなく、他の物体からの反射光も計算されます。


 

四、実験結果

 

論文の著者は、さまざまなシーンを使用して実験を行い、そのすべてがリアルタイムのフレームレートを達成できます。実験データを下図に示します。

 

より多くのレンダリング結果の比較を以下に示します。

 


 

まとめ

 

この論文の著者は、SHの回転不変性と直交性を利用して、事前計算で物体を照らすときの光伝達のプロセスをシミュレートし、このプロセスの伝達関数をSHに投影します。リアルタイムレンダリングでは、SH上の光源の投影係数を計算し、伝達関数のSH投影を使用して内積を実行して照明情報を計算するだけで済みます。このアルゴリズムは、グローバルライトをリアルタイムで計算する効果を実現します。

 

PRTは、リアルタイムのグローバルイルミネーションの方法を提供するだけでなく、さらに重要なことに、リアルタイムのレンダリングパフォーマンスを最適化するためのアイデア、つまり事前計算を提供します。どのレンダリング計算でも、事前計算とリアルタイム計算のバランスを見つけることができます。リアルタイムの要件が高く、ハードウェアのパフォーマンスが要件を満たしていない場合は、事前にいくつかの計算を行ってから、少量な必要な変数をいくつか保持することができます。リアルタイム計算では、テーブルを検索して事前計算結果を読み取り、簡単なフィッティングで最終結果を計算します。もちろん、事前計算方式を使用する場合は、サンプリングが必要であり、ストレージ容量が増加することを意味します。さらに、入力環境が変化しても、事前に計算された変数は変化しないため、必然的に制約が生じます。たとえば、この記事で紹介した論文のPRTは、伝達関数を使用して物体間の光線の伝達プロセスを事前に計算するため、静的物体のグローバルイルミネーションのみをリアルタイムで計算できます。物体間の幾何学的関係が変化すると、事前計算された伝達関数は無効になります。


 

六、論文情報

 

参考ビデオURL:https://v.qq.com/x/page/x0382thpc7b.html

 

著者について:

有名なコンピュータグラフィックス学者であるPeter-PikeSloanは、かつてMicrosoft Researchでグラフィックスの研究に従事し、現在はActivisionBlizzardでグラフィックスの研究を行っています。

有名なコンピュータグラフィックス学者であるJanKautzは、かつてmax planck institut informatik Instituteで学び、現在はNvidiaでグラフィックスの研究を行っています。

有名なコンピュータグラフィックス学者であるJohn Snyderは、かつてマイクロソフト研究院でグラフィックス研究に従事していました。

 

ダウンロードリンク:

www-inst.eecs.berkeley.edu/~cs283/fa10/lectures/p527-sloan.pdf

 


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com