2008-12-03 16 views
6

¿Cómo se calcula el ángulo entre dos normales en glsl? Estoy intentando agregar el efecto fresnel a los bordes exteriores de un objeto (combinando ese efecto con el sombreado phong), y creo que el ángulo es lo único que me falta.¿Cómo se calcula el ángulo entre dos normales en glsl?

Fragmento de 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; 
} 

variando vec3

Respuesta

5

A partir del producto escalar de dos vectores se puede obtener el coseno del ángulo entre ellos

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

Al usar esto, no necesita calcular el coseno cuando calcula F. Dado que sus vectores son vectores unitarios, p. Ej., Tienen longitud uno, incluso puede evitar la división.

+0

glsl incluso tiene un operador de producto de punto incorporado. La línea de código sería maravillosamente simple: cA = punto (v1, v2); Después de esto, todas las referencias de cos (A) podrían reemplazarse con cA. –

11

producto de punto entre dos vectores devolverá el coseno del ángulo (en GLSL es punto (a, b)). Tomar arco-coseno de eso devolverá el ángulo en radianes (en GLSL es acos (x)).

El producto de punto es muy barato, el arco coseno es bastante caro.

Sin embargo, el efecto Fresnel realmente no necesita el ángulo. Solo es suficiente tener un resultado de punto entre los vectores. Hay muchas aproximaciones para el efecto Fresnel, una de las más baratas es usar el punto directamente. O cuadratándola (x * x), o aumentando a otra potencia.

En su sombreador de arriba, parece que solo quiere elevar el punto a la quinta potencia. Algo como:

float oneMinusDot = 1.0 - dot(L, N); 
float F = pow(oneMinusDot, 5.0); 
Cuestiones relacionadas