在OpenGL中使用多个光源时如何解决我的照明问题(片段着色器问题?)

我正在一个需要在opengl中安装两个光源的项目中。这些应该是定向灯。我99%的确定自己走的路线比需要的复杂,但我对项目的理解不尽如人意,所以我上班所能走的就是走的路线。我有一个带有纹理的金字塔对象。我也有两个单独的灯,一个补光灯和一个键灯。补光灯更多地用于环境照明,而键光本身就是主要的“灯泡”。对于所有3个对象,我都有一个顶点着色器和片段着色器(尽管我不知道我是否真的需要/应该这样做)。我有一系列绘制形状,包含法线和纹理坐标的折点。主要金字塔对象使用所有这三个属性,但是灯光仅使用顶点,因此它们具有相同的形状。

我的主要问题是灯工作不正常。金字塔仅通过钥匙灯的环境照明来点亮。它没有正确地合并漫反射或镜面照明组件。补光灯似乎也被很大程度上忽略了,但这似乎是因为关键灯覆盖了所有其他灯光数据。

这是我的主要金字塔着色器的外观:

/* Pyramid Vertex Shader Source Code */
const GLchar * pyramidVertexShaderSource = GLSL(330,layout (location = 0) in vec3 position; // Vertex data from Vertex Attrib Pointer 0
    layout (location = 1) in vec3 normal; // VAP position 1 for normals
    layout (location = 2) in vec2 textureCoordinate; // Color data from Vertex Attrib Pointer 1

    out vec3 Normal; // For outgoing normals to fragment shader
    out vec3 FragmentPos; // For outgoing color / pixels to fragment shader
    out vec2 mobileTextureCoordinate; // variable to transfer Texture data to the fragment shader


    // Global variables for the transform matrices
    uniform mat4 model;
    uniform mat4 view;
    uniform mat4 projection;

void main(){
        gl_Position = projection * view * model * vec4(position,1.0f); // transforms vertices to clip coordinates
        FragmentPos = vec3(model * vec4(position,1.0f)); // Gets fragment / pixel position in world space only (exclude view and projection)
        mobileTextureCoordinate = vec2(textureCoordinate.x,1.0f - textureCoordinate.y); // flips the texture horizontal
        Normal = mat3(transpose(inverse(model))) * normal; // get normal vectors in world space only and exclude normal translation properties
    }
);


