Я пишу шейдер, который должен реализовывать модель освещения Phong. Проблема в том, что я не использую glRotatef
и эти функции, вместо этого я передаю масштаб и перевод вектора, и матрицу вращения в шейдер. Я рисую чайник на экране, и он выглядит нормально, за исключением случаев, когда я поворачиваю его. Кажется, что свет не движется, это как если бы он был подключен к чайнику и вращался вместе.
Вершинный шейдер:
#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);
}
Я уже отлаживал шейдер, и я думаю, что нет никаких проблем в расчете вывода, за исключением того факта, что он не учитывает вращение объекта. Поэтому я предлагаю не слишком фокусироваться на вычислении уравнения Фонга.
Это скриншот чайника, нарисованного перед вращением:
И этот после вращения вокруг оси Y:
Как вы видите, как будто свет движется вместе с чайником, но свет находится в фиксированном положении: всегда (0,0, -15)!
Проблема в том, что я не использую 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);
Но, честно говоря, вам гораздо лучше просто вычислить правильную матрицу из ваших трех параметров и умножить ее на матрицу просмотра модели в ЦП, прежде чем что-либо рисовать, поскольку вы все еще используете gl_ModelViewMatrix
в любом случае, чтобы вычислить положение вершины (если это необходимо, учитывая, что вы, кажется, не устанавливаете для нее какие-либо значения, это другой вопрос). И я также пока проигнорирую, что ваше умножение с rotation
Матрица фактически противоположна порядку, который обычно использует OpenGL (и что вы используете себя с другими матрицами), предполагая, что вы знаете об этом и знаете, что делаете.
Других решений пока нет …