c++ - 点光源随相机移动

标签 c++ opengl glsl glm-math light

我目前正在使用OpenGL在场景中添加一些灯光(定向光,点光源和聚光灯)。
我的定向光和聚光灯似乎可以工作,但我的点光仍在摄像机后面。我想将点光源的位置设置在任意位置,例如(10,5,2)。
因此,我创建了一个片段着色器,使用点光源的这种结构来管理多个光源:

struct PointLight {    
   vec3 position;
   vec3  color;

   float constant;
   float linear;
   float quadratic;  };

这是我将数据发送到片段着色器的代码:
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);

点的光位置在 View 空间中表示。

顶点着色器:
#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);
}

最后,从点光源计算片段颜色的函数:
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;
}

此功能有点复杂,原因是金属粗糙度,并且许多线条与该问题无关。
综上所述,此函数与calcDirectionalLight非常相似(起作用),但区别在于我添加了一个衰减,并且L是light.position-FragPos而不是light.direction。
我不明白问题出在哪里,好像数据没有在正确的空间中表达,或者我忘记了什么。

最佳答案

我找到了解决方案,这很简单。
我从定向光复制了这一行:pos = glm::normalize(glm::vec3(viewMatrix * glm::vec4(pos, 1.)));(我将0替换为1,将dirLight替换为位置)
不幸的是,我忘了删除归一化功能,所以点光源接近(0,0,0):相机位置。这个结果使我确信,数据是在错误的空间中表达的,但事实并非如此。

关于c++ - 点光源随相机移动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60874414/

相关文章:

c++ - 在一个纹理中读取和写入 (OpenGL)

glsl - GLSL 相当于 LINES 的 gl_PointCoord 是什么?

c++ - 将数组传递给 lambda 函数

c++ - #在 C++ 中定义一个没有空终止的字符数组

java - 延迟渲染中的光积累

GLSL 中的 OpenGL 预乘 alpha 为 DDS 纹理提供了意想不到的结果

opengl-es - Opengl ES 2.0 着色器 - 丢弃 alpha == 0 的像素而不丢弃,如果

c++ - 无法显式调用默认构造函数

java - 多线程 JNI 调用

c++ - 在OpenGL/GLSL 4.3中读取和更新纹理缓冲区