MFC下OpenGL入门
1, 建一工程文件,我这里命名为first,现在first工程里面我们没有添加任何东西,所有的东西都是MFC自动帮我们创建的。
2, 添加链接库。这一步很关键。打开菜单栏下的项目->属性->配置属性->链接器->输入->附加依赖项里加入OpenGL32.lib GLu32.lib GLaux.lib,如图
3, 加头文件,在stdafx里面添加opengl的头文件。如下代码所示:
#include "stdio.h"
#include "math.h"
#include "gl\gl.h"
#include "gl\glu.h"
#include "gl\glaux.h"
//---------------------------------------------------------------------------<
4, CCY457OpenGLView类的属性栏,为下述消息加入消息处理函数:WM_CREATE (for OnCreate), WM_DESTROY (for OnDestroy), WM_SIZE (for OnSize), WM_ERASEBACKGROUND (for OnEraseBkground).如下图:
5, 设置窗口显示风格。窗口创建之前我们必须设置窗口风格包含WS_CLIPCHILDREN和 WS_CLIPSIBLINGS,从而避免OpenGL绘制到其他窗口中去。这些应该放在PreCreateWindow()中。
{
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;//Tramp
return CView::PreCreateWindow(cs);
}
6, 在CfirstView.h中加入如下语句:
/************************************************************************/
/* 设置的变量是Rendering Context(着色描述表)。每一个OpenGL都被连接到一个着
色描述表上。着色描述表将所有的OpenGL调用命令连接到Device Context(设备描述表)上。
我将OpenGL的着色描述表定义为hRC 。要让您的程序能够绘制窗口的话,还需要创建一个
设备描述表,也就是第二行的内容。Windows的设备描述表被定义为hDC 。DC将窗口连接到
GDI(Graphics Device Interface图形设备接口)。而RC将OpenGL连接到DC */
/************************************************************************/
HGLRC m_hRC; //Rendering Context着色描述表
CDC* m_pDC; //Device Context设备描述表
BOOL InitializeOpenGL(); //Initialize OpenGL
BOOL SetupPixelFormat(); //Set up the Pixel Format
void RenderScene(); //Render the Scene
7, 在OnCreate中我们将通过建立像素格式和绘制上下文来初始化OpenGL. 在InitializeOpenGL()中会创建一个设备上下文(DC),为这个DC选择一个像素格式,创建和这个DC相关的绘制上下文(RC),然后选择这个RC.这个函数会调用SetupPixelFormat()来建立像素格式。
int Clesson1View::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
InitializeOpenGL();//初始化openGL绘图
return 0;
}
//初始化opengl绘制
BOOL CfirstView::InitializeOpenGL()
{
//Get a DC for the Client Area
m_pDC = new CClientDC(this);
//Failure to Get DC
if(m_pDC == NULL)
{
//::MessageBox("Error Obtaining DC");
return FALSE;
}
//Failure to set the pixel format
if(!SetupPixelFormat())
{
return FALSE;
}
//Create Rendering Context
m_hRC = ::wglCreateContext (m_pDC->GetSafeHdc ());
//Failure to Create Rendering Context
if(m_hRC == 0)
{
// MessageBox("Error Creating RC");
return FALSE;
}
//Make the RC Current
if(::wglMakeCurrent (m_pDC->GetSafeHdc (), m_hRC)==FALSE)
{
// MessageBox("Error making RC Current");
return FALSE;
}
//Specify Black as the clear color
::glClearColor(0.0f,0.0f,0.0f,0.0f);
//Specify the back of the buffer as clear depth
::glClearDepth(1.0f);
//Enable Depth Testing
::glEnable(GL_DEPTH_TEST);
return TRUE;
}
//设置像素格式
BOOL CfirstView::SetupPixelFormat()
{
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
24, // 24-bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
16, // 16-bit z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
int m_nPixelFormat = ::ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd);
if ( m_nPixelFormat == 0 )
{
return FALSE;
}
if ( ::SetPixelFormat(m_pDC->GetSafeHdc(), m_nPixelFormat, &pfd) == FALSE)
{
return FALSE;
}
return TRUE;
}
8, 在OnSize()中一般用来设置视口和视锥,因为这些是和窗口大小相关的。基本操作包括设置视口,选择投影矩阵,设置模型视图矩阵。
void CfirstView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
// TODO: 在此处添加消息处理程序代码
GLdouble aspect_ratio; // width/height ratio
if ( 0 >= cx || 0 >= cy )
{
return;
}
// select the full client area
::glViewport(0, 0, cx, cy);
// compute the aspect ratio
// this will keep all dimension scales equal
aspect_ratio = (GLdouble)cx/(GLdouble)cy;
// select the projection matrix and clear it
::glMatrixMode(GL_PROJECTION);
::glLoadIdentity();
// select the viewing volume
::gluPerspective(45.0f, aspect_ratio, .01f, 200.0f);//画三维
//::gluOrtho2D(-10.0f, 10.0f, -10.0f, 10.0f); //二维
// switch back to the modelview matrix and clear it
::glMatrixMode(GL_MODELVIEW);
::glLoadIdentity();
}
9, 在绘制场景时,一般包括如下步骤:1)清空缓存。2)绘制场景。3)Flush掉渲染流水线。4)若设置了双缓冲,则交换前后台缓冲区。
void CfirstView::OnDraw(CDC* /*pDC*/)
{
CfirstDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
// Clear out the color & depth buffers
::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
RenderScene();//绘图都放在这
// Tell OpenGL to flush its pipeline
::glFinish();
// Now Swap the buffers
::SwapBuffers( m_pDC->GetSafeHdc() );
}
10, 为了使改变窗口大小时严重的闪烁,在OnEraseBkgnd里做一些操作,避免windows自己的窗口刷新闪烁。
BOOL CfirstView::OnEraseBkgnd(CDC* pDC)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
return TRUE;
}
11, 为了避免内存泄露,我们要将在SetupPixelFormat()中使用了new运算符来为CClientDC对象分配的内存在程序关闭时delete掉。
void CfirstView::OnDestroy()
{
CView::OnDestroy();
// TODO: 在此处添加消息处理程序代码
//Make the RC non-current
if(::wglMakeCurrent (0,0) == FALSE)
{
MessageBox(_T("Could not make RC non-current"));
}
//Delete the rendering context
if(::wglDeleteContext (m_hRC)==FALSE)
{
MessageBox(_T("Could not delete RC"));
}
//Delete the DC
if(m_pDC)
{
delete m_pDC;
}
//Set it to NULL
m_pDC = NULL;
}
12, 下面写主绘图函数,RenderScene(),在窗口画了一个正方体、一个四面体。
void CfirstView::RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity(); // Reset The Current Modelview Matrix
glTranslatef(-1.5f,0.0f,-6.0f); // Move Left 1.5 Units And Into The Screen 6.0
glRotatef(30,0.0f,1.0f,0.0f); // Rotate The Triangle On The Y axis ( NEW )
glBegin(GL_TRIANGLES); // Start Drawing A Triangle
glColor3f(1.0f,0.0f,0.0f); // Red
glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Front)
glColor3f(0.0f,1.0f,0.0f); // Green
glVertex3f(-1.0f,-1.0f, 1.0f); // Left Of Triangle (Front)
glColor3f(0.0f,0.0f,1.0f); // Blue
glVertex3f( 1.0f,-1.0f, 1.0f); // Right Of Triangle (Front)
glColor3f(1.0f,0.0f,0.0f); // Red
glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Right)
glColor3f(0.0f,0.0f,1.0f); // Blue
glVertex3f( 1.0f,-1.0f, 1.0f); // Left Of Triangle (Right)
glColor3f(0.0f,1.0f,0.0f); // Green
glVertex3f( 1.0f,-1.0f, -1.0f); // Right Of Triangle (Right)
glColor3f(1.0f,0.0f,0.0f); // Red
glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Back)
glColor3f(0.0f,1.0f,0.0f); // Green
glVertex3f( 1.0f,-1.0f, -1.0f); // Left Of Triangle (Back)
glColor3f(0.0f,0.0f,1.0f); // Blue
glVertex3f(-1.0f,-1.0f, -1.0f); // Right Of Triangle (Back)
glColor3f(1.0f,0.0f,0.0f); // Red
glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Left)
glColor3f(0.0f,0.0f,1.0f); // Blue
glVertex3f(-1.0f,-1.0f,-1.0f); // Left Of Triangle (Left)
glColor3f(0.0f,1.0f,0.0f); // Green
glVertex3f(-1.0f,-1.0f, 1.0f); // Right Of Triangle (Left)
glEnd(); // Done Drawing The Pyramid
glLoadIdentity(); // Reset The Current Modelview Matrix
glTranslatef(1.5f,0.0f,-7.0f); // Move Right 1.5 Units And Into The Screen 7.0
glRotatef(25,1.0f,1.0f,1.0f); // Rotate The Quad On The X axis ( NEW )
glBegin(GL_QUADS); // Draw A Quad
glColor3f(0.0f,1.0f,0.0f); // Set The Color To Green
glVertex3f( 1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Top)
glVertex3f(-1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Top)
glVertex3f(-1.0f, 1.0f, 1.0f); // Bottom Left Of The Quad (Top)
glVertex3f( 1.0f, 1.0f, 1.0f); // Bottom Right Of The Quad (Top)
glColor3f(1.0f,0.5f,0.0f); // Set The Color To Orange
glVertex3f( 1.0f,-1.0f, 1.0f); // Top Right Of The Quad (Bottom)
glVertex3f(-1.0f,-1.0f, 1.0f); // Top Left Of The Quad (Bottom)
glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Bottom)
glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Bottom)
glColor3f(1.0f,0.0f,0.0f); // Set The Color To Red
glVertex3f( 1.0f, 1.0f, 1.0f); // Top Right Of The Quad (Front)
glVertex3f(-1.0f, 1.0f, 1.0f); // Top Left Of The Quad (Front)
glVertex3f(-1.0f,-1.0f, 1.0f); // Bottom Left Of The Quad (Front)
glVertex3f( 1.0f,-1.0f, 1.0f); // Bottom Right Of The Quad (Front)
glColor3f(1.0f,1.0f,0.0f); // Set The Color To Yellow
glVertex3f( 1.0f,-1.0f,-1.0f); // Top Right Of The Quad (Back)
glVertex3f(-1.0f,-1.0f,-1.0f); // Top Left Of The Quad (Back)
glVertex3f(-1.0f, 1.0f,-1.0f); // Bottom Left Of The Quad (Back)
glVertex3f( 1.0f, 1.0f,-1.0f); // Bottom Right Of The Quad (Back)
glColor3f(0.0f,0.0f,1.0f); // Set The Color To Blue
glVertex3f(-1.0f, 1.0f, 1.0f); // Top Right Of The Quad (Left)
glVertex3f(-1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Left)
glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Left)
glVertex3f(-1.0f,-1.0f, 1.0f); // Bottom Right Of The Quad (Left)
glColor3f(1.0f,0.0f,1.0f); // Set The Color To Violet
glVertex3f( 1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Right)
glVertex3f( 1.0f, 1.0f, 1.0f); // Top Left Of The Quad (Right)
glVertex3f( 1.0f,-1.0f, 1.0f); // Bottom Left Of The Quad (Right)
glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Right)
glEnd(); // Done Drawing The Quad
}
附,坐标交互操作的实现:
//控制旋转和位置的变量
GLfloat m_xAngle;//
GLfloat m_yAngle;
GLfloat m_xPos;
GLfloat m_yPos;
CPoint m_MouseDownPoint;
旋转的关键操作:
m_xAngle+=(point.y-m_MouseDownPoint.y)/3.6;
m_yAngle+=(point.x-m_MouseDownPoint.x)/3.6;
//Set the mouse point
m_MouseDownPoint=point;
InvalidateRect(NULL,FALSE);
绘图:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity();
glTranslatef(m_xPos, m_yPos, -5.0f);
glRotatef(m_xAngle, 1.0f,0.0f,0.0f);
glRotatef(m_yAngle, 0.0f,1.0f,0.0f);
绘图操作......