简体   繁体   English

OpenTK (OpenGL) 照明:为什么纹理仅在 object 的内部可见?

[英]OpenTK (OpenGL) Lighting: Why textures are only visible in the INSIDE of an object?

I'm trying to implement lighting in my OpenTK rendered scene.我正在尝试在我的 OpenTK 渲染场景中实现照明。 The strange thing, that since I implemented diffuse lighting in my shader & code, all object textures are only visible in the INSIDES of objects.奇怪的是,由于我在我的着色器和代码中实现了漫反射照明,所以所有 object 纹理仅在对象的 INSIDES 中可见。 Or it only looks like that.或者它只是看起来像那样。

外部

里面

Can you help me with that?你能帮我吗? I hope it only is a simple dummie problem.我希望这只是一个简单的虚拟问题。

You can find the full code here: https://github.com/BanditBloodwyn/TerritorySimulator .您可以在此处找到完整代码: https://github.com/BanditBloodwyn/TerritorySimulator

The important files are:重要的文件是:

  • Rendering.Core.Rendering.Renderer.cs渲染.Core.Rendering.Renderer.cs
  • Rendering.Core.Classes.Shapes.GLSphere.cs Rendering.Core.Classes.Shapes.GLSphere.cs
  • Rendering.Core.Classes.Shaders.GLSL.Fragment渲染.Core.Classes.Shaders.GLSL.Fragment

This is the shader:这是着色器:

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

This is the render function:这是渲染 function:

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

To make it clearer: According to what I understand, I set the light source position to {100, 1, 2} in the world space.说得更清楚:据我了解,我在世界空间中将光源position设置为{100,1,2}。 Since the world sphere's radius is 20, the light should be located outside of it, so it should be illuminated from the outside.由于世界球体的半径为 20,灯光应该位于它的外部,因此它应该从外部照亮。 All parameters for the material are from an OpenTK tutorial which shows me the basics of OpenGL and OpenTK, so I hope they are correct or at least not the reason for my problem.该材料的所有参数均来自 OpenTK 教程,该教程向我展示了 OpenGL 和 OpenTK 的基础知识,因此我希望它们是正确的,或者至少不是我出现问题的原因。 The light parameters are similar to the same tutorial, except for the ambient strength, which I set to 1.0 to "disable" the dimming effect of ambient lighting.灯光参数与同一教程类似,除了环境强度,我将其设置为 1.0 以“禁用”环境照明的调光效果。 "Shapes" is the Array which contains all objects in the world. “形状”是包含世界上所有对象的数组。

Here the shader is set:这里设置了着色器:

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

The stride and offset values for the VertexAttribPointer function will become clear in the next function where you can see how the vertices are built: 3 floats for the position, 3 floats for the normal, 2 texture coordinates. VertexAttribPointer function 的步幅和偏移值将在接下来的 function 中变得清晰,您可以在其中看到顶点是如何构建的:3 个浮点数用于 position,3 个浮点数用于法线,2 个纹理坐标。

The objects are created like this (all spheres in my case).对象是这样创建的(在我的例子中是所有领域)。 Please see how the vertices and the normals are created:请查看顶点和法线是如何创建的:

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

UPDATE: I made some experiments with the fragment shader.更新:我用片段着色器做了一些实验。 Instead of the textures I tried white lights and an orange color for the objects.我尝试用白光和橙色来代替物体的纹理。 Instead of visible illuminated objects I got a static orange image.我得到的不是可见的发光物体,而是一张 static 的橙色图像。 Maybe this helps with the diagnosis.也许这有助于诊断。

在此处输入图像描述

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

The shader program needs to be installed with GL.UseProgram , before the uniforms are set.在设置制服之前,着色器程序需要与GL.UseProgram一起安装。 GL.Uniform * sets a value of a uniform in the default uniform block of the currently installed program: 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());

I found one problem.我发现了一个问题。 The Vertex shader wasn't configured correctly.顶点着色器配置不正确。 I updated it as seen below.我更新了它,如下所示。 The result now is, that finally I can see diffuse and specular lighting effects, but still only in the INSIDE of my spheres.现在的结果是,我终于可以看到漫反射和镜面反射照明效果,但仍然只在我的球体内部。

外部 里面

there you can see the diffuse and the specular lighting working (I set the ambient light to 0.0 so I can see the other light components better).在那里您可以看到漫反射和镜面反射照明正在工作(我将环境光设置为 0.0,以便我可以更好地看到其他光分量)。 The light position is set to x: 1000.0f, y: 1.0f, z: 0.0f , since the world sphere has a radius of 20.0f .灯光 position 设置为x: 1000.0f, y: 1.0f, z: 0.0f ,因为世界球体的半径为 20.0f I wanted the light to be OUTSIDE (of course I want that) and far away of it.我希望光线在外面(当然我想要那个)并且远离它。

What could solve this "outside-in-problem"?什么可以解决这个“外来问题”? Wrong normals?法线错误? Wrong or missing negation anywhere?哪里有错误或遗漏的否定?

Here the "new" vertex shader:这里是“新”顶点着色器:

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

And here the current state of the fragment shader:这里是片段着色器的当前 state:

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

I found the problem.我发现了问题。 I forgot to mention that right above the earth sphere is another sphere with a transparent texture.我忘了说,地球球体的正上方是另一个具有透明纹理的球体。 With the new light implementation the alpha blending doesn't work.在新的光照实现中,alpha 混合不起作用。

I put that into a new question.我把它放到了一个新问题中。 Thank you Rabbid76 for your engagement!感谢 Rabbid76 的参与!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM