MFC+OpenGL三维绘图(一)——简单绘图平台的搭建与实现图像的旋转、缩放

声明:本文章为小白本人第一次创作,文章可能会有诸多不足,希望大家批评指正!


     VS2013下载:https://pan.baidu.com/s/1Y7TuZlLaGsbj2KCZV_uckw

    OpenGL下载:https://download.csdn.net/download/belence_zhao/10352366

    OpenGL的配置方法网上有很多大家可以自行查找。

一、创建项目

1.打开VS2013建立一个单文档工程,项目名字openGLDrawing。

2.添加初始化和终止代码

    首先,在打开类COpenGLDrawingView,在其头文件添加“gl.h”“glut.h”“glu.h”三个头文件,然后添加两个记录绘图的成员变量。

 
 
#include "Gl/gl.h"
#include "GL/glu.h"
#include "gl/glut.h"

在类COpenGLDrawingView的头文件中添加两个成员变量CClientDC *m_pDC;HGLRC m_hglrc;

protected:

// 生成的消息映射函数
protected:
	DECLARE_MESSAGE_MAP()
public:
	CClientDC *m_pDC;
	HGLRC m_hglrc;

然后,给类COpenGLDrawingView分别添加WM_CREATE、WM_SIZE、WM_DESDROY响应函数OnCreate、OnSize和OnDesdory函数。

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

	// TODO:  在此添加您专用的创建代码
	int n;
	m_pDC = new CClientDC(this);
	ASSERT(m_pDC != NULL);
	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;
	}
	

	n = ::GetPixelFormat(m_pDC->GetSafeHdc());
	::DescribePixelFormat(m_pDC->GetSafeHdc(),n,sizeof(pfd),&pfd);
	

	//Create Rendering Context  
	m_hglrc = ::wglCreateContext(m_pDC->GetSafeHdc());
	//Failure to Create Rendering Context  
	if (m_hglrc == 0)
	{
		MessageBox("Error Creating RC");
		return FALSE;
	}
	//Make the RC Current  
	if (::wglMakeCurrent(m_pDC->GetSafeHdc(), m_hglrc) == 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 0;

}

void COpenGLDrawingView::OnDestroy()
{
	// TODO:  在此处添加消息处理程序代码
	
	//Delete the rendering context  
	::wglMakeCurrent(NULL, NULL);
	if (m_hglrc)
		::wglDeleteContext(m_hglrc);
	if (m_pDC)
		delete m_pDC;
	CView::OnDestroy();
}

此外还要再类PreCreateWindow中,还要对窗口风格进行设置。

BOOL COpenGLDrawingView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO:  在此处通过修改
	//  CREATESTRUCT cs 来修改窗口类或样式
	//cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW);
	cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_MAXIMIZE;
	return CView::PreCreateWindow(cs);
}

3.根据窗口大小设置场景

    在MFC应用中,窗口位置的大小和和位置的改变都会引发一个WM_SIZE消息,执行所在的OnSize函数。

void COpenGLDrawingView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);
	if (m_hglrc)
		wglMakeCurrent(m_pDC->GetSafeHdc(), m_hglrc);
	else
		return;

	// TODO:  在此处添加消息处理程序代码

	if (0 >= cx || 0 >= cy)
	{
		return;
	}
	 //select the full client area  
	::glViewport(0, 0, cx, cy);
	::glMatrixMode(GL_PROJECTION);
	::glLoadIdentity();
	if (cx < cy)
		glOrtho(-10.0, 100.0, -10.0*(GLfloat)cy / (GLfloat)cx, 10.0*(GLfloat)cy / (GLfloat)cx, -100.0, 100.0);
	else
		glOrtho(-10.0*(GLfloat)cx / (GLfloat)cy, 10.0*(GLfloat)cx / (GLfloat)cy, -10.0, 10.0, -100.0, 100.0);
	// switch back to the modelview matrix and clear it  
	::glMatrixMode(GL_MODELVIEW);
	::glLoadIdentity();
}

4.添加绘制代码

    在MFC中绘图是通过OnDraw函数中执行的,因此OpenGL函数的命令在这里执行。

void COpenGLDrawingView::OnDraw(CDC* /*pDC*/)
{
	COpenGLDrawingDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO:  在此处为本机数据添加绘制代码
	if (m_hglrc)
		wglMakeCurrent(m_pDC->GetSafeHdc(), m_hglrc);
	else
		return;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	glColor3f(1.0,1.0,0.0);
	Rendenr();
	::SwapBuffers(m_pDC->GetSafeHdc());
	
}

在这里,我们为了进行简单的说明,采用OpenGL中的glutwireTeapot函数进行快速的茶壶绘制。

这时候,我们就已经完成了一个简单的绘图平台,运行一下程序就会看到一个完美的茶壶图形,如下图:



但是,此时我们所完成的只是一个简单的二维图形,无法想其他专业的三维绘图软件一样,进行图像的旋转、缩放等功能。这个功能的实现我们可以通过添加鼠标消息响应来实现图像的这些功能。

