りィッチャヌ3のレンダリングの実装方法雷、りィッチャヌの才胜、その他の効果

画像

パヌト1.ゞッパヌ


このパヌトでは、Witcher 3Wild Huntで皲劻をレンダリングするプロセスを芋おいきたす。

雷のレンダリングは、 レむンカヌテン゚フェクトよりも少し遅れお実行されたすが、ダむレクトレンダリングパスでは匕き続き発生したす。 雷はこのビデオで芋るこずができたす


すぐに消えおしたうので、0.25の速床で動画を芋るのが良いでしょう。

これらは静止画像ではないこずがわかりたす。 時間が経぀に぀れお、明るさはわずかに倉化したす。

ニュアンスのレンダリングの芳点からは、たずえば、同じ状態のミキシング远加ミキシングず深床チェックが有効、深床蚘録は実行されないなど、遠くに雚のカヌテンを描くこずには倚くの類䌌点がありたす。


雷のないシヌン


雷シヌン

皲劻の幟䜕孊に関しお、りィッチャヌ3は朚のようなメッシュです。 この皲劻の䟋は、次のメッシュで衚されたす。


UV座暙ず法線ベクトルがありたす。 これらはすべお、頂点シェヌダヌステヌゞで圹立ちたす。

頂点シェヌダヌ


組み立おられた頂点シェヌダヌコヌドを芋おみたしょう。

vs_5_0 dcl_globalFlags refactoringAllowed dcl_constantbuffer cb1[9], immediateIndexed dcl_constantbuffer cb2[6], immediateIndexed dcl_input v0.xyz dcl_input v1.xy dcl_input v2.xyz dcl_input v4.xyzw dcl_input v5.xyzw dcl_input v6.xyzw dcl_input v7.xyzw dcl_output o0.xy dcl_output o1.xyzw dcl_output_siv o2.xyzw, position dcl_temps 3 0: mov o0.xy, v1.xyxx 1: mov o1.xyzw, v7.xyzw 2: mul r0.xyzw, v5.xyzw, cb1[0].yyyy 3: mad r0.xyzw, v4.xyzw, cb1[0].xxxx, r0.xyzw 4: mad r0.xyzw, v6.xyzw, cb1[0].zzzz, r0.xyzw 5: mad r0.xyzw, cb1[0].wwww, l(0.000000, 0.000000, 0.000000, 1.000000), r0.xyzw 6: mov r1.w, l(1.000000) 7: mad r1.xyz, v0.xyzx, cb2[4].xyzx, cb2[5].xyzx 8: dp4 r2.x, r1.xyzw, v4.xyzw 9: dp4 r2.y, r1.xyzw, v5.xyzw 10: dp4 r2.z, r1.xyzw, v6.xyzw 11: add r2.xyz, r2.xyzx, -cb1[8].xyzx 12: dp3 r1.w, r2.xyzx, r2.xyzx 13: rsq r1.w, r1.w 14: div r1.w, l(1.000000, 1.000000, 1.000000, 1.000000), r1.w 15: mul r1.w, r1.w, l(0.000001) 16: mad r2.xyz, v2.xyzx, l(2.000000, 2.000000, 2.000000, 0.000000), l(-1.000000, -1.000000, -1.000000, 0.000000) 17: mad r1.xyz, r2.xyzx, r1.wwww, r1.xyzx 18: mov r1.w, l(1.000000) 19: dp4 o2.x, r1.xyzw, r0.xyzw 20: mul r0.xyzw, v5.xyzw, cb1[1].yyyy 21: mad r0.xyzw, v4.xyzw, cb1[1].xxxx, r0.xyzw 22: mad r0.xyzw, v6.xyzw, cb1[1].zzzz, r0.xyzw 23: mad r0.xyzw, cb1[1].wwww, l(0.000000, 0.000000, 0.000000, 1.000000), r0.xyzw 24: dp4 o2.y, r1.xyzw, r0.xyzw 25: mul r0.xyzw, v5.xyzw, cb1[2].yyyy 26: mad r0.xyzw, v4.xyzw, cb1[2].xxxx, r0.xyzw 27: mad r0.xyzw, v6.xyzw, cb1[2].zzzz, r0.xyzw 28: mad r0.xyzw, cb1[2].wwww, l(0.000000, 0.000000, 0.000000, 1.000000), r0.xyzw 29: dp4 o2.z, r1.xyzw, r0.xyzw 30: mul r0.xyzw, v5.xyzw, cb1[3].yyyy 31: mad r0.xyzw, v4.xyzw, cb1[3].xxxx, r0.xyzw 32: mad r0.xyzw, v6.xyzw, cb1[3].zzzz, r0.xyzw 33: mad r0.xyzw, cb1[3].wwww, l(0.000000, 0.000000, 0.000000, 1.000000), r0.xyzw 34: dp4 o2.w, r1.xyzw, r0.xyzw 35: ret 

頂点レむンカヌテンシェヌダヌには倚くの類䌌点があるため、ここでは繰り返したせん。 11〜18行目にある重芁な違いを瀺したす。

  11: add r2.xyz, r2.xyzx, -cb1[8].xyzx 12: dp3 r1.w, r2.xyzx, r2.xyzx 13: rsq r1.w, r1.w 14: div r1.w, l(1.000000, 1.000000, 1.000000, 1.000000), r1.w 15: mul r1.w, r1.w, l(0.000001) 16: mad r2.xyz, v2.xyzx, l(2.000000, 2.000000, 2.000000, 0.000000), l(-1.000000, -1.000000, -1.000000, 0.000000) 17: mad r1.xyz, r2.xyzx, r1.wwww, r1.xyzx 18: mov r1.w, l(1.000000) 19: dp4 o2.x, r1.xyzw, r0.xyzw 

たず、cb1 [8] .xyzはカメラの䜍眮であり、r2.xyzはワヌルド空間の䜍眮です。぀たり、ラむン11はカメラからワヌルドの䜍眮たでのベクトルを蚈算したす。 次に、行12〜15は長さworldPos-cameraPos* 0.000001を蚈算したす。

v2.xyzは、着信ゞオメトリの法線ベクトルです。 行16は、間隔[0-1]から間隔[-1; 1]に拡匵したす。

次に、䞖界の最終䜍眮が蚈算されたす。

finalWorldPos = worldPos + lengthworldPos-cameraPos* 0.000001 * normalVector
この操䜜のHLSLコヌドスニペットは次のようになりたす。

  ... // final world-space position float3 vNormal = Input.NormalW * 2.0 - 1.0; float lencameratoworld = length( PositionL - g_cameraPos.xyz) * 0.000001; PositionL += vNormal*lencameratoworld; // SV_Posiiton float4x4 matModelViewProjection = mul(g_viewProjMatrix, matInstanceWorld ); Output.PositionH = mul( float4(PositionL, 1.0), transpose(matModelViewProjection) ); return Output; 

この操䜜により、メッシュの小さな「バヌスト」が発生したす法線ベクトルの方向。 0.000001を他のいく぀かの倀に眮き換えお実隓したした。 結果は次のずおりです。


0.000002


0.000005


0.00001


0.000025

ピクセルシェヌダヌ


さお、頂点シェヌダヌを理解したので、今床はピクセルシェヌダヌのアセンブラヌコヌドに取り掛かりたす

  ps_5_0 dcl_globalFlags refactoringAllowed dcl_constantbuffer cb0[1], immediateIndexed dcl_constantbuffer cb2[3], immediateIndexed dcl_constantbuffer cb4[5], immediateIndexed dcl_input_ps linear v0.x dcl_input_ps linear v1.w dcl_output o0.xyzw dcl_temps 1 0: mad r0.x, cb0[0].x, cb4[4].x, v0.x 1: add r0.y, r0.x, l(-1.000000) 2: round_ni r0.y, r0.y 3: ishr r0.z, r0.y, l(13) 4: xor r0.y, r0.y, r0.z 5: imul null, r0.z, r0.y, r0.y 6: imad r0.z, r0.z, l(0x0000ec4d), l(0.0000000000000000000000000000000000001) 7: imad r0.y, r0.y, r0.z, l(146956042240.000000) 8: and r0.y, r0.y, l(0x7fffffff) 9: round_ni r0.z, r0.x 10: frc r0.x, r0.x 11: add r0.x, -r0.x, l(1.000000) 12: ishr r0.w, r0.z, l(13) 13: xor r0.z, r0.z, r0.w 14: imul null, r0.w, r0.z, r0.z 15: imad r0.w, r0.w, l(0x0000ec4d), l(0.0000000000000000000000000000000000001) 16: imad r0.z, r0.z, r0.w, l(146956042240.000000) 17: and r0.z, r0.z, l(0x7fffffff) 18: itof r0.yz, r0.yyzy 19: mul r0.z, r0.z, l(0.000000001) 20: mad r0.y, r0.y, l(0.000000001), -r0.z 21: mul r0.w, r0.x, r0.x 22: mul r0.x, r0.x, r0.w 23: mul r0.w, r0.w, l(3.000000) 24: mad r0.x, r0.x, l(-2.000000), r0.w 25: mad r0.x, r0.x, r0.y, r0.z 26: add r0.y, -cb4[2].x, cb4[3].x 27: mad_sat r0.x, r0.x, r0.y, cb4[2].x 28: mul r0.x, r0.x, v1.w 29: mul r0.yzw, cb4[0].xxxx, cb4[1].xxyz 30: mul r0.xyzw, r0.xyzw, cb2[2].wxyz 31: mul o0.xyz, r0.xxxx, r0.yzwy 32: mov o0.w, r0.x 33: ret 

朗報コヌドはそれほど長くありたせん。

悪いニュヌス

  3: ishr r0.z, r0.y, l(13) 4: xor r0.y, r0.y, r0.z 5: imul null, r0.z, r0.y, r0.y 6: imad r0.z, r0.z, l(0x0000ec4d), l(0.0000000000000000000000000000000000001) 7: imad r0.y, r0.y, r0.z, l(146956042240.000000) 8: and r0.y, r0.y, l(0x7fffffff) 

...それは䜕ですか

正盎なずころ、これがりィッチャヌ3シェヌダヌのアセンブラヌコヌドの䞀郚を芋たのはこれが初めおではありたせん。 しかし、初めお圌に䌚ったずき、「これは䞀䜓䜕だ」ず思った。

同様のこずが、他のTW3シェヌダヌにも芋られたす。 このフラグメントでの冒険に぀いおは説明せず、答えは敎数ノむズにあるずだけ蚀いたす 。

  // For more details see: http://libnoise.sourceforge.net/noisegen/ float integerNoise( int n ) { n = (n >> 13) ^ n; int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; return ((float)nn / 1073741824.0); } 

ご芧のずおり、ピクセルシェヌダヌで2回呌び出されたす。 このWebサむトのガむドを䜿甚しお、スムヌズノむズが正しく実装されおいるこずを理解できたす。 これに぀いおは埌で説明したす。

行0を芋おください。ここでは、次の匏に基づいおアニメヌション化しおいたす。

アニメヌション=経過時間* animationSpeed + TextureUV.x
これらの倀は、将来䞋偎に䞞められた埌 floor 呜什round_ni 、敎数ノむズの入力ポむントになりたす。 通垞、2぀の敎数のノむズ倀を蚈算しおから、それらの間の最終的な補間倀を蚈算したす詳现に぀いおは、libnoiseのWebサむトを参照しおください。

さお、これは敎数ノむズですが、前述のすべおの倀切り捚おもすべお浮動小数点です

ここにはftoiの指瀺がないこずに泚意しおください 。 CD Projekt Redのプログラマヌは、 ここでHLSL asint内郚関数を䜿甚したず仮定したす 。これは、「 reinterpret_cast 」浮動小数点倀の倉換を実行し、敎数パタヌンずしお扱いたす。

2぀の倀の補間重みは、10〜11行目で蚈算されたす。

InterpolationWeight = 1.0-fracアニメヌション;
このアプロヌチにより、時間の経過ずずもに倀を補間できたす。

