简体   繁体   中英

Point light move with the camera

I'm currently working on OpenGL to add some lights in a my scene (directional light, point lights, and spot light). My directional light and my spot light seem to work, but my point light still following the camera. I want to set the position of that point light in a arbitrary place, for example (10, 5, 2). So, I created a fragment shader to manage several lights with this structure for the point light :

struct PointLight {    
   vec3 position;
   vec3  color;

   float constant;
   float linear;
   float quadratic;  };

And here the code where I send the data to the fragment shader :

glm::vec3 pos(-10.f, 5.f, 0.f);
pos = glm::normalize(glm::vec3(viewMatrix * glm::vec4(pos, 1.)));
glUniform3f(pointLightPositionLocation, pos.x, pos.y, pos.z);
glUniform3f(pointLightColorLocation, 0.0f, 1.0f, 0.0f);
glUniform1f(pointLightConstantLocation, 1.0f);
glUniform1f(pointLightLinearLocation, 0.09f);
glUniform1f(pointLightQuadraticLocation, 0.032f);

The point's light position is expressed in view space.

The vertex shader :

#version 330

layout(location = 0) in vec3 aPosition;
layout(location = 1) in vec3 aNormal;
layout(location = 2) in vec2 aTexCoords;

out vec3 vViewSpacePosition;
out vec3 vViewSpaceNormal;
out vec2 vTexCoords;
out vec3 vFragPos; 

uniform mat4 uModelViewProjMatrix;
uniform mat4 uModelViewMatrix;
uniform mat4 uNormalMatrix;

void main()
{
    vViewSpacePosition = vec3(uModelViewMatrix * vec4(aPosition, 1));
    vViewSpaceNormal = normalize(vec3(uNormalMatrix * vec4(aNormal, 0)));
    vTexCoords = aTexCoords;
    gl_Position =  uModelViewProjMatrix * vec4(aPosition, 1);
}

And finally, the fonction where I calculate the fragment color from the point light :

vec3 calculatePointLight(PointLight light) {
    vec3 N = normalize(vViewSpaceNormal);
    vec3 L = normalize(light.position - vViewSpacePosition);
    vec3 V = normalize(-vViewSpacePosition);
    vec3 H = normalize(L + V);

    vec4 baseColorFromTexture = SRGBtoLINEAR(texture(uBaseColorTexture, vTexCoords));
    vec4 baseColor = baseColorFromTexture * uBaseColorFactor;
    float NdotL = clamp(dot(N, L), 0, 1);
    float NdotV = clamp(dot(N, V), 0, 1);
    float NdotH = clamp(dot(N, H), 0, 1);
    float VdotH = clamp(dot(V, H), 0, 1);

    float metallic = texture(uMetallicRoughnessTexture, vTexCoords).z * uMetallicFactor;
    float roughness = texture(uMetallicRoughnessTexture, vTexCoords).y * uRoughnessFactor;

    vec3 cDiff = mix(baseColor.rgb * (1 - dielectricSpecular.r), black, metallic);
    vec3 f0 = mix(dielectricSpecular, baseColor.rgb, metallic);
    float a = uRoughnessFactor * roughness;
    float a2 = a * a;

    // You need to compute baseShlickFactor first
    float baseShlickFactor = (1 - VdotH);
    float shlickFactor = baseShlickFactor * baseShlickFactor; // power 2
    shlickFactor *= shlickFactor; // power 4
    shlickFactor *= baseShlickFactor; // power 5
    vec3 F = f0 + (1 - f0) * shlickFactor;

    float deno = NdotL * sqrt(NdotV * NdotV * (1 - a2) + a2) + NdotV * sqrt(NdotL* NdotL * (1 - a2) + a2);
    float Vis;
    if (deno == 0.) {
        Vis = 0;
    }
    else {
        Vis = 0.5 / deno;
    }

    deno = M_PI * (NdotH * NdotH * (a2 - 1) + 1) * (NdotH * NdotH * (a2 - 1) + 1);
    float D;
    if (deno == 0.) {
        D = 0;
    }
    else {
        D = a2 / deno;
    }

    vec3 diffuse = cDiff * M_1_PI;
    vec3 f_diffuse = (1 - F) * diffuse;
    vec3 f_specular = F * Vis * D;

    vec4 emissive = texture(uEmissiveTexture, vTexCoords) * vec4(uEmissiveFactor, 1);

    vec4 occlusion = texture(uOcclusionTexture, vTexCoords);

    // attenuation
    float distance    = length(light.position - vViewSpacePosition);
    float attenuation = 1.0 / (light.constant + light.linear * distance + 
                 light.quadratic * (distance * distance));

    f_diffuse *= attenuation;
    f_specular *= attenuation;

    vec3 color = (f_diffuse + f_specular) * light.color * NdotL + emissive.xyz;
    color = mix(color, color * occlusion.x, uOcclusionStrength);
    color = LINEARtoSRGB(color);
    return color;
}

This function is kinda complicate beacuse of metallic roughness and lot of lines are not related to the problem. To sum up, this function is very similar to calcDirectionalLight (which works), but the differences are that I added an attenuation and L is light.position - FragPos instead of light.direction. I don't understand where is the problem, it looks like a data is not expressed in the correct space or I forgot something.

I found the solution and it's very simple. I copied this line : pos = glm::normalize(glm::vec3(viewMatrix * glm::vec4(pos, 1.))); from the directional light (I replaced 0 by 1 and dirLight by position) Unfortunately I forgot to remove the normalize, so the point light is close of (0, 0, 0) : the camera position. This result convinced me that a data was expressed in the wrong space but It wasn't.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM