我正在编写一个应该实现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);
}
我已经调试了着色器,我认为输出计算没有问题,除了它没有考虑对象旋转这一事实。所以我建议不要过多关注Phong方程计算。
这是旋转前绘制的茶壶的屏幕截图:
围绕Y轴旋转后的这个:
就像你看到的那样,如果光线与茶壶一起移动,但光线处于固定位置:始终(0,0,-15)!
答案 0 :(得分: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通常使用的顺序相反(并且你将自己与其他矩阵一起使用),假设你已经意识到这一点并且知道什么你正在做。