2013-11-19 3 views
1

Я пишу шейдер, который должен реализовать модель освещения Фонга. Проблема в том, что я не использую glRotatef, и эти функции вместо этого передают масштаб и переводят вектор и матрицу вращения в шейдер. Я рисую чайник на экране, и он выглядит нормально, за исключением случаев, когда я поворачиваю его. Свет, кажется, не двигается, это похоже на то, что свет подключен к чайнику, и он вращается.Выход шейдера фрагмента не зависит от поворотов

Vertex шейдеров:

#version 120 

varying vec3 normal, position; 
uniform vec3 scale, translation; 
uniform mat4 rotation; 

void main() 
{ 
    vec4 vertex= (gl_Vertex * rotation) * vec4(scale,1.0) + vec4(translation,0.0); 
    gl_Position= gl_ProjectionMatrix * gl_ModelViewMatrix *vertex ; 
    normal= normalize(gl_NormalMatrix * gl_Normal); 
    position= vec3(gl_ModelViewMatrix * gl_Vertex); 
} 

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

#version 120 

#pragma optionNV(unroll none) 

uniform int model; 
// 1: phong, 2: blinn-phong 
varying vec3 normal, position; 
// 1: directional, 2:point, 3:spot 
uniform int lightType; 
uniform float spotExponent; 


vec4 phong(vec3 L, vec3 N, vec3 V, int light) { 
    float LdotN= max(dot(L,N),0.0); 
    vec3 R= 2.0 * LdotN * N - L; 
    vec4 color= gl_FrontMaterial.ambient * gl_LightSource[light].ambient; 
    color+= gl_FrontMaterial.diffuse * gl_LightSource[light].diffuse * LdotN; 
    color+= gl_FrontMaterial.specular * gl_LightSource[light].specular * pow(max(dot(R,V),0.0),gl_FrontMaterial.shininess); 
    return color; 
} 

vec4 blinnPhong(vec3 L, vec3 N, vec3 V, int light) { 
    float LdotN= max(dot(L,N),0.0); 
    vec3 H= normalize(L+V); 
    vec4 color= gl_FrontMaterial.ambient * gl_LightSource[light].ambient; 
    color+= gl_FrontMaterial.diffuse * gl_LightSource[light].diffuse * LdotN; 
    color+= gl_FrontMaterial.specular * gl_LightSource[light].specular * pow(max(dot(H,N),0.0),gl_FrontMaterial.shininess); 
    return color; 
} 

float norm(vec3 v) { 
    return sqrt(v.x*v.x + v.y*v.y + v.z*v.z); 
} 

float pointLightAttenuation(float range, int light) { 
    float distance= norm(gl_LightSource[light].position.xyz - position); 
    if(distance > range) 
     return 0.0; 
    else 
     return max(1.0,1.0/(gl_LightSource[light].quadraticAttenuation*distance*distance+gl_LightSource[light].linearAttenuation*distance+gl_LightSource[light].constantAttenuation)); 
} 

float spotLightAttenuation(vec3 L, int light) 
{ 
    //return pow(max(dot(normalize(gl_LightSource[light].spotDirection),-L),0.0),spotExponent); 
    return max(dot(normalize(gl_LightSource[light].spotDirection),-L),0.0); 
} 


void main() 
{ 
    vec3 N= normalize(normal); 
    vec3 L; 
    float attenuation= 1.0; 
    if(lightType== 1) { 
     // If light is directional 
     L= normalize(- position); 
    } 
    else { 
     L= normalize(gl_LightSource[0].position.xyz - position); 
     attenuation= pointLightAttenuation(90.0,0); 
     if(lightType== 3) 
      attenuation*= spotLightAttenuation(L,0); 
    } 
    vec3 V= -normalize(position); 
    if(model==1) 
     gl_FragColor= attenuation * phong(L,N,V,0); 
    else 
     gl_FragColor= attenuation * blinnPhong(L,N,V,0); 
} 

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

Это скриншот из чайника отрисовывается перед вращением:

enter image description here

И это одна после того, как вращение вокруг оси Y:

enter image description here

Как вы видите, это как если свет движется вместе с чайником, но свет находится в фиксированном положении: всегда (0,0, -15)!

+1

Эй, «позиция», которую вы передаете из вершинного шейдера в фрагментарный шейдер, вычисляется с помощью 'gl_ModelViewMatrix * gl_Vertex', в котором вы не использовали преобразование и вращение вектора. – starrify

ответ

3

Проблема заключается в том, что я не использую glRotatef и эти функции, вместо этого я передаю масштаб и перевести вектор и матрица поворота в затенении.

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

Так просто изменить

normal= normalize(gl_NormalMatrix * gl_Normal); 
position= vec3(gl_ModelViewMatrix * gl_Vertex); 

в

normal = normalize(gl_NormalMatrix * ((gl_Normal * mat3(rotation))/scale)); 
position = vec3(gl_ModelViewMatrix * vertex); 

Но если честно, вы гораздо лучше, просто вычисляя правильную матрицу из ваших трех параметров, помноженной на видовую матрицу на CPU, прежде чем рисовать что-либо, поскольку вы все равно используете gl_ModelViewMatrix в любом случае, чтобы вычислить положение вершины (хотя это необходимо, если вы не настроили его на какие-либо значения, это другой вопрос). И теперь я также проигнорирую, что умножение с матрицей rotation фактически противоположно порядку, который обычно использует OpenGL (и который вы используете сами с другими матрицами), предполагая, что вы знаете об этом и знаете, что делаете ,

+0

Отличная помощь, спасибо! –

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