OpenGL从定向/点转换为聚光灯

Posted

技术标签:

【中文标题】OpenGL从定向/点转换为聚光灯【英文标题】:OpenGL Converting from Directional/point to Spotlight 【发布时间】:2015-05-08 04:53:46 【问题描述】:

所以我目前正在尝试在我的顶点着色器中创建聚光灯,目前我可以使用 Phong 照明模型产生定向和/或点光。

我发现很难计算聚光灯的正确角度,基本上只想要一个来自眼睛空间 0,0,0 并向下看 Z 坐标的聚光灯。

我正在尝试让锥体中的所有东西(现在)都变成亮白色,而外面的所有东西都变暗

#version 130

uniform mat4 model_view_matrix;
uniform mat4 projection_matrix;
uniform mat3 normal_matrix;
uniform int light_mode;

uniform vec4 light_pos;
uniform vec3 light_ambient;
uniform vec3 light_diffuse;
uniform vec3 light_specular;

uniform vec3 mtl_ambient;
uniform vec3 mtl_diffuse;
uniform vec3 mtl_specular;
uniform float mtl_shininess;

// Spotlight test
const float spotCutOff = 100.00f;

in vec3 position;
in vec3 normal;
in vec2 texCoord;

out vec2 st;
out vec4 litColour;


vec3 phongLight(in vec4 position, in vec3 norm)

    // s is the direction from the light to the vertex
    vec3 s;
    if (light_pos.w == 0.0) 
        s = normalize(light_pos.xyz);
    
    else 
        s = normalize(vec3(light_pos - position));
    

    // v is the direction from the eye to the vertex
    vec3 v = normalize(-position.xyz);

    // r is the direction of light reflected from the vertex
    vec3 r = reflect(-s, norm);

    vec3 ambient = light_ambient * mtl_ambient;

    // The diffuse component
    float sDotN = max(dot(s,norm), 0.0);
    vec3 diffuse = light_diffuse * mtl_diffuse * sDotN;

    // Specular component
    vec3 spec = vec3(0.0);
    if (sDotN > 0.0)
        spec = light_specular * mtl_specular * pow(max(dot(r,v), 0.0), mtl_shininess);

    return ambient + diffuse + spec;


vec3 spotLight(in vec4 position, in vec3 norm)

    vec3 ambient = vec3(0.2, 0.2, 0.2);

    vec3 lightDir = normalize(vec3(light_pos - position));
    vec3 spotDir = vec3(0.0, 0.0, -1.0);



    float angle = degrees(acos(dot(spotDir, lightDir)));
    //angle = max (angle, 0);

    if ((angle) < spotCutOff) 
        return vec3(1.0, 1.0, 1.0);
    

    float dist = sqrt(positon.x * position.x + position.y + position.y + position.z * position.z);

    if (dist < 1) 
        return vec3(1.0,1.0,0.0);
    

    return vec3(0.2, 0.2, 0.2);


void main(void)

    // Convert normal and position to eye coords
    vec3 eyeNorm = normalize(normal_matrix * normal);
    vec4 eyePos = model_view_matrix * vec4(position, 1.0);

    // No lighting effect
    if (light_mode == 0)
    
        litColour = vec4(1.0, 1.0, 1.0, 1.0);
    
    // Directional overhead light
    else if (light_mode == 1)
    
        litColour = vec4(phongLight(eyePos, eyeNorm), 1.0);
    
    // Point light
    else if (light_mode == 2)
    
        litColour = vec4(phongLight(eyePos, eyeNorm), 1.0);
    
    else if (light_mode == 3)
    
        litColour = vec4(spotLight(eyePos, eyeNorm), 1.0);
    

    //litColour = vec4(normal*1000, 1.0);

    gl_Position = projection_matrix * eyePos;
    st = texCoord;

【问题讨论】:

【参考方案1】:

您的聚光灯由位置 (ps) 和方向 (ds) 定义。因此,对于位置 vp 的每个顶点,您可以计算 d=vp-ps,将其归一化为 dn=normalize(d),然后 dot(dn,ds) 将为您提供聚光灯下的角度。只需对其进行缩放或将其与截断值进行比较即可获得标量!

或者,从长远来看更好的是,将聚光灯视为相机。对相机做同样的事情:模型和视图矩阵!将每个顶点转换为该空间,并将其从 x,y,z,w 投影到 x,y,z。 z 是始终对照明有用的距离,而 x,y 可用于在具有圆形(或任何其他形状)的纹理中查找。

使用这两种技术要注意的一点是反向投影:确保检查光线只指向前方!检查 z 的符号或点积!

【讨论】:

以上是关于OpenGL从定向/点转换为聚光灯的主要内容,如果未能解决你的问题,请参考以下文章

C++ Opengl - 使用聚光灯照明

OpenGL光照设置

一步步学OpenGL(21) -《聚光灯光源》

点光源随相机移动

使用立方体贴图(OpenGL/GLSL)的点光源是不是可以实现软阴影?

OpenGL:移动相机时如何使光线静止?