您的位置:首页 > 运维架构

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

2015-08-07 19:55 495 查看
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;

}

运行结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: