Graphics 版 (精华区)

发信人: crystal (花), 信区: Graphics
标  题: opengl
发信站: 紫  丁  香 (Fri Nov 28 14:03:00 1997), 转信

 

开 发 基 于OpenGL 的 三 维 图 形 应 用 
南 京 理 工 大 学 计 算 机 系 研95(210094)孔 小 斌    章 萍 

--------------------------------------------------------------------------------

         OpenGL 三 维 图 形 标 准 是 由AT &T 公 司UNIX 软 件 实 验 室、IBM、DEC、SUN、HP、Microsoft 和SGI 等 多 家 公 司 在GL 图 形 库 标 准 的 基 础 上 联 合 推 出 的 开 放 式 图 形 库, 它 使 在 微 机 上 实 现 三 维 真 实 感 图 形 的 生 成 与 显 示 
成 为 可 能。 由 于OpenGL 是 开 放 的 图 形 标 准, 用 户 原 先 在UNIX 下 开 发 的OpenGL 图 形 软 件 很 容 易 移 植 到 微 机 上 的Windows NT /95 上。 笔 者 在Visual C + +4.1( 以 下 简 称VC) 集 成 环 境 下, 开 发 了 基 于OpenGL 的 三 维 真 实 感 图 
形 应 用 程 序, 现 介 绍 如 下。 

微 机 上 的OpenGL 开 发 环 境
         基 于OpenGL 标 准 开 发 的 应 用 程 序 必 须 运 行 于32 位Windows 平 台 下, 如Windows NT 或Windows95 环 境; 而 且 运 行 时 还 需 有 动 态 链 接 库OpenGL32.DLL、Glu32.DLL, 这 两 个 文 件 在 安 装Windows NT 时 已 自 动 装 载 
到C:\WINNT\SYSTEM32 目 录 下( 这 里 假 定 用 户 将Windows NT 安 装 在C 盘 上); 而 对 于 使 用Windows 95 平 台 的 用 户, 则 需 手 工 将 两 个 动 态 库 复 制 到Windows 95 目 录 的SYSTEM 子 目 录 中。 安 装 了Windows NT /95 和VC4.1 后, 用 户 就 具 
备 了 基 于OpenGL 开 发 三 维 图 形 软 件 的 基 本 条 件。 
OpenGL 程 序 设 计 的 基 本 步 骤
         1.OpenGL 在Windows NT 下 的 运 行 机 制 
         OpenGL 工 作 在 客 户 机 / 服 务 器 模 式 下, 当 客 户 方( 即 基 于OpenGL 标 准 开 发 的 应 用 程 序) 向 服 务 器(OpenGL 核 心 机 制) 发 出 命 令 时, 由 服 务 器 负 责 解 释 这 些 命 令。 通 常 情 况 下, 客 户 方 和 服 务 器 是 运 行 在 
同 一 台 微 机 上 的。 由 于OpenGL 的 运 行 机 制 是 客 户 机 / 服 务 器 模 式, 这 使 得 用 户 能 够 十 分 方 便 地 在 网 络 环 境 下 使 用OpenGL,OpenGL 在Windows NT 上 的 这 种 实 现 方 式 通 常 称 为 网 络 透 明 性。 

         OpenGL 的 图 形 库 函 数 封 装 在 动 态 链 接 库OpenGL32.DLL 中, 客 户 机 中 的 所 有OpenGL 函 数 调 用, 都 被 传 送 到 服 务 器 上, 由WinSrv.DLL 实 现 功 能, 再 将 经 过 处 理 的 指 令 发 送 到Win32 设 备 驱 动 接 口(DDI), 从 而 实 现 
在 计 算 机 屏 幕 上 产 生 图 像。 

         若 使 用OpenGL 图 形 加 速 卡, 则 上 述 机 制 中 将 添 加 两 个 驱 动 器:OpenGL 可 装 载 客 户 模 块(OpenGL ICD) 将 安 装 在 客 户 端; 硬 件 指 定DDI 将 安 装 在 服 务 器 端, 与Win DDI 同 一 级 别。 

         2.OpenGL 的 库 函 数 

         开 发 基 于OpenGL 的 应 用 程 序, 必 须 先 了 解OpenGL 的 库 函 数。OpenGL 函 数 命 令 方 式 十 分 有 规 律, 每 个 库 函 数 均 有 前 缀gl、glu、aux, 分 别 表 示 该 函 数 属 于OpenGL 基 本 库、 实 用 库 或 辅 助 库。Windows NT 下 的OpenGL 
包 含 了100 多 个 核 心 函 数, 均 以gl 作 为 前 缀, 同 时 还 支 持 另 外 四 类 函 数: 

OpenGL 实 用 库 函 数:43 个, 以glu 作 为 前 缀; 

