Problem glTexGen in Open GL ES 2.0

2019-07-19 17:17发布

问题:

I have a problem somehow similar to this post : glTexGen in OpenGL ES 2.0

I've looked up on the web a couple of other websites without finding out how to solve my issue.

Basically, I want to map a texture onto a 2D quad after having set up an orthographic projection. The problem I have is that the texture is distorted as you can see on this picture where I used a coloured pattern instead of a texture:

I would like the lines of the texture to stay straight on the quad, but as you can see, they are distorted. I guess that I should modify the vertex shader in order for the texture coordinates to map the quad but I can't figure out how.

Thanks a lot, Jim

回答1:

what you need is a different kind of interpolation (I believe that would be quadratic interpolation), because in this case (edge lengths in space do not correspond with edge lengths in texture), linear interpolation won't cut it.

It is unfortunately rather complex task to do in OpenGL (very simple using software rasterization, though). You are trying to find a transform of an arbitrary quad in screenspace onto a unit square in texture space. You can find complete solution of your problem here: http://alumni.media.mit.edu/~cwren/interpolator/ This would get you a matrix by which you need to multiply screenspace coordinates to get correct texture coordinates (in fragment shader).

As that involves rather nasty math, i would suggest a simple solution which actually kind of works for simple static cases (requires manual tweaking). The texture coordinate calculated in vertex shader is actually only off on the center edge, the rest is correct. Assuming your texcoords are (0, 0), (1, 0), (1, 1) and (0, 1), The correction factor is:

u * v // for the first triangle
(1 - u) * (1 - v) // for the second triangle

You need to estimate the correction vector, and then put it all together. I tested using a simple C++ OpenGL app, i draw the following:

Vector2f ta(0, 1), tb(1, 1), tc(1, 0), td(0, 0);
Vector2f a(-.1f, 1), b(1, .7f), c(1, .1f), d(0, 0);
// quad texcoords and vertices

Vector2f t_corr(-.01f, .5f);
// correction for the above quad

glBegin(GL_TRIANGLES);
glMultiTexCoord2f(GL_TEXTURE1, 1, -1); // first triangle
glTexCoord4f(ta.x, ta.y, t_corr.x, t_corr.y);
glVertex2f(a.x, a.y);
glTexCoord4f(tb.x, tb.y, t_corr.x, t_corr.y);
glVertex2f(b.x, b.y);
glTexCoord4f(tc.x, tc.y, t_corr.x, t_corr.y);
glVertex2f(c.x, c.y);

glMultiTexCoord2f(GL_TEXTURE1, 0, 1); // second triangle
glTexCoord4f(ta.x, ta.y, t_corr.x, t_corr.y);
glVertex2f(a.x, a.y);
glTexCoord4f(tc.x, tc.y, t_corr.x, t_corr.y);
glVertex2f(c.x, c.y);
glTexCoord4f(td.x, td.y, t_corr.x, t_corr.y);
glVertex2f(d.x, d.y);
glEnd();

And the vertex shader looks like this:

void main()
{
    gl_Position = ftransform();
    gl_FrontColor = gl_Color;
    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_TexCoord[1] = gl_MultiTexCoord1; // just copy coords, nothing else to do
}

Fragment shader:

uniform sampler2D sam;
void main()
{
    vec2 corr = vec2(gl_TexCoord[1].x + gl_TexCoord[1].y * gl_TexCoord[0].x,
                     gl_TexCoord[1].x + gl_TexCoord[1].y * gl_TexCoord[0].y);
    gl_FragColor = texture2D(sam, gl_TexCoord[0].xy + gl_TexCoord[0].zw * corr.x * corr.y);
}

This is very simple, but by adjusting the correction vector properly, you can make this into that: http://www.luki.webzdarma.cz/up/deskew.png

Another option is to do this with a real quad in 3D and manually rotate it to such position that it looks like your 2D quad. Or devise "depth" texture coordinates for your quad, calculate 1/depth in vertex shader, interpolate (u/depth, v/depth, 1/depth), and divide by interpolated 1/depth later on in fragment shader to get good values. While this might seem simple, note it is quite hard to come up with good depth values.