英文:
Specular lighting in LWJGL 3 not working [Phong Shading]
问题
我在我的引擎中实现了光照,但存在一些问题,物体未正确地发光。 镜面光照根本不起作用。
以下是顶点着色器:
#version 330
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 tex_coords;
layout (location = 2) in vec3 normals;
uniform mat4 projectionMatrix;
uniform mat4 worldMatrix;
uniform mat4 viewMatrix;
out vec2 coords;
out vec3 vertexNormals;
out vec3 vertexPos;
void main() {
vec4 mVerPos = worldMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * viewMatrix * worldMatrix * vec4(position, 1.0);
coords = tex_coords;
vertexNormals = normalize(worldMatrix * vec4(normals, 0.0)).xyz;
vertexPos = mVerPos.xyz;
}
以下是片段着色器:
#version 330
// 结构体和函数的定义...
void main() {
setUpColor(material, coords);
vec4 diffuseSpecularComp = calcDirLight(dirLight, vertexPos, vertexNormals);
diffuseSpecularComp += calcPointLight(pointLight, vertexPos, vertexNormals);
fragColor = ambientC * vec4(ambientColor, 1) + diffuseSpecularComp;
}
源代码在这里:https://www.dropbox.com/scl/fo/hwlnz913jm6c9xli2dsb6/h?dl=0&rlkey=b2zj0w6kttwu3b1di9rejwnq3
当我将 float diffuseFactor = max(dot(normal, to_light_dir ), 0.0);
和 float specularFactor = max(dot(camera_direction, reflected_light), 0.0);
中的0.0 更改为大于0.1时,我得到以下结果,但镜面光照根本不起作用。
英文:
I implemented lighting in my engine. But there is some problem the object does not lights up properly
The specular lighting does not work at all
Here is the vertex shader :
#version 330
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 tex_coords;
layout (location = 2) in vec3 normals;
uniform mat4 projectionMatrix;
uniform mat4 worldMatrix;
uniform mat4 viewMatrix;
out vec2 coords;
out vec3 vertexNormals;
out vec3 vertexPos;
void main() {
vec4 mVerPos = worldMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * viewMatrix * worldMatrix * vec4(position, 1.0);
coords = tex_coords;
vertexNormals = normalize(worldMatrix * vec4(normals, 0.0)).xyz;
vertexPos = mVerPos.xyz;
}
Here is the fragment shader :
#version 330
struct Material {
vec4 ambient;
vec4 diffuse;
vec4 specular;
int hasTexture;
float reflectance;
};
struct PointLight {
vec3 color;
vec3 position;
float intensity;
float constant;
float linear;
float exponent;
};
struct DirLight {
vec3 position;
vec3 color;
float intensity;
};
out vec4 fragColor;
in vec2 coords;
in vec3 vertexNormals;
in vec3 vertexPos;
uniform sampler2D sampler;
uniform vec3 ambientColor;
uniform Material material;
uniform PointLight pointLight;
uniform float specularPower;
uniform DirLight dirLight;
vec4 ambientC;
vec4 diffuseC;
vec4 specularC;
void setUpColor(Material material, vec2 coords) {
if (material.hasTexture == 1) {
ambientC = texture(sampler, coords);
diffuseC = ambientC;
specularC = ambientC;
}
else {
ambientC = material.ambient;
diffuseC = material.diffuse;
specularC = material.specular;
}
}
vec4 calcLightColor(vec3 lightColor, float lightIntensity, vec3 position, vec3 to_light_dir, vec3 normal) {
vec4 diffuseColour = vec4(0, 0, 0, 0);
vec4 specColour = vec4(0, 0, 0, 0);
// Diffuse Light
float diffuseFactor = max(dot(normal, to_light_dir ), 0.0);
diffuseColour = diffuseC * vec4(lightColor, 1.0) * lightIntensity * diffuseFactor;
// Specular Light
vec3 camera_direction = normalize(-position);
vec3 from_light_dir = -to_light_dir;
vec3 reflected_light = normalize(reflect(from_light_dir, normal));
float specularFactor = max(dot(camera_direction, reflected_light), 0.0);
specularFactor = pow(specularFactor, specularPower);
specColour = specularC * lightIntensity * specularFactor * material.reflectance * vec4(lightColor, 1.0);
return (diffuseColour + specColour);
};
vec4 calcPointLight(PointLight light, vec3 position, vec3 normal)
{
vec3 light_direction = light.position - position;
vec3 to_light_source = normalize(light_direction);
vec4 lightColor = calcLightColor(light.color, light.intensity, position, to_light_source, normal);
// Attenuation
float distance = length(light_direction);
float attenuationInv = light.constant + light.linear * distance +
light.exponent * distance * distance;
return lightColor / attenuationInv;
}
vec4 calcDirLight(DirLight light, vec3 position, vec3 normal) {
return calcLightColor(light.color, light.intensity, position, normalize(light.position), normal);
}
void main() {
setUpColor(material, coords);
vec4 diffuseSpecularComp = calcDirLight(dirLight, vertexPos, vertexNormals);
diffuseSpecularComp += calcPointLight(pointLight, vertexPos, vertexNormals);
fragColor = ambientC * vec4(ambientColor, 1) + diffuseSpecularComp;
}
Here is the source code : https://www.dropbox.com/scl/fo/hwlnz913jm6c9xli2dsb6/h?dl=0&rlkey=b2zj0w6kttwu3b1di9rejwnq3
When I changed the value of zero at float diffuseFactor = max(dot(normal, to_light_dir ), 0.0);
and at float specularFactor = max(dot(camera_direction, reflected_light), 0.0);
the to something above like 0.1
this what I get but the specular does not work at all.
答案1
得分: 0
你的代码存在一些问题,但我不确定是什么导致了这个问题。
问题
- 在顶点着色器中,你没有正确计算
vertexNormals
。这在你的特定情况下可能不是问题,因为你似乎没有非均匀缩放网格,但值得一提,因为这是一个常见错误。你将对象空间法线与世界矩阵相乘,但应该改为与世界矩阵的逆转置相乘。 - 在片段着色器中直接使用了
vertexNormals
,但这是不正确的。虽然你在顶点着色器中对法线进行了归一化,但片段着色器得不到那个特定向量。它得到三个vertexNormals
的线性插值(基本上是加权平均值),结果不一定是归一化的。因此,你应该在片段着色器中也进行归一化。 - 在
setUpColor
函数中,为什么将相同的值分配给ambientC
、diffuseC
和specularC
?通常,这些有不同的纹理,但至少对于漫反射和镜面反射来说是这样。
其他随机观察
- 在顶点着色器中,你将
position
与worldMatrix
相乘两次,但为什么?这似乎是浪费性能(也许编译器会优化它)。 - 在
DirLight
结构中,你有一个position
成员,但定向光没有位置,它们只有一个方向。我看到你从位置计算方向,但这似乎不寻常。 - 同样的,相机始终位于原点,定向光的方向始终指向原点。如果这是有意的,没问题,只是看起来不寻常。
- 在
Material
结构中(以及其他地方),你使用vec4
而不是vec3
,但我猜最后的分量总是 1。这是对内存的浪费,你可以在main
的末尾将 alpha 值设为1.0f
。
英文:
There are a couple of problems in your code, but I'm not entirely sure which causes the problem.
Problems
- In the vertex shader, you don't calculate
vertexNormals
correctly. It shouldn't be a problem in your specific case, because seemingly you don't scale your mesh nonuniformly, but it's worth mentioning because it's a common mistake. You multiply the object space normal with the world matrix, but you should instead multiply it with the inverse transposed of the world matrix. - In the fragment shader you use directly the
vertexNormals
, but it's not correct. Although you normalized the normal in the vertex shader, but the fragment shader doesn't get that specific vector. It gets the linear interpolation (basically a weighted average) of the 3vertexNormals
and the result is not necessarily normalized. So you should normalize it in the fragment shader as well. - In the
setUpColor
function, why do you assign the same value toambientC
,diffuseC
, andspecularC
? Usually, there are different textures for these, but at least for diffuse and specular.
Other random observations
- In the vertex shader, you multiply the
position
twice withworldMatrix
, but why? It seems like wasted performance (maybe the compiler optimizes it). - In the
DirLight
struct you have aposition
member, but directional lights don't have a position, they just have a direction. I see that you compute the direction from the position, but it seems unusual. - In the same vein the camera is always at the origin and the directional light's direction always points to the origin. If it's intentional, it's okay, it just seems unusual.
- In the
Material
struct (and in other places) you usevec4
s instead ofvec3
s, but I guess, the last components are always ones. It's a waste of memory, you could just set the alpha value to1.0f
at the end ofmain
.
Joey de Vries has amazing tutorials, including the Phong shading (using C++). In the One last thing section he also explains why it's important to use the inverse transposed matrix to transform the normal.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论