6

glslで2つの法線間の角度をどのように計算しますか? オブジェクトの外縁にフレネル効果を追加しようとしています (その効果をフォン シェーディングと組み合わせます)。欠けているのは角度だけだと思います。

フラグメント シェーダー:

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

頂点シェーダー:

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

4

2 に答える 2

11

2つのベクトル間の内積は、角度の正弦を返します(GLSLではdot(a、b)です)。そのアークコサインを取ると、角度がラジアンで返されます(GLSLではacos(x)です)。

ドット積は非常に安価で、アークコサインは非常に高価です。

ただし、フレネル効果は実際には角度を必要としません。ベクトル間にドットの結果があるだけで十分です。フレネル効果には多くの近似値がありますが、最も安価なものの1つは、ドットを直接使用することです。または、2乗(x * x)するか、他の累乗にします。

上記のシェーダーでは、ドットを5乗したいようです。何かのようなもの:

float oneMinusDot = 1.0 - dot(L, N);
float F = pow(oneMinusDot, 5.0);
于 2008-12-04T11:17:30.497 に答える
5

2 つのベクトルの内積から、それらの間の角度のコサインを取得できます。

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

これを使用すると、F を計算するときにコサインを計算する必要はありません。ベクトルは単位ベクトルであるため、たとえば長さが 1 であるため、除算を回避することもできます。

于 2008-12-03T21:34:27.973 に答える