OpenGL directional light shader

北战南征 提交于 2020-07-08 13:33:11

问题


I want to add directional light to my scene using OpenGL and GLSL. The problem is that the theoretically correct way to do so has the wrong results.

In the vertex shader I do the following:

The direction of the light is given in world-coordinates and transformed using the viewMatrix to camera-coordinates. The normal of the vertex is transformed using the normal-matrix to camera-coordinates.

void main () {
    vary_textureCoord = attribute_textureCoord;
    vary_normal = mat3(normalMatrix) * attribute_normal;

    vary_directionalLight_direction = viewMatrix * vec4(lightDir, 1.0);

    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(attribute_position, 1.0);
}

So both vectors are in camera-coordinates and passed to the fragment shader. The fragment shader calculates the light intensity using the normal and the direction of the light.

void main () {
    vec3 normalizedNormal = normalize(vary_normal);
    vec4 color = texture(tex, vary_textureCoord);

    float directionalLightIntensity = max(0.0, dot(normalizedNormal, normalize(-vary_directionalLight_direction.xyz)));

    out_color =  color * directionalLightIntensity;
}

This shader leads to the result that the light is not static but moves along with the camera. Changing the vertex shader using this line instead:

vary_directionalLight_direction = transpose(inverse(viewMatrix)) * vec4(lightDir, 1.0);

has the desired results. So what am I doing wrong or where do I have a misunderstanding?

Here the full shader codes:

Vertexshader:

# version 330

layout(location = 0) in vec3 attribute_position;
layout(location = 2) in vec2 attribute_textureCoord;
layout(location = 3) in vec3 attribute_normal;

uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform mat4 normalMatrix;
uniform vec3 lightDir;

out vec2 vary_textureCoord;
out vec3 vary_normal;
out vec4 vary_directionalLight_direction;

void main () {
    vary_textureCoord = attribute_textureCoord;
    vary_normal = mat3(normalMatrix) * attribute_normal;

    vary_directionalLight_direction = viewMatrix * vec4(lightDir, 1.0);

    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(attribute_position, 1.0);
}

Fragmentshader:

# version 330

in vec2 vary_textureCoord;
in vec3 vary_normal;
in vec4 vary_directionalLight_direction;

uniform sampler2D tex;

out vec4 out_color;

void main () {
    vec3 normalizedNormal = normalize(vary_normal);
    vec4 color = texture(tex, vary_textureCoord);

    float directionalLightIntensity = max(0.0, dot(normalizedNormal, normalize(-vary_directionalLight_direction.xyz)));

    out_color =  color * directionalLightIntensity;
}

回答1:


A transformation matrix looks like this:

( X-axis.x, X-axis.y, X-axis.z, 0 )
( Y-axis.x, Y-axis.y, Y-axis.z, 0 )
( Z-axis.x, Z-axis.y, Z-axis.z, 0 )
( trans.x,  trans.y,  trans.z,  1 ) 

If you want to transform a position, then you have to apply the full transformation matrix to the position.

mat4 viewMatrix;
vec3 pos;
vec4 viewPos = viewMatrix * vec4(pos, 1.0);

This applies the orientation and the position of the view to the position pos.

But a direction has no origin. A direction has only an orientation. This means, if you want to transform a direction vector, by the view, then you have to multiply it by the upper left 3*3 part of the 4*4 viewMatrix:

vary_directionalLight_direction = vec4(mat3(viewMatrix) * lightDir, 1.0);


来源:https://stackoverflow.com/questions/47992011/opengl-directional-light-shader

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!