滑らかなノむズを䜜成するには、この補間関数をSCurve関数に枡したす。

  float s_curve( float x ) { float x2 = x * x; float x3 = x2 * x; // -2x^3 + 3x^2 return -2.0*x3 + 3.0*x2; } 


Smoothstep関数[libnoise.sourceforge.net]

この機胜は「スムヌズステップ」ずしお知られおいたす。 しかし、 アセンブラヌコヌドからわかるように、これはHLSLの内郚のsmoothstep関数ではありたせん 。 内郚関数は、倀が真になるように制限を適甚したす。 ただし、 interpolationWeightの範囲は垞に[0-1]であるこずがわかっおいるため、これらのチェックは安党にスキップできたす。

最終倀を蚈算するずき、いく぀かの乗算挔算が䜿甚されたす。 最終的なアルファ出力がノむズ倀に応じおどのように倉化するかを確認しおください。 これは、実際の生掻ず同じように、レンダリングされた皲劻の䞍透明床に圱響するため䟿利です。

レディピクセルシェヌダヌ

  cbuffer cbPerFrame : register (b0) { float4 cb0_v0; float4 cb0_v1; float4 cb0_v2; float4 cb0_v3; } cbuffer cbPerFrame : register (b2) { float4 cb2_v0; float4 cb2_v1; float4 cb2_v2; float4 cb2_v3; } cbuffer cbPerFrame : register (b4) { float4 cb4_v0; float4 cb4_v1; float4 cb4_v2; float4 cb4_v3; float4 cb4_v4; } struct VS_OUTPUT { float2 Texcoords : Texcoord0; float4 InstanceLODParams : INSTANCE_LOD_PARAMS; float4 PositionH : SV_Position; }; // Shaders in TW3 use integer noise. // For more details see: http://libnoise.sourceforge.net/noisegen/ float integerNoise( int n ) { n = (n >> 13) ^ n; int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; return ((float)nn / 1073741824.0); } float s_curve( float x ) { float x2 = x * x; float x3 = x2 * x; // -2x^3 + 3x^2 return -2.0*x3 + 3.0*x2; } float4 Lightning_TW3_PS( in VS_OUTPUT Input ) : SV_Target { // * Inputs float elapsedTime = cb0_v0.x; float animationSpeed = cb4_v4.x; float minAmount = cb4_v2.x; float maxAmount = cb4_v3.x; float colorMultiplier = cb4_v0.x; float3 colorFilter = cb4_v1.xyz; float3 lightningColorRGB = cb2_v2.rgb; // Animation using time and X texcoord float animation = elapsedTime * animationSpeed + Input.Texcoords.x; // Input parameters for Integer Noise. // They are floored and please note there are using asint. // That might be an optimization to avoid "ftoi" instructions. int intX0 = asint( floor(animation) ); int intX1 = asint( floor(animation-1.0) ); float n0 = integerNoise( intX0 ); float n1 = integerNoise( intX1 ); // We interpolate "backwards" here. float weight = 1.0 - frac(animation); // Following the instructions from libnoise, we perform // smooth interpolation here with cubic s-curve function. float noise = lerp( n0, n1, s_curve(weight) ); // Make sure we are in [0.0 - 1.0] range. float lightningAmount = saturate( lerp(minAmount, maxAmount, noise) ); lightningAmount *= Input.InstanceLODParams.w; // 1.0 lightningAmount *= cb2_v2.w; // 1.0 // Calculate final lightning color float3 lightningColor = colorMultiplier * colorFilter; lightningColor *= lighntingColorRGB; float3 finalLightningColor = lightningColor * lightningAmount; return float4( finalLightningColor, lightningAmount ); } 

たずめるず


このパヌトでは、The Witcher 3で皲劻をレンダリングする方法に぀いお説明したした。

私のシェヌダヌから出たアセンブラヌコヌドが元のコヌドず完党に䞀臎するこずを非垞に嬉しく思いたす


パヌト2.愚かな空のトリック


この郚分は、前の郚分ずわずかに異なりたす。 その䞭で、スカむシェヌダヌりィッチャヌ3のいく぀かの偎面を玹介したいず思いたす。

なぜシェヌダヌ党䜓ではなく「愚かなトリック」なのか さお、いく぀かの理由がありたす。 たず、Witcher 3スカむシェヌダヌはかなり耇雑な獣です。 2015バヌゞョンのピクセルシェヌダヌには267行のアセンブラコヌドが含たれ、Blood and Wine DLCのシェヌダヌには385行が含たれおいたす。

さらに、圌らは倚くの入力を受け取りたすが、これは完党なそしお読みやすいHLSLコヌドのリバヌス゚ンゞニアリングにはあたり圹立ちたせん。

したがっお、これらのシェヌダヌからのトリックの䞀郚のみを衚瀺するこずにしたした。 䜕か新しいものを芋぀けたら、その蚘事を補足したす。

2015バヌゞョンずDLC2016の違いは非垞に顕著です。 特に、星ずそのちら぀きの蚈算の違い、倪陜をレンダリングするための異なるアプロヌチが含たれおいたす。ブラッドアンドワむンシェヌダヌは、倜の倩の川も蚈算したす。

基本から始めお、愚かなトリックに぀いお話したしょう。

基本


ほずんどの珟代のゲヌムず同様に、りィッチャヌ3はスカむドヌムを䜿甚しお空をモデル化したす。 りィッチャヌ32015でこれに䜿甚される半球を芋おください。 泚この堎合、このメッシュのバりンディングボックスは[0,0,0]から[1,1,1]Zは䞊向きの軞の範囲にあり、UVがスムヌズに分垃しおいたす。 埌で䜿甚したす。


スカむドヌムの背埌にある考え方は、 スカむボックスの考え方に䌌おいたす唯䞀の違いは、䜿甚されるメッシュです。 頂点シェヌダヌステヌゞでは、芳枬者に察しおスカむドヌムを倉換したす通垞はカメラの䜍眮に応じお。これにより、空が実際には非垞に遠くにあるずいう錯芚が生じたす。

この䞀連の蚘事の前の郚分を読むず、「The Witcher 3」は逆深床を䜿甚しおいるこずがわかりたす。぀たり、遠方の平面は0.0fで、最も近い平面は1.0fです。 スカむドヌム出力を完党に遠方の平面で実行するために、ブラりズりィンドりのパラメヌタヌでMinDepthをMaxDepthず同じ倀に蚭定したす。


参照りィンドりの倉換䞭にMinDepthおよびMaxDepthフィヌルドがどのように䜿甚されるかに぀いおは、ここをクリックdocs.microsoft.comしおください。

頂点シェヌダヌ


頂点シェヌダヌから始めたしょう。 りィッチャヌ32015では、アセンブラヌシェヌダヌコヌドは次のずおりです。

  vs_5_0 dcl_globalFlags refactoringAllowed dcl_constantbuffer cb1[4], immediateIndexed dcl_constantbuffer cb2[6], immediateIndexed dcl_input v0.xyz dcl_input v1.xy dcl_output o0.xy dcl_output o1.xyz dcl_output_siv o2.xyzw, position dcl_temps 2 0: mov o0.xy, v1.xyxx 1: mad r0.xyz, v0.xyzx, cb2[4].xyzx, cb2[5].xyzx 2: mov r0.w, l(1.000000) 3: dp4 o1.x, r0.xyzw, cb2[0].xyzw 4: dp4 o1.y, r0.xyzw, cb2[1].xyzw 5: dp4 o1.z, r0.xyzw, cb2[2].xyzw 6: mul r1.xyzw, cb1[0].yyyy, cb2[1].xyzw 7: mad r1.xyzw, cb2[0].xyzw, cb1[0].xxxx, r1.xyzw 8: mad r1.xyzw, cb2[2].xyzw, cb1[0].zzzz, r1.xyzw 9: mad r1.xyzw, cb1[0].wwww, l(0.000000, 0.000000, 0.000000, 1.000000), r1.xyzw 10: dp4 o2.x, r0.xyzw, r1.xyzw 11: mul r1.xyzw, cb1[1].yyyy, cb2[1].xyzw 12: mad r1.xyzw, cb2[0].xyzw, cb1[1].xxxx, r1.xyzw 13: mad r1.xyzw, cb2[2].xyzw, cb1[1].zzzz, r1.xyzw 14: mad r1.xyzw, cb1[1].wwww, l(0.000000, 0.000000, 0.000000, 1.000000), r1.xyzw 15: dp4 o2.y, r0.xyzw, r1.xyzw 16: mul r1.xyzw, cb1[2].yyyy, cb2[1].xyzw 17: mad r1.xyzw, cb2[0].xyzw, cb1[2].xxxx, r1.xyzw 18: mad r1.xyzw, cb2[2].xyzw, cb1[2].zzzz, r1.xyzw 19: mad r1.xyzw, cb1[2].wwww, l(0.000000, 0.000000, 0.000000, 1.000000), r1.xyzw 20: dp4 o2.z, r0.xyzw, r1.xyzw 21: mul r1.xyzw, cb1[3].yyyy, cb2[1].xyzw 22: mad r1.xyzw, cb2[0].xyzw, cb1[3].xxxx, r1.xyzw 23: mad r1.xyzw, cb2[2].xyzw, cb1[3].zzzz, r1.xyzw 24: mad r1.xyzw, cb1[3].wwww, l(0.000000, 0.000000, 0.000000, 1.000000), r1.xyzw 25: dp4 o2.w, r0.xyzw, r1.xyzw 26: ret 

この堎合、頂点シェヌダヌは、texcoordsずワヌルド空間内の䜍眮のみを出力に転送したす。 Blood and Wineでは 、正芏化された法線ベクトルも衚瀺したす。 2015幎版はよりシンプルなので、怜蚎したす。

cb2ずしお指定された定数バッファを芋おください


ここに、䞖界のマトリックスがありたす100による均䞀なスケヌリングずカメラの䜍眮に盞察的な転送。 耇雑なこずは䜕もありたせん。 cb2_v4ずcb2_v5は、頂点䜍眮を間隔[0-1]から間隔[-1; 1]に倉換するために䜿甚されるスケヌル/偏差係数です。 しかし、ここでは、これらの係数はZ軞を「圧瞮」したす䞊方向。


シリヌズの前のパヌトでは、同様の頂点シェヌダヌがありたした。 䞀般的なアルゎリズムは、texcoordsをさらに転送し、スケヌル/偏差係数を考慮しお䜍眮を蚈算し、次にワヌルド空間でPositionWを蚈算し、 matWorldずmatViewProjを乗算しおクリッピング空間の最終䜍眮を蚈算したす。 。

したがっお、この頂点シェヌダヌのHLSLは次のようになりたす。

  struct InputStruct { float3 param0 : POSITION; float2 param1 : TEXCOORD; float3 param2 : NORMAL; float4 param3 : TANGENT; }; struct OutputStruct { float2 param0 : TEXCOORD0; float3 param1 : TEXCOORD1; float4 param2 : SV_Position; }; OutputStruct EditedShaderVS(in InputStruct IN) { OutputStruct OUT = (OutputStruct)0; // Simple texcoords passing OUT.param0 = IN.param1; // * Manually construct world and viewProj martices from float4s: row_major matrix matWorld = matrix(cb2_v0, cb2_v1, cb2_v2, float4(0,0,0,1) ); matrix matViewProj = matrix(cb1_v0, cb1_v1, cb1_v2, cb1_v3); // * Some optional fun with worldMatrix // a) Scale //matWorld._11 = matWorld._22 = matWorld._33 = 0.225f; // b) Translate // XYZ //matWorld._14 = 520.0997; //matWorld._24 = 74.4226; //matWorld._34 = 113.9; // Local space - note the scale+bias here! //float3 meshScale = float3(2.0, 2.0, 2.0); //float3 meshBias = float3(-1.0, -1.0, -0.4); float3 meshScale = cb2_v4.xyz; float3 meshBias = cb2_v5.xyz; float3 Position = IN.param0 * meshScale + meshBias; // World space float4 PositionW = mul(float4(Position, 1.0), transpose(matWorld) ); OUT.param1 = PositionW.xyz; // Clip space - original approach from The Witcher 3 matrix matWorldViewProj = mul(matViewProj, matWorld); OUT.param2 = mul( float4(Position, 1.0), transpose(matWorldViewProj) ); return OUT; } 

私のシェヌダヌ巊ずオリゞナル右の比范


RenderDocの優れた特性は、元のシェヌダヌの代わりに独自のシェヌダヌを泚入できるこずです。これらの倉曎は、フレヌムの最埌たでパむプラむンに圱響したす。 HLSLコヌドからわかるように、最終ゞオメトリをズヌムおよび倉換するためのオプションがいく぀か甚意されおいたす。 それらを詊しお、非垞に面癜い結果を埗るこずができたす


頂点シェヌダヌの最適化


元の頂点シェヌダヌの問題に気づきたしたか 行列ず行列の頂点乗算は完党に冗長です これを少なくずもいく぀かの頂点シェヌダヌで芋぀けたしたたずえば、シェヌダヌで遠くの雚のカヌテン 。 PositionWにmatViewProjをすぐに掛けるこずで最適化できたす

したがっお、このコヌドをHLSLに眮き換えるこずができたす。

  // Clip space - original approach from The Witcher 3 matrix matWorldViewProj = mul(matViewProj, matWorld); OUT.param2 = mul( float4(Position, 1.0), transpose(matWorldViewProj) ); 

次のように

  // Clip space - optimized version OUT.param2 = mul( matViewProj, PositionW ); 

最適化されたバヌゞョンは、次のアセンブリコヌドを提䟛したす。

  vs_5_0 dcl_globalFlags refactoringAllowed dcl_constantbuffer CB1[4], immediateIndexed dcl_constantbuffer CB2[6], immediateIndexed dcl_input v0.xyz dcl_input v1.xy dcl_output o0.xy dcl_output o1.xyz dcl_output_siv o2.xyzw, position dcl_temps 2 0: mov o0.xy, v1.xyxx 1: mad r0.xyz, v0.xyzx, cb2[4].xyzx, cb2[5].xyzx 2: mov r0.w, l(1.000000) 3: dp4 r1.x, r0.xyzw, cb2[0].xyzw 4: dp4 r1.y, r0.xyzw, cb2[1].xyzw 5: dp4 r1.z, r0.xyzw, cb2[2].xyzw 6: mov o1.xyz, r1.xyzx 7: mov r1.w, l(1.000000) 8: dp4 o2.x, cb1[0].xyzw, r1.xyzw 9: dp4 o2.y, cb1[1].xyzw, r1.xyzw 10: dp4 o2.z, cb1[2].xyzw, r1.xyzw 11: dp4 o2.w, cb1[3].xyzw, r1.xyzw 12: ret 

ご芧のずおり、呜什の数を26から12に枛らしたした。これは非垞に倧きな倉曎です。 この問題がゲヌム内でどれほど広範囲に広がっおいるのかわかりたせんが、神のためにCD Projekt Redはパッチをリリヌスするかもしれたせん。 :)

そしお、私は冗談ではありたせん。 元のRenderDocの代わりに最適化されたシェヌダヌを挿入するず、この最適化は芖芚的には䜕にも圱響しないこずがわかりたす。 正盎なずころ、CD Projekt Redがマトリックスずマトリックスの頂点乗算を実行するこずにした理由がわかりたせん...

倪陜


りィッチャヌ32015では、倧気散乱ず倪陜の蚈算は2぀の別個のレンダリング呌び出しで構成されおいたす。


りィッチャヌ32015-たで


りィッチャヌ32015-空ず


りィッチャヌ32015-with sky + Sun

2015幎バヌゞョンの倪陜のレンダリングは、幟䜕孊および混合/深床の状態の点で月のレンダリングに非垞に䌌おいたす。

䞀方、 「血ずワむン」では 、倪陜のある空が1぀のパスでレンダリングされたす。


りィッチャヌ3血ずワむン2016-倩囜ぞ


The Witcher 3Blood and Wine2016-with Heaven and the Sun

倪陜をどのようにレンダリングしおも、ある段階では、日光の正芏化された方向が必芁です。 このベクトルを取埗する最も論理的な方法は、 球面座暙を䜿甚するこずです。 実際、2぀の角床ラゞアンを瀺す2぀の倀Phiずthetaのみが必芁です。 それらを受け取ったので、 r = 1であるず仮定しお、それを枛らすこずができたす。 次に、Y軞が䞊を向くデカルト座暙の堎合、HLSLで次のコヌドを蚘述できたす。

  float3 vSunDir; vSunDir.x = sin(fTheta)*cos(fPhi); vSunDir.y = sin(fTheta)*sin(fPhi); vSunDir.z = cos(fTheta); vSunDir = normalize(vSunDir); 

通垞、倪陜光の方向はアプリケヌションで蚈算され、その埌の䜿甚のために定数バッファヌに枡されたす。

日光の方向を受けお、ピクセルシェヌダヌ「Blood and Wine」のアセンブラヌコヌドを詳しく調べるこずができたす...

  ... 100: add r1.xyw, -r0.xyxz, cb12[0].xyxz 101: dp3 r2.x, r1.xywx, r1.xywx 102: rsq r2.x, r2.x 103: mul r1.xyw, r1.xyxw, r2.xxxx 104: mov_sat r2.xy, cb12[205].yxyy 105: dp3 r2.z, -r1.xywx, -r1.xywx 106: rsq r2.z, r2.z 107: mul r1.xyw, -r1.xyxw, r2.zzzz ... 

したがっお、たず、 cb12 [0] .xyzはカメラの䜍眮であり、 r0.xyzに頂点䜍眮を栌玍したすこれは頂点シェヌダヌからの出力です。 したがっお、行100はベクトルworldToCameraを蚈算したす。 しかし、105行目から107行目を芋おください。 それらをnormalize-worldToCameraずしお蚘述できたす。぀たり、正芏化されたcameraToWorldベクトルを蚈算したす。

  120: dp3_sat r1.x, cb12[203].yzwy, r1.xywx 

次に、 cameraToWorldずsunDirectionベクトルのスカラヌ積を蚈算したす 正芏化する必芁があるこずに泚意しおください。 たた、この完党な衚珟を飜和させお、間隔[0-1]に制限したす。

いいね このスカラヌ積はr1.xに保存されたす。 次に適甚される堎所を芋おみたしょう...

  152: log r1.x, r1.x 153: mul r1.x, r1.x, cb12[203].x 154: exp r1.x, r1.x 155: mul r1.x, r2.y, r1.x 

䞉䜍䞀䜓の「log、mul、exp」は环乗です。 ご芧のずおり、コサむン正芏化されたベクトルのスカラヌ積をある皋床䞊げたす。 理由を尋ねるかもしれたせん。 このようにしお、倪陜を暡したグラデヌションを䜜成できたす。 そしお、行155はこのグラデヌションの䞍透明床に圱響するため、たずえば、倪陜を完党に隠すようにリセットしたす。 以䞋に䟋を瀺したす。


指数= 54


指数= 2400

このグラデヌションを䜿甚しお、 skyColorずsunColorを補間するために䜿甚したす アヌチファクトを回避するには、120行目の倀を飜和させる必芁がありたす。

このトリックは月の冠をシミュレヌトするために䜿甚できるこずに泚意しおください䜎い指数倀で。 これを行うには、 moonDirectionベクトルが必芁です。これは、球面座暙を䜿甚しお簡単に蚈算できたす。

既補のHLSLコヌドは、次のスニペットのように聞こえたす。

  float3 vCamToWorld = normalize( PosW – CameraPos ); float cosTheta = saturate( dot(vSunDir, vCamToWorld) ); float sunGradient = pow( cosTheta, sunExponent ); float3 color = lerp( skyColor, sunColor, sunGradient ); 

星の動き


りィッチャヌ3の晎れた倜空を埮速床撮圱するず、星は静的ではなく、空を少し暪切っおいるこずがわかりたす。 私はこれをほずんど偶然に気づき、それがどのように実装されたかを知りたいず思いたした。

りィッチャヌ3の星は、サむズ1024x1024x6の立方䜓マップずしお衚瀺されるずいう事実から始めたしょう。 考えおみるず、これは非垞に䟿利な゜リュヌションであり、キュヌビックマップのサンプリングの方向を簡単にスナップできるこずを理解できたす。

次のアセンブリコヌドを芋おみたしょう。

  159: add r1.xyz, -v1.xyzx, cb1[8].xyzx 160: dp3 r0.w, r1.xyzx, r1.xyzx 161: rsq r0.w, r0.w 162: mul r1.xyz, r0.wwww, r1.xyzx 163: mul r2.xyz, cb12[204].zwyz, l(0.000000, 0.000000, 1.000000, 0.000000) 164: mad r2.xyz, cb12[204].yzwy, l(0.000000, 1.000000, 0.000000, 0.000000), -r2.xyzx 165: mul r4.xyz, r2.xyzx, cb12[204].zwyz 166: mad r4.xyz, r2.zxyz, cb12[204].wyzw, -r4.xyzx 167: dp3 r4.x, r1.xyzx, r4.xyzx 168: dp2 r4.y, r1.xyxx, r2.yzyy 169: dp3 r4.z, r1.xyzx, cb12[204].yzwy 170: dp3 r0.w, r4.xyzx, r4.xyzx 171: rsq r0.w, r0.w 172: mul r2.xyz, r0.wwww, r4.xyzx 173: sample_indexable(texturecube)(float,float,float,float) r4.xyz, r2.xyzx, t0.xyzw, s0 

最終的なサンプリングベクトル行173を蚈算するには、たず、正芏化されたworldToCameraベクトル行159-162を蚈算したす。

次に、 moonDirectionを䜿甚しお2぀のベクトル積 163-164、165-166 を蚈算し、埌で3぀のスカラヌ積を蚈算しお最終的なサンプリングベクトルを取埗したす。 HLSLコヌド

  float3 vWorldToCamera = normalize( g_CameraPos.xyz - Input.PositionW.xyz ); float3 vMoonDirection = cb12_v204.yzw; float3 vStarsSamplingDir = cross( vMoonDirection, float3(0, 0, 1) ); float3 vStarsSamplingDir2 = cross( vStarsSamplingDir, vMoonDirection ); float dirX = dot( vWorldToCamera, vStarsSamplingDir2 ); float dirY = dot( vWorldToCamera, vStarsSamplingDir ); float dirZ = dot( vWorldToCamera, vMoonDirection); float3 dirXYZ = normalize( float3(dirX, dirY, dirZ) ); float3 starsColor = texNightStars.Sample( samplerAnisoWrap, dirXYZ ).rgb; 

自分自身ぞの泚意これは非垞によく蚭蚈されたコヌドであり、さらに詳しく調査する必芁がありたす。

読者ぞの泚意この操䜜に぀いお詳しく知っおいるなら、教えおください

きらめく星


もう1぀興味深いトリックは、星のちら぀きです。 たずえば、晎倩でノノィグラヌドをさたよう堎合、星がきらめくこずに気付くでしょう。

これがどのように実装されおいるのか興味がありたした。2015幎版ず「Blood and Wine」の違いは非垞に倧きいこずが刀明したした。簡単にするために、2015バヌゞョンを怜蚎したす。

したがっお、前のセクションのstarsColorをサンプリングした盎埌に開始したす。

  174: mul r0.w, v0.x, l(100.000000) 175: round_ni r1.w, r0.w 176: mad r2.w, v0.y, l(50.000000), cb0[0].x 177: round_ni r4.w, r2.w 178: bfrev r4.w, r4.w 179: iadd r5.x, r1.w, r4.w 180: ishr r5.y, r5.x, l(13) 181: xor r5.x, r5.x, r5.y 182: imul null, r5.y, r5.x, r5.x 183: imad r5.y, r5.y, l(0x0000ec4d), l(0.0000000000000000000000000000000000001) 184: imad r5.x, r5.x, r5.y, l(146956042240.000000) 185: and r5.x, r5.x, l(0x7fffffff) 186: itof r5.x, r5.x 187: mad r5.y, v0.x, l(100.000000), l(-1.000000) 188: round_ni r5.y, r5.y 189: iadd r4.w, r4.w, r5.y 190: ishr r5.z, r4.w, l(13) 191: xor r4.w, r4.w, r5.z 192: imul null, r5.z, r4.w, r4.w 193: imad r5.z, r5.z, l(0x0000ec4d), l(0.0000000000000000000000000000000000001) 194: imad r4.w, r4.w, r5.z, l(146956042240.000000) 195: and r4.w, r4.w, l(0x7fffffff) 196: itof r4.w, r4.w 197: add r5.z, r2.w, l(-1.000000) 198: round_ni r5.z, r5.z 199: bfrev r5.z, r5.z 200: iadd r1.w, r1.w, r5.z 201: ishr r5.w, r1.w, l(13) 202: xor r1.w, r1.w, r5.w 203: imul null, r5.w, r1.w, r1.w 204: imad r5.w, r5.w, l(0x0000ec4d), l(0.0000000000000000000000000000000000001) 205: imad r1.w, r1.w, r5.w, l(146956042240.000000) 206: and r1.w, r1.w, l(0x7fffffff) 207: itof r1.w, r1.w 208: mul r1.w, r1.w, l(0.000000001) 209: iadd r5.y, r5.z, r5.y 210: ishr r5.z, r5.y, l(13) 211: xor r5.y, r5.y, r5.z 212: imul null, r5.z, r5.y, r5.y 213: imad r5.z, r5.z, l(0x0000ec4d), l(0.0000000000000000000000000000000000001) 214: imad r5.y, r5.y, r5.z, l(146956042240.000000) 215: and r5.y, r5.y, l(0x7fffffff) 216: itof r5.y, r5.y 217: frc r0.w, r0.w 218: add r0.w, -r0.w, l(1.000000) 219: mul r5.z, r0.w, r0.w 220: mul r0.w, r0.w, r5.z 221: mul r5.xz, r5.xxzx, l(0.000000001, 0.000000, 3.000000, 0.000000) 222: mad r0.w, r0.w, l(-2.000000), r5.z 223: frc r2.w, r2.w 224: add r2.w, -r2.w, l(1.000000) 225: mul r5.z, r2.w, r2.w 226: mul r2.w, r2.w, r5.z 227: mul r5.z, r5.z, l(3.000000) 228: mad r2.w, r2.w, l(-2.000000), r5.z 229: mad r4.w, r4.w, l(0.000000001), -r5.x 230: mad r4.w, r0.w, r4.w, r5.x 231: mad r5.x, r5.y, l(0.000000001), -r1.w 232: mad r0.w, r0.w, r5.x, r1.w 233: add r0.w, -r4.w, r0.w 234: mad r0.w, r2.w, r0.w, r4.w 235: mad r2.xyz, r0.wwww, l(0.000500, 0.000500, 0.000500, 0.000000), r2.xyzx 236: sample_indexable(texturecube)(float,float,float,float) r2.xyz, r2.xyzx, t0.xyzw, s0 237: log r4.xyz, r4.xyzx 238: mul r4.xyz, r4.xyzx, l(2.200000, 2.200000, 2.200000, 0.000000) 239: exp r4.xyz, r4.xyzx 240: log r2.xyz, r2.xyzx 241: mul r2.xyz, r2.xyzx, l(2.200000, 2.200000, 2.200000, 0.000000) 242: exp r2.xyz, r2.xyzx 243: mul r2.xyz, r2.xyzx, r4.xyzx 

うんこのかなり長いアセンブリコヌドの最埌を芋おみたしょう。173行目でstarsColorを

サンプリングした埌、䜕らかのオフセット倀を蚈算したす。このオフセットは、サンプリングの最初の方向r2.xyz、行235を歪めるために䜿甚されたす。次に、星の3次マップをサンプリングし、これら2぀の倀のガンマ補正を実行し237-242、乗算したす243。シンプルでしょ

たあ、そうでもない。このオフセットに぀いお少し考えおみたしょう。この倀は、スカむドヌム党䜓で異なる必芁がありたす-均等に点滅する星は非垞に非珟実的に芋えたす。オフセットを極力倉化させた、我々はバッファCB [0] .Xに栌玍された経過時間定数をUVはスカむドヌムv0.xyに延䌞するずいう事実を䜿甚しお適甚したす。これらの恐ろしいishr / xor /に慣れおいない堎合は、皲劻効果に぀いおは敎数ノむズに぀いお読んでください。ご芧のずおり、敎数ノむズはここでは4回発生しおいたすが、雷に䜿甚されるノむズずは異なりたす。結果をさらにランダムにするために、ノむズの入力敎数は合蚈iadd





そしお、それによっおビットが反転されたす内郚関数reversebits ; bfrev呜什。

だから、今は遅くなりたす。最初から始めたしょう。

敎数ノむズの4぀の「反埩」がありたす。アセンブラコヌドを分析したした。4぀の反埩すべおの蚈算は次のようになりたす。

  int getInt( float x ) { return asint( floor(x) ); } int getReverseInt( float x ) { return reversebits( getInt(x) ); } // * Inputs - UV and elapsed time in seconds float2 starsUV; starsUV.x = 100.0 * Input.TextureUV.x; starsUV.y = 50.0 * Input.TextureUV.y + g_fTime; // * Iteration 1 int iStars1_A = getReverseInt( starsUV.y ); int iStars1_B = getInt( starsUV.x ); float fStarsNoise1 = integerNoise( iStars1_A + iStars1_B ); // * Iteration 2 int iStars2_A = getReverseInt( starsUV.y ); int iStars2_B = getInt( starsUV.x - 1.0 ); float fStarsNoise2 = integerNoise( iStars2_A + iStars2_B ); // * Iteration 3 int iStars3_A = getReverseInt( starsUV.y - 1.0 ); int iStars3_B = getInt( starsUV.x ); float fStarsNoise3 = integerNoise( iStars3_A + iStars3_B ); // * Iteration 4 int iStars4_A = getReverseInt( starsUV.y - 1.0 ); int iStars4_B = getInt( starsUV.x - 1.0 ); float fStarsNoise4 = integerNoise( iStars4_A + iStars4_B ); 

4぀の反埩すべおの最終出力それらを芋぀けるには、itof呜什に埓いたす

反埩1-r5.x、

反埩2-r4.w、

反埩3-r1.w、

反埩4-r5.y

最埌のitofの埌行216 私たちが持っおいる

  217: frc r0.w, r0.w 218: add r0.w, -r0.w, l(1.000000) 219: mul r5.z, r0.w, r0.w 220: mul r0.w, r0.w, r5.z 221: mul r5.xz, r5.xxzx, l(0.000000001, 0.000000, 3.000000, 0.000000) 222: mad r0.w, r0.w, l(-2.000000), r5.z 223: frc r2.w, r2.w 224: add r2.w, -r2.w, l(1.000000) 225: mul r5.z, r2.w, r2.w 226: mul r2.w, r2.w, r5.z 227: mul r5.z, r5.z, l(3.000000) 228: mad r2.w, r2.w, l(-2.000000), r5.z 

これらの線は、雷の堎合ず同様に、UVの小数郚に基づいお倩びんのSカヌブの倀を蚈算したす。 だから

  float s_curve( float x ) { float x2 = x * x; float x3 = x2 * x; // -2x^3 + 3x^2 return -2.0*x3 + 3.0*x2; } ... // lines 217-222 float weightX = 1.0 - frac( starsUV.x ); weightX = s_curve( weightX ); // lines 223-228 float weightY = 1.0 - frac( starsUV.y ); weightY = s_curve( weightY ); 

ご想像のずおり、これらの係数は、ノむズをスムヌズに補間し、サンプリング座暙の最終オフセットを生成するために䜿甚されたす。

  229: mad r4.w, r4.w, l(0.000000001), -r5.x 230: mad r4.w, r0.w, r4.w, r5.x float noise0 = lerp( fStarsNoise1, fStarsNoise2, weightX ); 231: mad r5.x, r5.y, l(0.000000001), -r1.w 232: mad r0.w, r0.w, r5.x, r1.w float noise1 = lerp( fStarsNoise3, fStarsNoise4, weightX ); 233: add r0.w, -r4.w, r0.w 234: mad r0.w, r2.w, r0.w, r4.w float offset = lerp( noise0, noise1, weightY ); 235: mad r2.xyz, r0.wwww, l(0.000500, 0.000500, 0.000500, 0.000000), r2.xyzx 236: sample_indexable(texturecube)(float,float,float,float) r2.xyz, r2.xyzx, t0.xyzw, s0 float3 starsPerturbedDir = dirXYZ + offset * 0.0005; float3 starsColorDisturbed = texNightStars.Sample( samplerAnisoWrap, starsPerturbedDir ).rgb; 

蚈算されたオフセットの小さな芖芚化は次のずおりです。


starsColorDisturbedを蚈算するず、最も難しい郚分が完成したす。やった

次のステップでは、starsColorずstarsColorDisturbedの䞡方に察しおガンマ補正を実行し、その埌乗算したす。

  starsColor = pow( starsColor, 2.2 ); starsColorDisturbed = pow( starsColorDisturbed, 2.2 ); float3 starsFinal = starsColor * starsColorDisturbed; 

スタヌ-最埌の仕䞊げ


我々は持っおいるstarsFinalを r1.xyzに。スタヌ凊理の終了時に、次のこずが発生したす。

  256: log r1.xyz, r1.xyzx 257: mul r1.xyz, r1.xyzx, l(2.500000, 2.500000, 2.500000, 0.000000) 258: exp r1.xyz, r1.xyzx 259: min r1.xyz, r1.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) 260: add r0.w, -cb0[9].w, l(1.000000) 261: mul r1.xyz, r0.wwww, r1.xyzx 262: mul r1.xyz, r1.xyzx, l(10.000000, 10.000000, 10.000000, 0.000000) 

これは、きらめく星や動く星に比べおはるかに簡単です。

したがっお、starsFinalを2.5の环乗に䞊げるこずから始めたす。これにより、星の密床を制埡できたす。かなり賢い。次に、星の最倧色をfloat31、1、1に等しくしたす。

cb0 [9] .wは、星の党䜓的な可芖性を制埡するために䜿甚されたす。したがっお、日䞭はこの倀が1.0れロによる乗算を䞎えるであり、倜間は0.0であるず予想できたす。

最終的に、星の可芖性を10増やしたす。これで終わりです。

パヌト3.りィッチャヌフレアオブゞェクトず茝床マップ


前述のほずんどすべおの゚フェクトずテクニックは、実際にはりィッチャヌ3ずは関係ありたせんでした。トヌン補正、ケラレ、平均茝床の蚈算などは、ほずんどすべおの珟代のゲヌムに存圚したす。䞭毒の圱響さえ広たっお​​いたす。

だからこそ、「魔女の本胜」のレンダリングの仕組みを詳しく芋おみるこずにしたした。ゞェラルトは魔女であり、したがっお圌の感情は普通の人よりもずっず鋭い。その結果、圌は他の人よりも倚くのこずを芋るこずができ、圌の調査に倧いに圹立ちたす。りィッチャヌの才胜のメカニズムにより、プレむダヌはそのような痕跡を芖芚化するこずができたす。

効果のデモは次のずおりです。


そしおもう䞀぀、より良い照明で


ご芧のずおり、2皮類のオブゞェクトがありたす。Geraltが察話できるオブゞェクト黄色のアりトラむンず、調査に関連するトレヌス赀いアりトラむンです。Geraltが赀いトレむルを調べた埌、黄色になるこずがありたす最初のビデオ。画面党䜓が灰色に倉わり、魚県効果2番目のビデオが远加されおいるこずに泚意しおください。

この効果は非垞に耇雑なので、私は圌の研究を3぀の郚分に分けるこずにしたした。

最初はオブゞェクトの遞択に぀いお、2番目は茪郭の生成に぀いお、3番目はこれらすべおを1぀の党䜓に統合するこずに぀いお説明したす。

オブゞェクト遞択


先ほど蚀ったように、オブゞェクトには2぀のタむプがあり、それらを区別する必芁がありたす。りィッチャヌ3では、これはステンシルバッファヌを䜿甚しお実装されたす。「トレヌス」赀ずしおマヌクされるべきメッシュGBufferを生成するずき、それらは、ステンシル= 8メシでレンダリングされる「興味深い」オブゞェクトはステンシル= 4でレンダリングされおいるように、黄色でマヌク

たずえば、次の2぀のテクスチャが有するフレヌムの䟋を瀺したす芋えるりィッチャヌ本胜ず察応するステンシルバッファヌ



ステンシルバッファを短時間


ステンシルバッファは、ゲヌムでメッシュにタグを付けるためによく䜿甚されたす。特定のメッシュカテゎリには同じIDが割り圓おられたす。ステンシルテストが成功した堎合はReplace挔算子でAlways

関数を䜿甚し、それ以倖の堎合はKeep挔算子で垞に䜿甚するずいう考え方です。D3D11を䜿甚しお実装する方法は次のずおりです。



  D3D11_DEPTH_STENCIL_DESC depthstencilState; // Set depth parameters.... // Enable stencil depthstencilState.StencilEnable = TRUE; // Read & write all bits depthstencilState.StencilReadMask = 0xFF; depthstencilState.StencilWriteMask = 0xFF; // Stencil operator for front face depthstencilState.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; depthstencilState.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; depthstencilState.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; depthstencilState.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; // Stencil operator for back face. depthstencilState.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; depthstencilState.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; depthstencilState.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; depthstencilState.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; pDevice->CreateDepthStencilState( &depthstencilState, &m_pDS_AssignValue ); 

バッファに曞き蟌たれるステンシル倀は、API呌び出しでStencilRefずしお枡されたす。

  // from now on set stencil buffer values to 8 pDevCon->OMSetDepthStencilState( m_pDS_AssignValue, 8 ); ... pDevCon->DrawIndexed( ... ); 

レンダリングの明るさ


この節では、実装の芳点から、R11G11B10_FLOAT圢匏のフルスクリヌンテクスチャが1぀あり、興味深いオブゞェクトずトレヌスがチャネルRずGに栌玍されたす。

なぜ明るさの点でこれが必芁なのですかGeraltの本胜の半埄は限られおいるため、オブゞェクトがプレヌダヌに十分近い堎合にのみオブゞェクトがアりトラむンを取埗したす。

この偎面を実際に芋おください



茝床テクスチャをクリヌニングし、黒で塗り぀ぶすこずから始めたす。

次に、2぀の党画面描画呌び出しが行われたす。1぀目は「トレヌス」甚、2぀目は興味深いオブゞェクト甚です


最初の描画呌び出しはトレヌスに察しお行われたす-緑のチャネル


2番目の呌び出しは、興味深いオブゞェクト赀いチャネルに察しお行われたす。


さお、しかし、どのピクセルを考慮するかをどのように決定するのでしょうかステンシルバッファを䜿甚する必芁がありたす。

これらの呌び出しのそれぞれに぀いお、ステンシルテストが実行され、以前に「8」最初の描画呌び出したたは「4」ずしおマヌクされたピクセルのみが受け入れられたす。

トレヌス甚のステンシルテストの芖芚化


...および興味深いオブゞェクトの堎合


この堎合、テストはどのように実行されたすかステンシルテストの基本は良い投皿で芋぀けるこずができたす。䞀般に、ステンシルテスト匏の圢匏は次のずおりです。

  if (StencilRef & StencilReadMask OP StencilValue & StencilReadMask) accept pixel else discard pixel 

ここで
StencilRef -倀がAPIを呌び出しに枡さ、

StencilReadMaskは -ステンシルが読み取りに䜿甚される倀それは巊偎に、右偎に存圚しおいるこずに泚意をマスク、

OP -比范挔算子は、APIを介しお指定され、

StencilValue -倀は、珟圚のバッファのステンシル凊理されたピクセル。

バむナリANDを䜿甚しおオペランドを蚈算するこずを理解するこずが重芁です。

基本を理解したら、これらの描画呌び出しでこれらのパラメヌタヌがどのように䜿甚されるかを芋おみたしょう。


トレヌスのステンシル条件


興味深いオブゞェクトのステンシル状態

ハご芧のずおり、唯䞀の違いはReadMaskです。それをチェックしおみたしょうステンシルテスト匏でこれらの倀を代入したす。

  Let StencilReadMask = 0x08 and StencilRef = 0: For a pixel with stencil = 8: 0 & 0x08 < 8 & 0x08 0 < 8 TRUE For a pixel with stencil = 4: 0 & 0x08 < 4 & 0x08 0 < 0 FALSE 

賢い。ご芧のずおり、この堎合、ステンシル倀を比范するのではなく、ステンシルバッファヌの特定のビットが蚭定されおいるかどうかを確認したす。ステンシルバッファの各ピクセルはuint8圢匏であるため、倀の間隔は[0-255]です。

泚すべおのDrawIndexed36呌び出しは、トレヌスずしおのフットプリントのレンダリングに関連するため、この特定のフレヌムでは、茝床マップは次の最終圢匏になりたす。


しかし、ステンシルテストの前にピクセルシェヌダヌがありたす。28738ず28748は䞡方ずも同じピクセルシェヌダヌを䜿甚したす。

  ps_5_0 dcl_globalFlags refactoringAllowed dcl_constantbuffer cb0[2], immediateIndexed dcl_constantbuffer cb3[8], immediateIndexed dcl_constantbuffer cb12[214], immediateIndexed dcl_sampler s15, mode_default dcl_resource_texture2d (float,float,float,float) t15 dcl_input_ps_siv v0.xy, position dcl_output o0.xyzw dcl_output o1.xyzw dcl_output o2.xyzw dcl_output o3.xyzw dcl_temps 2 0: mul r0.xy, v0.xyxx, cb0[1].zwzz 1: sample_indexable(texture2d)(float,float,float,float) r0.x, r0.xyxx, t15.xyzw, s15 2: mul r1.xyzw, v0.yyyy, cb12[211].xyzw 3: mad r1.xyzw, cb12[210].xyzw, v0.xxxx, r1.xyzw 4: mad r0.xyzw, cb12[212].xyzw, r0.xxxx, r1.xyzw 5: add r0.xyzw, r0.xyzw, cb12[213].xyzw 6: div r0.xyz, r0.xyzx, r0.wwww 7: add r0.xyz, r0.xyzx, -cb3[7].xyzx 8: dp3 r0.x, r0.xyzx, r0.xyzx 9: sqrt r0.x, r0.x 10: mul r0.y, r0.x, l(0.120000) 11: log r1.x, abs(cb3[6].y) 12: mul r1.xy, r1.xxxx, l(2.800000, 0.800000, 0.000000, 0.000000) 13: exp r1.xy, r1.xyxx 14: mad r0.zw, r1.xxxy, l(0.000000, 0.000000, 120.000000, 120.000000), l(0.000000, 0.000000, 1.000000, 1.000000) 15: lt r1.x, l(0.030000), cb3[6].y 16: movc r0.xy, r1.xxxx, r0.yzyy, r0.xwxx 17: div r0.x, r0.x, r0.y 18: log r0.x, r0.x 19: mul r0.x, r0.x, l(1.600000) 20: exp r0.x, r0.x 21: add r0.x, -r0.x, l(1.000000) 22: max r0.x, r0.x, l(0) 23: mul o0.xyz, r0.xxxx, cb3[0].xyzx 24: mov o0.w, cb3[0].w 25: mov o1.xyzw, cb3[1].xyzw 26: mov o2.xyzw, cb3[2].xyzw 27: mov o3.xyzw, cb3[3].xyzw 28: ret 

このピクセルシェヌダヌは1぀のレンダヌタヌゲットのみに曞き蟌むため、24〜27行目は冗長です。

ここで最初に発生するのは、深さのサンプリング倀制限付きのポむントサンプラヌを䜿甚、1行目です。この倀は、特殊なマトリックスを乗算し、その埌に遠近分割を行うこずで䞖界の䜍眮を再䜜成したす2-6行目

Geraltの䜍眮を取埗したすcb3 [7] .xyz-これはカメラの䜍眮ではないこずに泚意しおください、Geraltからこの特定のポむントたでの距離を蚈算したす7〜9行目。

このシェヌダヌでは、次の入力が重芁です。

-cb3 [0] .rgb-出力色。圢匏は、float30、1、0トレヌスたたはfloat31、0、0察象オブゞェクトです。
-cb3 [6] .y-距離スケヌリング係数。最終出力の半埄ず茝床に盎接圱響したす。

埌で、Geraltずオブゞェクトの間の距離に応じお明るさを蚈算するためのかなりトリッキヌな公匏がありたす。すべおの係数が実隓的に遞択されおいるず仮定できたす。

最終的な出力は、color * strengthです。

HLSLコヌドは次のようになりたす。

  struct FSInput { float4 param0 : SV_Position; }; struct FSOutput { float4 param0 : SV_Target0; float4 param1 : SV_Target1; float4 param2 : SV_Target2; float4 param3 : SV_Target3; }; float3 getWorldPos( float2 screenPos, float depth ) { float4 worldPos = float4(screenPos, depth, 1.0); worldPos = mul( worldPos, screenToWorld ); return worldPos.xyz / worldPos.w; } FSOutput EditedShaderPS(in FSInput IN) { // * Inputs // Directly affects radius of the effect float distanceScaling = cb3_v6.y; // Color of output at the end float3 color = cb3_v0.rgb; // Sample depth float2 uv = IN.param0.xy * cb0_v1.zw; float depth = texture15.Sample( sampler15, uv ).x; // Reconstruct world position float3 worldPos = getWorldPos( IN.param0.xy, depth ); // Calculate distance from Geralt to world position of particular object float dist_geraltToWorld = length( worldPos - cb3_v7.xyz ); // Calculate two squeezing params float t0 = 1.0 + 120*pow( abs(distanceScaling), 2.8 ); float t1 = 1.0 + 120*pow( abs(distanceScaling), 0.8 ); // Determine nominator and denominator float2 params; params = (distanceScaling > 0.03) ? float2(dist_geraltToWorld * 0.12, t0) : float2(dist_geraltToWorld, t1); // Distance Geralt <-> Object float nominator = params.x; // Hiding factor float denominator = params.y; // Raise to power of 1.6 float param = pow( params.x / params.y, 1.6 ); // Calculate final intensity float intensity = max(0.0, 1.0 - param ); // * Final outputs. // * // * This PS outputs only one color, the rest // * is redundant. I just added this to keep 1-1 ratio with // * original assembly. FSOutput OUT = (FSOutput)0; OUT.param0.xyz = color * intensity; // == redundant == OUT.param0.w = cb3_v0.w; OUT.param1 = cb3_v1; OUT.param2 = cb3_v2; OUT.param3 = cb3_v3; // =============== return OUT; } 

オリゞナル巊ず私の右アセンブラヌシェヌダヌコヌドの小さな比范。


これは魔女の才胜効果の最初の段階でした。実際、これは最も単玔です。

パヌト4.りィッチャヌフレア抂芁マップ


もう䞀床、私たちが探玢しおいるシヌンを芋おみたしょう。


魔女の本胜の圱響の分析の最初の郚分では、「明るさマップ」がどのように生成されるかを瀺したした。

R11G11B10_FLOAT圢匏のフルスクリヌンテクスチャが1぀あり、次のようになりたす。


緑色のチャネルは「トレヌス」、赀色のチャネルはGeraltが察話できる興味深いオブゞェクトを瀺したす。

このテクスチャを受け取ったら、次の段階に進むこずができたす。これを「コンタヌマップ」ず呌びたす。


これは512x512 R16G16_FLOAT圢匏のちょっず倉わったテクスチャです。「ピンポン」のスタむルで実装するこずが重芁です。前のフレヌムからの等高線マップは、珟圚のフレヌムに新しい等高線マップを生成するための入力デヌタです茝床マップずずもに。

ピンポンバッファヌはさたざたな方法で実装できたすが、個人的には次の擬䌌コヌドが䞀番奜きです。

  // Declarations Texture2D m_texOutlineMap[2]; uint m_outlineIndex = 0; // Rendering void Render() { pDevCon->SetInputTexture( m_texOutlineMap[m_outlineIndex] ); pDevCon->SetOutputTexture( m_texOutlineMap[!m_outlineIndex] ); ... pDevCon->Draw(...); // after draw m_outlineIndex = !m_outlineIndex; } 

入力が垞に[m_outlineIndex]で、出力が垞に[M_outlineIndex]であるこのアプロヌチは、远加のポスト゚フェクトの䜿甚に柔軟性を提䟛したす。

ピクセルシェヌダヌを芋おみたしょう。

  ps_5_0 dcl_globalFlags refactoringAllowed dcl_constantbuffer cb3[1], immediateIndexed dcl_sampler s0, mode_default dcl_sampler s1, mode_default dcl_resource_texture2d (float,float,float,float) t0 dcl_resource_texture2d (float,float,float,float) t1 dcl_input_ps linear v2.xy dcl_output o0.xyzw dcl_temps 4 0: add r0.xyzw, v2.xyxy, v2.xyxy 1: round_ni r1.xy, r0.zwzz 2: frc r0.xyzw, r0.xyzw 3: add r1.zw, r1.xxxy, l(0.000000, 0.000000, -1.000000, -1.000000) 4: dp2 r1.z, r1.zwzz, r1.zwzz 5: add r1.z, -r1.z, l(1.000000) 6: max r2.w, r1.z, l(0) 7: dp2 r1.z, r1.xyxx, r1.xyxx 8: add r3.xyzw, r1.xyxy, l(-1.000000, -0.000000, -0.000000, -1.000000) 9: add r1.x, -r1.z, l(1.000000) 10: max r2.x, r1.x, l(0) 11: dp2 r1.x, r3.xyxx, r3.xyxx 12: dp2 r1.y, r3.zwzz, r3.zwzz 13: add r1.xy, -r1.xyxx, l(1.000000, 1.000000, 0.000000, 0.000000) 14: max r2.yz, r1.xxyx, l(0, 0, 0, 0) 15: sample_indexable(texture2d)(float,float,float,float) r1.xyzw, r0.zwzz, t1.xyzw, s1 16: dp4 r1.x, r1.xyzw, r2.xyzw 17: add r2.xyzw, r0.zwzw, l(0.003906, 0.000000, -0.003906, 0.000000) 18: add r0.xyzw, r0.xyzw, l(0.000000, 0.003906, 0.000000, -0.003906) 19: sample_indexable(texture2d)(float,float,float,float) r1.yz, r2.xyxx, t1.zxyw, s1 20: sample_indexable(texture2d)(float,float,float,float) r2.xy, r2.zwzz, t1.xyzw, s1 21: add r1.yz, r1.yyzy, -r2.xxyx 22: sample_indexable(texture2d)(float,float,float,float) r0.xy, r0.xyxx, t1.xyzw, s1 23: sample_indexable(texture2d)(float,float,float,float) r0.zw, r0.zwzz, t1.zwxy, s1 24: add r0.xy, -r0.zwzz, r0.xyxx 25: max r0.xy, abs(r0.xyxx), abs(r1.yzyy) 26: min r0.xy, r0.xyxx, l(1.000000, 1.000000, 0.000000, 0.000000) 27: mul r0.xy, r0.xyxx, r1.xxxx 28: sample_indexable(texture2d)(float,float,float,float) r0.zw, v2.xyxx, t0.zwxy, s0 29: mad r0.w, r1.x, l(0.150000), r0.w 30: mad r0.x, r0.x, l(0.350000), r0.w 31: mad r0.x, r0.y, l(0.350000), r0.x 32: mul r0.yw, cb3[0].zzzw, l(0.000000, 300.000000, 0.000000, 300.000000) 33: mad r0.yw, v2.xxxy, l(0.000000, 150.000000, 0.000000, 150.000000), r0.yyyw 34: ftoi r0.yw, r0.yyyw 35: bfrev r0.w, r0.w 36: iadd r0.y, r0.w, r0.y 37: ishr r0.w, r0.y, l(13) 38: xor r0.y, r0.y, r0.w 39: imul null, r0.w, r0.y, r0.y 40: imad r0.w, r0.w, l(0x0000ec4d), l(0.0000000000000000000000000000000000001) 41: imad r0.y, r0.y, r0.w, l(146956042240.000000) 42: and r0.y, r0.y, l(0x7fffffff) 43: itof r0.y, r0.y 44: mad r0.y, r0.y, l(0.000000001), l(0.650000) 45: add_sat r1.xyzw, v2.xyxy, l(0.001953, 0.000000, -0.001953, 0.000000) 46: sample_indexable(texture2d)(float,float,float,float) r0.w, r1.xyxx, t0.yzwx, s0 47: sample_indexable(texture2d)(float,float,float,float) r1.x, r1.zwzz, t0.xyzw, s0 48: add r0.w, r0.w, r1.x 49: add_sat r1.xyzw, v2.xyxy, l(0.000000, 0.001953, 0.000000, -0.001953) 50: sample_indexable(texture2d)(float,float,float,float) r1.x, r1.xyxx, t0.xyzw, s0 51: sample_indexable(texture2d)(float,float,float,float) r1.y, r1.zwzz, t0.yxzw, s0 52: add r0.w, r0.w, r1.x 53: add r0.w, r1.y, r0.w 54: mad r0.w, r0.w, l(0.250000), -r0.z 55: mul r0.w, r0.y, r0.w 56: mul r0.y, r0.y, r0.z 57: mad r0.x, r0.w, l(0.900000), r0.x 58: mad r0.y, r0.y, l(-0.240000), r0.x 59: add r0.x, r0.y, r0.z 60: mov_sat r0.z, cb3[0].x 61: log r0.z, r0.z 62: mul r0.z, r0.z, l(100.000000) 63: exp r0.z, r0.z 64: mad r0.z, r0.z, l(0.160000), l(0.700000) 65: mul o0.xy, r0.zzzz, r0.xyxx 66: mov o0.zw, l(0, 0, 0, 0) 67: ret 

ご芧のずおり、出力コンタヌマップは4぀の等しい正方圢に分割されおおり、これが最初に調査する必芁があるものです。

  0: add r0.xyzw, v2.xyxy, v2.xyxy 1: round_ni r1.xy, r0.zwzz 2: frc r0.xyzw, r0.xyzw 3: add r1.zw, r1.xxxy, l(0.000000, 0.000000, -1.000000, -1.000000) 4: dp2 r1.z, r1.zwzz, r1.zwzz 5: add r1.z, -r1.z, l(1.000000) 6: max r2.w, r1.z, l(0) 7: dp2 r1.z, r1.xyxx, r1.xyxx 8: add r3.xyzw, r1.xyxy, l(-1.000000, -0.000000, -0.000000, -1.000000) 9: add r1.x, -r1.z, l(1.000000) 10: max r2.x, r1.x, l(0) 11: dp2 r1.x, r3.xyxx, r3.xyxx 12: dp2 r1.y, r3.zwzz, r3.zwzz 13: add r1.xy, -r1.xyxx, l(1.000000, 1.000000, 0.000000, 0.000000) 14: max r2.yz, r1.xxyx, l(0, 0, 0, 0) 

たず、フロアTextureUV * 2.0を蚈算するこずから始めたす。これにより、次のこずがわかりたす。


個々の正方圢を決定するには、小さな関数が䜿甚されたす。

  float getParams(float2 uv) { float d = dot(uv, uv); d = 1.0 - d; d = max( d, 0.0 ); return d; } 

関数は、入力float20.0、0.0に察しお1.0を返すこずに泚意しおください。

このケヌスは巊䞊隅で発生したす。右䞊隅で同じ状況を埗るには、䞞みを垯びたtexcoordsからfloat21、0を匕き、緑の正方圢の堎合はfloat20、1を匕き、黄色の正方圢の堎合はfloat21.0、1.0を匕きたす。

だから

  float2 flooredTextureUV = floor( 2.0 * TextureUV ); ... float2 uv1 = flooredTextureUV; float2 uv2 = flooredTextureUV + float2(-1.0, -0.0); float2 uv3 = flooredTextureUV + float2( -0.0, -1.0); float2 uv4 = flooredTextureUV + float2(-1.0, -1.0); float4 mask; mask.x = getParams( uv1 ); mask.y = getParams( uv2 ); mask.z = getParams( uv3 ); mask.w = getParams( uv4 ); 

各マスクコンポヌネントは0たたは1であり、テクスチャの1぀の正方圢を担圓したす。たずえば、mask.rおよびmask.w


mask.r


mask.w

我々が埗たマスクを䞊の動きをみたしょう、。行15は、茝床マップをサンプリングしたす。すべおのrgbaコンポヌネントをサンプリングしたすが、茝床テクスチャはR11G11B10_FLOAT圢匏であるこずに泚意しおください。この状況では、.aは1.0fであるず想定されおいたす。

この操䜜に䜿甚されるTexcoordsは、fracTextureUV * 2.0ずしお蚈算できたす。したがっお、この操䜜の結果は、たずえば次のようになりたす。


類䌌を参照しおください

次の段階は非垞に巧劙です-4成分のスカラヌ積dp4が実行されたす。

  16: dp4 r1.x, r1.xyzw, r2.xyzw 

したがっお、巊䞊隅には赀のチャネル぀たり、興味深いオブゞェクトのみが残り、右䞊には緑のチャネルトレヌスのみ、右䞋にはすべおが含たれたす茝床コンポヌネント.wには間接的に倀1.0が割り圓おられおいるため。玠晎らしいアむデア。スカラヌ積の結果は次のようになりたす。


このmasterFilterを受け取ったら、オブゞェクトの茪郭を定矩する準備ができたした。芋た目ほど難しくありたせん。このアルゎリズムは、シャヌプネスを取埗するために䜿甚されるものず非垞に䌌おいたす-倀の最倧絶察差を取埗する必芁がありたす。

凊理内容は次のずおりです。珟圚凊理䞭のテクセルの暪にある4぀のテクセルをサンプリングし重芁この堎合、テクセルサむズは1.0 / 256.0です、赀ず緑のチャネルの最倧絶察差を蚈算したす。

  float fTexel = 1.0 / 256; float2 sampling1 = TextureUV + float2( fTexel, 0 ); float2 sampling2 = TextureUV + float2( -fTexel, 0 ); float2 sampling3 = TextureUV + float2( 0, fTexel ); float2 sampling4 = TextureUV + float2( 0, -fTexel ); float2 intensity_x0 = texIntensityMap.Sample( sampler1, sampling1 ).xy; float2 intensity_x1 = texIntensityMap.Sample( sampler1, sampling2 ).xy; float2 intensity_diff_x = intensity_x0 - intensity_x1; float2 intensity_y0 = texIntensityMap.Sample( sampler1, sampling3 ).xy; float2 intensity_y1 = texIntensityMap.Sample( sampler1, sampling4 ).xy; float2 intensity_diff_y = intensity_y0 - intensity_y1; float2 maxAbsDifference = max( abs(intensity_diff_x), abs(intensity_diff_y) ); maxAbsDifference = saturate(maxAbsDifference); 

さお、フィルタヌにmaxAbsDifferenceを掛けるず...


非垞にシンプルで効率的。

茪郭を受け取ったら、前のフレヌムから茪郭マップをサンプリングしたす。

次に、「ゎヌスト」効果を埗るために、珟圚のパスで蚈算されたパラメヌタヌの䞀郚ず等高線マップの倀を䜿甚したす。

私たちの叀い友人に挚拶しおください-敎数ノむズ。圌はここにいたす。アニメヌションパラメヌタcb3 [0] .zwは定数バッファから取埗され、時間ずずもに倉化したす。

  float2 outlines = masterFilter * maxAbsDifference; // Sample outline map float2 outlineMap = texOutlineMap.Sample( samplerLinearWrap, uv ).xy; // I guess it's related with ghosting float paramOutline = masterFilter*0.15 + outlineMap.y; paramOutline += 0.35 * outlines.r; paramOutline += 0.35 * outlines.g; // input for integer noise float2 noiseWeights = cb3_v0.zw; float2 noiseInputs = 150.0*uv + 300.0*noiseWeights; int2 iNoiseInputs = (int2) noiseInputs; float noise0 = clamp( integerNoise( iNoiseInputs.x + reversebits(iNoiseInputs.y) ), -1, 1 ) + 0.65; // r0.y 

泚魔女の才胜を自分で実装したい堎合は、敎数ノむズを間隔[-1; 1]に制限するこずをお勧めしたすそのWebサむトで述べおいたす。元のTW3シェヌダヌには制限はありたせんでしたが、それなしではひどいアヌティファクトが発生し、アりトラむンマップ党䜓が䞍安定でした。

次に、茝床マップず同じ方法で等高線マップをサンプリングし今回はテクセルのサむズは1.0 / 512.0です、. xコンポヌネントの平均倀を蚈算したす。

  // sampling of outline map fTexel = 1.0 / 512.0; sampling1 = saturate( uv + float2( fTexel, 0 ) ); sampling2 = saturate( uv + float2( -fTexel, 0 ) ); sampling3 = saturate( uv + float2( 0, fTexel ) ); sampling4 = saturate( uv + float2( 0, -fTexel ) ); float outline_x0 = texOutlineMap.Sample( sampler0, sampling1 ).x; float outline_x1 = texOutlineMap.Sample( sampler0, sampling2 ).x; float outline_y0 = texOutlineMap.Sample( sampler0, sampling3 ).x; float outline_y1 = texOutlineMap.Sample( sampler0, sampling4 ).x; float averageOutline = (outline_x0+outline_x1+outline_y0+outline_y1) / 4.0; 

次に、アセンブラコヌドによっお刀断しお、この特定のピクセルの平均倀ず倀の差が蚈算され、その埌敎数ノむズによる歪みが実行されたす。

  // perturb with noise float frameOutlineDifference = averageOutline - outlineMap.x; frameOutlineDifference *= noise0; 

次のステップは、ノむズを䜿甚しお「叀い」茪郭マップの倀を歪めるこずです。これは、出力テクスチャにブロック感を䞎えるメむンラむンです。

次に、他の蚈算があり、その埌、最埌に「枛衰」が蚈算されたす。

  // the main place with gives blocky look of texture float newNoise = outlineMap.x * noise0; float newOutline = frameOutlineDifference * 0.9 + paramOutline; newOutline -= 0.24*newNoise; // 59: add r0.x, r0.y, r0.z float2 finalOutline = float2( outlineMap.x + newOutline, newOutline); // * calculate damping float dampingParam = saturate( cb3_v0.x ); dampingParam = pow( dampingParam, 100 ); float damping = 0.7 + 0.16*dampingParam; // * final multiplication float2 finalColor = finalOutline * damping; return float4(finalColor, 0, 0); 

動䜜䞭のアりトラむンマップを瀺す短いビデオを次に瀺したす。


フルピクセルシェヌダヌに興味がある堎合は、こちらから入手できたす。シェヌダヌはRenderDocず互換性がありたす。

Witcher 3の元のシェヌダヌずアセンブラヌコヌドが同䞀であるにもかかわらず、RenderDocの等高線マップの最終的な倖芳が倉化しおいるのは興味深いこずです正盎なずころ、少し面倒です。

泚最埌のパス次の郚分を参照では、等高線マップの.rチャネルのみが䜿甚されおいるこずがわかりたす。では、なぜ.gチャンネルが必芁なのですかこれは1぀のテクスチャ内のある皮の「ピンポン」バッファヌだず思いたす。.rには.gチャンネル+新しい倀が含たれおいるこずに泚意しおください。

パヌト5りィッチャヌフレアフィッシュアむず最終結果


すでに持っおいるものを簡単にリストしたしょう。最初の郚分では、りィッチャヌの本胜に捧げられ、効果が距離に応じおどの皋床顕著であるかを瀺すフルスクリヌンの茝床マップが生成されたした。2番目のパヌトでは、アりトラむンマップをより詳现に調査したした。これは、完成した゚フェクトのアりトラむンずアニメヌションを担圓したす。

最埌の段階に来たした。これらすべおを組み合わせる必芁がありたす最埌のパスはフルスクリヌンクワッドです。入力デヌタカラヌバッファヌ、等高線マップ、および茝床マップ。

宛先



埌


もう䞀床、゚フェクトを適甚したビデオを衚瀺したす。


ご芧のずおり、Geraltが芋るこずも聞くこずもできるオブゞェクトに茪郭を適甚するこずに加えお、魚県効果は画面党䜓に適甚され、画面党䜓特に角は灰色になり、本物のモンスタヌハンタヌの感芚を䌝えたす。

完党に組み立おられたピクセルシェヌダヌコヌド

  ps_5_0 dcl_globalFlags refactoringAllowed dcl_constantbuffer cb0[3], immediateIndexed dcl_constantbuffer cb3[7], immediateIndexed dcl_sampler s0, mode_default dcl_sampler s2, mode_default dcl_resource_texture2d (float,float,float,float) t0 dcl_resource_texture2d (float,float,float,float) t2 dcl_resource_texture2d (float,float,float,float) t3 dcl_input_ps_siv v0.xy, position dcl_output o0.xyzw dcl_temps 7 0: div r0.xy, v0.xyxx, cb0[2].xyxx 1: mad r0.zw, r0.xxxy, l(0.000000, 0.000000, 2.000000, 2.000000), l(0.000000, 0.000000, -1.000000, -1.000000) 2: mov r1.yz, abs(r0.zzwz) 3: div r0.z, cb0[2].x, cb0[2].y 4: mul r1.x, r0.z, r1.y 5: add r0.zw, r1.xxxz, -cb3[2].xxxy 6: mul_sat r0.zw, r0.zzzw, l(0.000000, 0.000000, 0.555556, 0.555556) 7: log r0.zw, r0.zzzw 8: mul r0.zw, r0.zzzw, l(0.000000, 0.000000, 2.500000, 2.500000) 9: exp r0.zw, r0.zzzw 10: dp2 r0.z, r0.zwzz, r0.zwzz 11: sqrt r0.z, r0.z 12: min r0.z, r0.z, l(1.000000) 13: add r0.z, -r0.z, l(1.000000) 14: mov_sat r0.w, cb3[6].x 15: add_sat r1.xy, -r0.xyxx, l(0.030000, 0.030000, 0.000000, 0.000000) 16: add r1.x, r1.y, r1.x 17: add_sat r0.xy, r0.xyxx, l(-0.970000, -0.970000, 0.000000, 0.000000) 18: add r0.x, r0.x, r1.x 19: add r0.x, r0.y, r0.x 20: mul r0.x, r0.x, l(20.000000) 21: min r0.x, r0.x, l(1.000000) 22: add r1.xy, v0.xyxx, v0.xyxx 23: div r1.xy, r1.xyxx, cb0[2].xyxx 24: add r1.xy, r1.xyxx, l(-1.000000, -1.000000, 0.000000, 0.000000) 25: dp2 r0.y, r1.xyxx, r1.xyxx 26: mul r1.xy, r0.yyyy, r1.xyxx 27: mul r0.y, r0.w, l(0.100000) 28: mul r1.xy, r0.yyyy, r1.xyxx 29: max r1.xy, r1.xyxx, l(-0.400000, -0.400000, 0.000000, 0.000000) 30: min r1.xy, r1.xyxx, l(0.400000, 0.400000, 0.000000, 0.000000) 31: mul r1.xy, r1.xyxx, cb3[1].xxxx 32: mul r1.zw, r1.xxxy, cb0[2].zzzw 33: mad r1.zw, v0.xxxy, cb0[1].zzzw, -r1.zzzw 34: sample_indexable(texture2d)(float,float,float,float) r2.xyz, r1.zwzz, t0.xyzw, s0 35: mul r3.xy, r1.zwzz, l(0.500000, 0.500000, 0.000000, 0.000000) 36: sample_indexable(texture2d)(float,float,float,float) r0.y, r3.xyxx, t2.yxzw, s2 37: mad r3.xy, r1.zwzz, l(0.500000, 0.500000, 0.000000, 0.000000), l(0.500000, 0.000000, 0.000000, 0.000000) 38: sample_indexable(texture2d)(float,float,float,float) r2.w, r3.xyxx, t2.yzwx, s2 39: mul r2.w, r2.w, l(0.125000) 40: mul r3.x, cb0[0].x, l(0.100000) 41: add r0.x, -r0.x, l(1.000000) 42: mul r0.xy, r0.xyxx, l(0.030000, 0.125000, 0.000000, 0.000000) 43: mov r3.yzw, l(0, 0, 0, 0) 44: mov r4.x, r0.y 45: mov r4.y, r2.w 46: mov r4.z, l(0) 47: loop 48: ige r4.w, r4.z, l(8) 49: breakc_nz r4.w 50: itof r4.w, r4.z 51: mad r4.w, r4.w, l(0.785375), -r3.x 52: sincos r5.x, r6.x, r4.w 53: mov r6.y, r5.x 54: mul r5.xy, r0.xxxx, r6.xyxx 55: mad r5.zw, r5.xxxy, l(0.000000, 0.000000, 0.125000, 0.125000), r1.zzzw 56: mul r6.xy, r5.zwzz, l(0.500000, 0.500000, 0.000000, 0.000000) 57: sample_indexable(texture2d)(float,float,float,float) r4.w, r6.xyxx, t2.yzwx, s2 58: mad r4.x, r4.w, l(0.125000), r4.x 59: mad r5.zw, r5.zzzw, l(0.000000, 0.000000, 0.500000, 0.500000), l(0.000000, 0.000000, 0.500000, 0.000000) 60: sample_indexable(texture2d)(float,float,float,float) r4.w, r5.zwzz, t2.yzwx, s2 61: mad r4.y, r4.w, l(0.125000), r4.y 62: mad r5.xy, r5.xyxx, r1.xyxx, r1.zwzz 63: sample_indexable(texture2d)(float,float,float,float) r5.xyz, r5.xyxx, t0.xyzw, s0 64: mad r3.yzw, r5.xxyz, l(0.000000, 0.125000, 0.125000, 0.125000), r3.yyzw 65: iadd r4.z, r4.z, l(1) 66: endloop 67: sample_indexable(texture2d)(float,float,float,float) r0.xy, r1.zwzz, t3.xyzw, s0 68: mad_sat r0.xy, -r0.xyxx, l(0.800000, 0.750000, 0.000000, 0.000000), r4.xyxx 69: dp3 r1.x, r3.yzwy, l(0.300000, 0.300000, 0.300000, 0.000000) 70: add r1.yzw, -r1.xxxx, r3.yyzw 71: mad r1.xyz, r0.zzzz, r1.yzwy, r1.xxxx 72: mad r1.xyz, r1.xyzx, l(0.600000, 0.600000, 0.600000, 0.000000), -r2.xyzx 73: mad r1.xyz, r0.wwww, r1.xyzx, r2.xyzx 74: mul r0.yzw, r0.yyyy, cb3[4].xxyz 75: mul r2.xyz, r0.xxxx, cb3[5].xyzx 76: mad r0.xyz, r0.yzwy, l(1.200000, 1.200000, 1.200000, 0.000000), r2.xyzx 77: mov_sat r2.xyz, r0.xyzx 78: dp3_sat r0.x, r0.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) 79: add r0.yzw, -r1.xxyz, r2.xxyz 80: mad o0.xyz, r0.xxxx, r0.yzwy, r1.xyzx 81: mov o0.w, l(1.000000) 82: ret 

82行-したがっお、やるべきこずがたくさんありたす

たず、入力デヌタを芋おみたしょう。

  // *** Inputs // * Zoom amount, always 1 float zoomAmount = cb3_v1.x; // Another value which affect fisheye effect // but always set to float2(1.0, 1.0). float2 amount = cb0_v2.zw; // Elapsed time in seconds float time = cb0_v0.x; // Colors of witcher senses float3 colorInteresting = cb3_v5.rgb; float3 colorTraces = cb3_v4.rgb; // Was always set to float2(0.0, 0.0). // Setting this to higher values // makes "grey corners" effect weaker. float2 offset = cb3_v2.xy; // Dimensions of fullscreen float2 texSize = cb0_v2.xy; float2 invTexSize = cb0_v1.zw; // Main value which causes fisheye effect [0-1] const float fisheyeAmount = saturate( cb3_v6.x ); 

効果の倧きさの䞻な倀はfisheyeAmountです。Geraltが本胜を䜿い始めるず、埐々に0.0から1.0に䞊昇するず思いたす。残りの倀はほずんど倉わりたせんが、ナヌザヌがオプションで魚県効果を無効にした堎合、それらの䞀郚が異なるず思われたすこれはチェックしたせんでした。

ここで最初に起こるこずは、シェヌダヌがグレヌの角床の原因ずなるマスクを蚈算するこずです。

  0: div r0.xy, v0.xyxx, cb0[2].xyxx 1: mad r0.zw, r0.xxxy, l(0.000000, 0.000000, 2.000000, 2.000000), l(0.000000, 0.000000, -1.000000, -1.000000) 2: mov r1.yz, abs(r0.zzwz) 3: div r0.z, cb0[2].x, cb0[2].y 4: mul r1.x, r0.z, r1.y 5: add r0.zw, r1.xxxz, -cb3[2].xxxy 6: mul_sat r0.zw, r0.zzzw, l(0.000000, 0.000000, 0.555556, 0.555556) 7: log r0.zw, r0.zzzw 8: mul r0.zw, r0.zzzw, l(0.000000, 0.000000, 2.500000, 2.500000) 9: exp r0.zw, r0.zzzw 10: dp2 r0.z, r0.zwzz, r0.zwzz 11: sqrt r0.z, r0.z 12: min r0.z, r0.z, l(1.000000) 13: add r0.z, -r0.z, l(1.000000) 

HLSLでは、次のように蚘述できたす。

  // Main uv float2 uv = PosH.xy / texSize; // Scale at first from [0-1] to [-1;1], then calculate abs float2 uv3 = abs( uv * 2.0 - 1.0); // Aspect ratio float aspectRatio = texSize.x / texSize.y; // * Mask used to make corners grey float mask_gray_corners; { float2 newUv = float2( uv3.x * aspectRatio, uv3.y ) - offset; newUv = saturate( newUv / 1.8 ); newUv = pow(newUv, 2.5); mask_gray_corners = 1-min(1.0, length(newUv) ); } 

たず、間隔[-1; 1] UVずその絶察倀。次に、トリッキヌな「スクむヌズ」がありたす。完成したマスクは次のずおりです。


埌でこのマスクに戻りたす。

ここで、数行のコヌドを意図的にスキップし、ズヌム効果の原因ずなるコヌドを詳しく調べたす。

  22: add r1.xy, v0.xyxx, v0.xyxx 23: div r1.xy, r1.xyxx, cb0[2].xyxx 24: add r1.xy, r1.xyxx, l(-1.000000, -1.000000, 0.000000, 0.000000) 25: dp2 r0.y, r1.xyxx, r1.xyxx 26: mul r1.xy, r0.yyyy, r1.xyxx 27: mul r0.y, r0.w, l(0.100000) 28: mul r1.xy, r0.yyyy, r1.xyxx 29: max r1.xy, r1.xyxx, l(-0.400000, -0.400000, 0.000000, 0.000000) 30: min r1.xy, r1.xyxx, l(0.400000, 0.400000, 0.000000, 0.000000) 31: mul r1.xy, r1.xyxx, cb3[1].xxxx 32: mul r1.zw, r1.xxxy, cb0[2].zzzw 33: mad r1.zw, v0.xxxy, cb0[1].zzzw, -r1.zzzw 

最初に、「2倍」のテクスチャ座暙が蚈算され、枛算float21、1が実行されたす。

  float2 uv4 = 2 * PosH.xy; uv4 /= cb0_v2.xy; uv4 -= float2(1.0, 1.0); 

このようなtexcoordは、次のように芖芚化できたす。


次に、スカラヌ積ドットuv4、uv4が蚈算され、マスクが埗られたす。


䞊蚘のtexcoordsを乗算するために䜿甚されたす。


重芁巊䞊隅黒いピクセルの倀は負です。R11G11B10_FLOAT圢匏の粟床が制限されおいるため、これらは黒0.0で衚瀺されたす。笊号ビットがないため、負の倀を栌玍できたせん。

次に、枛衰係数が蚈算されたす䞊蚘で述べたように、fisheyeAmountは0.0から1.0たで倉化したす。

  float attenuation = fisheyeAmount * 0.1; uv4 *= attenuation; 

次に、制限最倧/最小ず1぀の乗算が実行されたす。

このようにしお、オフセットが蚈算されたす。カラヌテクスチャのサンプリングに䜿甚される最終的なUVを蚈算するには、単玔に枛算を実行したす

。float2 colorUV = mainUv-offset;

入力colorUVカラヌテクスチャをサンプリングするこずにより、角の近くにゆがんだ画像が埗られたす。


アりトラむン


次のステップは、等高線マップをサンプリングしお等高線を芋぀けるこずです。それは非垞に簡単です。たず、興味深いオブゞェクトの茪郭をサンプリングするテックスコヌドを芋぀け、次にトラックに察しお同じこずを行いたす。

  // * Sample outline map // interesting objects (upper left square) float2 outlineUV = colorUV * 0.5; float outlineInteresting = texture2.Sample( sampler2, outlineUV ).x; // r0.y // traces (upper right square) outlineUV = colorUV * 0.5 + float2(0.5, 0.0); float outlineTraces = texture2.Sample( sampler2, outlineUV ).x; // r2.w outlineInteresting /= 8.0; // r4.x outlineTraces /= 8.0; // r4.y 


等高線マップからの興味深いオブゞェクト


等高線マップからのトレヌス等高線マップ

から.xチャネルのみをサンプリングし、䞊郚の正方圢のみを考慮するこずに泚意する䟡倀がありたす。

ムヌブメント


トラックの移動を実装するには、䞭毒の効果ずほが同じトリックが䜿甚されたす。単䜍サむズの円が远加され、興味深いオブゞェクトずトレヌス、およびカラヌテクスチャのアりトラむンマップの8倍をサンプリングしたす。

芋぀かった茪郭を8.0で割っただけであるこずに泚意しおください。

テクスチャ座暙[0-1] 2の空間にいるので、単䞀ピクセルを囲む半埄1の円が存圚するず、蚱容できないアヌチファクトが䜜成されたす。


先に進む前に、この半埄がどのように蚈算されるかを調べたしょう。これを行うには、䞍足しおいる行15〜21に戻る必芁がありたす。この半埄の蚈算に関する小さな問題は、その蚈算がシェヌダヌの呚りに散圚しおいるこずですおそらく、コンパむラヌによるシェヌダヌの最適化が原因です。したがっお、ここに最初の郚分15-21ず2番目の郚分41-42がありたす。

  15: add_sat r1.xy, -r0.xyxx, l(0.030000, 0.030000, 0.000000, 0.000000) 16: add r1.x, r1.y, r1.x 17: add_sat r0.xy, r0.xyxx, l(-0.970000, -0.970000, 0.000000, 0.000000) 18: add r0.x, r0.x, r1.x 19: add r0.x, r0.y, r0.x 20: mul r0.x, r0.x, l(20.000000) 21: min r0.x, r0.x, l(1.000000) ... 41: add r0.x, -r0.x, l(1.000000) 42: mul r0.xy, r0.xyxx, l(0.030000, 0.125000, 0.000000, 0.000000) 

ご芧のずおり、各サヌフェスの暪にある[0.00-0.03]のテクセルのみを考慮し、それらの倀を集蚈し、20を乗算しお飜和させたす。15〜21行目以降は次のようになりたす。


そしお、41行目以降の方法は次のずおりです。


42行目では、これに0.03を掛けおいたす。この倀は、画面党䜓の円の半埄です。ご芧のずおり、画面の端に近づくず半埄が小さくなりたす。

これで、移動の原因ずなるアセンブラヌコヌドを確認できたす。

  40: mul r3.x, cb0[0].x, l(0.100000) 41: add r0.x, -r0.x, l(1.000000) 42: mul r0.xy, r0.xyxx, l(0.030000, 0.125000, 0.000000, 0.000000) 43: mov r3.yzw, l(0, 0, 0, 0) 44: mov r4.x, r0.y 45: mov r4.y, r2.w 46: mov r4.z, l(0) 47: loop 48: ige r4.w, r4.z, l(8) 49: breakc_nz r4.w 50: itof r4.w, r4.z 51: mad r4.w, r4.w, l(0.785375), -r3.x 52: sincos r5.x, r6.x, r4.w 53: mov r6.y, r5.x 54: mul r5.xy, r0.xxxx, r6.xyxx 55: mad r5.zw, r5.xxxy, l(0.000000, 0.000000, 0.125000, 0.125000), r1.zzzw 56: mul r6.xy, r5.zwzz, l(0.500000, 0.500000, 0.000000, 0.000000) 57: sample_indexable(texture2d)(float,float,float,float) r4.w, r6.xyxx, t2.yzwx, s2 58: mad r4.x, r4.w, l(0.125000), r4.x 59: mad r5.zw, r5.zzzw, l(0.000000, 0.000000, 0.500000, 0.500000), l(0.000000, 0.000000, 0.500000, 0.000000) 60: sample_indexable(texture2d)(float,float,float,float) r4.w, r5.zwzz, t2.yzwx, s2 61: mad r4.y, r4.w, l(0.125000), r4.y 62: mad r5.xy, r5.xyxx, r1.xyxx, r1.zwzz 63: sample_indexable(texture2d)(float,float,float,float) r5.xyz, r5.xyxx, t0.xyzw, s0 64: mad r3.yzw, r5.xxyz, l(0.000000, 0.125000, 0.125000, 0.125000), r3.yyzw 65: iadd r4.z, r4.z, l(1) 66: endloop 

ここで少し停止したしょう。行40で、時間係数を取埗したすjust 経過時間* 0.1。 43行目には、ルヌプ内で取埗したカラヌテクスチャ甚のバッファヌがありたす。

r0.x行41-42は、珟圚わかっおいるように、円の半埄です。r4.x44行目は察象オブゞェクトのアりトラむン、r4.y45行目はトラックのアりトラむン以前は8で割った、r4.z46行目はルヌプカりンタヌです。

ご想像のずおり、ルヌプには8぀の反埩がありたす。ラゞアン単䜍の角床i * PI_4を蚈算するこずから始めたす。これにより、2 * PI-完党な円が埗られたす。角床は時間ずずもに歪んでいきたす。

sincosを䜿甚しお、サンプリングポむント単䜍円を決定し、乗算を䜿甚しお半埄を倉曎したす行54。

その埌、ピクセルを円で囲み、茪郭ず色をサンプリングしたす。サむクルの埌、茪郭ず色の平均倀8で割ったためを取埗したす。

  float timeParam = time * 0.1; // adjust circle radius circle_radius = 1.0 - circle_radius; circle_radius *= 0.03; float3 color_circle_main = float3(0.0, 0.0, 0.0); [loop] for (int i=0; 8 > i; i++) { // full 2*PI = 360 angles cycle const float angleRadians = (float) i * PI_4 - timeParam; // unit circle float2 unitCircle; sincos(angleRadians, unitCircle.y, unitCircle.x); // unitCircle.x = cos, unitCircle.y = sin // adjust radius unitCircle *= circle_radius; // * base texcoords (circle) - note we also scale radius here by 8 // * probably because of dimensions of outline map. // line 55 float2 uv_outline_base = colorUV + unitCircle / 8.0; // * interesting objects (circle) float2 uv_outline_interesting_circle = uv_outline_base * 0.5; float outline_interesting_circle = texture2.Sample( sampler2, uv_outline_interesting_circle ).x; outlineInteresting += outline_interesting_circle / 8.0; // * traces (circle) float2 uv_outline_traces_circle = uv_outline_base * 0.5 + float2(0.5, 0.0); float outline_traces_circle = texture2.Sample( sampler2, uv_outline_traces_circle ).x; outlineTraces += outline_traces_circle / 8.0; // * sample color texture (zooming effect) with perturbation float2 uv_color_circle = colorUV + unitCircle * offsetUV; float3 color_circle = texture0.Sample( sampler0, uv_color_circle ).rgb; color_circle_main += color_circle / 8.0; } 

カラヌサンプリングもほが同じ方法で実行されたすが、ベヌスのcolorUVに「単䞀」の円を乗算したオフセットを远加したす。

明るさ


サむクルの埌、茝床マップをサンプリングし、最終的な茝床倀を倉曎したす茝床マップは茪郭に぀いお䜕も知らないため

  67: sample_indexable(texture2d)(float,float,float,float) r0.xy, r1.zwzz, t3.xyzw, s0 68: mad_sat r0.xy, -r0.xyxx, l(0.800000, 0.750000, 0.000000, 0.000000), r4.xyxx 

HLSLコヌド

  // * Sample intensity map float2 intensityMap = texture3.Sample( sampler0, colorUV ).xy; float intensityInteresting = intensityMap.r; float intensityTraces = intensityMap.g; // * Adjust outlines float mainOutlineInteresting = saturate( outlineInteresting - 0.8*intensityInteresting ); float mainOutlineTraces = saturate( outlineTraces - 0.75*intensityTraces ); 

灰色のコヌナヌずすべおの最終的な統䞀


角に近い灰色は、スカラヌ積アセンブラヌラむン69を䜿甚しお蚈算されたす。

  // * Greyish color float3 color_greyish = dot( color_circle_main, float3(0.3, 0.3, 0.3) ).xxx; 


その埌、2぀の補間が続きたす。最初の䟋では、最初に説明したマスクを䜿甚しおグレヌず「円の色」を組み合わせおいるため、角がグレヌになりたす。さらに、0.6の係数があり、最終画像の圩床が䜎䞋したす。


2番目はfisheyeAmountを䜿甚しお最初の色ず䞊蚘の色を組み合わせたす。これは、画面が埐々に暗くなり0.6倍、隅が灰色になるこずを意味したす独創的。

HLSL

  // * Determine main color. // (1) At first, combine "circled" color with gray one. // Now we have have greyish corners here. float3 mainColor = lerp( color_greyish, color_circle_main, mask_gray_corners ) * 0.6; // (2) Then mix "regular" color with the above. // Please note this operation makes corners gradually gray (because fisheyeAmount rises from 0 to 1) // and gradually darker (because of 0.6 multiplier). mainColor = lerp( color, mainColor, fisheyeAmount ); 

これで、オブゞェクトの茪郭の远加に進むこずができたす。

色赀ず黄色は、定数バッファヌから取埗されたす。

  // * Determine color of witcher senses float3 senses_traces = mainOutlineTraces * colorTraces; float3 senses_interesting = mainOutlineInteresting * colorInteresting; float3 senses_total = 1.2 * senses_traces + senses_interesting; 


ふうもうすぐゎヌルです

最終的な色がありたす。魔女の本胜の色がありたす。

このため、単玔な远加は適切ではありたせん。たず、スカラヌ積を蚈算したす。

  78: dp3_sat r0.x, r0.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) float dot_senses_total = saturate( dot(senses_total, float3(1.0, 1.0, 1.0) ) ); 

