Étant donné le triangle ▲ ABC, nous divisons l'angle ∠BAC avec la droite AD, dérivé du théorème de l' angle bissecteur :
BA / BD = CA / CD Le
point E représente notre position raffinée objective sur le triangle incrusté résultant souhaité. Comme il repose sur la bissectrice d'angle AD, il est équidistant des côtés BA & CA, formant des triangles rectangles identiques ▲ AFE & ▲ AGE. Nous pouvons maintenant utiliser Sine for Right Triangles pour trouver la longueur de AE:
AE = EG / Sin (∠EAG)
C'est tout le calcul dont nous avons besoin, alors préparons du GLSL!
Nous commençons avec tous les attributs typiques: les matrices de position, normale et de transformation, mais comme le vertex shader ne fonctionne que sur un seul sommet, nous devons ajouter les sommets voisins comme attributs supplémentaires. De cette façon, chaque sommet trouvera son propre "point E", créant le triangle incrusté résultant. (Remarque: je ne les appelle pas "B" et "C" ici, car ils ne sont pas encore dans l'espace écran .)
attribute vec3 left; //vertex to the left of this vertex
attribute vec3 right; //vertex to the right of this vertex
En parlant d'espace d'écran, j'inclus également le rapport d'aspect de l'affichage (et en le rendant uniforme, au cas où la fenêtre serait redimensionnée.)
Après avoir préparé différentes normales pour le fragment shader et transformé le visage en espace de détourage, nous pouvons passer à l'application des mathématiques ci-dessus:
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;
}
Ce code nous donne les résultats ci-dessous.
Remarque, il y a quelques cas de bord liés à des triangles presque triés sur la face arrière qui sont retournés par ce processus, et j'ai commencé à traiter cela dans le code, mais j'ai décidé de simplement éviter ces cas pour l'instant. Je vais peut-être y revenir lorsque j'aurai terminé ce projet.