13

整数値 (1、2、3 など) に変換すると、タイル間に黒い線がなく、きれいに見えます。しかし、それが非整数 (1.1、1.5、1.67) に変換されると、各タイルの間に小さな黒っぽい線ができます (サブピクセル レンダリングによるものだと想像していますよね?) ...そして、きれいに見えません。 =P

それで...どうすればいいですか?

ちなみに、これは私の画像読み込みコードです:

bool Image::load_opengl() {
    this->id = 0;

    glGenTextures(1, &this->id);

    this->bind();

    // Parameters... TODO: Should we change this?
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, this->size.x, this->size.y,
   0, GL_BGRA, GL_UNSIGNED_BYTE, (void*) FreeImage_GetBits(this->data));

    this->unbind();

    return true;
}

私も使ってみました:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

と:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

ここに私の画像描画コードがあります:

void Image::draw(Pos pos, CROP crop, SCALE scale) {
    if (!this->loaded || this->id == 0) {
        return;
    }

    // Start position & size
    Pos s_p;
    Pos s_s;

    // End size
    Pos e_s;

    if (crop.active) {
        s_p = crop.pos / this->size;
        s_s = crop.size / this->size;
        //debug("%f %f", s_s.x, s_s.y);
        s_s = s_s + s_p;
        s_s.clamp(1);
        //debug("%f %f", s_s.x, s_s.y);
    } else {
        s_s = 1;
    }

    if (scale.active) {
        e_s = scale.size;
    } else if (crop.active) {
        e_s = crop.size;
    } else {
        e_s = this->size;
    }

    // FIXME: Is this okay?
    s_p.y = 1 - s_p.y;
    s_s.y = 1 - s_s.y;

    // TODO: Make this use VAO/VBO's!!
    glPushMatrix();

        glTranslate(pos.x, pos.y, 0);

        this->bind();

        glBegin(GL_QUADS);

            glTexCoord2(s_p.x, s_p.y);
            glVertex2(0, 0);

            glTexCoord2(s_s.x, s_p.y);
            glVertex2(e_s.x, 0);

            glTexCoord2(s_s.x, s_s.y);
            glVertex2(e_s.x, e_s.y);

            glTexCoord2(s_p.x, s_s.y);
            glVertex2(0, e_s.y);

        glEnd();

        this->unbind();

    glPopMatrix();
}

OpenGL 初期化コード:

void game__gl_init() {
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0, config.window.size.x, config.window.size.y, 0.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glDisable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glEnable(GL_TEXTURE_2D);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

問題のスクリーンショット:

スクリーンショット 1 スクリーンショット 2

4

3 に答える 3

24

テクスチャ アトラス (スプライト シート) の使用と隣接テクセルのリークの問題は、線形テクスチャ フィルタリングの動作に関係しています。

テクセルの中心で正確にサンプリングされていないテクスチャ内の任意のポイントについて、リニア サンプリングは 4 つの隣接するテクセルをサンプリングし、4 つすべての重み付けされた (サンプル ポイントからの距離に基づく) 平均として、指定した位置の値を計算します。サンプル。

これは問題の素晴らしい視覚化です:

画像0

テクスチャ アトラスのようなものは使用できないためGL_CLAMP_TO_EDGE、各テクスチャのエッジの周りに境界テクセルを作成する必要があります。これらの境界テクセルは、アトラス内のまったく異なるテクスチャからの隣接サンプルが、上で説明した加重補間によって画像を変更するのを防ぎます。

異方性フィルタリングを使用する場合、境界線の幅を広げる必要がある場合があることに注意してください。これは、異方性フィルタリングが極端な角度でサンプル近傍のサイズを大きくするためです。


各テクスチャの端に境界線を使用することの意味を説明するために、OpenGL で使用できるさまざまなラップ モードを考えてみましょう。に特に注意してCLAMP TO EDGEください。

画像1

「Clamp to Border」と呼ばれるモードがありますが、これは実際には私たちが関心を持っているものではありません。このモードでは、正規化された [0.0 -1.0] 範囲。

私たちが望むのはCLAMP_TO_EDGE、(サブ)テクスチャの適切な範囲外のテクスチャ座標が、範囲外であった方向の最後のテクセル中心の値を受け取る の動作を複製することです。ほぼ完全に制御できるため、アトラス システムのテクスチャ座標。(有効な) テクスチャ座標がテクスチャの外側の場所を参照する可能性がある唯一のシナリオは、テクスチャ フィルタリングの加重平均ステップ中です。

GL_LINEAR上の図に示すように、4 つの最近傍がサンプリングされることがわかっているため、必要なのは 1 テクセル境界だけです。異方性フィルタリングを使用する場合は、特定の条件下でサンプルの近傍サイズが大きくなるため、より広いテクセル境界が必要になる場合があります。

境界線をより明確に示すテクスチャの例を次に示しますが、目的に応じて境界線の幅を 1 テクセルまたは 2 テクセルにすることができます。

画像2

(注: 私が言及している境界線は、画像の 4 つのエッジすべてを囲む黒ではなく、チェッカーボード パターンが定期的に繰り返されなくなった領域です)

ご参考までに、私が異方性フィルタリングを取り上げ続ける理由は次のとおりです。角度に基づいてサンプル近傍の形状を変更し、フィルタリングに 4 つを超えるテクセルが使用される可能性があります。

画像3

使用する異方性の度合いが大きいほど、4 つを超えるテクセルを含むサンプル近傍を処理しなければならない可能性が高くなります。ほとんどの異方性フィルタリングの状況では、2 テクセル境界で十分です。


最後に、テクスチャ フィルタGL_CLAMP_TO_EDGEの存在下で動作 を複製するパック テクスチャ アトラスを構築する方法を次に示します。GL_LINEAR

(黒座標の X と Y から 1 を引いてください。投稿する前に画像を校正していませんでした。 )

ボーダー ストレージのため、このアトラスに 4 つの 256x256 テクスチャを格納するには、寸法が 516x516 のテクスチャが必要です。境界線は、アトラスの作成中にテクセル データで塗りつぶす方法に基づいて色分けされています。

  • 赤 = 直下のテクセルに置換
  • 黄 = 真上のテクセルに置き換える
  • 緑 = 左のテクセルに置き換えます
  • 青 = すぐ右側のテクセルに置き換えます

このパックされた例では、事実上、アトラスの各テクスチャはアトラスの 258x258 領域を使用しますが、可視の 256x256 領域にマップするテクスチャ座標を生成します。境界テクセルは、テクスチャ フィルタリングがアトラスのテクスチャのエッジで行われる場合にのみ使用され、その設計方法はGL_CLAMP_TO_EDGE動作を模倣します。

ご参考までに、同様のアプローチを使用して他のタイプのラップ モードをGL_REPEAT実装できます。これは、テクスチャ アトラスで左/右および上/下の境界テクセルを交換し、少し巧妙なテクスチャ座標計算をシェーダー。これはもう少し複雑なので、今は気にしないでください。あなたはスプライトシートだけを扱っているのでGL_CLAMP_TO_EDGE:)

于 2013-10-26T21:18:33.950 に答える