OpenGL 辅 助 库 函 数:31 个, 以aux 作 为 前 缀; 

Windows 专 用 库 函 数(WGL):6 个, 以wgl 作 为 前 缀; 

Win32 API 函 数(WGL):5 个, 无 前 缀。
         OpenGL 的115 个 核 心 函 数 提 供 了 最 基 本 的 功 能, 可 以 实 现 三 维 建 模、 建 立 光 照 模 型、 反 走 样、 纹 理 映 射 等;OpenGL 实 用 库 函 数 在 核 心 函 数 的 上 一 层, 这 类 函 数 提 供 了 简 单 的 调 用 方 法, 其 实 质 是 调 用 
核 心 函 数, 目 的 是 减 轻 开 发 者 的 编 程 工 作 量;OpenGL 辅 助 库 函 数 是 一 些 特 殊 的 函 数, 可 以 供 初 学 者 熟 悉OpenGL 的 编 程 机 制, 然 而 使 用 辅 助 库 函 数 的 应 用 程 序 只 能 在Win32 环 境 中 使 用, 可 移 植 性 较 差, 所 以 
开 发 者 应 尽 量 避 免 使 用 辅 助 库 函 数;Windows 专 用 库 函 数(WGL) 主 要 针 对Windows NT /95 环 境 的OpenGL 函 数 调 用;Win32 API 函 数 用 于 处 理 像 素 存 储 格 式、 双 缓 存 等 函 数 调 用。 
         3.VC 环 境 下 基 于OpenGL 的 编 程 步 骤 

         下 面 介 绍 在VC 环 境 中 建 立 基 于OpenGL 标 准 的 应 用 程 序 框 架 的 具 体 方 法 与 步 骤: 

         (1) 创 建 项 目 文 件: 选 择File /New 菜 单 选 项, 建 立 一 个 名 为MyTest 项 目 文 件,MyTest 基 于 单 文 档(SDI),View 类 基 于Cview。 

         (2) 选 择Build /Setting 菜 单 选 项, 在Link 栏 的Lib 输 入 域 中 添 加openg132.lib、glu32.lib, 若 需 使 用OpenGL 的 辅 助 库 函 数, 则 还 需 添 加glaux.lib。 

         (3) 选 择View /ClassWizard 菜 单 选 项, 打 开MFC 对 话 框, 在ClassName 栏 中 选 择CMyTestView 类, 进 行 以 下 操 作: 

选 择WM_CREATE 消 息, 鼠 标 单 击EditCode, 将OpenGL 初 始 化 代 码 添 加 到OnCreate() 函 数 中:
         / * 定 义 像 素 存 储 格 式 * / 
PIXELFORMATDESCRIPTOR pfd=
                       {
                         sizeof(PIXELFORMATDESCRIPTOR),
                         1,
                         PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL,
                         PFD_TYPE_RGBA,
                         24,
                         0,0,0,0,0,0,
                         0,0,0,0,0,0,0
                         32,
                         0,0,
                         PFD_MAIN_PLANE,
                         0,
                         0,0,0,
                       }
CCLient dc(this);
int pixelFormat=ChoosePixelFormat(dc.m_hDC,&pfd);
BOOL success=SetPixelFormat(dc.m_hDC,pixelFormat,&pfd);
m_hRC=wglCreateContext(dc.m_hDC);
选择WM_DESTORY消息,在OnDestory()中添加以下代码:
  wglDeleteContext(m_hRC);
在MyTestView.cpp中,将以下代码添加到PreCreateWindows()函数中:
  cs.style|=WS_CLIPCHILDREN|WS_CLIPSIBLINGS;
  OpenGL只对WS_CLIPCHILDREN|WS_CLIPSIBLINGS类型窗口有效;
在MyTestView.cpp中,将以下代码添加到OnDraw()函数中:
  wglMakeCurrent(pDC->m_hDC,m_hRC);
  DrawScene(); //用户自定义函数,用于绘制三维场景;
  wglMakeCurrent(pDC->m_hDC,NULL);
在MyTestView.cpp中,添加成员函数DrawScene():
  void CMyTestView::DrawScene()
  {/*绘制三维场景*/}
(4)在MyTestView.h中包含以下头文件并添加类成员说明:
     #include 
     #include 
     #include 
在CTestView类中的protected:段中添加成员变量声明:
      HGLRC m_hRC;
同时添加成员函数声明:
      DrawScene();
         这 样, 一 个 基 于OpenGL 标 准 的 程 序 框 架 已 经 构 造 好, 用 户 只 需 在DrawScene() 函 数 中 添 加 程 序 代 码 即 可。 
