3
$\begingroup$

I am a bit confused in terms of directional light calculation in OpenGL. Generally we care about the direction of the directional light and we use it with the normal and view (toCamera) vector to calculate lighting. Let's say I do my calculation in view-space ... would I need to multiply the direction of the directional light with ViewMatrix (and then normalize) ? I tried both and they don't seem to make a difference ... I'm leaning towards "yes I need to do that". Is this correct? Here's part of my fragment shader that does lighting for directional light:

vec4 calculateDirectionalLightIntensities(in vec3 N, in vec3 V)
{
    vec4 result = vec4(0.0, 0.0, 0.0, 1.0);
    for(int i=0; i<DirectionalLightCount; ++i)
    {
        //vec3 L = normalize( (ViewMatrix * -vec4(DirectionalLightDirections[i], 0.0)).xyz );
        vec3 L = normalize(-DirectionalLightDirections[i].xyz);
        vec4 currentResult = calculateDiffuse(N, L);
        currentResult += calculateSpecular(N, L, V);
        currentResult *= DirectionalLightIntensities[i];
        result += currentResult;
    }
    return result;
}

Basically N would be the normal vector and V is vector pointing towards camera in view-space and it is calculated as:

void main()
{
    normal = normalize(NormalMatrix * vec4(NORMAL, 0.0)).xyz;       //We use 0 because normals are directional vectors
    uv0 = TEXCOORD0;

    vec4 viewSpacePosition = ModelViewMatrix * vec4(POSITION, 1.0);

#if defined(BLINN_PHONG_LIGHTING)

    toCamera = -viewSpacePosition.xyz; //CALCULATED HERE

#endif

    gl_Position = ProjectionMatrix * viewSpacePosition;
}

Should I be multiplying my dir of directional light in the vertex shader? If so, is there a performance hit to having multiple lights that results in having array of varying variables being set to the fragment shader?

$\endgroup$
2
$\begingroup$

It just depends on which space your light directions are actually specified in. You compute both your normal and view vector correctly in view space in order to perform your lighting computations in view space. So you need your normalized light direction in view space, too.

So it depends on how you actually transfer your light direction into the shader. Usually it's best to transform the light direction into view space before uploading it to the shader (from whatever space it's originally in in the scene, likely some kind of object space local to a certain light source, but in case of a directional light maybe already in world/view space). This has a few advantages:

  • As you realized yourself already, you won't have to perform a tedious matrix transformation for each and every vertex when the light is actiually constant for all vertices of a draw call (it's probably a uniform variable). While a matrix multiplication per-vertex doesn't really kill anyone, there's really no need to do that extra work, in contrast to simply transforming the light direction on the CPU once a frame.

  • But there's another problem to transforming it in every shader call. Usually your light direction isn't easily specified in object space at all (or not the local object space of whatever object your currently drawing). If anything, it comes from a local light source that has its own model transformation, but that is not the one encapsulated in the current modelview matrix, which usually depends on the model you're drawing. So using the modelview matrix you transform your vertices with is most likely the wrong way. You could use the view matrix (as you do) if it is specified in world space already, but as said above, that's usually not necessary.

So what you do depends on the space in which your light direction is stored in the scene. If it is stored in world space (e.g. the sun as the directional light example par-excellence), you just have to transform it into view space (e.g. by multiplying it with the camera/view matrix) right before uploading it into the shader (i.e. likely each frame, since it's view dependent). If it is actually view independent (e.g. a kind of "flashlight" always shining straight into the camera direction), you don't really have to transform it at all. And if it's local to some specific scene object (more appropriate for point light sources, though), you transform it by that object's modelview matrix.

$\endgroup$
  • $\begingroup$ Thank you for the clarification! I shall now to avoid extra work in my shaders :) $\endgroup$ – ChaoSXDemon Dec 17 '17 at 10:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.