Dato triangolo ▲ ABC, biseciamo l'angolo ∠BAC con la linea AD, derivata dal teorema della bisettrice angolare :
BA / BD = CA / CD Il
punto E rappresenta la nostra posizione raffinata oggettiva sul triangolo dell'inserto risultante desiderato. Come si trova sulla bisettrice angolare AD, è equidistante dai lati BA e CA, formando identici triangoli retti ▲ AFE & ▲ AGE. Ora possiamo usare Sine for Right Triangles per trovare la lunghezza di AE:
AE = EG / Sin (∠EAG)
Questa è tutta la matematica di cui abbiamo bisogno, quindi prepariamo un po 'di GLSL!
Iniziamo con tutti gli attributi tipici: matrici di posizione, normali e di trasformazione, ma poiché lo shader di vertici funziona solo su un singolo vertice, è necessario aggiungere i vertici vicini come attributi aggiuntivi. In questo modo, ciascun vertice troverà il proprio "punto E", creando il triangolo dell'inserto risultante. (Nota: non li chiamo "B" e "C" qui, perché non sono ancora nello spazio dello schermo .)
attribute vec3 left; //vertex to the left of this vertex
attribute vec3 right; //vertex to the right of this vertex
Parlando di spazio sullo schermo, sto anche includendo le proporzioni del display (e rendendolo uniforme, nel caso in cui la finestra venga ridimensionata).
Dopo aver preparato varie normali per lo shader di frammenti e trasformato la faccia in spazio di ritaglio, possiamo dedicarci all'applicazione della matematica di cui sopra:
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;
}
Questo codice ci fornisce i risultati seguenti.
Nota, ci sono alcuni casi limite che hanno a che fare con il ribaltamento di triangoli quasi abbattuti sul retro da questo processo, e ho iniziato ad occuparmene in codice, ma per ora ho deciso di evitare questi casi. Forse lo rivisiterò quando avrò finito questo progetto.