二、实现图像的旋转、平移与缩放

    实现图像的旋转、移动、缩放功能是通过鼠标的消息响应函数分别实现的。在MFC中每当鼠标动一下,就会触发消息响应函数,这样绘图区就会重新绘图,正是这种思想,我们才可以简单的实现图形的操作。

    通过对类COpenGLDrawingView分别添加WM_LBUTTONDOWN、WM_LBUTTONUP、WM_MOUSEWHEEL、WM_MOUSEMOVE和WM_KEYDOWN消息相应的响应函数来实现这些功能。在对鼠标消息命令之前先进设置。

首先在类COpenGLDrawingView的头文件中添加变量:m_yAngle; m_xAngle;m_zAngle; m_xPos; m_yPos; m_zPos;m_MouseDownPoint; m_Scale;分别表示要旋转的角度与位置,代码如下:

public:
	CClientDC *m_pDC;
	HGLRC m_hglrc;
	GLfloat m_yAngle;
	GLfloat m_xAngle;
	GLfloat m_zAngle;
	GLfloat m_xPos;
	GLfloat m_yPos;
	GLfloat m_zPos;
	CPoint m_MouseDownPoint;
	float m_Scale;

然后在构造函数中对这些变量进行初始化:

COpenGLDrawingView::COpenGLDrawingView()
{
	// TODO:  在此处添加构造代码
	m_xPos = 0.0f;
	m_yPos = 0.0f;
	m_zPos = 0.0f;
	m_xAngle = 0.0f;
	m_yAngle = 0.0f;
	m_zAngle = 0.0f;
	m_Scale = 1.0f;

}

由于鼠标每次移动都要进行图形的重新绘制,在OnDraw函数中要进行一定的设置。本次工程我们采用OpenGL中的glTranslatef()实现图形的平移,通过glRotatef()函数实现图像的旋转,通过glScalef()函数实现图像的缩放功能,代码如下:

        glTranslatef(m_xPos, m_yPos, m_zPos);
	glRotatef(m_xAngle, 1.0f, 0.0f, 0.0f);
	glRotatef(m_yAngle, 0.0f, 1.0f, 0.0f);
	glScalef(m_Scale, m_Scale, m_Scale);
	glColor3f(1.0,1.0,0.0);

鼠标的移动:

void COpenGLDrawingView::OnMouseMove(UINT nFlags, CPoint point)
{
	// TODO:  在此添加消息处理程序代码和/或调用默认值

	if (GetCapture() == this)
	{
		//Increment the object rotation angles  
		m_xAngle += (point.y - m_MouseDownPoint.y) / 3.6;
		m_yAngle += (point.x - m_MouseDownPoint.x) / 3.6;
		//Redraw the view  
		InvalidateRect(NULL, FALSE);
		//Set the mouse point  
		m_MouseDownPoint = point;
	};
	CView::OnMouseMove(nFlags, point);
}

1.实现图像的缩放

    图新的缩放功能是通过鼠标中间的转动实现的,当中键向上图形放大,中建向下图形缩小。

BOOL COpenGLDrawingView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
	// TODO:  在此添加消息处理程序代码和/或调用默认值
	if (m_Scale >= 0)
	{
		m_Scale += 0.05 *zDelta / 120;
	}
	else
	{
		if (zDelta > 0)
		{
			m_Scale += 0.05 *zDelta / 120;
		}
	}
	InvalidateRect(NULL, FALSE);
	return CView::OnMouseWheel(nFlags, zDelta, pt);
	
}

2.实现图像的移动

    图像的移动,通过键盘上的箭头来控制的,箭头的上下左右分别控制图形的上下左右平移。

void COpenGLDrawingView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO:  在此添加消息处理程序代码和/或调用默认值

	switch (nChar)
	{
	case VK_UP:        m_yPos = m_yPos + 1.0f;
		break;
	case VK_DOWN:    m_yPos = m_yPos - 1.0f;
		break;
	case VK_LEFT:    m_xPos = m_xPos - 1.0f;
		break;
	case VK_RIGHT:  m_xPos = m_xPos + 1.0f;
		break;
	default:        MessageBox("Press the arrow keys only");
		break;
	}

	InvalidateRect(NULL, FALSE);
	CView::OnKeyDown(nChar, nRepCnt, nFlags);

3.实现图像的旋转

void COpenGLDrawingView::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO:  在此添加消息处理程序代码和/或调用默认值

	m_MouseDownPoint = point;
	SetCapture();
	CView::OnLButtonDown(nFlags, point);
}

void COpenGLDrawingView::OnLButtonUp(UINT nFlags, CPoint point)
{
	// TODO:  在此添加消息处理程序代码和/或调用默认值

	m_MouseDownPoint = CPoint(0, 0);
	ReleaseCapture();
	CView::OnLButtonUp(nFlags, point);
}

此刻,到了我们该欢呼的时刻了,我们已经完成了程序的设计过程,让我们运行一下:



本文代码地址:https://download.csdn.net/download/belence_zhao/10408772


猜你喜欢

转载自blog.csdn.net/Belence_zhao/article/details/80279976