2015-04-18 5 views
3

У меня есть простое приложение, которое рисует сферу с одним направленным светом. Я создаю сферу, начиная с октаэдра и разбивая каждый треугольник на 4 меньших треугольника.Почему мои зеркальные блики так сильно проявляются на краях многоугольника?

С просто рассеянным освещением шар выглядит очень гладким. Однако, когда я добавляю зеркальные блики, края треугольников проявляются довольно сильно. Вот некоторые примеры:

Диффузный только:

Sphere with only diffuse lighting

Диффузный и Отраженный:

Sphere with diffuse and specular

Я считаю, что нормалей подвергаются интерполяции правильно. Глядя только нормали, я получаю это:

Sphere normals

В самом деле, если я переключаюсь на затенение, где нормали за полигон вместо за вершины, я получаю это:

enter image description here

В моем вершинном шейдере, я умножая нормали модели матрицы транспонированного обратный видовой:

#version 330 core 

layout (location = 0) in vec4 vPosition; 
layout (location = 1) in vec3 vNormal; 
layout (location = 2) in vec2 vTexCoord; 

out vec3 fNormal; 
out vec2 fTexCoord; 

uniform mat4 transInvModelView; 
uniform mat4 ModelViewMatrix; 
uniform mat4 ProjectionMatrix; 

void main() 
{ 
    fNormal = vec3(transInvModelView * vec4(vNormal, 0.0)); 
    fTexCoord = vTexCoord; 
    gl_Position = ProjectionMatrix * ModelViewMatrix * vPosition; 
} 

и в пиксельный шейдер, я вычисляя блики следующим образом:

#version 330 core 

in vec3 fNormal; 
in vec2 fTexCoord; 

out vec4 color; 

uniform sampler2D tex; 
uniform vec4 lightColor;  // RGB, assumes multiplied by light intensity 
uniform vec3 lightDirection; // normalized, assumes directional light, lambertian lighting 
uniform float specularIntensity; 
uniform float specularShininess; 
uniform vec3 halfVector;  // Halfway between eye and light 
uniform vec4 objectColor; 

void main() 
{ 
    vec4 texColor = objectColor; 

    float specular = max(dot(halfVector, fNormal), 0.0); 
    float diffuse  = max(dot(lightDirection, fNormal), 0.0); 

    if (diffuse == 0.0) 
    { 
     specular = 0.0; 
    } 
    else 
    { 
     specular = pow(specular, specularShininess) * specularIntensity; 
    } 

    color = texColor * diffuse * lightColor + min(specular * lightColor, vec4(1.0)); 
} 

Я был немного смущен о том, как рассчитать halfVector. Я делаю это на процессоре и передаю его как униформу. Он рассчитывается следующим образом:

vec3 lightDirection(1.0, 1.0, 1.0); 
lightDirection = normalize(lightDirection); 
vec3 eyeDirection(0.0, 0.0, 1.0); 
eyeDirection = normalize(eyeDirection); 
vec3 halfVector = lightDirection + eyeDirection; 
halfVector = normalize(halfVector); 
glUniform3fv(halfVectorLoc, 1, &halfVector [ 0 ]); 

Это правильная формулировка для halfVector? Или это нужно делать в шейдерах?

ответ

8

Интерполирующие нормали в лицо могут (и почти всегда будут) приводить к сокращению нормы. Вот почему подсветка темнее в центре лица и ярче на углах и краях. Если вы сделаете это, просто повторно нормализовать нормальный в пиксельный шейдер:

fNormal = normalize(fNormal); 

Btw, вы не можете предвычисления половину вектора, как это вид зависит (в этом вся точка зеркального освещения). В текущем сценарии подсветка не изменится, когда вы просто перемещаете камеру (сохраняя направление).

Один из способов сделать это в шейдере - передать дополнительную форму для положения глаз, а затем вычислить направление просмотра как eyePosition - vertexPosition. Затем продолжайте, как и на CPU.

+0

Спасибо! Это объясняет некоторые вещи, о которых мне было интересно. – user1118321

+0

Для записи 'fNormal = normalize (fNormal);' фактически не будет работать, потому что 'fNormal' является входной переменной. Мне пришлось создать новую переменную, например 'vec3 normal = normalize (fNormal);'. – user1118321

Смежные вопросы