/* Pyramid Fragment Shader Source Code */
const GLchar * pyramidFragmentShaderSource = GLSL(330,in vec2 mobileTextureCoordinate; // Variable to hold incoming color data from vertex shader
        in vec3 Normal; // For incoming normals
        in vec3 FragmentPos; // For incoming fragment position

        out vec4 pyramidColor; // For outgoing pyramid color


        // Uniform variables for object color,light color,light position,and camera/view position
        uniform vec3 fillLightColor;
        uniform vec3 fillLightPos;
        uniform vec3 keyLightColor;
        uniform vec3 keyLightPos;
        uniform vec3 viewPosition;
        uniform sampler2D uTexture; // Useful when working with multiple textures

        void main() {
            /* Phong lighting model calculations to generate ambient,diffuse,and specular components */

            // Calculate Ambient lighting
            float ambientStrength = 0.3f; // Set ambient or global lighting strength
            vec3 ambient = ambientStrength * fillLightColor; // Generate ambient light color

            // Calculate Diffuse lighting for fill lamp
            vec3 norm = normalize(Normal); // Normalize vectors to 1 unit
            vec3 lightDirection = normalize(fillLightPos - FragmentPos); // Calculate distance (light direction) between fill light source and fragments/pixels
            float impact = max(dot(norm,lightDirection),0.0); // Calculate diffuse impact by generating dot product of normal and light
            vec3 diffuse = impact * fillLightColor; // Generate diffuse light color

            // Calculate Specular lighting for fill lamp
            float specularIntensity = 0.8f; // Set specular light strength
            float highlightSize = 16.0f; // Set specular highlight size
            vec3 viewDir = normalize(viewPosition - FragmentPos); // Calculate view direction
            vec3 reflectDir = reflect (-lightDirection,norm); // Calculate reflection vector
            //Calculate specular component
            float specularComponent = pow(max(dot(viewDir,reflectDir),0.0),highlightSize);
            vec3 specular = specularIntensity * specularComponent * fillLightColor;

            // Calculate Ambient lighting for key lamp
            float keyAmbientStrength = 1.0f;
            vec3 keyAmbient = keyAmbientStrength * keyLightColor;

            // Calculate Diffuse lighting for key lamp
            vec3 keyLightDirection = normalize(keyLightPos - FragmentPos); // Calculate distance between key light source and fragments
            float keyImpact = max(dot(norm,keyLightDirection),0.0);
            vec3 keyDiffuse = keyImpact * keyLightColor;

            // Calculate Specular lighting for key lamp
            float keySpecularIntensity = 0.8f; // Set specular light strength
            float keyHighlightSize = 32.0f; // Set specular highlight size
            vec3 keyReflectDir = reflect (-keyLightDirection,norm); // Calculate reflection vector
            //Calculate specular component
            float keySpecularComponent = pow(max(dot(viewDir,keyReflectDir),keyHighlightSize);
            vec3 keySpecular = keySpecularIntensity * keySpecularComponent * keyLightColor;

            // Calculate phong result
            vec3 objectColor = texture(uTexture,mobileTextureCoordinate).xyz;
            vec3 fillResult = (ambient + diffuse + specular);
            vec3 keyResult = (keyAmbient + keyDiffuse + keySpecular);
            vec3 lightingResult = fillResult + keyResult;
            vec3 phong = (lightingResult) * objectColor;
            pyramidColor = vec4(phong,1.0f); // Send lighting results to GPU

        }
    ); 

据我所知,我的问题在于计算照明的数学中,但是无论我如何尝试改变它……我都不足够聪明,无法确切知道到底发生了什么。诚然,我的线性代数技能是垃圾,所以我真的很难受。我确定我的代码中有很多错误以及如何解决此问题,但是经过15到20个小时的尝试之后,这是我能够设法加载并看起来甚至可以远程纠正的最佳方法。

填充光几乎应该是白光,照常照亮纹理。按键灯应该是绿色的,因此暴露于按键灯的一面应具有绿色外观。目前,整个金字塔仅以相同的绿色照明(没有阴影或灯光有方向性)。

yangdebin7 回答:在OpenGL中使用多个光源时如何解决我的照明问题(片段着色器问题?)

乍一看,您的代码看起来正确。当然,片段的颜色取决于浅色和对象(纹理)的颜色。通常乘(调制)对象颜色和浅色。另一种可能性是将对象颜色和浅色相加。无论如何,这不是您的着色器代码中的问题。

但是有很多可能的问题。确保所有制服均正确摆放。确保光源不在对象“后面”,并且光源的颜色不是“零”。

一个经常看到的问题是点光源位于网格中。在这种情况下,对象的内部被照亮(您看不到),而外部在阴影侧。

一个常见的问题是曲面的法线向量指向网格的内部。因为Dot product计算出的值与两个矢量之间的角度的余弦成比例,所以根本不会产生漫射和镜面反射光。如果两个向量之间的角度大于90°,​​则余弦将变为负,因此点积也将为负。

您可以通过实现双面光模型并反转法线向量(如果它不面向视图)来消除这种情况。在片段着色器的开头执行以下操作:

vec3 norm    = normalize(Normal);
vec3 viewDir = normalize(viewPosition - FragmentPos);

if (dot(norm,viewDir) < 0.0)
    norm = -norm;

如果没有正确指定法线向量属性,并且所有法线向量均为(0,0,0),则无论如何都无济于事。
要评估法向向量,您可以执行简单的调试测试。只需将法线向量添加到片段着色器的最后一行中的pyramidColor

void main() {
    // [...]

    pyramidColor.rgb += abs(norm.xyz);
}
,

这是我在Stack上的第一个答案,所以我想逐步介绍它。显然,您正在使用LearnOpenGL教程(可能是错误的,但是代码看起来很熟悉)。在本教程的帮助下,我刚刚克服了基本的照明问题,我也是一个初学者,但希望提供一些帮助。

顶点着色器

因此,对于您的Vertex Shader,您需要使用3个“ attrib”指针:位置,法线和纹理坐标-这是标准的,我希望您可以正确缓冲/传递数据。

layout (location = 0) in vec3 position; 
layout (location = 1) in vec3 normal; 
layout (location = 2) in vec2 textureCoordinate;

这没问题,我看不到它是怎么回事(没有看到您的其余代码)。

out vec3 Normal;
out vec3 FragmentPos; 
out vec2 mobileTextureCoordinate; 

您还将顶点法线,片段位置和纹理坐标传递给片段着色器(顺便说一句-为什么您将其称为“移动纹理坐标”?我不太熟悉猜测) ;到这里为止一切都很好:没问题。

然后便有了制服:模型,视图和投影矩阵声明-当然,没问题。

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

现在进入顶点着色器的主要功能。问题可能不是出在这里,因为显然您的金字塔可以正确渲染-仅在光线不正确的情况下。

void main(){
        gl_Position = projection * view * model * vec4(position,1.0f); 

看起来不错。

    FragmentPos = vec3(model * vec4(position,1.0f)); 

看起来不错,您可以忽略投影矩阵,也可以忽略视图矩阵。

    mobileTextureCoordinate = vec2(textureCoordinate.x,1.0f - textureCoordinate.y);

您水平翻转纹理坐标(不知道为什么-随便)

        Normal = mat3(transpose(inverse(model))) * normal; 
    }
);

