Opengl 如何在GLSL中将平行光转换为相机空间

Opengl 如何在GLSL中将平行光转换为相机空间,opengl,transform,glsl,lighting,uniform,Opengl,Transform,Glsl,Lighting,Uniform,我有以下用于照明的GLSL代码: uniform vec3 lightDir; // Parallel light uniform float ambient; uniform vec3 lightColour; void main() { gl_Position = ftransform(); vec3 eyeNormal = normalize(gl_NormalMatrix * gl_Normal); float intensity = max(ambie

我有以下用于照明的GLSL代码:

uniform vec3 lightDir; // Parallel light
uniform float ambient;
uniform vec3 lightColour;

void main()
{
     gl_Position = ftransform();

     vec3 eyeNormal = normalize(gl_NormalMatrix * gl_Normal);
     float intensity = max(ambient, dot(eyeNormal, normalize(-lightDir));

     gl_FrontColor = gl_Color * vec4(lightColour, 1.0) * intensity;
}
光矢量在世界空间中指定。我使用
gluLookAt
设置相机方向和位置。由于OpenGL假定光矢量位于摄影机空间中,因此灯光随摄影机移动,而不是停留在固定方向上


我尝试在调用
gluLookAt
之前和之后激活着色器并设置光向量,但得到了相同的效果。要正确变换光向量,我必须做些什么?

着色器中的问题是,您有眼睛空间法线和世界空间灯光。
我不确定,但是通过法线矩阵变换光向量应该可以解决这个问题


或者,为了提高效率,您可以在对象空间(在程序代码中)变换灯光向量,然后不需要对每个法线进行变换。

着色器中的代码计算不随灯光位置变化的平行光,因此您应该使用聚光灯或点光源功能


尝试为这些光源查找着色器。如果您找不到,请告诉我,我会寄给您一个。

您必须决定在哪个空间进行照明。如果您想遵循“标准”OpenGL,那么它就是视图空间。然后,在传递到着色器(imho最简单的解决方案)之前,必须通过视图矩阵的旋转部分旋转光向量


您也可以在其他空间(切线、对象、世界甚至屏幕空间-用于不同的着色)中应用灯光,但这是不同的主题。还请注意,对于高级使用,您需要忘记OpenGL,使用自己的矩阵和着色器(没有默认的照明/转换功能)完成所有操作。

您有一个常见的问题,经常在GLSL在线教程中看到。您正在通过“统一”传递照明值。为什么不像固定函数渲染一样使用
glLight
调用,并从
gl\u LightSource[n]
中提取值呢。不同之处在于openGL将自动转换视图空间中的所有内容

void main()
{
    // remember: directional lights are GL_POSITION with w = 0
    vec3 lightDir = vec3(gl_LightSource[0].position); 
    float ambient = gl_LightSource[0].ambient;
    vec3 lightColour = vec3(gl_LightSource[0].diffuse);


    gl_Position = ftransform();

    vec3 eyeNormal = normalize(gl_NormalMatrix * gl_Normal);
    float intensity = max(ambient, dot(eyeNormal, normalize(-lightDir));

    gl_FrontColor = gl_Color * vec4(lightColour, 1.0) * intensity;
}
这是一个非常好的主题资源:


GLSL作弊总是有用的:

我怀疑部分问题在于:
float intensity=max(环境光,点(眼法线,归一化(-lightDir));

在基于Lambertian的着色器中,环境项是按点积缩放的。在这里,环境项通常会声明自己,因为它可能大于点积。使用gl_NormalMatrix也是一个问题,因为如上所述,这意味着lightDir位于对象空间中,而法向量从obje变换出来ct空间和眼睛坐标

尝试:


我在着色器中尝试将lightDir与gl_NormalMatrix相乘,但没有效果。我还尝试了与gl_ModelViewMatrix相乘,如下所示:
vec3 lightEyeDir=normalize(vec3(gl_ModelViewMatrix*vec4(-lightDir,1.0)))
这样做完全消除了漫反射贡献。要在程序代码中变换光矢量,我应该做什么变换?通过逆模型矩阵变换光方向,您应该获得模型空间光。法线矩阵只是ModelView矩阵的旋转部分(无平移和缩放).将灯光与之相乘意味着也应用模型旋转(您不希望这样)@Tyrum,但前提是
lightDir
在眼睛空间。但这是他的问题,因为他希望它在世界空间中。因为没有模型矩阵,只有模型视图矩阵。但在这种情况下,我认为你不需要否定光的方向,因为
位置
字段中的值应该已经是光的向量(理论上指无限远处的位置)。请注意,现在不推荐使用glLight调用,这与将照明值作为制服传递不同。这是错误的。现在您假定
lightDir
位于模型空间中。而环境项是一个欺骗项,即使没有平行光,它也始终发出灯光,因此它绝对不应该乘以点积,而是添加(或者只在光线不足的情况下使用,就像他所做的那样)。你可能指的是光的固有强度,在他的例子中,由他乘以点积的
lightcolor
表示。
vec3 n=normalize(normal);
float ndotl=max(0.0, dot(n, normalize(lightDir)));

vec3 diffuse=ambient * ndotl;