OpenTK (OpenGL) 光照:为什么纹理只在对象的内部可见?
OpenTK (OpenGL) Lighting: Why textures are only visible in the INSIDE of an object?
我正在尝试在我的 OpenTK 渲染场景中实现光照。奇怪的是,由于我在我的着色器和代码中实现了漫射照明,所以所有对象纹理仅在对象的内部可见。或者它只是看起来像那样。
你能帮我吗?我希望这只是一个简单的傻瓜问题。
您可以在此处找到完整代码:https://github.com/BanditBloodwyn/TerritorySimulator。
重要文件有:
- Rendering.Core.Rendering.Renderer.cs
- Rendering.Core.Classes.Shapes.GLSphere.cs
- Rendering.Core.Classes.Shaders.GLSL.Fragment
这是着色器:
#version 420 core
in vec3 normal;
in vec2 texCoord;
in vec3 FragPos;
out vec4 FragColor;
uniform sampler2D texture0;
uniform sampler2D texture1;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Material material;
uniform Light light;
void main()
{
// Ambient
vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));
// Diffuse
vec3 norm = normalize(normal);
vec3 lightDir = normalize(vec3(light.position - FragPos));
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));
vec3 result = ambient + diffuse;
//if(result.a < 0.1)
// discard;
FragColor = vec4(result, 1.0);
}
这是渲染函数:
public void Render()
{
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
if (Shapes == null || Shapes.Length == 0)
return;
IntPtr offset = (IntPtr)0;
foreach (GLShape shape in Shapes)
{
ApplyTextures(shape);
ApplyModelTransforms(shape, out Matrix4 model);
objectShader.SetMatrix4("model", model);
GL.DrawElements(PrimitiveType.Triangles, shape.Indices.Length, DrawElementsType.UnsignedInt, offset);
offset += shape.IndexBufferSize;
}
objectShader.SetVector3("material.ambient", new Vector3(1.0f, 0.5f, 0.31f));
objectShader.SetVector3("material.diffuse", new Vector3(1.0f, 0.5f, 0.31f));
objectShader.SetVector3("material.specular", new Vector3(0.5f, 0.5f, 0.5f));
objectShader.SetVector3("light.position", new Vector3(100f, 1.0f, 2.0f));
objectShader.SetVector3("light.ambient", new Vector3(1.0f));
objectShader.SetVector3("light.diffuse", new Vector3(0.5f));
objectShader.SetVector3("light.specular", new Vector3(1.0f));
objectShader.SetMatrix4("view", Camera.GetViewMatrix());
objectShader.SetMatrix4("projection", Camera.GetProjectionMatrix());
objectShader.Use();
}
说得更清楚:据我了解,我将光源位置设置为世界space中的{100,1,2}。由于世界球体的半径为 20,灯光应该位于它的外部,因此它应该从外部照亮。
material 的所有参数均来自 OpenTK 教程,该教程向我展示了 OpenGL 和 OpenTK 的基础知识,因此我希望它们是正确的,或者至少不是我出现问题的原因。
灯光参数与同一教程类似,除了环境强度,我将其设置为 1.0 以“禁用”环境照明的调光效果。
“形状”是包含世界上所有对象的数组。
这里设置了着色器:
private void SetupObjectShader()
{
string vertexPath = Path.Combine(Environment.CurrentDirectory, @"GLSL\", "Vertex.vert");
string fragmentPath = Path.Combine(Environment.CurrentDirectory, @"GLSL\", "Fragment.frag");
objectShader = new Shader(vertexPath, fragmentPath);
objectShader.Use();
int vertexLocation = objectShader.GetAttribLocation("aPosition");
GL.EnableVertexAttribArray(vertexLocation);
GL.VertexAttribPointer(
vertexLocation,
3,
VertexAttribPointerType.Float,
false,
8 * sizeof(float),
0);
int normCoordLocation = objectShader.GetAttribLocation("aNormal");
GL.EnableVertexAttribArray(normCoordLocation);
GL.VertexAttribPointer(
normCoordLocation,
3,
VertexAttribPointerType.Float,
false,
8 * sizeof(float),
3 * sizeof(float));
int texCoordLocation = objectShader.GetAttribLocation("aTexCoord");
GL.EnableVertexAttribArray(texCoordLocation);
GL.VertexAttribPointer(
texCoordLocation,
2,
VertexAttribPointerType.Float,
false,
8 * sizeof(float),
6 * sizeof(float));
objectShader.SetInt("texture0", 0);
objectShader.SetInt("texture1", 1);
}
VertexAttribPointer 函数的步长和偏移值将在下一个函数中变得清晰,您可以在其中看到顶点是如何构建的:3 个浮点用于位置,3 个浮点用于法线,2 个纹理坐标。
对象是这样创建的(在我的例子中是所有球体)。请查看顶点和法线是如何创建的:
private void RecreateVertices()
{
List<float> vertices = new List<float>();
float alpha = 2 * (float)Math.PI / rasterization;
for (int i = 0; i < rasterization + 1; i++)
{
for (int j = 0; j < rasterization + 1; j++)
{
float x = radius * (float)Math.Sin(i * alpha * 1.0) * (float)Math.Sin(j * alpha);
float y = radius * (float)Math.Sin(i * alpha * 1.0) * (float)Math.Cos(j * alpha);
float z = radius * (float)Math.Cos(i * alpha * 1.0);
float textureX = (float)j / rasterization;
float textureY = (float)i / rasterization * 2;
Vector3 normal = CreateNormal(x, y, z);
vertices.AddRange(new[] { x, y, z, normal[0], normal[1], normal[2], textureX, textureY });
}
}
Vertices = vertices.ToArray();
}
private Vector3 CreateNormal(float x, float y, float z)
{
Vector3 normVector3 = new Vector3(x, y, z);
normVector3.Normalize();
return normVector3;
}
更新:
我用片段着色器做了一些实验。
我尝试用白光和橙色来代替物体的纹理。我得到的不是可见的发光物体,而是静态的橙色图像。也许这有助于诊断。
#version 420 core
in vec3 normal;
in vec2 texCoord;
in vec3 FragPos;
out vec4 FragColor;
uniform sampler2D texture0;
uniform sampler2D texture1;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Material material;
uniform Light light;
uniform vec3 viewPos;
void main()
{
// Ambient
// vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));
vec3 ambient = light.ambient * vec3(1.0f, 1.0f, 1.0f);
// Diffuse
vec3 norm = normalize(normal);
vec3 lightDir = normalize(vec3(light.position - FragPos));
float diff = max(dot(norm, lightDir), 0.0);
//vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));
vec3 diffuse = light.diffuse * diff * vec3(1.0f, 1.0f, 1.0f);
// Specular
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// vec3 specular = light.specular * spec * vec3(texture(material.specular, texCoord));
vec3 specular = light.specular * spec * vec3(1.0f, 1.0f, 1.0f);
vec3 result = (ambient + diffuse + specular) * vec3(1.0f, 0.5f, 0.31f);
//if(result.a < 0.1)
// discard;
FragColor = vec4(result, 1.0);
}
在设置制服之前,需要使用 GL.UseProgram
安装着色器程序。 GL.Uniform
* 在当前安装程序的默认统一块中设置统一值:
objectShader.Use();
objectShader.SetVector3("material.ambient", new Vector3(1.0f, 0.5f, 0.31f));
objectShader.SetVector3("material.diffuse", new Vector3(1.0f, 0.5f, 0.31f));
objectShader.SetVector3("material.specular", new Vector3(0.5f, 0.5f, 0.5f));
objectShader.SetVector3("light.position", new Vector3(100f, 1.0f, 2.0f));
objectShader.SetVector3("light.ambient", new Vector3(1.0f));
objectShader.SetVector3("light.diffuse", new Vector3(0.5f));
objectShader.SetVector3("light.specular", new Vector3(1.0f));
objectShader.SetMatrix4("view", Camera.GetViewMatrix());
objectShader.SetMatrix4("projection", Camera.GetProjectionMatrix());
我发现了一个问题。顶点着色器配置不正确。我更新了它,如下所示。现在的结果是,我终于可以看到漫反射和镜面反射照明效果,但仍然只在我的球体内部。
在那里你可以看到漫反射和镜面照明在工作(我将环境光设置为 0.0 这样我可以更好地看到其他光分量)。
光源位置设置为 x: 1000.0f, y: 1.0f, z: 0.0f,因为世界球体的 半径为 20.0f.我希望光线在外面(当然我想要那个)并且远离它。
什么可以解决这个“outside-in-problem”?法线错误?哪里有错误或遗漏的否定?
这里是“新”顶点着色器:
#version 420 core
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoord;
out vec2 texCoord;
out vec3 FragPos;
out vec3 Normal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main(void)
{
texCoord = aTexCoord;
FragPos = vec3(vec4(aPosition, 1.0) * model);
Normal = -aNormal * mat3(transpose(inverse(model)));
gl_Position = vec4(aPosition, 1.0) * model * view * projection;
}
这里是片段着色器的当前状态:
#version 420 core
in vec3 FragPos;
in vec3 Normal;
in vec2 texCoord;
out vec4 FragColor;
uniform sampler2D texture0;
uniform sampler2D texture1;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Material material;
uniform Light light;
uniform vec3 viewPos;
void main()
{
// Ambient
vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));
// Diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(vec3(light.position - FragPos));
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));
// Specular
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 specular = light.specular * spec * vec3(texture(material.specular, texCoord));
vec3 result = ambient + diffuse + specular;
FragColor = vec4(result, 1.0);
}
我发现了问题。我忘了说,地球球体的正上方是另一个具有透明纹理的球体。使用新的灯光实现,alpha 混合不起作用。
我把它放到了一个新问题中。感谢 Rabbid76 的参与!
我正在尝试在我的 OpenTK 渲染场景中实现光照。奇怪的是,由于我在我的着色器和代码中实现了漫射照明,所以所有对象纹理仅在对象的内部可见。或者它只是看起来像那样。
你能帮我吗?我希望这只是一个简单的傻瓜问题。
您可以在此处找到完整代码:https://github.com/BanditBloodwyn/TerritorySimulator。
重要文件有:
- Rendering.Core.Rendering.Renderer.cs
- Rendering.Core.Classes.Shapes.GLSphere.cs
- Rendering.Core.Classes.Shaders.GLSL.Fragment
这是着色器:
#version 420 core
in vec3 normal;
in vec2 texCoord;
in vec3 FragPos;
out vec4 FragColor;
uniform sampler2D texture0;
uniform sampler2D texture1;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Material material;
uniform Light light;
void main()
{
// Ambient
vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));
// Diffuse
vec3 norm = normalize(normal);
vec3 lightDir = normalize(vec3(light.position - FragPos));
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));
vec3 result = ambient + diffuse;
//if(result.a < 0.1)
// discard;
FragColor = vec4(result, 1.0);
}
这是渲染函数:
public void Render()
{
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
if (Shapes == null || Shapes.Length == 0)
return;
IntPtr offset = (IntPtr)0;
foreach (GLShape shape in Shapes)
{
ApplyTextures(shape);
ApplyModelTransforms(shape, out Matrix4 model);
objectShader.SetMatrix4("model", model);
GL.DrawElements(PrimitiveType.Triangles, shape.Indices.Length, DrawElementsType.UnsignedInt, offset);
offset += shape.IndexBufferSize;
}
objectShader.SetVector3("material.ambient", new Vector3(1.0f, 0.5f, 0.31f));
objectShader.SetVector3("material.diffuse", new Vector3(1.0f, 0.5f, 0.31f));
objectShader.SetVector3("material.specular", new Vector3(0.5f, 0.5f, 0.5f));
objectShader.SetVector3("light.position", new Vector3(100f, 1.0f, 2.0f));
objectShader.SetVector3("light.ambient", new Vector3(1.0f));
objectShader.SetVector3("light.diffuse", new Vector3(0.5f));
objectShader.SetVector3("light.specular", new Vector3(1.0f));
objectShader.SetMatrix4("view", Camera.GetViewMatrix());
objectShader.SetMatrix4("projection", Camera.GetProjectionMatrix());
objectShader.Use();
}
说得更清楚:据我了解,我将光源位置设置为世界space中的{100,1,2}。由于世界球体的半径为 20,灯光应该位于它的外部,因此它应该从外部照亮。 material 的所有参数均来自 OpenTK 教程,该教程向我展示了 OpenGL 和 OpenTK 的基础知识,因此我希望它们是正确的,或者至少不是我出现问题的原因。 灯光参数与同一教程类似,除了环境强度,我将其设置为 1.0 以“禁用”环境照明的调光效果。 “形状”是包含世界上所有对象的数组。
这里设置了着色器:
private void SetupObjectShader()
{
string vertexPath = Path.Combine(Environment.CurrentDirectory, @"GLSL\", "Vertex.vert");
string fragmentPath = Path.Combine(Environment.CurrentDirectory, @"GLSL\", "Fragment.frag");
objectShader = new Shader(vertexPath, fragmentPath);
objectShader.Use();
int vertexLocation = objectShader.GetAttribLocation("aPosition");
GL.EnableVertexAttribArray(vertexLocation);
GL.VertexAttribPointer(
vertexLocation,
3,
VertexAttribPointerType.Float,
false,
8 * sizeof(float),
0);
int normCoordLocation = objectShader.GetAttribLocation("aNormal");
GL.EnableVertexAttribArray(normCoordLocation);
GL.VertexAttribPointer(
normCoordLocation,
3,
VertexAttribPointerType.Float,
false,
8 * sizeof(float),
3 * sizeof(float));
int texCoordLocation = objectShader.GetAttribLocation("aTexCoord");
GL.EnableVertexAttribArray(texCoordLocation);
GL.VertexAttribPointer(
texCoordLocation,
2,
VertexAttribPointerType.Float,
false,
8 * sizeof(float),
6 * sizeof(float));
objectShader.SetInt("texture0", 0);
objectShader.SetInt("texture1", 1);
}
VertexAttribPointer 函数的步长和偏移值将在下一个函数中变得清晰,您可以在其中看到顶点是如何构建的:3 个浮点用于位置,3 个浮点用于法线,2 个纹理坐标。
对象是这样创建的(在我的例子中是所有球体)。请查看顶点和法线是如何创建的:
private void RecreateVertices()
{
List<float> vertices = new List<float>();
float alpha = 2 * (float)Math.PI / rasterization;
for (int i = 0; i < rasterization + 1; i++)
{
for (int j = 0; j < rasterization + 1; j++)
{
float x = radius * (float)Math.Sin(i * alpha * 1.0) * (float)Math.Sin(j * alpha);
float y = radius * (float)Math.Sin(i * alpha * 1.0) * (float)Math.Cos(j * alpha);
float z = radius * (float)Math.Cos(i * alpha * 1.0);
float textureX = (float)j / rasterization;
float textureY = (float)i / rasterization * 2;
Vector3 normal = CreateNormal(x, y, z);
vertices.AddRange(new[] { x, y, z, normal[0], normal[1], normal[2], textureX, textureY });
}
}
Vertices = vertices.ToArray();
}
private Vector3 CreateNormal(float x, float y, float z)
{
Vector3 normVector3 = new Vector3(x, y, z);
normVector3.Normalize();
return normVector3;
}
更新: 我用片段着色器做了一些实验。 我尝试用白光和橙色来代替物体的纹理。我得到的不是可见的发光物体,而是静态的橙色图像。也许这有助于诊断。
#version 420 core
in vec3 normal;
in vec2 texCoord;
in vec3 FragPos;
out vec4 FragColor;
uniform sampler2D texture0;
uniform sampler2D texture1;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Material material;
uniform Light light;
uniform vec3 viewPos;
void main()
{
// Ambient
// vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));
vec3 ambient = light.ambient * vec3(1.0f, 1.0f, 1.0f);
// Diffuse
vec3 norm = normalize(normal);
vec3 lightDir = normalize(vec3(light.position - FragPos));
float diff = max(dot(norm, lightDir), 0.0);
//vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));
vec3 diffuse = light.diffuse * diff * vec3(1.0f, 1.0f, 1.0f);
// Specular
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// vec3 specular = light.specular * spec * vec3(texture(material.specular, texCoord));
vec3 specular = light.specular * spec * vec3(1.0f, 1.0f, 1.0f);
vec3 result = (ambient + diffuse + specular) * vec3(1.0f, 0.5f, 0.31f);
//if(result.a < 0.1)
// discard;
FragColor = vec4(result, 1.0);
}
在设置制服之前,需要使用 GL.UseProgram
安装着色器程序。 GL.Uniform
* 在当前安装程序的默认统一块中设置统一值:
objectShader.Use();
objectShader.SetVector3("material.ambient", new Vector3(1.0f, 0.5f, 0.31f));
objectShader.SetVector3("material.diffuse", new Vector3(1.0f, 0.5f, 0.31f));
objectShader.SetVector3("material.specular", new Vector3(0.5f, 0.5f, 0.5f));
objectShader.SetVector3("light.position", new Vector3(100f, 1.0f, 2.0f));
objectShader.SetVector3("light.ambient", new Vector3(1.0f));
objectShader.SetVector3("light.diffuse", new Vector3(0.5f));
objectShader.SetVector3("light.specular", new Vector3(1.0f));
objectShader.SetMatrix4("view", Camera.GetViewMatrix());
objectShader.SetMatrix4("projection", Camera.GetProjectionMatrix());
我发现了一个问题。顶点着色器配置不正确。我更新了它,如下所示。现在的结果是,我终于可以看到漫反射和镜面反射照明效果,但仍然只在我的球体内部。
在那里你可以看到漫反射和镜面照明在工作(我将环境光设置为 0.0 这样我可以更好地看到其他光分量)。 光源位置设置为 x: 1000.0f, y: 1.0f, z: 0.0f,因为世界球体的 半径为 20.0f.我希望光线在外面(当然我想要那个)并且远离它。
什么可以解决这个“outside-in-problem”?法线错误?哪里有错误或遗漏的否定?
这里是“新”顶点着色器:
#version 420 core
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoord;
out vec2 texCoord;
out vec3 FragPos;
out vec3 Normal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main(void)
{
texCoord = aTexCoord;
FragPos = vec3(vec4(aPosition, 1.0) * model);
Normal = -aNormal * mat3(transpose(inverse(model)));
gl_Position = vec4(aPosition, 1.0) * model * view * projection;
}
这里是片段着色器的当前状态:
#version 420 core
in vec3 FragPos;
in vec3 Normal;
in vec2 texCoord;
out vec4 FragColor;
uniform sampler2D texture0;
uniform sampler2D texture1;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Material material;
uniform Light light;
uniform vec3 viewPos;
void main()
{
// Ambient
vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));
// Diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(vec3(light.position - FragPos));
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));
// Specular
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 specular = light.specular * spec * vec3(texture(material.specular, texCoord));
vec3 result = ambient + diffuse + specular;
FragColor = vec4(result, 1.0);
}
我发现了问题。我忘了说,地球球体的正上方是另一个具有透明纹理的球体。使用新的灯光实现,alpha 混合不起作用。
我把它放到了一个新问题中。感谢 Rabbid76 的参与!