OpenGL定向照明+定位

Posted

技术标签:

【中文标题】OpenGL定向照明+定位【英文标题】:OpenGL Directional Lighting + Positioning 【发布时间】:2012-02-28 23:48:02 【问题描述】:

我正在编写一个引擎并使用 Light 0 作为场景的“太阳”。太阳是定向光。

我设置了场景的 Ortho 视点,然后将灯光设置在屏幕的“东”侧(以及角色)(x/y 是平面地形的坐标,正 z 朝向相机并且指示地形上的“高度”——场景也会旋转以获得 x 轴上的等距视图)。

灯光似乎在 0,0,0 的“东”处闪烁,但随着角色移动,它不会移动(CenterCamera 在提供的值的负值上执行 glTranslate3f,以便可以映射指定世界坐标)。意思是,我越往西走,它总是黑暗的,没有光。

    Graphics.BeginRenderingLayer();
    
        Video.MapRenderingMode();

        Graphics.BeginLightingLayer( Graphics.AmbientR, Graphics.AmbientG, Graphics.AmbientB, Graphics.DiffuseR, Graphics.DiffuseG, Graphics.DiffuseB, pCenter.X, pCenter.Y, pCenter.Z );
        
            Graphics.BeginRenderingLayer();
            
                Graphics.CenterCamera( pCenter.X, pCenter.Y, pCenter.Z );
                RenderMap( pWorld, pCenter, pCoordinate );
            
            Graphics.EndRenderingLayer();

            Graphics.BeginRenderingLayer();
            
                Graphics.DrawMan( pCenter );
            
            Graphics.EndRenderingLayer();
        
        Graphics.EndLightingLayer();
    
    Graphics.EndRenderingLayer();

Graphics.BeginRenderingLayer = PushMatrix, EndRenderingLayer = PopMatrix Video.MapRenderingMode = Ortho Projection and Scene Rotation/Zoom CenterCamera 会转换到 X/Y/Z 的反面,这样角色现在就以 X/Y/ 为中心Z 在屏幕中间。

有什么想法吗?也许我在这里有些混淆了我的一些代码?

照明代码如下:

    public static void BeginLightingLayer( float pAmbientRed, float pAmbientGreen, float pAmbientBlue, float pDiffuseRed, float pDiffuseGreen, float pDiffuseBlue, float pX, float pY, float pZ )
    
        Gl.glEnable( Gl.GL_LIGHTING );
        Gl.glEnable( Gl.GL_NORMALIZE );
        Gl.glEnable( Gl.GL_RESCALE_NORMAL );
        Gl.glEnable( Gl.GL_LIGHT0 );

        Gl.glShadeModel( Gl.GL_SMOOTH );

        float[] AmbientLight = new float[4]  pAmbientRed, pAmbientGreen, pAmbientBlue, 1.0f ;
        float[] DiffuseLight = new float[4]  pDiffuseRed, pDiffuseGreen, pDiffuseBlue, 1.0f ;
        float[] PositionLight = new float[4]  pX + 10.0f, pY, 0, 0.0f ;
        //Light position of Direction is 5 to the east of the player.

        Gl.glLightfv( Gl.GL_LIGHT0, Gl.GL_AMBIENT, AmbientLight );
        Gl.glLightfv( Gl.GL_LIGHT0, Gl.GL_DIFFUSE, DiffuseLight );
        Gl.glLightfv( Gl.GL_LIGHT0, Gl.GL_POSITION, PositionLight );

        Gl.glEnable( Gl.GL_COLOR_MATERIAL );
        Gl.glColorMaterial( Gl.GL_FRONT_AND_BACK, Gl.GL_AMBIENT_AND_DIFFUSE );
    

【问题讨论】:

发布您的代码以显示您设置灯光的位置可能会有所帮助。 编辑原件以包含照明代码。 您是否正在计算并发送每个顶点的法线? 【参考方案1】:

您需要为每个表面提供法线。正在发生的事情(没有法线)是定向光基本上照在零以东的所有位置上,而那里的所有东西的法线都是 0,0,1(它面向西)。

据我所知,您不需要为每个顶点发送法线,而是因为 GL 是一个状态机,所以您需要确保每当法线发生变化时都会对其进行更改。所以如果你在一个立方体上渲染一个面,“西”面应该有一个单独的调用

glNormal3i(0,0,1);
glTexCoord..
glVertex3f...
glTexCoord..
etc.

对于 x-y-z 对齐的直角棱镜,“整数”就足够了。对于不面向六个基本方向之一的面,您需要对其进行归一化。根据我的经验,除非四边形不平坦,否则您只需要标准化前三个点。这是通过找到由四边形中的前三个边形成的三角形的法线来完成的。

我发现一些关于“计算法线”的简单教程很有启发性。

第二部分是,由于它是定向光,因此 (W=0) 根据玩家位置重新定位它是没有意义的。除非光线本身是从相机后面发出的,并且您正在旋转您面前的物体(例如模型),并且您希望始终保持正面照明,否则它的位置可能应该类似于

float[] PositionLight = new float[4]  0.0f, 0.0f, 1.0f, 0.0f ;

或者,如果 GLx 方向被解释为东西方向(即您最初面向北/南)

float[] PositionLight = new float[4]  1.0f, 0.0f, 0.0f, 0.0f ;

这个概念是您正在计算每个面的光,如果光不移动并且场景本身不移动(只是相机在场景中移动),方向计算将始终保持正确。如果法线准确,GL 可以计算出特定面部上显示的光强度。

最后一点是 GL 不会自动为您处理阴影。基本 GL_Light 足以用于一系列凸形的受控照明,因此您必须确定是否应将光(例如太阳)应用于面部。在某些情况下,这只是获取脸部所属的实体,并查看太阳光的矢量在到达“天空”之前是否与另一个实体相交。

在光照贴图和阴影贴图中寻找东西。

【讨论】:

【参考方案2】:

可能会绊倒很多人的一件事是发送到glLightFv 的位置是由当前矩阵堆栈转换的。因此,如果您想将灯光设置到世界坐标中的特定位置,则必须在调用glLightFv 时在矩阵堆栈上设置并激活相机和投影矩阵。

【讨论】:

以上是关于OpenGL定向照明+定位的主要内容,如果未能解决你的问题,请参考以下文章

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

光照在 OpenGL 中不显示

C++ OpenGL中定位光和直射光的区别?

OpenGL的漫射照明问题

照明在opengl中不起作用[关闭]

OpenGL透视和照明不起作用?