我在片段着色器中实现了Blinn-Phong着色,以计算具有多个光源的每个片段的光照。除了一部分,计算似乎都很好。我的定向光计算正确但我的位置光不是。
图片谈论的不仅仅是文字:
错误的灯光位置:
着色器的工作原理如下:
我用世界空间中的位置更新灯光阵列。然后对于每个对象,我上传他们的材料信息并使用此片段着色器绘制它们以获得正确的颜色。顶点着色器的唯一任务(关于光照)是传递片段的法线。我的所有计算都是在世界空间完成的。
我已经检查了每盏灯的位置,它们是正确的。这就是我来这里的原因。我想我在计算入射角的余弦时犯了一个错误,但我不知道在哪里。
以下是我的片段着色器的代码:
编辑:我在Nico Schertler的帮助下纠正了一些错误,这是带有片段和顶点着色器的新代码
编辑2:经过另一轮检查,实际上并不是错位的灯光位置。但正常和光方向之间的点矢量计算错误。
片段着色器
#version 330 compatibility
struct light {
vec4 position; // position.w indicates if it's a direction or point lighting
vec3 diffuse; // diffuse color of the light
vec3 specular; // specular color of the light
float attenuation; // attenuation of the light
};
struct material {
vec3 diffuse;
vec3 specular;
vec3 ambient;
float shininess;
};
uniform material objMaterial;
uniform light lights[9];
uniform int nbLight;
uniform mat4 viewMatrix; // Matrix to view coordinate
uniform mat4 viewInvMatrix; // invert view matrix to find the position of the viewer
in vec3 worldNormal; // normal in worldspace
in vec3 position; // position in worldspace
vec3 ambiant = vec3(0.2,0.2,0.2);
void main()
{
int i;
vec3 viewDirection = normalize((viewInvMatrix * vec4(0.0, 0.0, 0.0, 1.0) - vec4(position, 1.)).xyz);
vec3 lightDirection, lightPositon;
vec3 normalizeWorldNormal = normalize(worldNormal);
float attenuation;
vec3 totalLight = ambiant * objMaterial.ambient;
float cosAngIncidence;
float blinnTerm;
for(i=0; i<9; i=i+1){
if(i < nbLight){
lightPositon = lights[i].position.xyz;
if (0.0 == lights[i].position.w) // directional light?
{
attenuation = 1.0; // no attenuation
lightDirection = normalize(lightPositon);
}
else // point light
{
vec3 positionToLightSource = lightPositon - position;
lightDirection = normalize(positionToLightSource);
float dis = length(positionToLightSource);
attenuation = 1.0 / (lights[i].attenuation * dis);
}
cosAngIncidence = dot(normalizeWorldNormal, lightDirection);
cosAngIncidence = clamp(cosAngIncidence, 0, 1);
vec3 halfAngle = normalize(lightDirection + viewDirection);
blinnTerm = dot(normalizeWorldNormal, halfAngle);
blinnTerm = clamp(blinnTerm, 0, 1);
blinnTerm = cosAngIncidence != 0.0 ? blinnTerm : 0.0;
blinnTerm = pow(blinnTerm, objMaterial.shininess*5);
totalLight = totalLight
+ (lights[i].diffuse * objMaterial.diffuse * attenuation * cosAngIncidence)
+ (lights[i].specular * objMaterial.specular * attenuation * blinnTerm);
}
}
gl_FragColor = vec4(totalLight.xyz, 1.0);
}
顶点着色器
#version 330 compatibility
layout(location=0) in vec3 vx_pos;
layout(location=1) in vec3 vx_nor;
layout(location=3) in vec3 vx_col;
uniform mat4 modelMatrix; // Matrix to world coordinate
uniform mat4 normalInvTransMatrix; // Matrix for normal in world coordinate
uniform mat4 viewMatrix; // Matrix to view coordinate
uniform mat4 projectionMatrix; // Matrix to projection coordinate
out vec3 worldNormal;
out vec3 position;
void main() {
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(vx_pos,1.0);
worldNormal = vec3(normalInvTransMatrix * vec4(vx_nor, 0.));
position = vec3(modelMatrix * vec4(vx_pos,0.));
}