OpenGLのドキュメントには、そのfwidthを述べましたreturns the sum of the absolute value of derivatives in x and y
。
これは数学的な用語ではあまり意味がなく、視覚化する方法はありますか?
関数の私の理解に基づいて、隣接するピクセルのfwidth(p)
値にアクセスできますp
。これは、パフォーマンスに大きな影響を与えることなくGPUでどのように機能し、すべてのピクセルで確実かつ均一に機能しますか
OpenGLのドキュメントには、そのfwidthを述べましたreturns the sum of the absolute value of derivatives in x and y
。
これは数学的な用語ではあまり意味がなく、視覚化する方法はありますか?
関数の私の理解に基づいて、隣接するピクセルのfwidth(p)
値にアクセスできますp
。これは、パフォーマンスに大きな影響を与えることなくGPUでどのように機能し、すべてのピクセルで確実かつ均一に機能しますか
回答:
ピクセルスクリーンスペースの派生物はパフォーマンスに大きく影響しますが、使用するかどうかに関係なくパフォーマンスに影響するため、特定の観点からは無料です!
最近の歴史のすべてのGPUは4つのピクセルのクワッドをまとめて同じワープ/ウェーブフロントに配置します。つまり、GPU上で隣接して実行されているため、それらの値にアクセスするのは非常に安価です。ワープ/ウェーブフロントはロックステップで実行されるため、他のピクセルもシェーダー内のあなたとまったく同じ場所にあるため、p
これらのピクセルの値はレジスタを待機しているだけです。これらの他の3つのピクセルは、結果が破棄される場合でも常に実行されます。したがって、1つのピクセルをカバーする三角形は、常に4つのピクセルをシェーディングし、3つのピクセルの結果を破棄します。これにより、これらの派生機能が機能します。
これは、fwidth
これらの派生物を使用するような機能ではないため、許容できるコストと見なされます(テクスチャのミップマップを読み取るために、すべての単一のテクスチャサンプルも同様に機能します)。考慮してください:サーフェスに非常に近い場合、テクスチャのサンプリングに使用しているUV座標は、画面空間で非常に小さい導関数を持ちます。つまり、より大きなミップマップを使用する必要があります。画面スペースのより大きな導関数、つまり、より小さなミップマップを使用する必要があることを意味します。
より少ない数学用語でそれが意味する限り、はとfwidth
同等abs(dFdx(p)) + abs(dFdy(p))
です。dFdx(p)
はp
、ピクセルx + 1の値とピクセルxの値の差p
であり、同様にですdFdy(p)
。
dFdx
2x2グリッドの2つの隣接ピクセルのそれぞれに対して、本質的に同じ値が計算されます。そして、この値は、2つの隣接する値の間の差を使用して計算されます。これは、それがまさにここにあるという概念に依存している、p(x+1)-p(x)
またはp(x)-p(x-1)
単に依存している場合x
です。ただし、結果は同じです。ええ、あなたは正しいです。
完全に技術的な用語で、fwidth(p)
次のように定義されます
fwidth(p) := abs(dFdx(p)) + abs(dFdy(p))
及びdFdx(p)
/ dFdy(p)
値の部分的誘導体であるp
に対するx
およびy
画面寸法。そのため、p
1ピクセル右(x
)または1ピクセル上(y
)に移動したときの値の動作を示します。
では、実際にどのように計算できるのでしょうか?の近傍ピクセルの値がわかっている場合は、実際の数学的導関数の近似p
として直接有限差分としてこれらの導関数を計算できます(正確な解析解がまったくない場合があります)。
dFdx(p) := p(x+1) - p(x)
しかし、当然のことながらp
、近隣ピクセルの値(シェーダープログラム内で任意に計算された値である可能性があります)をどのようにして知ることができますか?シェーダー全体の計算を2回(または3回)行うことで、大きなオーバーヘッドを発生させずにこれらの値を計算するにはどうすればよいですか?
隣のピクセルに対してフラグメントシェーダーも実行するため、とにかくこれらの近隣の値が計算されます。したがって、必要なのは、隣接するピクセルに対して実行するときに、この隣接するフラグメントシェーダーの呼び出しにアクセスすることだけです。しかし、これらの隣接値もまったく同時に計算されるため、さらに簡単です。
最新のラスタライザは、隣接する複数のピクセルの大きなタイルでフラグメントシェーダを呼び出します。最小でも、それらはピクセルの2x2グリッドになります。そして、そのようなピクセルブロックごとにフラグメントシェーダーがピクセルごとに呼び出され、それらの呼び出しは完全に並列のロックステップで実行されるため、ブロック内のピクセルごとにすべての計算がまったく同じ順序で同時に行われます(これは、断片シェーダーでの分岐は、致命的ではありませんが、可能であれば回避する必要がある理由ですこの関連する質問への回答にも記載されているように、その後の結果)。そのため、いつでもフラグメントシェーダーは理論的には、隣接するピクセルのフラグメントシェーダー値にアクセスできます。あなたはそれらの値に直接アクセスすることはできませんが、あなたが派生関数のように、それらから計算された値へのアクセス権を持っていますdFdx
、dFdy
、fwidth
、...
dFdx(p) = p(x1) - p(x)
、クワッド内のピクセルの位置に応じて、またはのx1
いずれ(x+1)
か(x-1)
になりますx
。いずれにしx1
ても、と同じワープ/波面になければなりませんx
。私は正しいですか?