【问题标题】:OpenTK (OpenGL) Lighting: Why textures are only visible in the INSIDE of an object?OpenTK (OpenGL) Lighting:为什么纹理只在对象的内部可见?
【发布时间】:2020-10-26 11:10:58
【问题描述】:

我正在尝试在我的 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();
    }

为了更清楚一点:据我了解,我在世界空间中将光源位置设置为{100, 1, 2}。由于世界球体的半径是 20,所以灯光应该位于它的外面,所以它应该从外面照亮。 材料的所有参数都来自 OpenTK 教程,它向我展示了 OpenGL 和 OpenTK 的基础知识,所以我希望它们是正确的,或者至少不是我的问题的原因。 灯光参数与同一个教程类似,除了环境强度,我将其设置为 1.0 以“禁用”环境照明的调光效果。 “Shapes”是包含世界上所有对象的数组。

这里设置了着色器:

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

【问题讨论】:

  • 如果你这样做会发生什么float diff = max(dot(-norm, lightDir), 0.0);
  • @Rabbid76 没有任何变化。
  • 对不起,那不可能。 float diff = max(dot(-norm, lightDir), 0.0);float diff = max(dot(norm, lightDir), 0.0); 相比必须引起差异

标签: c# winforms opengl opentk


【解决方案1】:

在设置制服之前,需要使用GL.UseProgram 安装着色器程序。 GL.Uniform* 在当前安装程序的默认uniform块中设置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());

【讨论】:

    【解决方案2】:

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

    在那里您可以看到漫反射和镜面反射照明工作(我将环境光设置为 0.0,这样我可以更好地看到其他光组件)。 光源位置设置为 x: 1000.0f, y: 1.0f, z: 0.0f,因为世界球体的 半径为 20.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);
    }
    

    【讨论】:

      【解决方案3】:

      我发现了问题。我忘了提到地球球体的正上方是另一个具有透明纹理的球体。在新的灯光实现中,Alpha 混合不起作用。

      我把它放到了一个新问题中。感谢 Rabbid76 的参与!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-25
        • 1970-01-01
        相关资源
        最近更新 更多