GLSL - 每片段照明

GLSL - per-fragment lighting

我开始使用多种光源进行照明。我看到的所有手册都没有考虑光源和物体之间的距离(例如https://learnopengl.com/Lighting/Basic-Lighting)。所以我写了我的着色器,但我不确定它的正确性。请分析这个着色器,并告诉我它有什么问题/不正确。我将非常感谢任何帮助!下面我带来了着色器本身,以及它对不同的 n 和 k 值的工作结果。

片段着色器:

#version 130

precision mediump float;                    // Set the default precision to medium. We don't need as high of a
                                            // precision in the fragment shader.

#define MAX_LAMPS_COUNT 8                   // Max lamps count.

uniform vec3 u_LampsPos[MAX_LAMPS_COUNT];   // The position of lamps in eye space.
uniform vec3 u_LampsColors[MAX_LAMPS_COUNT];
uniform vec3 u_AmbientColor = vec3(1, 1, 1);
uniform sampler2D u_TextureUnit;
uniform float u_DiffuseIntensivity = 12;
uniform float ambientStrength = 0.1;
uniform int u_LampsCount;

varying vec3 v_Position;                    // Interpolated position for this fragment.
varying vec3 v_Normal;                      // Interpolated normal for this fragment.
varying vec2 v_Texture;                     // Texture coordinates.

// The entry point for our fragment shader.
void main() {
    float n = 2;
    float k = 2;

    float finalDiffuse = 0;
    vec3 finalColor = vec3(0, 0, 0);

    for (int i = 0; i<u_LampsCount; i++) {
        // Will be used for attenuation.
        float distance = length(u_LampsPos[i] - v_Position);

        // Get a lighting direction vector from the light to the vertex.
        vec3 lightVector = normalize(u_LampsPos[i] - v_Position);

        // Calculate the dot product of the light vector and vertex normal. If the normal and light vector are
        // pointing in the same direction then it will get max illumination.
        float diffuse = max(dot(v_Normal, lightVector), 0.1);

        // Add attenuation.
        diffuse = diffuse / (1 + pow(distance, n));

        // Calculate final diffuse for fragment
        finalDiffuse += diffuse;

        // Calculate final light color
        finalColor += u_LampsColors[i] / (1 + pow(distance, k));
    }

    finalColor /= u_LampsCount;

    vec3 ambient = ambientStrength * u_AmbientColor;

    vec3 diffuse = finalDiffuse * finalColor * u_DiffuseIntensivity;

    gl_FragColor = vec4(ambient + diffuse, 1) * texture2D(u_TextureUnit, v_Texture);
}

顶点着色器:

#version 130

uniform mat4 u_MVPMatrix;      // A constant representing the combined model/view/projection matrix.
uniform mat4 u_MVMatrix;       // A constant representing the combined model/view matrix.

attribute vec4 a_Position;     // Per-vertex position information we will pass in.
attribute vec3 a_Normal;       // Per-vertex normal information we will pass in.
attribute vec2 a_Texture;      // Per-vertex texture information we will pass in.

varying vec3 v_Position;       // This will be passed into the fragment shader.
varying vec3 v_Normal;         // This will be passed into the fragment shader.
varying vec2 v_Texture;        // This will be passed into the fragment shader.

void main() {
    // Transform the vertex into eye space.
    v_Position = vec3(u_MVMatrix * a_Position);

    // Pass through the texture.
    v_Texture = a_Texture;

    // Transform the normal's orientation into eye space.
    v_Normal = vec3(u_MVMatrix * vec4(a_Normal, 0.0));

    // gl_Position is a special variable used to store the final position.
    // Multiply the vertex by the matrix to get the final point in normalized screen coordinates.
    gl_Position = u_MVPMatrix * a_Position;
}

n=2 k=2

n=1 k=3

n=3 k=1

n=3 k=3

如果我的着色器是正确的,那么我该如何命名这些参数 (n, k)?

"correct" 我假设您的意思是代码是否正常工作。这些光照计算在物理上绝不准确。除非你要与旧设备完全兼容,否则我建议你使用更高版本的 glsl,它允许你使用 inout 以及一些其他有用的 glsl 功能。当前版本是 450,而您仍在使用 130。顶点着色器看起来不错,因为它只是将值传递给片段着色器。

至于片段着色器,您可以进行一项优化。

计算u_LampsPos[i] - v_Position不必重复两次。执行一次,然后对一次计算的相同结果执行 lengthnormalize

代码非常小,所以在 glsl 方面不会出错,但我想知道你为什么这样做:finalColor /= u_LampsCount;?

这对我来说没有意义。