2012-11-21 52 views
6

誰もがGLSLでバイキュービックテクスチャフィルタリングを行うには、完全な作業、および効率的なコードを持っている場合、私は思ったんだけど。あり、このです:GLSLの効率的なバイキュービックフィルタリングコード?

http://www.codeproject.com/Articles/236394/Bi-Cubic-and-Bi-Linear-Interpolation-with-GLSL または https://github.com/visionworkbench/visionworkbench/blob/master/src/vw/GPU/Shaders/Interp/interpolation-bicubic.glsl

はなく、唯一の4が必要であるところの両方が16テクスチャが読みください:

https://groups.google.com/forum/#!topic/comp.graphics.api.opengl/kqrujgJfTxo

上記の方法が不足している "立方()" を使用していますが私はそれが何をすべきか分からず、また説明できない "texscale"パラメータを取る。

も、NVidiaのバージョンがあります:

http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter20.html

が、私はこれは、NVIDIAのカードに固有のCUDAを使用しています信じています。私はglslが必要です。

私でしおそらくポートGLSLにnvidiaのバージョンが、私は誰もがすでに完了し、作業GLSLバイキュービックシェーダを持っているかどうかを確認するために最初にお願いしたいと思いました。

+3

"*しかし、両方とも16個のテクスチャ読み取りを行いますが、4つしか必要ありません。*"その投稿はあなたに横たわっています。バイキュービック補間は、4つの双一次サンプリングを行いません。これは大規模な線形フィルタリングに過ぎません。バイキュービック補間では、線形補間ではなく、値の* 3次補間が必要です。また、線形補間を行うことで3次補間を行うことはできません。これは、ベジェ曲線と、4つのベジェ点を結んで作成される線の違いに似ています。まったく同じことではありませんか? –

+0

Shaderはtexcoord = cubic(lerp(texcoord))のように何かを投稿していますので、基本的にテクスチャ座標補間の上に余分な機能を適用しています。このタイプのフィルタリングは、画像のサイズ変更に使用できます。 – JAre

+5

@ニコルボラス:あなたは間違っています。下記の[GPUGems 2章](http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter20.html)に記載されており、JAreとMafによって以下に書かれているように、4線形補間を使用してバイキュービックルックアップを行うことは完全に可能です。 –

答えて

7

私は、私の古いPERFORCEの活動を掘り下げて、欠けているcubic()関数を見つけました。楽しい! :)

vec4 cubic(float v) 
{ 
    vec4 n = vec4(1.0, 2.0, 3.0, 4.0) - v; 
    vec4 s = n * n * n; 
    float x = s.x; 
    float y = s.y - 4.0 * s.x; 
    float z = s.z - 4.0 * s.y + 6.0 * s.x; 
    float w = 6.0 - x - y - z; 
    return vec4(x, y, z, w); 
} 
4

(EDIT)

cubic spline

  • Texscaleサンプリングウィンドウサイズ係数です。 1.0の値から始めることができます。

vec4 filter(sampler2D texture, vec2 texcoord, vec2 texscale) 
{ 
    float fx = fract(texcoord.x); 
    float fy = fract(texcoord.y); 
    texcoord.x -= fx; 
    texcoord.y -= fy; 

    vec4 xcubic = cubic(fx); 
    vec4 ycubic = cubic(fy); 

    vec4 c = vec4(texcoord.x - 0.5, texcoord.x + 1.5, texcoord.y - 
0.5, texcoord.y + 1.5); 
    vec4 s = vec4(xcubic.x + xcubic.y, xcubic.z + xcubic.w, ycubic.x + 
ycubic.y, ycubic.z + ycubic.w); 
    vec4 offset = c + vec4(xcubic.y, xcubic.w, ycubic.y, ycubic.w)/
s; 

    vec4 sample0 = texture2D(texture, vec2(offset.x, offset.z) * 
texscale); 
    vec4 sample1 = texture2D(texture, vec2(offset.y, offset.z) * 
texscale); 
    vec4 sample2 = texture2D(texture, vec2(offset.x, offset.w) * 
texscale); 
    vec4 sample3 = texture2D(texture, vec2(offset.y, offset.w) * 
texscale); 

    float sx = s.x/(s.x + s.y); 
    float sy = s.z/(s.z + s.w); 

    return mix(
     mix(sample3, sample2, sx), 
     mix(sample1, sample0, sx), sy); 
} 

