【问题标题】:OpenGL, target spot-light "following me around the room"!OpenGL,目标聚光灯“在房间里跟着我”!
【发布时间】:2012-12-10 12:11:53
【问题描述】:

我正在实施目标聚光灯。我有光锥,衰减和所有这些都可以正常工作。问题是当我围绕空间中的某个点旋转相机时,灯光似乎会跟随它,即无论相机在哪里,光总是相对于相机处于相同的角度。

这是我在顶点着色器中所做的:

void main()
{
    // Compute vertex normal in eye space.

    attrib_Fragment_Normal = (Model_ViewModelSpaceInverseTranspose * vec4(attrib_Normal, 0.0)).xyz;

    // Compute position in eye space.

    vec4 position = Model_ViewModelSpace * vec4(attrib_Position, 1.0);

    // Compute vector between light and vertex.

    attrib_Fragment_Light = Light_Position - position.xyz;

    // Compute spot-light cone direction vector.

    attrib_Fragment_Light_Direction = normalize(Light_LookAt - Light_Position);

    // Compute vector from eye to vertex.

    attrib_Fragment_Eye = -position.xyz;

    // Output texture coord.

    attrib_Fragment_Texture = attrib_Texture;

    // Return position.

    gl_Position = Camera_Projection * position;
}

我有一个由 Light_Position 和 Light_LookAt 定义的目标聚光灯(注视点当然是聚光灯注视的空间点)。 position 和 lookAt 都已经在眼睛空间中。我通过从它们两者中减去相机位置来计算眼睛空间 CPU 端。

然后,在顶点着色器中,我继续制作从灯光位置到灯光lookAt 点的光锥向量,它通知像素着色器光锥的主轴在哪里。

此时我想知道我是否也必须转换向量,如果是的话,应该怎么做?我已经尝试过视图矩阵的逆转置,但没有成功。

谁能帮我看看这个?

为了完整性,这里是像素着色器:

void main(void)
{   
    // Compute N dot L.

    vec3 N = normalize(attrib_Fragment_Normal);
    vec3 L = normalize(attrib_Fragment_Light);  
    vec3 E = normalize(attrib_Fragment_Eye);
    vec3 H = normalize(L + E);

    float NdotL = clamp(dot(L,N), 0.0, 1.0);
    float NdotH = clamp(dot(N,H), 0.0, 1.0);

    // Compute ambient term.

    vec4 ambient = Material_Ambient_Colour * Light_Ambient_Colour;

    // Diffuse.

    vec4 diffuse = texture2D(Map_Diffuse, attrib_Fragment_Texture) * Light_Diffuse_Colour * Material_Diffuse_Colour * NdotL;

    // Specular.

    float specularIntensity = pow(NdotH, Material_Shininess) * Material_Strength;

    vec4 specular = Light_Specular_Colour * Material_Specular_Colour * specularIntensity;

    // Light attenuation (so we don't have to use 1 - x, we step between Max and Min).

    float d = length(-attrib_Fragment_Light);

    float attenuation = smoothstep( Light_Attenuation_Max, 
                                    Light_Attenuation_Min, 
                                    d);

    // Adjust attenuation based on light cone.

    vec3 S = normalize(attrib_Fragment_Light_Direction);

    float LdotS = dot(-L, S);
    float CosI = Light_Cone_Min - Light_Cone_Max;

    attenuation *= clamp((LdotS - Light_Cone_Max) / CosI, 0.0, 1.0);

    // Final colour.

    Out_Colour = (ambient + diffuse + specular) * Light_Intensity * attenuation;    
}

感谢以下回复。我仍然无法解决这个问题。我现在正在将光转换为眼睛空间 CPU 端。所以应该不需要对光进行变换,但它仍然不起作用。

// Compute eye-space light position.

Math::Vector3d eyeSpacePosition = MyCamera->ViewMatrix() * MyLightPosition;

MyShaderVariables->Set(MyLightPositionIndex, eyeSpacePosition);



// Compute eye-space light direction vector.

Math::Vector3d eyeSpaceDirection = Math::Unit(MyLightLookAt - MyLightPosition);

MyCamera->ViewMatrixInverseTranspose().TransformNormal(eyeSpaceDirection);

MyShaderVariables->Set(MyLightDirectionIndex, eyeSpaceDirection);

...在顶点着色器中,我正在这样做(如下)。据我所知,光在眼睛空间中,顶点被转换为眼睛空间,光照矢量(attrib_Fragment_Light)在眼睛空间中。然而向量永远不会改变。原谅我有点厚!

// Transform normal from model space, through world space and into eye space (world * view * normal = eye).

attrib_Fragment_Normal = (Model_WorldViewInverseTranspose * vec4(attrib_Normal, 0.0)).xyz;

// Transform vertex into eye space (world * view * vertex = eye)

vec4 position = Model_WorldView * vec4(attrib_Position, 1.0);

// Compute vector from eye space vertex to light (which has already been put into eye space).

attrib_Fragment_Light = Light_Position - position.xyz;

// Compute vector from the vertex to the eye (which is now at the origin).

attrib_Fragment_Eye = -position.xyz;

// Output texture coord.

attrib_Fragment_Texture = attrib_Texture;

【问题讨论】:

  • 这已经很老了,但我会指出一些事情,因为有人会觉得它很有帮助。我曾经遇到过类似的问题,我花了一段时间才解决。问题是我在着色器中更改了灯光位置统一的名称,但在 CPU 代码中忘记了这样做。结果是着色器中的灯光位置保持不变,这导致了您在问题中描述的效果。

标签: opengl glsl light


【解决方案1】:

看起来你从position 中减去Light_Position,我假设你想成为一个世界空间坐标(因为你似乎对它当前在眼睛空间中感到沮丧),这是一个眼睛空间向量.

// Compute vector between light and vertex.
attrib_Fragment_Light = Light_Position - position.xyz;

如果要减去两个向量,它们必须都在同一个坐标空间中。如果你想在世界空间中进行光照计算,那么你应该使用世界空间位置向量,而不是视图空间位置向量。

这意味着将 attrib_Position 变量与 Model 矩阵相乘,而不是 ModelView 矩阵,并使用此向量作为光照计算的基础。

【讨论】:

  • 我已经用更多信息更新了这个问题。我认为我现在正在正确计算眼睛位置,但问题仍然存在。
  • 我必须标记这个,只是为了让我的回复保持在 100%!我的着色器仍然无法正常工作,所以我认为这不是答案。顺便说一句,两个向量都在眼睛空间中。
【解决方案2】:

您不能仅通过减去相机位置来计算眼睛位置,您必须乘以模型视图矩阵。

【讨论】:

  • 我已经用更多信息更新了这个问题。我认为我现在正在正确计算眼睛位置,但问题仍然存在。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多