27

テクスチャのある台形を描画しましたが、意図したとおりに結果が表示されません。

単一の途切れのない四辺形として表示される代わりに、2つの構成する三角形が交わる対角線で不連続性が発生します。

この図は、問題を示しています
ソーステクスチャ(市松模様)、期待される結果、および実際の(誤った)結果を示す図
(注:最後の画像は100%忠実な表現を意図したものではありませんが、要点を理解する必要があります。)

台形はGL_TRIANGLE_STRIP、OpenGL ES 2.0(iPhone上)を使用して描画されています。画面に完全に面して描画されており、傾いていません(つまり、表示されている3Dスケッチではありません!)

おそらく頂点シェーダーやフラグメントシェーダーで「遠近法補正」を実行する必要があることを理解しましたが、これを行う方法がわかりません。

私のコードにはいくつかの単純なモデル/ビュー/投影行列の計算が含まれていますが、現在、テクスチャ座標値に影響を与えるものはありません。更新:ユーザーの事実によるコメントによると、前のステートメントは正しくありません。

さらに、私はES 2.0仕様でこの一口を見つけましたが、それが何を意味するのか理解していません。

OpenGL ES 2.0ではすべての属性を遠近法で補間する必要があるため、PERSPECTIVECORRECTIONHINTはサポートされていません。

テクスチャを正しく描画するにはどうすればよいですか?


編集:以下にコードを追加しました:

// Vertex shader
attribute vec4 position;
attribute vec2 textureCoordinate;

varying vec2 texCoord;

uniform mat4 modelViewProjectionMatrix;

void main()
{
    gl_Position = modelViewProjectionMatrix * position;
    texCoord = textureCoordinate;
}

// Fragment shader
uniform sampler2D texture;
varying mediump vec2 texCoord;

void main()
{
    gl_FragColor = texture2D(texture, texCoord);
}

// Update and Drawing code (uses GLKit helpers from iOS)

- (void)update
{
    float fov = GLKMathDegreesToRadians(65.0f);
    float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
    projectionMatrix = GLKMatrix4MakePerspective(fov, aspect, 0.1f, 50.0f);
    viewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -4.0f); // zoom out
}

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(shaders[SHADER_DEFAULT]);

    GLKMatrix4 modelMatrix = GLKMatrix4MakeScale(0.795, 0.795, 0.795); // arbitrary scale

    GLKMatrix4 modelViewMatrix = GLKMatrix4Multiply(viewMatrix, modelMatrix);

    GLKMatrix4 modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, GL_FALSE, modelViewProjectionMatrix.m);

    glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_WALLS]);
    glUniform1i(uniforms[UNIFORM_TEXTURE], 0);

    glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, GL_FALSE, 0, wall.vertexArray);
    glVertexAttribPointer(ATTRIB_TEXTURE_COORDINATE, 2, GL_FLOAT, GL_FALSE, 0, wall.texCoords);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, wall.vertexCount);

}
4

3 に答える 3

21

(あなたの写真は台形のテクスチャリングから私が期待するものを正確に示していないため、ここで少しパントを取っています。おそらくあなたのケースでは何か他のことが起こっていますが、一般的な問題はよく知られています)

テクスチャは (デフォルトでは) 台形を横切って正しく補間されません。図形を三角形に分割して描画する場合、対角線の 1 つがエッジとして選択されます。そのエッジはテクスチャの中央をまっすぐ通過しますが、台形の中央を通過しません (対角線に沿って分割された形状を想像してください - 2 つの三角形はほとんど等しくありません)。

これを機能させるには、2D テクスチャ座標以上のものを提供する必要があります。3D (または射影) テクスチャ座標を提供し、フラグメント シェーダで遠近分割を実行し、ポスト補間を行う (またはテクスチャ ルックアップを使用する) 必要があります。同じことを行う関数)。

以下は、昔ながらの GL 関数を使用して台形のテクスチャ座標を提供する方法を示しています (デモンストレーション用に読みやすくなっています)。コメントアウトされた行は 2D テクスチャ座標であり、正しい補間を得るために射影座標に置き換えました。

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,640,0,480,1,1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