Source

+1

これは、私がオリジナルの投稿で与えたのとまったく同じリンクです(3番目のリンクを参照)。これはうまくいくでしょう...欠けているcubic()関数のために何を書く必要があるのか​​、そしてtexscaleのパラメータを渡すべきかを説明できるならば。あなたがそのことを説明できるなら、私はあなたの答えを最終的な答えとして記入して喜んでいます。 –

+0

ありがとうございます。 :-) –

+0

しかし、私はどのようにCで単一の入力パラメータを与える3次関数を書くのか分かりません。グーグルでは、多くの入力パラメータが必要でした。 –

6

JAre's answerで不足している機能cubic()は、次のようになります。

vec4 cubic(float x) 
{ 
    float x2 = x * x; 
    float x3 = x2 * x; 
    vec4 w; 
    w.x = -x3 + 3*x2 - 3*x + 1; 
    w.y = 3*x3 - 6*x2  + 4; 
    w.z = -3*x3 + 3*x2 + 3*x + 1; 
    w.w = x3; 
    return w/6.f; 
} 

それは立方Bスプラインのための4つのウェイトを返します。

これは、すべてのNVidia Gemsに説明されています。 http://www.dannyruijters.nl/cubicinterpolation/CI.zip

編集:キュービック補間コードがあるトライ -cubic補間を行うことがGLSLコードに興味を持って誰のために

1

、キュービック補間を使用してレイキャスティングコードがで例/ glCubicRayCastフォルダで見つけることができますgithubの上で利用可能になりまし:CUDAバージョンとWebGLバージョン、およびGLSLサンプル。

4

うわー。私は上記のコードを認識しています(私は評判が<でコメントできません)。2011年初めにそれを思いつきました。私が解決しようとしていた問題は古いIBM T42(正確なモデル番号は私を逃してしまって申し訳ありません)ラップトップとATIのグラフィックススタックに関連していました。私はNVカードのコードを開発し、もともとは16のテクスチャフェッチを使用しました。それはちょっと遅かったが、私の目的にとっては十分に速かった。誰かがノートパソコンで動作しないと報告したとき、断片ごとに十分なテクスチャフェッチをサポートしていないことが明らかになりました。私は回避策を工夫しなければなりませんでした。私が思いつくことができる最高のものは、機能するテクスチャフェッチの数でそれを行うことでした。

私はこれについてこう考えました。大丈夫です。線形フィルタを使って各四角形(2x2)を処理すると、残りの問題は行と列が重みを共有できますか?それは私がコードを作るために出発したときの私の心の唯一の問題でした。もちろん、それらは共有することができます。重みは各列と行で同じです。完璧!

今私は4つのサンプルを持っていました。残りの問題はサンプルを正しく組み合わせる方法でした。それが克服する最大の障害でした。鉛筆と紙で約10分かかりました。私は震えている手でコードを入力した。それはうまくいった。それから彼は彼のT42(?)でそれをチェックすることを約束した男にバイナリをアップロードし、彼はそれが働いたと報告した。終わり。 :)

私は、方程式がチェックアウトし、数学的に同じ結果をサンプルを個別に計算することを保証することができます。参考:CPUを使用すると、水平と垂直のスキャンを別々に行う方が高速です。 GPUを複数回使用することは素晴らしいアイデアではありません。特に、典型的なユースケースではおそらく実現不可能な場合です。

思考のための食べ物:cubic()関数のテクスチャルックアップを使うことができます。より速いのはGPUに依存しますが、一般にサンプラーは算術演算を行うALU側では軽いので、バランスをとることになります。 YMMV。

1

私は一年以上@Mafのキュービックスプラインレシピを使用してきた、と立方Bスプラインがニーズを満たしている場合、私は、それをお勧めします。

しかし私は最近、私の特定のアプリケーションでは、強度がサンプルポイントで正確に一致することが重要であることを認識しました。講義ノートでは、三次スプラインの他のフレーバーの数のためにそれらを

