MFC框架下的OPENGL
转载 柴树杉 2007-04-13 于 Visiontek 的教程,顺便自己修改了一下,以免以后再用到
1. 导入opengl32.lib glu32.lib glaux.lib
2. 导入#include <GL/glaux.h>
3. 创建OpenGL描述表(OnCreate)
4. 设置渲染环境(OnInitialUpdate)
5. 设置各个矩阵(OnSize)
6. 绘制场景(OnDraw)
{
private:
HGLRC m_hRC;
CClientDC* m_pDC;
int CTestGLView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// 创建DC
m_pDC = new CClientDC(this);
ASSERT(m_pDC != NULL);
// 选择像素格式
if(!bSetDCPixelFormat()) return -1;
// 创建渲染环境, 并使它成为当前渲染环境
m_hRC = wglCreateContext(m_pDC->GetSafeHdc());
wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC);
return 0;
BOOL CTestGLView::bSetDCPixelFormat()
{
// 设置像素格式
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // 结构的大小
1, // 结构的版本
PFD_DRAW_TO_WINDOW | // 在窗口(而不是位图)中绘图
PFD_SUPPORT_OPENGL | // 支持在窗口中进行OpenGL调用
PFD_DOUBLEBUFFER, // 双缓冲模式
PFD_TYPE_RGBA, // RGBA颜色模式
32, // 需要32位颜色
0, 0, 0, 0, 0, 0, // 不用于选择模式
0, 0, // 不用于选择模式
0, 0, 0, 0, 0, // 不用于选择模式
16, // 深度缓冲区的大小
0, // 在此不使用
0, // 在此不使用
0, // 在此不使用
0, // 在此不使用
0, 0, 0 // 在此不使用
};
// 选择一种与pfd所描述的最匹配的像素格式
int nPixelFormat = ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd);
if(0 == nPixelFormat) return false;
// 为设备环境设置像素格式
return SetPixelFormat(m_pDC->GetSafeHdc(), nPixelFormat, &pfd);
}
void CTestGLView::OnDestroy()
{
CView::OnDestroy();
// 释放资源
wglMakeCurrent(NULL, NULL);
wglDeleteContext(m_hRC);
delete m_pDC;
}
为OpenGL分配资源和释放资源一般是成对的操作,就像C语言中{}括弧一样,因此我们放在一起。
{
CView::OnInitialUpdate();
// 设置背景色
glClearColor(0.0, 0.0, 0.0, 1.0);
}
因为OnInitialUpdate在窗口被创建的之后会被调用一次,因此最适合用于设置OpenGL的渲染环境。
{
CView::OnSize(nType, cx, cy);
// 设置视口
glViewport(0, 0, cx, cy);
// 设置投影矩阵(透视投影)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)cx/(GLfloat)cy, 1.0, 1000.0);
// 设置模型视图矩阵
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}
在OnSize中设置视口、投影矩阵和模型视图矩阵。
{
CTestGLDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// 清除颜色
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 绘制场景
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
{
// 绘制坐标系
drawUnitAxes();
}
glPopMatrix();
// 交换缓冲区
SwapBuffers(wglGetCurrentDC());
// 绘制坐标轴
void CTestGLView::drawUnitAxes()
{
const GLfloat max = (GLfloat)1.0f;//INT_MAX;
// 实线部分
glBegin(GL_LINES);
// x
glColor3f(1.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(max, 0.0, 0.0);
// y
glColor3f(0.0, 1.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, max, 0.0);
// z
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, max);
glEnd();
// 虚线部分
glEnable(GL_LINE_STIPPLE);
glLineStipple(3, 0xAAAA);
glBegin(GL_LINES);
// x
glColor3f(1.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(-max, 0.0, 0.0);
// y
glColor3f(0.0, 1.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, -max, 0.0);
// z
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, -max);
glEnd();
glDisable(GL_LINE_STIPPLE);
在很多讲解关于opengl的书中提到的细节可能不止这么多。例如,设置窗口类的时候要添加CS_OWNDC属性;创建窗口的时候风格要添加WS_CLIPSIBLINGS和WS_CLIPCHILDREN分格(窗口类和窗口不是一个概念);屏蔽WM_ERASEBKGND消息等。但是这些在Windows2000(应该也包含其后)的系统中都不是必须的!起码在我自己的电脑中是这样。所以作为一个初次接触OpenGL的用户来说,完全没有必要被这里无关的东西迷失方向。
1. 导入opengl32.lib glu32.lib glaux.lib
2. 导入#include <GL/glaux.h>
3. 创建OpenGL描述表(OnCreate)
4. 设置渲染环境(OnInitialUpdate)
5. 设置各个矩阵(OnSize)
6. 绘制场景(OnDraw)
7. 释放OpenGL资源(OnDestroy)
一、创建一个名为“TestGL”的AppWizard工程文件
单文档,不使用Unicode,其他默认
二、导入OpenGL头文件
在stdafx.h文件
#include <afxcontrolbars.h> 语句下面
加入 #include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>
#include <gl\glut.h>
三、导入OpenGL库
解决方案属性--连接器-输入-添加附加依赖项:opengl32.lib glaux.lib glu32.lib glut32.lib
这里要注意的是在Debug/Release设置中需要单独设置。如果只是在debug中设置了,那么在编译Release版本的时候会提示错误。
四、在CTestGLView中添加m_hRC、m_pDC成员变量
class CTestGLView: public Cview
{
private:
HGLRC m_hRC;
CClientDC* m_pDC;
};
其中m_pDC记录当前的view对应的DC,m_hRC对应OpenGL的渲染环境。
五、创建窗口的时候设置OpenGL的像素格式
这里通过 (类视图)右击 view类-- 类向导-添加wm_create消息
// 创建OpenGL上下文int CTestGLView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// 创建DC
m_pDC = new CClientDC(this);
ASSERT(m_pDC != NULL);
// 选择像素格式
if(!bSetDCPixelFormat()) return -1;
// 创建渲染环境, 并使它成为当前渲染环境
m_hRC = wglCreateContext(m_pDC->GetSafeHdc());
wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC);
return 0;
}
这里通过添加 (类视图)右击 view类---添加函数
// 为一个特定的设备环境选择像素格式BOOL CTestGLView::bSetDCPixelFormat()
{
// 设置像素格式
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // 结构的大小
1, // 结构的版本
PFD_DRAW_TO_WINDOW | // 在窗口(而不是位图)中绘图
PFD_SUPPORT_OPENGL | // 支持在窗口中进行OpenGL调用
PFD_DOUBLEBUFFER, // 双缓冲模式
PFD_TYPE_RGBA, // RGBA颜色模式
32, // 需要32位颜色
0, 0, 0, 0, 0, 0, // 不用于选择模式
0, 0, // 不用于选择模式
0, 0, 0, 0, 0, // 不用于选择模式
16, // 深度缓冲区的大小
0, // 在此不使用
0, // 在此不使用
0, // 在此不使用
0, // 在此不使用
0, 0, 0 // 在此不使用
};
// 选择一种与pfd所描述的最匹配的像素格式
int nPixelFormat = ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd);
if(0 == nPixelFormat) return false;
// 为设备环境设置像素格式
return SetPixelFormat(m_pDC->GetSafeHdc(), nPixelFormat, &pfd);
}
六、关闭窗口的时候释放OpenGL资源
这里添加WM_DESTROY消息
// 释放OPenGL相关资源void CTestGLView::OnDestroy()
{
CView::OnDestroy();
// 释放资源
wglMakeCurrent(NULL, NULL);
wglDeleteContext(m_hRC);
delete m_pDC;
}
为OpenGL分配资源和释放资源一般是成对的操作,就像C语言中{}括弧一样,因此我们放在一起。
七、在OnInitialUpdate函数中设置渲染环境
这里 (类视图)右击 view类--重载OnInitialUpdate()方法
void CTestGLView::OnInitialUpdate(){
CView::OnInitialUpdate();
// 设置背景色
glClearColor(0.0, 0.0, 0.0, 1.0);
}
因为OnInitialUpdate在窗口被创建的之后会被调用一次,因此最适合用于设置OpenGL的渲染环境。
八、改变窗口大小
这里添加WM_SIZE消息
void CTestGLView::OnSize(UINT nType, int cx, int cy){
CView::OnSize(nType, cx, cy);
// 设置视口
glViewport(0, 0, cx, cy);
// 设置投影矩阵(透视投影)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)cx/(GLfloat)cy, 1.0, 1000.0);
// 设置模型视图矩阵
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}
在OnSize中设置视口、投影矩阵和模型视图矩阵。
九、绘制场景
void CTestGLView::OnDraw(CDC* pDC){
CTestGLDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// 清除颜色
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 绘制场景
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
{
// 绘制坐标系
drawUnitAxes();
}
glPopMatrix();
// 交换缓冲区
SwapBuffers(wglGetCurrentDC());
}
这里通过添加函数添加
这里的drawUnitAxes函数是绘制一个xyz的坐标系,代码如下:// 绘制坐标轴
void CTestGLView::drawUnitAxes()
{
const GLfloat max = (GLfloat)1.0f;//INT_MAX;
// 实线部分
glBegin(GL_LINES);
// x
glColor3f(1.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(max, 0.0, 0.0);
// y
glColor3f(0.0, 1.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, max, 0.0);
// z
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, max);
glEnd();
// 虚线部分
glEnable(GL_LINE_STIPPLE);
glLineStipple(3, 0xAAAA);
glBegin(GL_LINES);
// x
glColor3f(1.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(-max, 0.0, 0.0);
// y
glColor3f(0.0, 1.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, -max, 0.0);
// z
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, -max);
glEnd();
glDisable(GL_LINE_STIPPLE);
}
十、运行效果
备注:在很多讲解关于opengl的书中提到的细节可能不止这么多。例如,设置窗口类的时候要添加CS_OWNDC属性;创建窗口的时候风格要添加WS_CLIPSIBLINGS和WS_CLIPCHILDREN分格(窗口类和窗口不是一个概念);屏蔽WM_ERASEBKGND消息等。但是这些在Windows2000(应该也包含其后)的系统中都不是必须的!起码在我自己的电脑中是这样。所以作为一个初次接触OpenGL的用户来说,完全没有必要被这里无关的东西迷失方向。