OpenGL:雾

 雾也是大自然中最常见的现象之一,有了雾的效果,场景看起来会更加真实。在OpenGL中,很容易实现雾的效果。

在OpenGL中,雾的工作模式有两种:线性模式和指数模式。这两种模式是根据雾的浓度变化来区分的。

在线性模式下,只需要提供一个距离视点的开始位置和结束位置。从开始位置到结束位置之间,雾的浓度越来越高,浓度的变化和距离成正比。

在指数模式下,雾的浓度随着距离的增加呈指数增长。这种模式通常用来用于烟雾、烟幕等效果。

启用雾化的效果必须使用glEnable(GL_FOG),同样,取消雾的效果就是glDisable(GL_FOG)。启用雾化后,还需要设置雾的参数才能够真正实现雾的效果。设置雾的参数的命令是glFog,其原型如下。

 

void glFogf(

  GLenum pname,

  GLfloat param

);

 

void glFogi(

  GLenum pname,

  GLint param

);

 

void glFogfv(

  GLenum pname,

  const GLfloat *params

);

 

void glFogiv(

  GLenum pname,

 const GLint * params

);

 

pname 表示需要设置的雾的参数,取值及含义说明如下表9-1所示。

 

表9-1     glFog参数取值含义

pname取值
 对应params含义
 
GL_FOG_MODE
 params参数表示雾的工作模式。可以取三个值:GL_LINEAR, GL_EXP, and GL_EXP2,前者表示线性模式,后两种表示指数模式。缺省取值为GL_EXP。
 
GL_FOG_DENSITY
 params参数表示雾的密度,用于指数模式的指数。如果是负值,则被忽略,缺省值为1.0。
 
GL_FOG_START
 params参数表示雾化效果的开始距离,用于线性模式中。缺省值为0.0。
 
GL_FOG_END
 params参数表示雾化效果的结束距离,用于线性模式中,缺省距离为1.0。
 
GL_FOG_INDEX
 params参数表示在颜色索引表的颜色模式下,颜色的索引值if,缺省的索引值为0.0。
 
GL_FOG_COLOR
 仅用于glFogfv 和 glFogiv 函数,此时params参数表示雾的颜色Cf的向量RGBA值。不论取值是浮点数还是整数,最终的颜色值都映射到[0,1]范围。缺省的值为(0,0,0,0)。
 

 

经过雾化后,从观察者的角度来看,物体的颜色和其本身的颜色已经不同,这种差别是由混合因子来确定的,而混合因子又来自于雾的各参数。

假设z是从原点到在物体的距离,start是雾化的开始距离,end是雾化的结束距离,density是雾的密度指数,则在线性模式下,混合因子f为

 


 

在指数模式下有两种情况,当pname取值为GL_FOG_MODE,param取值为GL_EXP时,混合因子f为


 

当pname取值为GL_FOG_MODE,param取值为GL_EXP2时,混合因子f为


 

不论采取哪种雾化模式,f 最后都会被映射到[0, 1]之间。计算出f 之后,在RGBA颜色模式下,原来某像素的颜色是 ,雾的颜色为 , 则雾化后该像素的颜色就变成


在颜色索引表模式下,原来某像素的颜色索引为 ,雾的颜色索引为 ,则雾化后

该像素的颜色索引就变成


 

下面我们来在场景中增加雾的效果。

 

//global variant

GLuint fogMode[]={GL_LINEAR, GL_EXP, GL_EXP2}; 

GLuint fog=0;       //缺省模式为线性模式

BOOL bFog = TRUE;   //缺省为启动雾化效果

 

int glInit()

