opengl-es opengl-es-2.0

Perspectiva correcta de la textura del trapezoide en OpenGL ES 2.0



opengl-es opengl-es-2.0 (3)

Dibujé un trapecio texturizado, sin embargo, el resultado no aparece como lo había previsto.

En lugar de aparecer como un solo cuadrilátero ininterrumpido, se produce una discontinuidad en la línea diagonal donde se unen sus dos triángulos.

Esta ilustración demuestra el problema:

(Nota: la última imagen no pretende ser una representación fiel al 100%, pero debe mostrar el punto.)

El trapecio se está dibujando usando GL_TRIANGLE_STRIP en OpenGL ES 2.0 (en un iPhone). Se está dibujando completamente frente a la pantalla, y no se está inclinando (es decir, ¡no es un boceto 3D lo que estás viendo!)

Llegué a comprender que necesito realizar una "corrección de perspectiva", presumiblemente en mi sombreado de vértices y / o fragmentos, pero no tengo claro cómo hacerlo.

Mi código incluye algunas matrices matemáticas de Modelo / Vista / Proyección simples, pero ninguna de ellas influye actualmente en mis valores de coordenadas de textura. Actualización: la declaración anterior es incorrecta, de acuerdo con el comentario del usuario infact.

Además, he encontrado este dato en la especificación ES 2.0, pero no entiendo lo que significa:

La PUNTA DE CORRECCIÓN DE PERSPECTIVAS no se admite porque OpenGL ES 2.0 requiere que todos los atributos se interpolan con perspectiva.

¿Cómo puedo hacer que la textura se dibuje correctamente?

Edición: Código añadido a continuación:

// 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); }


(Estoy tomando un poco de despeje aquí, porque su imagen no muestra exactamente lo que esperaría de texturizar un trapecio, por lo que tal vez algo más esté sucediendo en su caso, pero el problema general es bien conocido)

Las texturas no se interpolarán (de forma predeterminada) correctamente en un trapezoide. Cuando la forma se triangula para dibujar, una de las diagonales se elegirá como un borde, y mientras que ese borde es recto a través de la mitad de la textura, no es a través de la mitad del trapecio (imagen de la forma dividida a lo largo de una diagonal - Los dos triángulos son muy diferentes no iguales.

Debe proporcionar más que una coordenada de textura 2D para que esto funcione: debe proporcionar una coordenada de textura 3D (o más bien, proyectiva) y realizar la división de perspectiva en el sombreado de fragmentos, post-interpolación (o bien utilice una búsqueda de texturas) función que hará lo mismo).

A continuación se muestra cómo proporcionar coordenadas de textura para un trapezoide utilizando las funciones GL de la vieja escuela (que son un poco más fáciles de leer para fines de demostración). Las líneas comentadas son las coordenadas de textura 2d, que he reemplazado con coordenadas proyectivas para obtener la interpolación correcta.

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();

La tercera coordenada no se usa aquí ya que solo estamos usando una textura 2D. La cuarta coordenada dividirá las otras dos después de la interpolación, proporcionando la proyección. Obviamente, si lo divides en los vértices, verás que obtienes las coordenadas de la textura original.

Así es como se ven las dos representaciones:

Si su trapecio es en realidad el resultado de transformar un quad, podría ser más fácil / mejor simplemente dibujar ese quad utilizando GL, en lugar de transformarlo en software y alimentar formas 2D a GL ...


La respuesta aceptada proporciona la solución y la explicación correctas, pero para aquellos que buscan un poco más de ayuda en el canal 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); }

Alternativamente, en el sombreador, según la respuesta de @maverick9888, puedes usar texture2Dproj aunque para iOS / OpenGLES2 todavía es compatible con una entrada vec3 ...

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

Realmente no lo he evaluado correctamente, pero para mi caso muy simple (una textura 1d realmente) la versión de la división parece un poco más ágil.


Lo que estás intentando aquí es una textura sesgada. Un shader de fragmentos de muestra es el siguiente:

precision mediump float; varying vec4 vtexCoords; uniform sampler2D sampler; void main() { gl_FragColor = texture2DProj(sampler,vtexCoords); }

2 cosas que deben verse diferentes son:

1) Estamos utilizando varying vec4 vtexCoords; . Las coordenadas de textura son 4 dimensiones. 2) se usa texture2D() lugar de texture2D()

En función de la longitud del lado grande y pequeño de su trapecio, asignará coordenadas de textura. La siguiente URL podría ayudar: http://www.xyzw.us/~cass/qcoord/