Estoy tratando de simular cosas como glPolygonMode( GL_BACK, GL_LINE) en WebGL. Puedo dibujar con el modo LINES en lugar de TRIANGLES, pero no puedo ver cómo WebGL podría determinar automáticamente si un segmento en particular está orientado hacia atrás, porque los segmentos no se enfrentan en ninguna parte.

Para resolver esto, paso la normalidad del triángulo original al sombreador. Es fácil calcular las transformaciones de esto bajo las transformaciones usuales de vista de modelo (rotaciones, escalado, traslaciones); entonces simplemente multiplico lo normal por la transposición de lo inverso. Según si los puntos normales entran o salen de la pantalla, puedo decidir si eliminar un segmento de línea.

Sin embargo, esto no está del todo bien. Necesito también el inverso de la matriz de proyección para tener en cuenta las distorsiones de perspectiva.

Estoy usando las funciones CanvasMatrix4.frustum() o CanvasMatrix4.ortho() para obtener la matriz de proyección. ¿Hay fórmulas o funciones disponibles para sus inversas?

Alternativamente, ¿hay una mejor manera de simular cosas como glPolygonMode( GL_BACK, GL_LINE)?

0
user2554330 27 dic. 2016 a las 15:31

3 respuestas

La mejor respuesta

La idea de enviar los otros vértices del triángulo como atributos adicionales parece funcionar.

Aquí está la parte clave del sombreador de vértices. El atributo aPos es la posición del vértice que se usa en el segmento de línea; v1 es el siguiente vértice que va alrededor del triángulo, y v2 es el siguiente.

He editado el código para dejar de lado las cosas relacionadas con la iluminación. Probablemente esta no sea la implementación más eficiente, pero parece funcionar.

attribute vec3 aPos;
uniform mat4 mvMatrix;
uniform mat4 prMatrix;
attribute vec3 v1;
attribute vec3 v2;
varying float normz;

void main(void) {
    gl_Position = prMatrix * (mvMatrix * vec4(aPos, 1.));
    vec4 v1p = (prMatrix*(mvMatrix*vec4(v1, 1.)));
    v1p = v1p/v1p.w - gl_Position/gl_Position.w;
    vec4 v2p = (prMatrix*(mvMatrix*vec4(v2, 1.)));
    v2p = v2p/v2p.w - gl_Position/gl_Position.w;
    normz = v1p.x*v2p.y - v1p.y*v2p.x; // z component of cross product
}

En el sombreador de fragmentos, descarte fragmentos basados en el signo de normz. yo suelo

if ((normz <= 0.) != front) discard; 

Donde front es un bool que indica si quiero mostrar el frente o no.

1
user2554330 27 dic. 2016 a las 23:35

Si usar extensiones WebGl es una opción, es posible que desee ver OES_standard_derivatives. Esta extensión se introdujo con el propósito específico de resolver su problema de corrección de perspectiva. Según WebGL Stats el soporte es bastante universal.

En su base de código principal, habilite esta extensión:

gl.getExtension("OES_standard_derivatives");

La extensión presenta las funciones dFdx y dFdy, lo que le permite hacer una prueba frontal / posterior como esta:

vec3 dx = dFdx(position);
vec3 dy = dFdy(position);
vec3 faceNormal = normalize(cross(dx, dy));
if (dot(normal, faceNormal) > 0.0) {
    // Front facing
}
0
Paul-Jan 27 dic. 2016 a las 15:43

Toma el área del triángulo. Si es positivo, dibuje si es negativo, elimínelo.

-1
Malcolm McLean 27 dic. 2016 a las 12:52