英文:
Sphere lighting wrong results
问题
我有一个简单的逐像素光照着色器,但我想要绘制的球看起来有点像逐顶点着色。我从昨天开始调查,但没有找到任何问题。一个球的法线与规范化的顶点位置相同,或者我错了吗?
顶点着色器:
#version 330 core
uniform mat4 ModelViewProjectionMatrix;
uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
in vec3 Position;
in vec3 Normal;
out vec3 VertexEyePosition;
out vec3 NormalEyePosition;
void main()
{
gl_Position = ModelViewProjectionMatrix * vec4(Position, 1.0f);
VertexEyePosition = vec3(ModelViewMatrix * vec4(Position, 1.0f));
NormalEyePosition = NormalMatrix * normalize(Normal);
}
片段着色器:
#version 330 core
uniform vec4 EyeLightPosition;
in vec3 VertexEyePosition;
in vec3 NormalEyePosition;
out vec4 FinalColor;
void main()
{
vec3 L = normalize(vec3(EyeLightPosition) - VertexEyePosition);
vec3 N = NormalEyePosition;
vec3 R = reflect(-L, N);
vec3 V = normalize(-VertexEyePosition);
vec3 Ambient = 0.1 * vec3(1.0, 0.0, 0.0);
vec3 Diffuse = 0.8 * vec3(1.0, 0.0, 0.0) * max(0.0, dot(N, L));
vec3 Specular = vec3(1.0) * pow(max(0.0, dot(R, V)), 8.0);
FinalColor = vec4(Ambient + Diffuse + Specular, 1.0);
}
对于立方体或平面,着色器工作正常。
球体生成:
void SphereMesh::GenerateGeometry()
{
// ... (这里省略了其他代码)
}
结果:
英文:
I have a simple per-pixel-lighting shader, but the sphere I want to draw looks a bit like per-vertex shading. I investigated this since yesterday, but didn't find any issues. The normals of a sphere are the same as the normalized vertex positions, or am I wrong?
Vertex shader:
#version 330 core
uniform mat4 ModelViewProjectionMatrix;
uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
in vec3 Position;
in vec3 Normal;
out vec3 VertexEyePosition;
out vec3 NormalEyePosition;
void main()
{
gl_Position = ModelViewProjectionMatrix * vec4(Position, 1.0f);
VertexEyePosition = vec3(ModelViewMatrix * vec4(Position, 1.0f));
NormalEyePosition = NormalMatrix * normalize(Normal);
}
Fragment shader:
#version 330 core
uniform vec4 EyeLightPosition;
in vec3 VertexEyePosition;
in vec3 NormalEyePosition;
out vec4 FinalColor;
void main()
{
vec3 L = normalize(vec3(EyeLightPosition) - VertexEyePosition);
vec3 N = NormalEyePosition;
vec3 R = reflect(-L, N);
vec3 V = normalize(-VertexEyePosition);
vec3 Ambient = 0.1 * vec3(1.0, 0.0, 0.0);
vec3 Diffuse = 0.8 * vec3(1.0, 0.0, 0.0) * max(0.0, dot(N, L));
vec3 Specular = vec3(1.0) * pow(max(0.0, dot(R, V)), 8.0);
FinalColor = vec4(Ambient + Diffuse + Specular, 1.0);
}
For a cube or plane the shader works fine.
Sphere generation:
void SphereMesh::GenerateGeometry()
{
vertices.clear();
uv_coords.clear();
normals.clear();
faces.clear();
vertices.reserve((segments + 1) * (rings + 1));
uv_coords.reserve((segments + 1) * (rings + 1));
// Generate vertices and UV coordinates;
for (unsigned int ring = 0; ring <= rings; ring++)
{
const float ring_sin = glm::sin(static_cast<float>(ring) / rings * glm::pi<float>() - 0.5f * glm::pi<float>());
const float ring_cos = glm::cos(static_cast<float>(ring) / rings * glm::pi<float>() - 0.5f * glm::pi<float>());
for (unsigned int segment = 0; segment <= segments; segment++)
{
if (((ring == 0) || (ring == rings)) && (segment == segments)) continue;
const float segment_sin = glm::sin(static_cast<float>(segment) / segments * 2.0f * glm::pi<float>());
const float segment_cos = glm::cos(static_cast<float>(segment) / segments * 2.0f * glm::pi<float>());
const float x = radius * ring_cos * segment_sin;
const float y = radius * ring_sin;
const float z = radius * ring_cos * segment_cos;
const float u = ((ring == 0) || (ring == rings)) && (segment == segments) ?
static_cast<float>(segment) / (segments - 1) + 0.5f * static_cast<float>(segment) / (segments - 1):
static_cast<float>(segment) / segments;
const float v = static_cast<float>(ring) / rings;
vertices.emplace_back(x, y, z);
uv_coords.emplace_back(u, v);
normals.emplace_back(glm::normalize(glm::vec3(x, y, z)));
}
}
// Generate faces
for (unsigned int ring = 0; ring < rings; ring++)
{
for (unsigned int segment = 0; segment < segments; segment++)
{
if (ring == 0) // Lower cap
{
Face face;
face.a = segment;
face.b = segments + segment + 1;
face.c = segments + segment;
faces.push_back(face);
}
else if (ring < rings - 1) // Body
{
const unsigned int v1 = segments + ((ring - 1) * (segments + 1)) + segment;
const unsigned int v2 = segments + ((ring - 1) * (segments + 1)) + segment + 1;
const unsigned int v3 = segments + ((ring - 1 + 1) * (segments + 1)) + segment;
const unsigned int v4 = segments + ((ring - 1 + 1) * (segments + 1)) + segment + 1;
Face face1, face2;
face1.a = v1;
face1.b = v2;
face1.c = v3;
face2.a = v3;
face2.b = v2;
face2.c = v4;
faces.push_back(face1);
faces.push_back(face2);
}
else // Upper cap
{
Face face;
face.a = segments + ((ring - 1) * (segments + 1)) + segment;
face.b = segments + ((ring - 1) * (segments + 1)) + segment + 1;
face.c = segments + ((ring - 1 + 1) * (segments + 1)) + segment;
faces.push_back(face);
}
}
}
}
Result:
答案1
得分: 1
NormalEyePosition
在片元着色器中也必须进行规范化,当插值向量时,向量的长度不会保持不变。
vec3 N = normalize(NormalEyePosition);
英文:
NormalEyePosition
must also be normalized in the fragment shader When interpolating vectors, the length of the vector is not maintained.
<s>vec3 N = NormalEyePosition;
</s>
vec3 N = normalize(NormalEyePosition);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论