2008-12-03 17 views
6

Wie berechnen Sie den Winkel zwischen zwei Normalen in GLSL? Ich versuche, den Fresnel-Effekt an den Außenkanten eines Objekts hinzuzufügen (kombiniert diesen Effekt mit einer Phong-Schattierung), und ich denke, dass der Winkel das einzige ist, was mir fehlt.Wie berechnen Sie den Winkel zwischen zwei Normalen in 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; 
} 

unterschiedlichen vec3

Antwort

5

Aus dem Skalarprodukt von zwei Vektoren Sie den Kosinus des Winkels zwischen ihnen

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

Damit müssen Sie den Kosinus bei der Berechnung von F nicht berechnen. Da Ihre Vektoren Einheitsvektoren sind, z. B. die Länge eins haben, können Sie sogar die Teilung vermeiden.

+0

Glsl hat sogar einen integrierten dot-Produkt-Betreiber. Die Codezeile wäre schön einfach: cA = Punkt (v1, v2); Danach könnten alle cos (A) Referenzen durch cA ersetzt werden. –

11

Punktprodukt zwischen zwei Vektoren wird den Kosinus des Winkels zurückgeben (in GLSL ist es Punkt (a, b)). Wenn man den Arkuskosinus nimmt, wird der Winkel im Bogenmaß zurückgegeben (in GLSL ist es acos (x)).

Dot Produkt ist sehr billig, Arc-Cosine ist ziemlich teuer.

Allerdings braucht Fresnel-Effekt nicht wirklich den Winkel. Nur ein Punkt-Ergebnis zwischen den Vektoren ist genug. Es gibt viele Näherungen für den Fresnel-Effekt, wobei einer der günstigsten ist, den Punkt direkt zu verwenden. Oder sie zu quadrieren (x * x) oder auf eine andere Potenz zu heben.

In Ihrem Shader oben sieht es so aus, als wollten Sie nur Punkt auf 5. Potenz erhöhen. Etwas wie:

float oneMinusDot = 1.0 - dot(L, N); 
float F = pow(oneMinusDot, 5.0); 
Verwandte Themen