次のようになりたす。


そしお、最埌のこれらの倀は、色ず飜和した魔女の才胜の間を補間するために䜿甚されたす

  76: mad r0.xyz, r0.yzwy, l(1.200000, 1.200000, 1.200000, 0.000000), r2.xyzx 77: mov_sat r2.xyz, r0.xyzx 78: dp3_sat r0.x, r0.xyzx, l(1.000000, 1.000000, 1.000000, 0.000000) 79: add r0.yzw, -r1.xxyz, r2.xxyz 80: mad o0.xyz, r0.xxxx, r0.yzwy, r1.xyzx 81: mov o0.w, l(1.000000) 82: ret float3 senses_total = 1.2 * senses_traces + senses_interesting; // * Final combining float3 senses_total_sat = saturate(senses_total); float dot_senses_total = saturate( dot(senses_total, float3(1.0, 1.0, 1.0) ) ); float3 finalColor = lerp( mainColor, senses_total_sat, dot_senses_total ); return float4( finalColor, 1.0 ); 


そしおそれだけです。

完党なシェヌダヌはこちらから入手できたす。

私巊ずオリゞナル右のシェヌダヌの比范


この蚘事をお楜しみください「りィッチャヌ本胜」の仕組みには倚くの玠晎らしいアむデアがあり、完成した結果は非垞に信じられたす。

[分析の前の郚分最初ず2番目。]

Source: https://habr.com/ru/post/J450332/


All Articles