2008-12-03 25 views
6

Làm cách nào để tính góc giữa hai chuẩn trong glsl? Tôi đang cố gắng thêm hiệu ứng fresnel vào các cạnh bên ngoài của một đối tượng (kết hợp hiệu ứng đó với hiệu ứng bóng nền), và tôi nghĩ rằng góc là thứ duy nhất tôi đang thiếu.Làm thế nào để bạn tính toán góc giữa hai normals trong glsl?

Fragment Shader:

varying vec3 N; 
varying vec3 v; 

void main(void) { 
    v = vec3(gl_ModelViewMatrix * gl_Vertex); 
    N = normalize(gl_NormalMatrix * gl_Normal); 
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
} 

Vertex Shader:

varying vec3 N; 
varying vec3 v; 

void main(void) { 
    vec3 L = normalize(gl_LightSource[0].position.xyz - v); 
    vec3 E = normalize(-v); 
    vec3 R = normalize(-reflect(L,N)); 

    vec4 Iamb = gl_FrontLightProduct[0].ambient 
    vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0); 
    vec4 Ispec = gl_FrontLightProduct[0].specular * pow(max(dot(R,E),0.0), gl_FrontMaterial.shininess); 
    vec4 Itot = gl_FrontLightModelProduct.sceneColor + Iamb + Idiff + Ispec; 

    vec3 A = //calculate the angle between the lighting direction and the normal// 
    float F = 0.33 + 0.67*(1-cos(A))*(1-cos(A))*(1-cos(A))*(1-cos(A))*(1-cos(A)); 
    vec4 white = {1.0, 1.0, 1.0, 1.0}; 

    gl_FragColor = F*white + (1.0-F)*Itot; 
} 

vec3

Trả lời

5

khác nhau Từ chấm sản phẩm của hai vectơ bạn có thể nhận cosin của góc giữa chúng

cos A = DotProduct(v1, v2)/(Length(v1) * Length(v2)) 

Sử dụng tính năng này, bạn không cần tính cosin khi tính F. Vì vectơ của bạn là vectơ đơn vị, ví dụ, có độ dài một, bạn thậm chí có thể tránh phân chia.

+0

glsl thậm chí có một toán tử dấu chấm được tích hợp sẵn. Dòng mã sẽ đẹp đơn giản: cA = dot (v1, v2); Sau này, tất cả các tham chiếu cos (A) có thể được thay thế bằng cA. –

11

sản phẩm chấm giữa hai vectơ sẽ trả về cosin của góc (trong GLSL là dấu chấm (a, b)). Lấy arc-cosin của nó sẽ trả về góc bằng radian (trong GLSL nó là acos (x)).

Sản phẩm Dot rất rẻ, arc-cosin khá đắt.

Tuy nhiên, hiệu ứng Fresnel không thực sự cần góc. Chỉ cần có kết quả dấu chấm giữa các vectơ là đủ. Có rất nhiều xấp xỉ cho hiệu ứng Fresnel, một trong những rẻ nhất là chỉ sử dụng dấu chấm trực tiếp. Hoặc bình phương nó (x * x), hoặc nâng lên một số sức mạnh khác.

Trong trình đổ bóng của bạn ở trên, có vẻ như bạn chỉ muốn tăng điểm đến lũy thừa thứ 5. Một cái gì đó như:

float oneMinusDot = 1.0 - dot(L, N); 
float F = pow(oneMinusDot, 5.0); 
Các vấn đề liên quan