GLSL - 每片段照明

时间:2018-03-29 07:20:14

标签: opengl glsl jogl fragment-shader light

我开始用几种光源照明。我看到的所有手册都没有考虑光源和物体之间的距离(例如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=2 k=2

n = 1 k = 3 n=1 k=3

n = 3 k = 1 n=3 k=1

n = 3 k = 3 n=3 k=3

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

1 个答案:

答案 0 :(得分:0)

通过“正确”我认为你的意思是代码工作正常。这些照明计算在任何情况下都不是物理上准确的。除非您要与旧设备完全兼容,否则我建议您使用更高版本的glsl,以便使用inout以及其他一些有用的glsl功能。当前版本为450,您仍然使用130.顶点着色器看起来没问题,因为它只是将值传递给片段着色器。

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

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

代码非常小,所以glsl明智地没有太大问题,但是我想知道你为什么这样做:finalColor /= u_LampsCount;

这对我没有意义。