Cho tam giác ▲ ABC, ta chia đôi góc BAC với đường thẳng AD, xuất phát với Định lý góc băm :
BA / BD = CA / CD
Điểm E thể hiện vị trí tinh chỉnh mục tiêu của chúng tôi trên tam giác chèn kết quả mong muốn. Vì nó nằm trên bisector góc AD, nó cách đều nhau từ các cạnh BA & CA, tạo thành các tam giác vuông giống hệt nhau ▲ AFE & ▲ AGE. Bây giờ chúng ta có thể sử dụng Sine cho tam giác vuông để tìm độ dài của AE:
AE = EG / Tội lỗi (EAG)
Đó là tất cả toán học chúng ta cần, vì vậy hãy nấu một số GLSL!
Chúng ta bắt đầu với tất cả các thuộc tính điển hình: ma trận vị trí, bình thường và ma trận biến đổi, nhưng vì trình tạo bóng đỉnh chỉ hoạt động trên một đỉnh duy nhất, chúng ta cần thêm các đỉnh lân cận làm thuộc tính bổ sung. Bằng cách này, mỗi đỉnh sẽ tìm thấy "điểm E" của riêng mình, tạo ra tam giác lồng kết quả. (Lưu ý: Tôi không gọi chúng là "B" & "C" ở đây, vì chúng chưa có trong không gian màn hình .)
attribute vec3 left; //vertex to the left of this vertex
attribute vec3 right; //vertex to the right of this vertex
Nói về không gian màn hình, tôi cũng bao gồm tỷ lệ khung hình của màn hình, (và làm cho nó đồng nhất, trong trường hợp cửa sổ được thay đổi kích thước.)
Sau khi chuẩn bị các quy tắc khác nhau cho trình tạo bóng mảnh và biến khuôn mặt thành không gian cắt, chúng ta có thể bắt tay vào công việc áp dụng toán học trên:
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;
}
Mã này cho chúng tôi kết quả dưới đây.
Lưu ý, có một vài trường hợp cạnh phải làm với các hình tam giác gần như bị lật ngược được lật theo quy trình này và tôi bắt đầu giải quyết vấn đề này trong mã, nhưng bây giờ quyết định chỉ đơn giản là tránh các trường hợp này. Có lẽ tôi sẽ xem lại nó khi tôi hoàn thành dự án này.