建 立 三 维 实 体 模 型
         三 维 实 体 建 模 是 整 个 图 形 学 的 基 础, 要 生 成 高 逼 真 度 的 图 像, 首 先 要 生 成 高 质 量 的 三 维 实 体 模 型。 
         OpenGL 中 提 供 了 十 几 个 生 成 三 维 实 体 模 型 的 辅 助 库 函 数, 这 些 函 数 均 以aux 作 为 函 数 名 的 前 缀。 简 单 的 模 型, 如 球 体、 立 方 体、 圆 柱 等 可 以 使 用 这 些 辅 助 函 数 来 实 现, 如auxWireSphere(GLdouble radius)( 
绘 制 一 半 径 为radius 的 网 状 球 体)。 但 是 这 些 函 数 难 以 满 足 建 立 复 杂 三 维 实 体 的 需 要, 所 以 用 户 可 以 通 过 其 它 建 模 工 具( 如3DS 等) 来 辅 助 建 立 三 维 实 体 模 型 数 据 库。 笔 者 在 三 维 实 体 的 建 模 过 程 中 采 用3DS 
提 供 的2D Shape、3D Lofter 和3D Editor 进 行 模 型 的 编 辑, 最 后 通 过 将 模 型 数 据 以DXF 文 件 格 式 输 出 存 储 供 应 用 程 序 使 用。 

真 实 感 图 形 的 绘 制
         1. 定 义 光 照 模 型 和 材 质 
         (1) 光 源。OpenGL 提 供 了 一 系 列 建 立 光 照 模 型 的 库 函 数, 使 用 户 可 以 十 分 方 便 地 在 三 维 场 景 中 建 立 所 需 的 光 照 模 型。OpenGL 中 的 光 照 模 型 由 环 境 光(Ambient Light)、 漫 射 光(Diffuse Light)、 镜 面 反 射 
光(Specular Light) 等 组 成, 同 时 还 可 设 置 光 线 衰 减 因 子 来 模 拟 真 实 的 光 源 效 果。 

         例 如, 定 义 一 个 黄 色 光 源 如 下: 

    Glfloat Light_position[]={1.0,1.0,1.0,0.0,};
    Glfloat Light_diffuse[]={1.0,1.0,0.0,1.0,};
    glLightfv(GL_LIGHT0,GL_POSTTION,light_position);//定义光源位置
    glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);//定义光源漫射光
光源必须经过启动后才会影响三维场景中的实体,可以通过以下指令使光源有效:<
    glEnable(LIGHTING);   //启动光照模型;
    glEnable(GL_LIGHT0); //使光源GL_LIGHT0有效;
OpenGL中一共可以定义GL_LIGHT0~GL_LIGHT7八个光源。
         (2) 材 质。OpenGL 中 的 材 质 是 指 构 成 三 维 实 体 的 材 料 在 光 照 模 型 中 对 于 红、 绿、 蓝 三 原 色 的 反 射 率。 与 光 源 的 定 义 类 似, 材 质 的 定 义 分 为 环 境、 漫 射、 镜 面 反 射 成 分, 另 外 还 有 镜 面 高 光 指 数、 辐 
射 成 分 等。 通 过 对 三 维 实 体 的 材 质 定 义 可 以 大 大 提 高 应 用 程 序 所 绘 制 的 三 维 场 景 的 逼 真 程 度。 例 如: 
         / * 设 置 材 质 的 反 射 成 分 * / 

   GLfloat mat_ambient[]={0.8,0.8,0.8,1.0};
   GLfloat mat_diffuse[]={0.8,0.0,0.8,1.0}; /*紫色*/
   GLfloat mat_specular[]={1.0,0.0,1.0,1.0};/*镜面高光亮紫色*/
   GLfloat mat_shiness[]={100.0};/*高光指数*/
   glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);/*定义环境光反射率*/
   glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);/*定义漫射光反射率*/
   glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);/*定义镜面光反射率*/
   glMaterialfv(GL_FRONT,GL_SHINESS,mat_shiness);/*定义高光指数*/
         (3) 材 质RGB 值 与 光 源RGB 值 的 关 系。OpenGL 中 材 质 的 颜 色 与 光 照 模 型 中 光 源 的 颜 色 含 义 略 有 不 同。 对 于 光 源,R、G、B 值 表 示 三 原 色 在 光 源 中 所 占 有 的 比 率; 而 对 于 材 质 定 义,R、G、B 的 值 表 示 具 有 这 
