OpenTKOpenGL照明:为什么纹理仅在对象的内部可见?

问题描述

我正在尝试在我的OpenTK渲染场景中实现照明。奇怪的是,由于我在着色器和代码中实施了漫射照明,因此所有对象纹理仅在对象的INSIDES中可见。或者只是看起来像这样。

outside

inside

您能帮我吗?我希望这只是一个简单的虚拟问题。

您可以在此处找到完整的代码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",0.31f));
        objectShader.SetVector3("material.specular",new Vector3(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();
    }

更清楚地说:根据我的理解,我将光源在世界空间中的位置设置为{100,1,2}。由于世界球体的半径为20,因此光源应位于其外部,因此应从外部进行照明。 资料的所有参数均来自OpenTK教程,该教程向我展示了OpenGL和OpenTK的基础知识,因此,我希望它们是正确的,或者至少不是造成我问题的原因。 除了环境强度(我将其设置为1.0以“禁用”环境照明的调光效果)外,光源参数与同一教程相似。 “形状”是包含世界上所有对象的数组。

在此处设置了着色器:

    private void SetupObjectShader()
    {
        string vertexPath = Path.Combine(Environment.CurrentDirectory,@"GLSL\","Vertex.vert");
        string fragmentPath = Path.Combine(Environment.CurrentDirectory,"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 * sizeof(float));


        int texCoordLocation = objectShader.GetAttribLocation("aTexCoord");
        GL.EnabLevertexAttribArray(texCoordLocation);
        GL.VertexAttribPointer(
            texCoordLocation,2,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,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,z);
        normVector3.normalize();

        return normVector3;
    }

更新: 我使用片段着色器进行了一些实验。 我尝试使用白色光和橙色作为对象,而不是使用纹理。我得到的是静态橙色图像,而不是可见的照明对象。也许这有助于诊断。

enter image description here

#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);

    // Diffuse 
    vec3 norm = normalize(normal);
    vec3 lightDir = normalize(vec3(light.position - FragPos));
    float diff = max(dot(norm,0.0);
    //vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse,texCoord));
    vec3 diffuse = light.diffuse * diff * vec3(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);

    vec3 result = (ambient + diffuse + specular) * vec3(1.0f,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",0.31f));
objectShader.SetVector3("material.specular",new Vector3(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());
,

我发现了一个问题。顶点着色器配置不正确。我更新了它,如下所示。现在的结果是,最终我可以看到漫反射和镜面反射的灯光效果,但仍然只在球体的内部。

outside inside

您可以看到漫反射和镜面反射光起作用(我将环境光设置为0.0,以便可以更好地看到其他光分量)。 由于世界球的半径为20.0f ,因此灯光位置设置为 x:1000.0f,y:1.0f,z:0.0f 。我希望光线在外面(当然是我想要的),并且远离它。

该如何解决“外部问题”?法线错误?错误或否定否定在任何地方?

这里是“新”顶点着色器:

#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);
}
,

我发现了问题。我忘了提及地球球体上方的另一个具有透明纹理的球体。在新的light实施中,alpha混合不起作用。

我将其提出了一个新问题。谢谢Rabbid76的参与!