const float trap_wide = 600;
const float trap_narrow = 300;
const float mid = 320;

glBegin(GL_TRIANGLE_STRIP);
glColor3f(1,1,1);

//  glTexCoord4f(0,0,0,1);
glTexCoord4f(0,0,0,trap_wide);
glVertex3f(mid - trap_wide/2,10,-10);

//  glTexCoord4f(1,0,0,1);
glTexCoord4f(trap_narrow,0,0,trap_narrow);
glVertex3f(mid - trap_narrow/2,470,-10);

//  glTexCoord4f(0,1,0,1);
glTexCoord4f(0,trap_wide,0,trap_wide);
glVertex3f(mid + trap_wide/2,10,-10);

//  glTexCoord4f(1,1,0,1);
glTexCoord4f(trap_narrow,trap_narrow,0,trap_narrow);
glVertex3f(mid + trap_narrow/2,470,-10);

glEnd();

2D テクスチャを使用しているだけなので、ここでは 3 番目の座標は使用されません。4 番目の座標は、補間後に他の 2 つを分割し、投影を提供します。明らかに、頂点で分割すると、元のテクスチャ座標が得られることがわかります。

2 つのレンダリングは次のようになります。

ここに画像の説明を入力

台形が実際に四角形を変換した結果である場合は、ソフトウェアで変換して 2D 形状を GL に供給するよりも、GL を使用してその四角形を描画する方が簡単/優れている可能性があります...

于 2013-03-06T10:40:57.243 に答える
0

受け入れられた答えは正しい解決策と説明を提供しますが、OpenGL (ES) 2.0 パイプラインについてもう少し助けを求めている人のために...

const GLfloat L = 2.0;
const GLfloat Z = -2.0;
const GLfloat W0 = 0.01;
const GLfloat W1 = 0.10;

/** Trapezoid shape as two triangles. */
static const GLKVector3 VERTEX_DATA[] = {
    {{-W0,    0,  Z}},
    {{+W0,    0,  Z}},
    {{-W1,    L,  Z}},

    {{+W0,    0,  Z}},
    {{+W1,    L,  Z}},
    {{-W1,    L,  Z}},
};

/** Add a 3rd coord to your texture data.  This is the perspective divisor needed in frag shader */
static const GLKVector3 TEXTURE_DATA[] = {
    {{0, 0, 0}},
    {{W0, 0, W0}},
    {{0, W1, W1}},

    {{W0, 0, W0}},
    {{W1, W1, W1}},
    {{0, W1, W1}},
};

////////////////////////////////////////////////////////////////////////////////////

// frag.glsl

varying vec3 v_texPos;
uniform sampler2D u_texture;

void main(void) 
{
    // Divide the 2D texture coords by the third projection divisor
    gl_FragColor = texture2D(u_texture, v_texPos.st / v_texPos.p);
}

または、シェーダーでは、@ maverick9888 の回答に従って、使用できますtexture2Dprojが、iOS/OpenGLES2 ではまだvec3入力のみをサポートしています...

void main(void) 
{
    gl_FragColor = texture2DProj(u_texture, v_texPos);
}

私はそれを適切にベンチマークしていませんが、私の非常に単純なケース (実際には 1D テクスチャ) では、分割バージョンの方が少しきびきびしているように見えます。

于 2014-09-09T06:45:57.083 に答える
0

ここで試しているのは Skewed texture です。サンプル フラグメント シェーダーは次のとおりです。

precision mediump float;
varying vec4 vtexCoords;
uniform sampler2D sampler;

void main()
{
   gl_FragColor = texture2DProj(sampler,vtexCoords);
}

異なるように見える2つのことは次のとおりです。

1) を使用してvarying vec4 vtexCoords;います。テクスチャ座標は 4 次元です。2)texture2DProj()の代わりに使用されますtexture2D()

台形の短辺と大辺の長さに基づいて、テクスチャ座標を割り当てます。次の URL が役に立つかもしれません: http://www.xyzw.us/~cass/qcoord/

于 2014-08-11T08:38:39.013 に答える