Dado el triángulo ▲ ABC, bisecamos el ángulo ∠BAC con la línea AD, derivada con el teorema de la bisectriz de ángulo :
BA / BD = CA / CD El
punto E representa nuestra posición objetiva refinada en el triángulo de inserción resultante deseado. Como yace sobre la bisectriz de ángulo AD, es equidistante de los lados BA y CA, formando triángulos rectángulos idénticos ▲ AFE y ▲ EDAD. Ahora podemos usar Seno para triángulos rectángulos para encontrar la longitud de AE:
AE = EG / Sin (∠EAG)
¡Esas son todas las matemáticas que necesitamos, así que cocinemos un poco de GLSL!
Comenzamos con todos los atributos típicos: posición, normal y matrices de transformación, pero dado que el sombreador de vértices solo funciona en un solo vértice, necesitamos agregar los vértices vecinos como atributos adicionales. De esta manera, cada vértice encontrará su propio "punto E", creando el triángulo insertado resultante. (Nota: no los llamo "B" y "C" aquí, porque todavía no están en el espacio de la pantalla ).
attribute vec3 left; //vertex to the left of this vertex
attribute vec3 right; //vertex to the right of this vertex
Hablando del espacio de la pantalla, también incluyo la relación de aspecto de la pantalla (y la hago uniforme, en caso de que la ventana cambie de tamaño).
Después de preparar diferentes valores normales para el sombreador de fragmentos y de transformar la cara en un espacio de recorte, podemos dedicarnos al negocio de aplicar las matemáticas anteriores:
attribute vec3 left; //vertex to the left of this vertex
attribute vec3 right; //vertex to the right of this vertex
uniform float aspect;
varying vec3 vNormal;
varying vec2 vUv;
void main() {
vNormal = normal;
vUv = uv;
mat4 xform= projectionMatrix * modelViewMatrix;
vec4 A = xform * vec4( position, 1.0 );
vec4 B = xform * vec4( left, 1.0 );
vec4 C = xform * vec4( right, 1.0 );
vec3 CB = C.xyz - B.xyz;
vec2 BA = B.xy - A.xy;
vec2 CA = C.xy - A.xy;
float lengthBA = length(BA);
float lengthCA = length(CA);
float ratio = lengthBA / ( lengthBA + lengthCA );
vec3 D = B.xyz + ratio * CB.xyz;
vec3 AD = D - A.xyz;
vec3 bisect = normalize(AD);
float theta = acos( dot(BA, CA) / (lengthBA * lengthCA) ) / 2.0;
float AE = 1.0/(sin(theta)*aspect);
newPos.z += AE/length(AD) * (D.z - A.z);
newPos.x += bisect.x*AE;
newPos.y += bisect.y*AE;
gl_Position = newPos;
}
Este código nos da los resultados a continuación.
Tenga en cuenta que hay algunos casos extremos que tienen que ver con triángulos casi sin fondo que se voltean por este proceso, y comencé a abordar esto en código, pero decidí simplemente evitar estos casos por ahora. Quizás lo vuelva a visitar cuando termine este proyecto.