不完全了解这里发生的情况,但不想尝试对其进行散列-您可能正在废除某些转换,以使法线仍然有效而不受模型转换或其他因素的影响(我真的不知道是否这是正确的,希望有人可以编辑我的回复。)

片段着色器:

    in vec2 mobileTextureCoordinate; 
    in vec3 Normal; 
    in vec3 FragmentPos; 
    out vec4 pyramidColor; // For outgoing pyramid color

到目前为止没有问题

    uniform vec3 fillLightColor;
    uniform vec3 fillLightPos;
    uniform vec3 keyLightColor;
    uniform vec3 keyLightPos;
    uniform vec3 viewPosition;
    uniform sampler2D uTexture; 

假设这些统一设置正确,并且您要调用 glUseProgram()/“ shader” .useProgram() /绑定等效的着色器,然后再通过glUniformX调用设置统一

    void main() {

        // Calculate Ambient lighting
        float ambientStrength = 0.3f; 
        vec3 ambient = ambientStrength * fillLightColor; 

        // Calculate Diffuse lighting for fill lamp
        vec3 norm = normalize(Normal); // Normalize vectors to 1 unit
        vec3 lightDirection = normalize(fillLightPos - FragmentPos); // Calculate distance (light direction) between fill light source and fragments/pixels
        float impact = max(dot(norm,lightDirection),0.0); // Calculate diffuse impact by generating dot product of normal and light
        vec3 diffuse = impact * fillLightColor; // Generate diffuse light color

        // Calculate Specular lighting for fill lamp
        float specularIntensity = 0.8f; // Set specular light strength
        float highlightSize = 16.0f; // Set specular highlight size
        vec3 viewDir = normalize(viewPosition - FragmentPos); // Calculate view direction
        vec3 reflectDir = reflect (-lightDirection,norm); // Calculate reflection vector
        //Calculate specular component
        float specularComponent = pow(max(dot(viewDir,reflectDir),0.0),highlightSize);
        vec3 specular = specularIntensity * specularComponent * fillLightColor;

        // Calculate Ambient lighting for key lamp
        float keyAmbientStrength = 1.0f;
        vec3 keyAmbient = keyAmbientStrength * keyLightColor;

        // Calculate Diffuse lighting for key lamp
        vec3 keyLightDirection = normalize(keyLightPos - FragmentPos); // Calculate distance between key light source and fragments
        float keyImpact = max(dot(norm,keyLightDirection),0.0);
        vec3 keyDiffuse = keyImpact * keyLightColor;

        // Calculate Specular lighting for key lamp
        float keySpecularIntensity = 0.8f; // Set specular light strength
        float keyHighlightSize = 32.0f; // Set specular highlight size
        vec3 keyReflectDir = reflect (-keyLightDirection,norm); // Calculate reflection vector
        //Calculate specular component
        float keySpecularComponent = pow(max(dot(viewDir,keyReflectDir),keyHighlightSize);
        vec3 keySpecular = keySpecularIntensity * keySpecularComponent * keyLightColor;

        // Calculate phong result
        vec3 objectColor = texture(uTexture,mobileTextureCoordinate).xyz;
        vec3 fillResult = (ambient + diffuse + specular);
        vec3 keyResult = (keyAmbient + keyDiffuse + keySpecular);
        vec3 lightingResult = fillResult + keyResult;
        vec3 phong = (lightingResult) * objectColor;
        pyramidColor = vec4(phong,1.0f); // Send lighting results to GPU

    }
); 

您确定金字塔颜色确实设置了片段的颜色吗?

从那里开始,一切看上去都像饼干切割机,但我还没有测试过自己!

本文链接:https://www.f2er.com/2404578.html

大家都在问