----要 学 习OpenGL 编 程, 希 望 读 者 具 备 基 本 的 图 形 知 识。 本 文 使 用 基 于Visual C + + 消 息 驱 动 编 程, 对 于 没 学 过 VC 的 读 者 也 有 一 定 的 帮 助。 我 们 的 第 一 个 程 序 将 明 建 立 一 个 视 窗 程 序 显 示OpenGL 图 形 的 最 小 需 求。 为 成 这 一 任 务 我 们 将 分 如 下5 步 来 进 行:
----1 设 置 窗 口 像 素 的 格 式;2 建 立RC;3 使 RC 设 为 当 前;4 创 建 视 口 和 矩 阵 模 型;5 画 一 个 立 方 体 和 一 个 茶 壶。
----现 在 你 可 以 打 开 你 的Visual C + +, 建 立 一 个 单 文 档 的 项 目。 首 先 我 们 在 该 项 目 中 加 进 所 有 必 需 的OpenGL 文 件 和 库, 在 菜 单 中 选 择Build Settings, 然 后 点 击LINK 按 钮( 或 者 按 Ctrl +Tab 键 来 移 动 到 那 儿)。 在Object/Library 栏 中 键 入Opengl32.lib glu32.lib glaux.lib, 并 确 定。 打 开 文 件stdafx.h 插 入 如 下 行:
#include < gl\gl.h > #include < gl\glu.h > #include < gl\glaux.h >
----OpenGL 仅 能 在 具 有WS_CLIPCHILDREN 和 WS_CLIPSIBLINGS 类 型 的 窗 口 显 示 图 形, 我 们 需 要 编 辑OnPreCreate 函 数, 指 定 一 下 窗 口 类 型。
BOOL COPView::PreCreateWindow(CREATESTRUCT & cs) {cs.style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS); return CView::PreCreateWindow(cs); }
----下 面 我 们 要 定 义 窗 口 的 像 素 格 式, 这 一 点 对 建 立RC 很 重 要。 首 先 我 们 需 要 建 立 一 个 受 保 护 的 成 员 函 数 BOOL SetWindowPixelFormat(HDC hDC)。 如 下 所 示:
BOOL COPView::SetWindowPixelFormat(HDC hDC) { PIXELFORMATDESCRIPTOR pixelDesc; pixelDesc.nSize = sizeof(PIXELFORMATDESCRIP ? TOR); pixelDesc.nVersion = 1; pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_SUPPORT_GDI |PFD_STEREO_DONTCARE; pixelDesc.iPixelType = PFD_TYPE_RGBA; pixelDesc.cColorBits = 32; pixelDesc.cRedBits = 8; pixelDesc.cRedShift = 16; pixelDesc.cGreenBits = 8; pixelDesc.cGreenShift = 8; pixelDesc.cBlueBits = 8; pixelDesc.cBlueShift = 0; pixelDesc.cAlphaBits = 0; pixelDesc.cAlphaShift = 0; pixelDesc.cAclearcase/" target="_blank" >ccumBits= 64; pixelDesc.cAccumRedBits = 16; pixelDesc.cAccumGreenBits = 16; pixelDesc.cAccumBlueBits = 16; pixelDesc.cAccumAlphaBits= 0; pixelDesc.cDepthBits = 32; pixelDesc.cStencilBits= 8; pixelDesc.cAuxBuffers = 0; pixelDesc.iLayerType= PFD_MAIN_PLANE; pixelDesc.bReserved = 0; pixelDesc.dwLayerMask= 0; pixelDesc.dwVisibleMask= 0; pixelDesc.dwDamageMask= 0; m_GLPixelIndex = ChoosePixelFormat( hDC, &pixelDesc); if (m_GLPixelIndex==0) // Let's choose a default index. { m_GLPixelIndex = 1; if (DescribePixelFormat(hDC, m_GLPixelIndex, sizeof (PIXELFORMATDESCRIPTOR), &pixelDesc)==0) { return FALSE; } } if (SetPixelFormat( hDC, m_GLPixelIndex, &pixelDesc)==FALSE) { return FALSE; } return TRUE; }
----加 入 一 个 成 员 变 量 到 视 类 中:
int m_GLPixelIndex; // protected
----最 后, 在ClassWizard 中 加 入 函 数OnCreate 来 响 应 消 息WM_CREATE, 函 数 如 下:
int COPView::OnCreate (LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; HWND hWnd = GetSafeHwnd(); HDC hDC = ::GetDC(hWnd); if (SetWindowPixelFormat(hDC)==FALSE) return 0; if (CreateViewGLContext(hDC)==FALSE) return 0; return 0; }
----下 面 需 要 作 的 步 骤 就 是 建 立RC, 并 置 为 当 前RC。
----在 视 类 中 加 入 保 护 函 数 CreateViewGLContext(HDC hDC) 和 变 量HGLRC m_hGLContext:
BOOL COPView::CreateViewGLContext(HDC hDC) { m_hGLContext = wglCreateContext(hDC); if (m_hGLContext == NULL) { return FALSE; } if (wglMakeCurrent(hDC, m_hGLContext)==FALSE) { return FALSE; } return TRUE; } 加 入 函 数OnDestroy 来 响 应WM_DESTROY: void COPView::OnDestroy() { if(wglGetCurrentContext()!=NULL) { wglMakeCurrent(NULL, NULL) ; } if (m_hGLContext!=NULL) { wglDeleteContext(m_hGLContext); m_hGLContext = NULL; } CView::OnDestroy(); }
----最 后, 编 辑 一 下COPView 类 构 造 函 数:
COPView::COPView() { m_hGLContext = NULL; m_GLPixelIndex = 0; }
----现 在, 我 们 就 可 以 进 行OpenGL 画 图 了, 虽 然 它 看 起 来 仍 然 像 一 个 典 型 的MFC 程 序。
----现 在 我 们 进 行 下 一 步 建 立 视 点 和 矩 阵 模 型, 用ClassWizard 在 视 类 中 加 入 函 数OnSize 响 应WM_SIZE。 如 下 所 示:
void COPView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); GLsizei width, height; GLdouble aspect; width = cx; height = cy; if (cy==0) aspect = (GLdouble)width; else aspect = (GLdouble)width/(GLdouble)height; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45, aspect, 1, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } 加 入 函 数:void COPView::OnPaint() { CPaintDC dc(this); // device context for painting COPDoc * pDoc = GetDocument(); pDoc ->RenderScene(); }
----在 文 档 类 中 加 入 公 共 函 数RenderScene():
void COPDoc::RenderScene(void) { glClear(GL_COLOR_BUFFER_BIT); glFlush(); }
----现 在 程 序 运 行 后 仅 是 黑 黑 的 屏 幕, 我 们 需 要 加 进 些 东 西。
----在 文 档 类 中 加 一 个 枚 举 变 量 GLDisplayListNames:
enum GLDisplayListNames { ArmPart1,ArmPart2 };
----为 将 来 建 立 显 示 列 表 用。 编 辑 函 数 OnNewDocument(), 编 码 如 下:
BOOL COPDoc::OnNewDocument() if (!CDocument::OnNewDocument()) return FALSE; glNewList(ArmPart1, GL_COMPILE); GLfloat RedSurface[] = { 1.0f, 0.0f, 0.0f, 1.0f}; GLfloat GreenSurface[] = { 0.0f, 1.0f, 0.0f, 1.0f}; GLfloat BlueSurface[] = { 0.0f, 0.0f, 1.0f, 1.0f}; GLfloat LightAmbient[] = { 0.1f, 0.1f, 0.1f, 0.1f }; GLfloat LightDiffuse[] = { 0.7f, 0.7f, 0.7f, 0.7f }; GLfloat LightSpecular[] = { 0.0f, 0.0f, 0.0f, 0.1f }; GLfloat LightPosition[] = { 5.0f, 5.0f, 5.0f, 0.0f }; glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient); glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, LightSpecular); glLightfv(GL_LIGHT0, GL_POSITION, LightPosition); glEnable(GL_LIGHT0); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, RedSurface); glBegin(GL_POLYGON); glNormal3d( 1.0, 0.0, 0.0); glVertex3d( 1.0, 1.0, 1.0); glVertex3d( 1.0, -1.0, 1.0); glVertex3d( 1.0, -1.0, -1.0); glVertex3d ( 1.0, 1.0, -1.0); // 画 第 一 个 面 glEnd(); glBegin(GL_POLYGON); glNormal3d( -1.0, 0.0, 0.0); // 此 处 同 上 画 第 二 个 面。 立 方 体 的 中 心 为 坐 标 原 点。 glEnd(); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, GreenSurface); // 此 处 同 上 画 第 三、 四 个 面, 注 意 平 面 法 向 和 坐 标。 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, BlueSurface); // 此 处 同 上 画 第 五、 六 个 面。 glEndList(); glNewList(ArmPart2, GL_COMPILE); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, GreenSurface); auxSolidTeapot(1.0);// 用 辅 助 库 函 数 画 茶 壶。 glEndList(); return TRUE; }
----下 面 就 看 怎 样 显 示 它 了。 编 辑RenderScene 函 数:
void COPDoc::RenderScene(void) { double m_angle1=60.0; double m_angle2=30.0; glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glPushMatrix(); glTranslated(3.0, 0.0, -8.0); glRotated( m_angle1, 0, 0, 1); glRotated( m_angle2, 0, 1, 0); glCallList(ArmPart1); glPopMatrix(); glPushMatrix(); glTranslated(0.0, 0.0, -8.0); glCallList(ArmPart2); glPopMatrix(); glFlush(); }