种 材 质 属 性 的 物 体 对 于 三 原 色 的 反 射 比 率, 场 景 中 物 体 所 呈 现 的 颜 色 与 光 照 模 型、 材 质 定 义 都 相 关。 例 如, 若 定 义 的 光 源 颜 色 是(Lr,Lg,Lb)=(1.0,1.0,1.0)( 白 光), 物 体 的 材 质 颜 色 定 义 
为(Mr,Mg,Mb)=(0.0,0.0,0.8), 则 最 终 到 达 人 眼 的 物 体 颜 色 应 当 是(Lr *Mr,Lg *Mg,Lb *Mb)=(0.0,0.0,0.8)( 蓝 色)。 
         2. 读 取 三 维 模 型 数 据 

         为 了 绘 制 三 维 实 体, 我 们 首 先 必 须 将 预 先 生 成 的 三 维 实 体 模 型 从 三 维 实 体 模 型 库 中 读 出。 下 图 描 述 了 读 取 三 维 实 体 模 型 的 流 程。 

         3. 三 维 实 体 绘 制 

         由 于3DS 的DXF 文 件 中 对 于 三 维 实 体 的 描 述 是 采 用 三 角 形 面 片 逼 近 的 方 法, 而 在OpenGL 函 数 库 中, 提 供 了 绘 制 三 角 形 面 片 的 方 法, 所 以 为 三 维 实 体 的 绘 制 提 供 了 方 便。 以 下 提 供 了 绘 制 三 角 形 面 片 
的 方 法: 

    glBegin(TRANGLES);          //定义三角形绘制开始
      glVertexf((GLfloat)x1,(GLfloat)y1,  (GLfloat)z1) ;//第一个顶点
      glVertexf((GLfloat)x2,(GLfloat)y2,  (GLfloat)z2) ;//第二个顶点
      glVertexf((GLfloat)x3,(GLfloat)y3,  (GLfloat)z3) ;//第三个顶点
   glEnd();                   //绘制结束
         为 了 提 高 三 维 实 时 动 画 的 显 示 速 度, 我 们 利 用 了OpenGL 库 中 的 显 示 列 表(DisplayList) 的 功 能, 将 三 维 场 景 中 的 实 体 分 别 定 义 为 单 独 的 显 示 列 表, 预 先 生 成 三 维 实 体。 在 图 形 显 示 时, 只 需 调 用 所 需 
的 显 示 列 表 即 可 显 示 相 应 的 三 维 实 体, 而 不 需 要 重 新 计 算 实 体 在 场 景 中 的 坐 标, 避 免 了 大 量 的 浮 点 运 算。 在 调 用 显 示 列 表 前 所 作 的 旋 转、 平 移、 光 照、 材 质 的 设 定 都 将 影 响 显 示 列 表 中 的 三 维 实 体 的 
显 示 效 果。 具 体 实 现 算 法 如 下: 
for(ObjectNo=0;ObjectNo<实体个数;ObjectNo++)
{
   glNewList(ObjectNo,GL_COMPILE); //创建第ObjectNo个实体的显示列表
   for(FaceNo=0;FaceNo<第ObjectNo个实体的三角形面片数;FaceNo++)
   {
    glBegin(GL_TRIANGLES);  //开始画第FaceNo个三角形
   /*定义第FaceNo个三角形的第一个顶点的法向量*/
  glNormal3fv((Glfloat*)VertexNormal[ObjectNo][(Face[ObjectNo][FaceNo][0])]);
  /*定义第FaceNo个三角形的第一个顶点的坐标*/
   glVertex3fv((Glfloat*)Vertex[ObjectNo][(Face[ObjectNo][FaceNo][0])]);
   定义第FaceNo个三角形的第二个顶点的法向量;
   定义第FaceNo个三角形的第二个顶点的坐标;
   定义第FaceNo个三角形的第三个顶点的法向量;
   定义第FaceNo个三角形的第三个顶点的坐标;
  glEnd();
  }
  glEndList();
}
………
/ * 显 示 三 维 实 体 * / 
         { 几 何 变 换、 投 影 变 换、 裁 剪、 视 区 变 换、 建 立 光 照 模 型、 定 义 实 体 材 质 等 操 作} 
         CallList(ObjectNo); / / 显 示 第ObjectNo 个 三 维 实 体 

         在 这 里, 要 提 到 的 是 在 绘 制 三 角 形 面 片 时, 每 个 三 角 形 顶 点 的 定 义 前 均 有 该 定 点 法 向 量 的 定 义, 这 是 为 了 使 得 绘 制 出 的 三 角 形 面 片 之 间 更 加 光 滑、 真 实。 

         程 序 运 行 结 束, 须 将 已 建 立 的 显 示 列 表 删 除, 释 放 所 占 用 的 内 存 空 间, 可 以 通 过 以 下 函 数 调 用 实 现 删 除 显 示 列 表: 

         / * 删 除 显 示 列 表 * / 

DeleteList(ObjectNo);     //删除第ObjectNo个实体的显示列表

   


--------------------------------------------------------------------------------
中国计算机世界出版服务公司版权所有  
-- 

※ 来源:.紫  丁  香 pclinux.hit.edu.cn.[FROM: robsn01.hit.edu]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:205.889毫秒