// Catmull-Rom spline actually passes through control points 
vec4 cubic(float x) // cubic_catmullrom(float x) 
{ 
    const float s = 0.5; // potentially adjustable parameter 
    float x2 = x * x; 
    float x3 = x2 * x; 
    vec4 w; 
    w.x = -s*x3 +  2*s*x2 - s*x + 0; 
    w.y = (2-s)*x3 + (s-3)*x2  + 1; 
    w.z = (s-2)*x3 + (3-2*s)*x2 + s*x + 0; 
    w.w =  s*x3 -  s*x2  + 0; 
    return w; 
} 

私はこれらの係数を見つけ、プラス:だから私はそうのような若干異なるレシピを使用してキャットマル-Romのスプラインを、使用に切り替え: http://www.cs.cmu.edu/afs/cs/academic/class/15462-s10/www/lec-slides/lec06.pdf

3

I)のドロップ内のテクスチャの代替(として使用することができ、この実装を発見した()固定1つの誤植(http://www.java-gaming.org/index.php?topic=35123.0から):

// from http://www.java-gaming.org/index.php?topic=35123.0 
vec4 cubic(float v){ 
    vec4 n = vec4(1.0, 2.0, 3.0, 4.0) - v; 
    vec4 s = n * n * n; 
    float x = s.x; 
    float y = s.y - 4.0 * s.x; 
    float z = s.z - 4.0 * s.y + 6.0 * s.x; 
    float w = 6.0 - x - y - z; 
    return vec4(x, y, z, w) * (1.0/6.0); 
} 

vec4 textureBicubic(sampler2D sampler, vec2 texCoords){ 

    vec2 texSize = textureSize(sampler, 0); 
    vec2 invTexSize = 1.0/texSize; 

    texCoords = texCoords * texSize - 0.5; 


    vec2 fxy = fract(texCoords); 
    texCoords -= fxy; 

    vec4 xcubic = cubic(fxy.x); 
    vec4 ycubic = cubic(fxy.y); 

    vec4 c = texCoords.xxyy + vec2 (-0.5, +1.5).xyxy; 

    vec4 s = vec4(xcubic.xz + xcubic.yw, ycubic.xz + ycubic.yw); 
    vec4 offset = c + vec4 (xcubic.yw, ycubic.yw)/s; 

    offset *= invTexSize.xxyy; 

    vec4 sample0 = texture(sampler, offset.xz); 
    vec4 sample1 = texture(sampler, offset.yz); 
    vec4 sample2 = texture(sampler, offset.xw); 
    vec4 sample3 = texture(sampler, offset.yw); 

    float sx = s.x/(s.x + s.y); 
    float sy = s.z/(s.z + s.w); 

    return mix(
     mix(sample3, sample2, sx), mix(sample1, sample0, sx) 
    , sy); 
} 

例:最も近い、バイリニア、バイキュービック:

enter image description here

この画像のImageDataを私は

enter image description here

この(他の多くの補間技術)を再生しようとしたが、私ながら、彼らは、パディングをクランプしている

{{{0.698039, 0.996078, 0.262745}, {0., 0.266667, 1.}, {0.00392157, 
    0.25098, 0.996078}, {1., 0.65098, 0.}}, {{0.996078, 0.823529, 
    0.}, {0.498039, 0., 0.00392157}, {0.831373, 0.00392157, 
    0.00392157}, {0.956863, 0.972549, 0.00784314}}, {{0.909804, 
    0.00784314, 0.}, {0.87451, 0.996078, 0.0862745}, {0.196078, 
    0.992157, 0.760784}, {0.00392157, 0.00392157, 0.498039}}, {{1., 
    0.878431, 0.}, {0.588235, 0.00392157, 0.00392157}, {0.00392157, 
    0.0666667, 0.996078}, {0.996078, 0.517647, 0.}}} 

あります境界を繰り返す(折り返す)。したがって、それはまったく同じではありません。

このバイキュービックビジネスは適切な補間ではないようです。つまり、データが定義されているポイントで元の値を引き継ぎません。