如何在 GLSL 中将定向光转换到相机空间

发布于 2024-08-14 12:23:23 字数 557 浏览 5 评论 0原文

我有以下用于照明的 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 之前和之后激活着色器并设置光矢量,但得到了相同的效果。我究竟需要做什么才能正确转换光矢量?

I have the following GLSL code for lighting:

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;
}

The light vector is specified in world space. I set the camera orientation and position using gluLookAt. Since OpenGL assumes the light vector is in camera space, the light moves with the camera instead of staying in a fixed orientation.

I tried activating the shader and setting the light vector both before and after I call gluLookAt, but I get the same effect. What exactly do I have to do to properly transform the light vector?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

与酒说心事 2024-08-21 12:23:23

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

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

You must decide in which space you will do the lighting. If you want to follow "standard" OpenGL then it is view space. Your light vector must then be rotated by rotation part of the view matrix before passing to a shader (imho simplest solution).

You can also apply lights in other spaces (tangent, object, world or even screen space - for deffered shading) but that's different topic. Also note that for advanced use you will need to forget OpenGL and do everything with your own matrices and shaders (no default lighting/transformation stuff).

念三年u 2024-08-21 12:23:23

您遇到了一个常见问题,经常在在线 GLSL 教程中看到。您通过制服传递照明值。为什么不使用 glLight 调用(例如固定函数渲染),并从 gl_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;
}

关于该主题的始终很棒的资源:http://www.lighthouse3d.com/ opengl/glsl/index.php?lights

GLSL Cheat 总是很有用:http://www.cs.brown.edu/courses/cs123/resources/glslQuickRef.pdf

You have a common problem, often seen in GLSL tutorials online. You are passing your lighting values via uniform. Why don't you use the glLight calls, like with fixed function rendering, and pull the values from gl_LightSource[n]. The difference is that openGL will automatically translate everything in view space.

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;
}

A always great resource on the subject: http://www.lighthouse3d.com/opengl/glsl/index.php?lights

And always useful is the GLSL Cheat Cheat: http://www.cs.brown.edu/courses/cs123/resources/glslQuickRef.pdf

梦晓ヶ微光ヅ倾城 2024-08-21 12:23:23

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

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

The problem in you shader, is that you have eye space normals, and worldspace lights.

I'm not sure, but transforming your light vector by your normal matrix should fix the problem.

Or, to be more efficient, you can transform the light vec in object-space (in program code), then no transformation for each normal is requiered.

素食主义者 2024-08-21 12:23:23

我怀疑部分问题在于:
floattensity = max(ambient, dot(eyeNormal, normalize(-lightDir));

在基于朗伯的着色器中,环境项是按点积缩放的。这里环境项经常会断言自己因为它可能大于点积。gl_NormalMatrix 的使用也是一个问题,因为如上所述,这意味着 lightDir 位于对象空间中,而法线向量则从对象空间转换为眼睛坐标

。 :

vec3 n=normalize(normal);
float ndotl=max(0.0, dot(n, normalize(lightDir)));

vec3 diffuse=ambient * ndotl; 

I suspect part of the problem lies in:
float intensity = max(ambient, dot(eyeNormal, normalize(-lightDir));.

The ambient term is, in Lambertian based shaders, scaled by the dot product. Here the ambient term will assert itself often because it is likely to be greater than the dot product. The use of gl_NormalMatrix is also a problem because, as commented above, it means the lightDir is in object space while the normal vector is transformed out of object space and into eye coordinates.

Try:

vec3 n=normalize(normal);
float ndotl=max(0.0, dot(n, normalize(lightDir)));

vec3 diffuse=ambient * ndotl; 
岁月染过的梦 2024-08-21 12:23:23

Shader中的代码计算的是方向光,它不随光的位置而变化,因此您应该使用spotLight或pointLight函数。

尝试为这些光源找到着色器。如果您找不到,请告诉我,以便我给您发送一份。

the code in shader calculates directional light which does not change with the position of light, so you should use spotLight or pointLight functions.

Try to find shaders for these light sources. if you can not find, tell me so i will send you one.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文