{

   

    // 启用纹理映射

    glEnable(GL_TEXTURE_2D);

   

    //启用阴影平滑(Smooth Shading)。

    glShadeModel(GL_SMOOTH);

   

    //使用深灰色背景

    glClearColor(0.5f,0.5f,0.5f,0.0f);

   

    //设置深度缓冲

    glClearDepth(1.0f);

   

//启动深度测试

    glEnable(GL_DEPTH_TEST);

   

//深度测试的类型

    glDepthFunc(GL_LEQUAL);

   

//进行透视修正

    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

   

    //以baby.bmp文件创建一个纹理

    g_Texture[0] = CreateTexture("baby.bmp");

    if(!g_Texture[0])   //创建失败则返回

    {

        MessageBox(g_hWnd, "创建纹理失败!", "提示", MB_OK);

        return FALSE;

    }

 

    //启动雾化效果

    glEnable(GL_FOG);

 

    //雾的颜色

    float fogColor[4] = {0.5f,0.5f,0.5f,1.0f};         

 

    //雾化效果使用线性模式

    glFogi(GL_FOG_MODE, GL_LINEAR);                

 

    //RGBA模式,设置雾的颜色

    glFogfv(GL_FOG_COLOR, fogColor);               

   

    //雾的浓度,用于指数模式中

    glFogf(GL_FOG_DENSITY, 0.1f);      

 

    // 雾的计算精度,使用GL_DONT_CARE或GL_FASTEST可以针对每个像素

// 的雾的计算进行调整,提高计算速度。

    glHint(GL_FOG_HINT, GL_DONT_CARE);                 

 

    // 雾化开始距离

    glFogf(GL_FOG_START, 0);                           

 

    // 雾化结束距离

    glFogf(GL_FOG_END, 20.0f);                     

 

    return TRUE;

}

 

void glMain()

{

    static int angle =0;

   

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();   //加载单位矩阵

    glTranslatef(0.0f, 0.0f, -25.0f);

    glRotated(angle, 1, 1, 0);

 

    //设置雾化模式

    glFogi(GL_FOG_MODE, fogMode[fog]);

   

    //根据bFog的值确定是否启动雾化效果

    if(!bFog)

        glDisable(GL_FOG);

    else

        glEnable(GL_FOG);

   

    glBindTexture(GL_TEXTURE_2D, g_Texture[0]); // 选择纹理

 

    //10个带纹理贴图的立方体   

    for(int i=0; i<10; i++)

    {

        glPushMatrix() ;

        glRotatef(36*i,0.0,1.0,0.0) ;

        glTranslatef(10.0,0.0,0.0) ;

        DrawCube();

        glPopMatrix();

    }

 

    angle++;

    SwapBuffers(g_hDC);//交换前后缓冲区

 

对于雾化模式的控制和启动通过按键来实现,这一部分代码放在WindProc中。

 

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

   

    switch (message)

    {

    case WM_ACTIVATE:

        {

            if (!HIWORD(wParam))

            {

                g_bActive=TRUE;

            }

            else

            {

                g_bActive=FALSE;

            }

            return 0;

        }  // 监视窗口激活消息

       

       

    case WM_SIZE:

        {

            glSceneResize(LOWORD(lParam),HIWORD(lParam)); 

            return 0;

        }

 

    //通过按键改变雾的工作模式

    case WM_KEYDOWN:

        switch(wParam)

        {

        case VK_ESCAPE:         //如果按下了ESC键就退出

            PostQuitMessage(0);

            return 0;

        case VK_SPACE:          //空格键进行雾化模式的切换

            if(fog==2)

                fog=0;

            else

                fog++;

            break;

        case VK_F1:             //F1键确定是否启动雾化效果

            bFog= !bFog;

            break;

        }

break;

       

    case WM_DESTROY:

        PostQuitMessage(0);

        break;

 

    default:

        return DefWindowProc(hWnd, message, wParam, lParam);

    }

    return 0;

}

 

程序运行后可以看到雾的效果非常明显,距离越远的立方体越模糊,最远的一个已经全然隐没在雾中。F1键可以就是否进行雾化进行切换,空格键则在三种雾化模式间进行变换,ESC键退出。同时也可以看到,在同样的密度下,GL_EXP2比GL_EXP的雾要更加浓厚一些。运行效果如图9-1所示。

 

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/LotusOne/archive/2009/11/14/4808815.aspx

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值