MFC+OPENGL配置+显示三维图形实现 旋转平移缩放+光照效果[对话框篇]
程序员文章站
2022-07-14 09:50:42
...
MFC+OPENGL配置+显示三维图形实现 旋转平移缩放+光照效果[对话框篇]
一、开发环境说明
- 操作系统:windows
- 开发软件:VS2017
- 编程语言:基于MFC对话框下的opengl
- 最终效果图:
二、配置操作
配置opengl,并搭建opnegl框架,使在MFC下能显示出绘制的图形
1、打开vs2017软件,依次点击【文件】–【新建】–【项目】,选择“Visual C++”下面的 MFC,如下图所示
2、点击【确定】–【下一步】选择【基于对话框】,点击【完成】。如图所示
3、在左侧【解决方案资源管理器】中,右键单击【project】选择【添加】–【类©】 如图所示
4、点击“添加”,填写内容如图所示 ,然后点击完成;
5、下载glut.h,glut32.lib 放在当前工程所在的文件夹下面,如图所示
6、在类视图下面,右键单击【MyOpengl】,选择类向导,添加如图三个消息函数 ,点击【编辑代码】
7、在“Myopengl.h”添加如图所示代码
8、在【Myopengl.cpp】中函数SetupPixelFormat(HDC hdc) 代码如下
BOOL MyOpengl::SetupPixelFormat(HDC hdc)//设置像素格式
{
PIXELFORMATDESCRIPTOR pfd = //像素格式
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | //绘制到窗口
PFD_SUPPORT_OPENGL |//支持opengl
PFD_DOUBLEBUFFER,//采用双缓冲
PFD_TYPE_RGBA,//像素类型 RGBA
24,//像素位数 4*8- 32
0, 0, 0, 0, 0, 0,//
0,
0,
0,
0, 0, 0, 0,
16,//深度缓冲区位数
0,//模板缓冲
0,
PFD_MAIN_PLANE,//
0,
0, 0, 0
};
int pixelformat;
if (0 == (pixelformat =ChoosePixelFormat(hdc, &pfd)))//匹配像素格式的索引
{return FALSE;
}
if (FALSE == ::SetPixelFormat(hdc,pixelformat, &pfd))//设置像素格式
{return FALSE;
}
return TRUE;
}
9、在【Myopengl.cpp】中函数OnCreate 实现代码如下
int MyOpengl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
hdc = ::GetDC(m_hWnd);//hdc设备上下文,m_hWnd窗口句柄
SetupPixelFormat(hdc);//设置像素格式
//CPaintDC dc(this);
hglrc = wglCreateContext(hdc);//hglrc :opengl设备上下文
wglMakeCurrent(hdc, hglrc);//hglrc绑定hdc; 绘制到当前设备上下文
glClearDepth(1.0f);//1.0是最大深度([0.0,1.0])
glEnable(GL_DEPTH_TEST);//启动深度检测
return 0;
}
10、在【Myopengl.cpp】中函数OnSize 实现代码如下
//控件窗口大小改变事件
void MyOpengl::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
// TODO: 在此处添加消息处理程序代码
GLdouble aspect_ratio;//窗口长宽比
if (0 >= cx || 0 >= cy)//窗口长、宽必须大于0
return;
glViewport(0, 0, cx, cy);//根据窗口的实时变化重绘窗口
aspect_ratio = (GLdouble)cx / (GLdouble)cy;//长宽比
glMatrixMode(GL_PROJECTION);//对投影矩阵应用随后的矩阵操作
glLoadIdentity();//重置当前投影矩阵指定的矩阵为单位矩阵
gluPerspective(45.0f, aspect_ratio, 0.1f, 10000.0f);//谁知投影矩阵
glMatrixMode(GL_MODELVIEW);//对模型视景矩阵堆栈应用随后的矩阵操作
glLoadIdentity();//重置当前模型矩阵为单位矩阵
}
11、在【Myopengl.cpp】中函数OnPaint 实现代码如下
//刷新绘制事件
void MyOpengl::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
// 不为绘图消息调用 CWnd::OnPaint()
wglMakeCurrent(hdc, hglrc);//hglrcopengl设备上下文--》绑定-->hdc当前设备上下文
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);//背景颜色
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除颜色缓冲以及深度缓冲
display();//绘制函数,在这个函数中绘制自己的图形
glFinish();//绘制结束
SwapBuffers(hdc);//交换前后缓冲区
wglMakeCurrent(hdc, NULL);//释放设备上下文
}
12、在【Myopengl.cpp】中函数display 实现代码如下
//在此函数中绘制图形
void MyOpengl::display()
{
glColor3f(1.0, 0, 0);//设置颜色为红色
glTranslatef(0, 0, -10);//平移(X,Y,Z)
glutSolidTeapot(1.0);//绘制一个茶壶,1.0:指的是茶壶大小
}
13、在【Myopengl.cpp】中函数reflesh 实现代码如下
//强制刷新重绘控件
void MyOpengl::reflesh()
{
Invalidate(false);//是控件无效
this->UpdateWindow();//更新控件
}
14、在【CprojectDlg.h】文件中添加代码如下
15、在【CprojectDlg.cpp】中函数OnInitDialog添加代码如下
16 在【资源视图】下双击【Dialog】文件夹下面的【IDD_PROJECT_DIALOG】,删除文本控件和按钮,如图所示
17 opengl配置完成,可以点击菜单栏【调试】–【开始执行】效果如图所示
三、添加平移、缩放、旋转交互操作和光照效果
1、在【Myopengl.h】定义变量,如图所示
2、在【Myopengl.cpp】中构造函数MyOpengl()中初始化变量
//构造函数,初始化变量
MyOpengl::MyOpengl()
{
//用于平移,对应X Y Z 平移量。按键W:上 S:下 A:左 D:右
m_tranlate[0] = 0;
m_tranlate[1] = 0;
m_tranlate[2] = -10;
//用于旋转,分别是绕X轴 和Y轴旋转的角度,用鼠标左键控制
m_rorate[0] = 0;
m_rorate[1] = 0;
//用于缩放,用鼠标中间滚轮控制
m_scale = 1.0;
//记录鼠标坐标点,用于控制旋转角度;
m_MouseDownPT.x = 0;
m_MouseDownPT.y = 0;
//记录鼠标左键是否按下,按下为true,初始值为false
m_bMouseDown = false;
}
3、在【Myopengl.cpp】中函数display添加代码如下
//在此函数中绘制图形
void MyOpengl::display()
{
glPushMatrix();//压栈
glColor3f(1.0, 0, 0);//设置颜色为红色
glTranslatef(m_tranlate[0], m_tranlate[1], m_tranlate[2]);//平移(X,Y,Z)
glRotatef(m_rorate[0], 1, 0, 0);//旋转 绕X轴
glRotatef(m_rorate[1], 0, 1, 0);//旋转 绕Y轴
glScalef(m_scale, m_scale, m_scale);//缩放(X,Y,Z)
glutSolidTeapot(1.0);//绘制一个茶壶,1.0:指的是茶壶大小
glPopMatrix();//出栈
}
4、添加 鼠标左键按下、鼠标左键弹起、鼠标滚轮滚动、鼠标移动事件(如图所示)和按键事件 ,点击【编辑代码】
5、实现缩放:通过鼠标滚轮滚动,如果向上滚动则放大,向下滚动则缩小
//滚轮事件
BOOL MyOpengl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if(zDelta>0)m_scale += 0.1;//放大
if (zDelta < 0)m_scale -= 0.1;//缩小
if (m_scale < 0.1) m_scale = 0.1;//最小倍数为0.1
reflesh();//刷新控件
return CWnd::OnMouseWheel(nFlags, zDelta, pt);
}
6、实现旋转:通过鼠标左键按下后移动鼠标来实现旋转角度的变化
6.1检测鼠标左键是否按下
//鼠标左键按下事件
void MyOpengl::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_MouseDownPT = point;//记录鼠标左键按下的坐标点
m_bMouseDown = true;//记录鼠标左键按下
CWnd::OnLButtonDown(nFlags, point);
}
6.2在鼠标左键按下的情况下通过移动鼠标进行旋转
//鼠标移动事件
void MyOpengl::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (m_bMouseDown)//如果鼠标左键按下
{
m_rorate[0] += point.y - m_MouseDownPT.y;//通过滑动鼠标改变旋转的角度
m_rorate[1] += point.x - m_MouseDownPT.x;//通过滑动鼠标改变旋转的角度
m_MouseDownPT = point;//记录当前点
}
reflesh();//刷新控件
CWnd::OnMouseMove(nFlags, point);
}
6.3鼠标左键弹起,结束旋转
//鼠标左键弹起事件
void MyOpengl::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_bMouseDown = false;//记录鼠标左键弹起
CWnd::OnLButtonUp(nFlags, point);
}
7、实现平移:通过监控键盘按键,改变平移变量的值,从而平移物体
BOOL MyOpengl::PreTranslateMessage(MSG* pMsg)
{
// TODO: 在此添加专用代码和/或调用基类
if (pMsg->message == WM_KEYDOWN)
{
switch (pMsg->wParam)
{
case'W'://上移动
m_tranlate[1] += 0.1;
return TRUE;
case'S'://下移动
m_tranlate[1] -= 0.1;
return TRUE;
case'A'://左移动
m_tranlate[0] -= 0.1;
return TRUE;
case'D'://右移动
m_tranlate[0] += 0.1;
return TRUE;
}
}
reflesh();//刷新控件
return CWnd::PreTranslateMessage(pMsg);
}
8、实现光照:启动光照
glEnable(GL_LIGHT0);//启动一号灯
glEnable(GL_LIGHTING);//开启光照
9、大功告成,点击菜单栏【调试】–【开始执行】 效果图如图所示
旋转 平移 缩放
四、工程代码下载
整个工程代码都可以下载,如果有疑惑可以留言,谢谢。