如何停止位置光随相机移动

Posted

技术标签:

【中文标题】如何停止位置光随相机移动【英文标题】:How to stop positional light moving with camera 【发布时间】:2019-05-15 15:09:54 【问题描述】:

当我在我的 openGL 项目中旋转和/或移动相机时,几乎就像有一个聚光灯随之移动,但是我已经将我的 gl 灯设置为定位并给它一个静态位置。

void Lighting::Display()

    glPushMatrix();

    glTranslatef(0.f, yoffset, 0.f); // move to start
    glTranslatef(0.f, ceilHeight * scale[0], 0.f);
    DrawLight();

    glDisable(GL_LIGHTING);

    glPushAttrib(GL_ALL_ATTRIB_BITS);
    // Match colour of sphere to diffuse colour of light
    glColor4fv(specular);
    glTranslatef(0.f, -10.0f * scale[1], 0.f);
    glutSolidSphere(5.0f * scale[0], 25, 25);

    glPopAttrib();
    glPopMatrix();
    // Re-enable lighting after light source has been drawn
    glEnable(GL_LIGHTING);

    // Set properties GL_LIGHT0
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
    //glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.0001f);

    GLfloat pos[4] =  0.f, 950.f, 0.f, 1.f ;
    glLightfv(GL_LIGHT0, GL_POSITION, pos);

    // enable GL_LIGHT0 with these defined properties
    glEnable(GL_LIGHT0);

我希望有一个单一的光源悬挂在场景的中心,光线从它的位置向所有方向均匀发射 然而,一束光似乎被发射为聚光灯。

这是展示问题的图片:

如您所见,发出了一条奇怪的光线。

【问题讨论】:

由于您使用的是旧版(非现代)OpenGL API,您可以使用gluLookAt 来移动眼睛位置而不是移动模型。 我指的相机已经使用 gluLookAt 移动了 @zombunny 天花板上的这个点是镜面高光,不是吗。镜面光取决于光的位置、法线向量和观察方向。当你改变观点时,特别的亮点必须改变。 啊,我明白这是个问题,这是否意味着我只能忍受它? @zombunny 是的。你有某种反射球吗?用点光源照亮它并在它周围移动,然后你可以看到Blinn–Phong reflection model试图模仿的自然效果。当然效果很差,尤其是在已弃用的OpenGL固定功能光照模型的Gouraud shading处。 【参考方案1】:

当灯光位置由glLightfv(GL_LIGHT0, GL_POSITION, pos)设置时,则pos乘以当前模型视图矩阵。

Blinn–Phong reflection model的环境光(Ia)、漫射光(Id)和镜面光(Is)的强度计算如下:

N  ... norlmal vector 
L  ... light vector (from the vertex position to the light) 
V  ... view vector (from the vertex position to the eye)
sh ... shininess

H     = normalize(V + L)
NdotH = max(dot(N, H), 0.0)

Ia    = 1
Id    = max(dot(N, L), 0.0)
Is    = pow(NdotH, sh)

因此环境光 (GL_AMBIENT) 与任何方向无关。

漫射光 (GL_DIFFUSE) 取决于表面的法线向量 (N) 和入射光的方向 (L)。它在光照表面上保持不变,与视角无关。

镜面光 (GL_SPECULAR) 取决于表面法线向量 (N) 和光方向 (L)。和查看方向 (V)。当您在场景中移动时,这会导致镜面高光发生变化,因为被照亮表面的观察方向会发生变化。

进一步注意,已弃用的 OpenGL 固定函数光照模型中的光照计算是按顶点完成的 (Gouraud Shading)。计算出的光被插在区域上,在图元的角之间。 现代 实现是对每个片段进行光计算 (Phong shading)。 Gouraud Shading 会导致天花板上镜面高光的斑点外观,并可能增加意想不到的外观。将区域细分为较小的区域可能会改善这一点,但最好的解决方案是切换到 现代 OpenGL,编写 Shader 并根据您的需要实现每个片段的光照模型。

【讨论】:

我已经尝试过你的建议,但似乎没有任何明显的不同 天花板上的这些点是高光,不是吗。镜面光取决于光的位置、法线向量和观察方向。当你改变视角时,高光必须改变。【参考方案2】:

在设置照明位置之前弹出矩阵。因此,您的灯光位置始终是您设置的位置。然后,您将其他所有内容乘以我假设的 View Matrix。视图矩阵本质上将世界转换为相机的视图。本质上,相机不会移动,世界围绕着相机移动。由于灯光没有与此视图矩阵相乘,因此您会得到一个看起来相对于相机保持恒定位置的灯光。

【讨论】:

以上是关于如何停止位置光随相机移动的主要内容,如果未能解决你的问题,请参考以下文章

触摸屏幕上的任何位置,除了 GUI 按钮 Android Unity

如何通过鼠标移动事件获取相机位置并在three.js中转换为屏幕坐标? [关闭]

c#monogame如何让相机在玩家后面慢慢重置位置

如何使用opencv从相机的所有位置检测带有android的人脸?

将相机分别移动到其位置

将 Google 地图相机移动到某个位置