新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     >>计算机科学论坛<<     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 计算机科学论坛计算机技术与应用『 C/C++编程思想 』 → 如何实现三维中的雾化和纹理效果? 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 3636 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: 如何实现三维中的雾化和纹理效果? 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     葛靖青001 美女呀,离线,快来找我吧!水瓶座1984-2-14
      
      
      等级:大三(研究MFC有点眉目了!)
      文章:168
      积分:595
      门派:XML.ORG.CN
      注册:2010/11/2

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给葛靖青001发送一个短消息 把葛靖青001加入好友 查看葛靖青001的个人资料 搜索葛靖青001在『 C/C++编程思想 』的所有贴子 点击这里发送电邮给葛靖青001 引用回复这个贴子 回复这个贴子 查看葛靖青001的博客楼主
    发贴心情 如何实现三维中的雾化和纹理效果?

    【转自互联网】

    雾化效果

      在真实世界中观察地面目标并不是在真空中进行的,而是有大气的存在,无论空气是干燥还是湿润,总会有或多或少的水蒸汽存在,而且还有少量的尘埃存在。它们的存在使得我们在观察远景目标时将不可避免地产生白茫茫的模糊效果,这种效果在OpenGL中也被称为"雾化"。虽然在现实世界中雾化现象妨碍了我们对远景目标的观察效果,但在仿真处理上如果缺少此效果反而会令人感觉不是那么真实。因此,这里就对雾化效果的实现做一个简单的介绍:

    if (m_bFogMode == FALSE){
     // 雾化效果启用切换
     m_bFogMode = TRUE; // 启用雾化处理
     glEnable(GL_FOG);
     glFogi(GL_FOG_MODE, GL_LINEAR); // 采用线性变化的雾化效果
     GLfloat fogColor[] = {0.8f, 0.8f, 0.8f, 1.0}; // 指定雾化颜色
     glFogfv(GL_FOG_COLOR, fogColor);
     glFogf(GL_FOG_START, 1.0); // 指定按线性变化时计算公式的参量
     glFogf(GL_FOG_END, 10000.0);
     glHint(GL_FOG_HINT, GL_DONT_CARE); //规定雾化效果的质量
    }else{
     m_bFogMode = FALSE; // 禁用雾化处理
     glDisable(GL_FOG);
    }

      这段代码允许使能或禁用雾化效果。如果需要启用雾化效果,首先需要通过glEnable()函数使能雾化效果(调用GL_FOG参数),并需通过glFogi()和glFogfv()指定采用何种方式的雾化效果和雾化颜色。这里采用的是线性变化方式,因此还要通过glFogf()指定按线性变化时计算公式的参量。最后调用的glHint()函数将对雾化效果的质量作出规定。如果需要禁用雾化效果,只需简单的调用glDisable()将GL_FOG选项禁用即可。下图分别为未使用雾化效果和使用了雾化效果的场景。可以看出,启用了雾化效果后的场景更加逼真:


     使用纹理

      由于任何真实场景都是有着复杂纹理的,因此为了达到具有真实感效果的仿真程度还必须对纹理的使用进行处理。这里使用的纹理必须是长、宽相等且均为2的整数次幂的位图。通常多采用当地区域的航拍照片或当地地图等作为纹理进行贴图。下面首先介绍一下纹理贴图的一般技术实现过程。

      在使用纹理时,首先需要指定待使用的纹理图象,并通过auxDIBImageLoad()函数将其载入到内存并保留其指针。将该指针作为参数去调用glGenTextures()创建一个纹理。接下来,通过对glBindTexture()的调用使用来自位图数据生成的典型纹理,并进一步通过glTexImage2D()生成纹理,同时还必须指定当缩小的比原始纹理小时或放大的比原始纹理大时所要采取的滤波方式。最后释放纹理图象所占用的资源。为了应用纹理,还必须做一些其他的辅助性工作,如启用阴影平滑、启用纹理映射、指定前后表面的建模方式等等。下面给出这部分工作的主要实现代码:

    glShadeModel(GL_SMOOTH); // 启用阴影平滑
    glEnable(GL_TEXTURE_2D); // 启用纹理映射
    glPolygonMode(GL_BACK, GL_FILL); // 后表面以面建模完全填充
    glPolygonMode(GL_FRONT, GL_FILL); // 前表面以点建模
    AUX_RGBImageRec *TextureImage[1]; // 创建纹理的存储空间
    memset(TextureImage, 0, sizeof(void*) * 1); // 清除图像记录,确保其内容为空
    TextureImage[0] = auxDIBImageLoad(sPath); // 载入纹理位图并返回指针
    glGenTextures(1, &m_nTexture[0]); // 创建纹理
    glBindTexture(GL_TEXTURE_2D, m_nTexture[0]); //使用来自位图数据生成的典型纹理
     // 生成纹理
     glTexImage2D(GL_TEXTURE_2D, // 2D纹理
     0, // 图像的详细程度
     3, // R,G,B三种数据成分
     TextureImage[0]->sizeX, // 纹理的宽度
     TextureImage[0]->sizeY, // 纹理的高度
     0, // 边框宽度
     GL_RGB, // 图像数据由红、绿、蓝三色数据组成
     GL_UNSIGNED_BYTE, // 组成图像的数据是无符号字节类型的
     TextureImage[0]->data); // 纹理数据的来源
    // 缩小得比原始纹理小时采用线形滤波
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    // 比放大得原始纹理大时采用线形滤波
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    if (TextureImage[0]) { // 检查纹理是否存在
     if (TextureImage[0]->data) {// 检查纹理图像是否存在
      free(TextureImage[0]->data); // 释放纹理图像占用的内存
     }
     free(TextureImage[0]); // 释放图像结构
    }

      纹理如果创建成功,应当在重绘场景的同时完成纹理到网格单元的贴图,而且这部分工作应当在执行显示列表之前完成。这部分处理的重点在于从纹理到网格单元的贴图,如果处理不好,将会出现纹理贴反、贴倒甚至有漏贴情况出现。为了确保贴图的正确,一般可以比照初始化该模型显示列表的那部分代码,并采取与之相同的网格定义和顶点定义顺序。例如,下面这段代码使用的就是与InitTerrainList()中相同的三角带网格,并且按照左下、左上、右下、右上的次序进行贴图:

    glBindTexture(GL_TEXTURE_2D, m_nTexture[0]); // 选择纹理
    float float_x; // 用来将纹理分割成很小的三角网格
    float float_y;
    float float_xb;
    float float_yb;
    // 每一个小网格分别映射纹理的对应三角形区域(顺序同地景网格创建顺序)
    for (int i = 0; i < m_nDemX - 1; i++) {
     for (int j = 0; j < m_nDemY - 1; j++) {
      glBegin(GL_TRIANGLE_STRIP); // 开始三角带
      float_x = float(i) / float(m_nDemX);
      float_y = float(j) / float(m_nDemY);
      float_xb = float(i + 1) / float(m_nDemX);
      float_yb = float(j + 1) / float(m_nDemY);
      glTexCoord2f(float_x, float_y); // 第一个纹理坐标 (左下角)
      glVertex3d(m_pDemX[j * m_nDemX + i], m_pDemY[j * m_nDemX + i], m_pDemH[j * m_nDemX + i]);
      glTexCoord2f(float_x, float_yb); // 第二个纹理坐标 (左上角)
      glVertex3d(m_pDemX[(j + 1) * m_nDemX + i], m_pDemY[(j + 1) * m_nDemX + i], m_pDemH[(j + 1) * m_nDemX + i]);
      glTexCoord2f(float_xb, float_y); // 第三个纹理坐标 (右下角)
      glVertex3d(m_pDemX[j * m_nDemX + i + 1], m_pDemY[j * m_nDemX + i + 1], m_pDemH[j * m_nDemX + i + 1]);
      glTexCoord2f(float_xb, float_yb); // 第四个纹理坐标 (右上角)
      glVertex3d(m_pDemX[(j + 1) * m_nDemX + i + 1], m_pDemY[(j + 1) * m_nDemX + i + 1], m_pDemH[(j + 1) *  m_nDemX + i + 1]);
      glEnd(); // 停止定义三角带
     }
    }
    }

      其中,glTexCoord2f()定义的是在纹理中的坐标,glVertex3d()定义的是在网格模型中的坐标,通过这两组坐标的定义将纹理和与之对应的网格绑定起来。使用了纹理的地景模型不仅更加逼真,而且可以通过使用不同类型的纹理而获取到不同的信息。下图给出的是经过纹理贴图后的地景模型。其中左图采用的纹理是由法国SPOT遥感卫星PAN全色波段采集的该地区平面遥感影象,通过纹理贴图,可以三维仿真的形式观看该地区的卫星遥感效果。右图将该地区的地图作为纹理使用,贴图后的地景模型可以作为三维电子沙盘使用。

      小结

      本文在前面几篇文章的基础之上进一步实现了雾化、纹理贴图等OpenGL高级技术。通过给出的仿真结果可以看出这些高级技术的应用极大改善了地景模型三维仿真的真实感,有效增加了对地景信息的综合利用价值。通过对本系列文章的介绍,读者应当能够对此类三维地景仿真软件的实现、设计过程有一个基本的认识,并可在此基础之上根据具体需求编写出适合自己的GIS应用程序。本文所述程序在Windows 2000 Professional + SP4下由Microsoft Visual C++ 6.0编译通过。


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    ---人之所以能,是相信能!!

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2010/11/16 12:00:00
     
     GoogleAdSense水瓶座1984-2-14
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 点击这里发送电邮给Google AdSense 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/5/6 22:51:30

    本主题贴数1,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    46.875ms