Как рассчитать угол между двумя нормалями в glsl? - PullRequest
6 голосов
/ 04 декабря 2008

Как вы рассчитываете угол между двумя нормалями в glsl? Я пытаюсь добавить эффект Френеля к внешним краям объекта (комбинируя этот эффект с затенением фонга), и я думаю, что угол - это единственное, чего мне не хватает.

Фрагмент шейдера:

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

Ответы [ 2 ]

11 голосов
/ 04 декабря 2008

произведение точек между двумя векторами вернет косинус угла (в GLSL это точка (a, b)). Взяв арккосинус, мы получим угол в радианах (в GLSL это acos (x)).

Точечный продукт очень дешевый, арккосинус довольно дорогой.

Однако эффекту Френеля не нужен угол. Достаточно иметь точечный результат между векторами. Существует много приближений к эффекту Френеля, одно из самых дешевых - это просто прямое использование точки. Или возводя его в квадрат (х * х), или поднимая до какой-то другой степени.

В вашем шейдере выше, похоже, вы просто хотите поднять точку до 5-й степени. Что-то вроде:

float oneMinusDot = 1.0 - dot(L, N);
float F = pow(oneMinusDot, 5.0);
5 голосов
/ 04 декабря 2008

Из точечного произведения двух векторов вы можете получить косинус угла между ними

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

Используя это, вам не нужно вычислять косинус при расчете F. Поскольку ваши векторы являются единичными векторами, например, имеют длину один, вы даже можете избежать деления.

...