8

以下は、指定されたテクスチャ座標がボックス内にある場合にテクセルを出力するGLSLフラグメントシェーダーです。それ以外の場合は、色が出力されます。これはばかげていると感じ、分岐せずにこれを行う方法があるはずですか?

uniform sampler2D texUnit;

varying vec4 color;
varying vec2 texCoord;

void main() {
  vec4 texel = texture2D(texUnit, texCoord);
  if (any(lessThan(texCoord, vec2(0.0, 0.0))) ||
      any(greaterThan(texCoord, vec2(1.0, 1.0))))
    gl_FragColor = color;
  else
    gl_FragColor = texel;
}

以下は分岐のないバージョンですが、それでも不器用です。「テクスチャ座標クランプ」のベストプラクティスは何ですか?

uniform sampler2D texUnit;

varying vec4 color;
varying vec4 labelColor;
varying vec2 texCoord;

void main() {
  vec4 texel = texture2D(texUnit, texCoord);
  bool outside = any(lessThan(texCoord, vec2(0.0, 0.0))) ||
                 any(greaterThan(texCoord, vec2(1.0, 1.0)));
  gl_FragColor = mix(texel*labelColor, color,
                     vec4(outside,outside,outside,outside));
}

これがレンダリング結果です

ラベルが付いている領域にテクセルをクランプしています-この場合、テクスチャのs&t座標は0から1の間になります。それ以外の場合は、ラベルがない場所に茶色を使用します。

必要のないときにテクスチャルックアップを実行しない分岐バージョンのコードを作成することもできることに注意してください。これは、常にテクスチャルックアップを実行する非分岐バージョンよりも高速ですか?多分いくつかのテストの時間...

4

4 に答える 4

20

関数を使用stepして分岐を回避し、最高のパフォーマンスを実現します。

// return 1 if v inside the box, return 0 otherwise
float insideBox(vec2 v, vec2 bottomLeft, vec2 topRight) {
    vec2 s = step(bottomLeft, v) - step(topRight, v);
    return s.x * s.y;   
}

float insideBox3D(vec3 v, vec3 bottomLeft, vec3 topRight) {
    vec3 s = step(bottomLeft, v) - step(topRight, v);
    return s.x * s.y * s.z; 
}

void main() {
    vec4 texel = texture2D(texUnit, texCoord);

    float t = insideBox(v_position, vec2(0, 0), vec2(1, 1));
    gl_FragColor = t * texel + (1 - t) * color;
}
于 2014-11-02T08:58:27.763 に答える
4

ダンファットの答えに基づいて、長方形の内側と外側の間をスムーズに移行するための関数を実装しました。

float inside_rectangle_smooth(vec2 p, vec2 bottom_left, vec2 top_right, float transition_area)
{
    vec2 s = smoothstep(bottom_left, bottom_left + vec2(transition_area), p) -
             smoothstep(top_right - vec2(transition_area), top_right, p);
    return(s.x * s.y);
}

「transition_area」パラメータを使用して、長方形の内側と外側の間の遷移領域のサイズを調整します。トランジションは、長方形の外側ではなく、長方形の内側でフェードします。また、「transition_area」パラメーターが「bottom_left」と「top_right」の間の距離(各次元)よりも小さいことを確認してください。
この関数を使用して、エンジンのシャドウをフェードさせています(シャドウマップ座標を使用)。

デモンストレーション: 上の画像は、次の呼び出しによって生成されます。
inside_rectangle_smooth(v_texture_coordinate、vec2(0.0)、vec2(1.0)、0.1)

inside_rectangle_smooth(v_texture_coordinate, vec2(0.0), vec2(1.0), 0.1)

于 2016-05-25T01:45:39.237 に答える
2

私はこのソリューションに出くわしました。https://github.com/stackgl/shader-school経由

bool inBox(highp vec2 lo, highp vec2 hi, highp vec2 p) {
    bvec4 b = bvec4(greaterThan(p, lo), lessThan(p, hi));
    return all(b);
}
于 2017-07-18T21:18:51.127 に答える
0

以下は、2つの可能な実装です。

(特にベンチマークを行った場合は、パフォーマンスについてコメントしてください。)

  1. step()比較は、 :への1回の呼び出しで行われます。

    bool rectContainsPoint(vec2 rectBottomLeft, vec2 rectTopRight, vec2 point)
    {
        vec4 pt = vec4(point, -point);
        vec4 r = vec4(rectBottomLeft, -rectTopRight);
        vec4 inside = step(r, pt);
        return all(bvec4(inside));
    }
    
  2. このシンプルな実装はもっと速くなるでしょうか?それとも遅いですか?

    bool rectContainsPoint(vec2 rectBottomLeft, vec2 rectTopRight, vec2 point) 
    {
        return all(point == clamp(point, rectBottomLeft, rectTopRight));
    }
    
于 2020-02-06T14:36:17.903 に答える