MFC+OpenGL单文档制作三维图像

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/Tan_HandSome/article/details/47342023

GDI:图形设备接口

DC:设备描述表

RC:着色描述表

OpenGL:专业图形程序接口

画图原理:每个GDI命令需要传给它一个DC,OpenGL需要绘制环境(RC),

RC与特定的DC联系起来,完成绘图工作。

产生OpenGL并使之成为当前的RC步骤:

1.设置窗口像素格式

2.产生RC

3.设置当前RC


1.创建一个MFC单文档项目命名为VCOpenGL2

   在stdafx里面添加OpenGL的头文件

    #include<GL\glut.h>

2.设置窗口显示风格

    窗口创建之前我们必须设置窗口风格包含

    WS_CLIPCHILDREN(创建父窗口使用的Windows风格,用于重绘时裁剪子窗口所覆盖的区域)和WS_CLIPSIBLINGS(创建子窗口使用Windows风格,用于重绘时裁剪其他子窗口覆盖的区域),从而避免OpenGL绘制到其他窗口中去。这些应该放在PreCreateWindow()中。

3.设置窗口像素格式

首先向VCOpenGL2View类中添加几个保护的成员和公共的成员函数。如下:

protected:
HGLRC m_hRC;//Rendering Context着色描述表
CClientDC *m_pDC; //Device Context设备描述表

intm_wide; //视口的宽度
int m_heigth;//视口的高度
BOOL InitializeOpenGL();//初始化OpenGL
BOOL SetupPixelFormat();//设置像素格式
void RenderScene();//绘制场景

VCOpenGL2View的构造函数中初始化m_hRC,m_pDC ;

CVCOpenGL2View::CVCOpenGL2View()
{
// TODO:  在此处添加构造代码
m_hRC = NULL;
m_pDC = NULL;
}

产生一个RC的第一步是定义窗口的像素格式。像素格式决定窗口所显示的图形在内存中 是如何表示的。由像素格式控制的参数包括:颜色深度、缓冲模式和所支持的绘画接口。在下面将在SetupPixelFormat();函数中对这些参数的设置。代码如下:

BOOL CVCOpenGL2View::SetupPixelFormat()
{
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),//pfd结构的大小
1, //版本号
PFD_DRAW_TO_WINDOW |//支持在窗口中绘图
PFD_SUPPORT_OPENGL |//支持OpenGL
PFD_DOUBLEBUFFER,//双缓存模式
PFD_TYPE_RGBA,//RGBA颜色模式
24, //24位颜色深度
0, 0, 0, 0, 0, 0,//忽略颜色位
0, //没有非透明度缓存
0, //忽略移位位
0, //无累计缓存
0, 0, 0, 0, //忽略累计位
32, //32位深度缓存
0, //无模板缓存
0, //无辅助缓存
PFD_MAIN_PLANE,//主层
0, //保留
0, 0, 0 //忽略层,可见性和损毁掩模
};
int pixelFormat;
//为设备描述表得到最匹配的像素格式
if ((pixelFormat = ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd)) == 0)
{
MessageBox(L"ChoosePixelFormat failed");
return FALSE;
}
//设置最匹配的像素格式为当前的像素格式
if (SetPixelFormat(m_pDC->GetSafeHdc(),pixelFormat,&pfd)==FALSE)
{
MessageBox(L"SetPixelFormat failed");
return FALSE;
}
return TRUE;
}


5.产生RC,设置为当前RC。

现在像素格式已经设定,我们下一步工作是产生绘制环境(RC)并使之成为当前绘制环境,即编写InitializeOpenGL()。代码如下:

BOOL CVCOpenGL2View::InitializeOpenGL()
{
PIXELFORMATDESCRIPTORpfd;
int n;
m_pDC = new CClientDC(this);
ASSERT(m_pDC != NULL);
//设置当前的绘图像素格式
if (!SetupPixelFormat())
{
return FALSE;
}
n = ::GetPixelFormat(m_pDC->GetSafeHdc());
::DescribePixelFormat(m_pDC->GetSafeHdc(), n, sizeof(pfd), &pfd);
//创建绘图描述表
m_hRC = wglCreateContext(m_pDC->GetSafeHdc());
if (m_hRC==NULL)
{
return FALSE;
}
//使绘图描述表为当前调用线程的当前绘图描述表
if (wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC) == FALSE)
{
return FALSE;
}
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
return TRUE;
}


在OnCreate()函数(用类向导添加)中调用InitializeOpenGL()函数。如下所示:

int CVCOpenGL2View::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;


// TODO:  在此添加您专用的创建代码
if (InitializeOpenGL())
{
return 0;
}


return 0;
}

6.设置视口

在OnSize()中一般用来设置视口和窗口大小相关的。代码如下:

void CVCOpenGL2View::RenderScene()
{
//设置清平颜色为黑色
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
//清除颜色缓冲区和深度缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//透视投影变换
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(80, (double)m_wide / (double)m_heigth, 1.5, 0);/*视角80度,纵横比,进裁剪面,远裁剪面*/
//视角变换
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(2, 2, 2, 0, 0, 0, 0, 1, 0);/*前三个参数是眼睛的位置,中间三个参数是物体所在的位置,后面三个参数表示向量,头顶朝上的方向*/
//矩阵堆栈函数,和glPopMatrix()相对应
glPushMatrix();
glBegin(GL_LINES);
glColor3d(1.0, 0.0, 0.0);//X轴 红色
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(2.0, 0.0, 0.0);
glColor3d(0.0, 1.0, 0.0);//Y轴 绿色
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, 2.0, 0.0);
glColor3d(0.0, 0.0, 1.0);//Z轴 蓝色
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, 0.0, 2.0);
glEnd();
glColor3f(1.0, 1.0, 1.0);
glutWireCube(0.5);


glPopMatrix();
glFinish();
SwapBuffers(wglGetCurrentDC());
}

别忘了,在OnDraw()函数中调用,代码如下:

记得把/*pDC的注释去掉*/

void CVCOpenGL2View::OnDraw(CDC* pDC)
{
CVCOpenGL2Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;


// TODO:  在此处为本机数据添加绘制代码
RenderScene();
}


8.一些收尾工作

8.1为了使改变窗口大小时严重的闪烁,在OnEraseBkgnd()里做一些操作,避免windows自己的窗口刷新闪烁。OnEraseBkgnd()函数需要重写,代码如下:

BOOL CVCOpenGL2View::OnEraseBkgnd(CDC* pDC)
{
// TODO:  在此添加消息处理程序代码和/或调用默认值
return TRUE;


//return CView::OnEraseBkgnd(pDC);
}

8.2为了避免内存泄露,OnDestroy()函数中加一些代码,如下:

void CVCOpenGL2View::OnDestroy()
{
CView::OnDestroy();


// TODO:  在此处添加消息处理程序代码
m_hRC = ::wglGetCurrentContext();
if (::wglMakeCurrent(0, 0) == FALSE)
{
MessageBox(L"Could not make RC non-current");
}
if (m_hRC)
{
if (::wglDeleteContext(m_hRC) == FALSE)
{
MessageBox(L"Could not delete RC");
}
}
if (m_pDC)
{
delete m_pDC;
}
m_pDC = NULL;
}

运行结果:












阅读更多

没有更多推荐了,返回首页