MFC+OPENGL配置+显示三维图形实现 旋转平移缩放+光照效果[对话框篇]

MFC+OPENGL配置+显示三维图形实现 旋转平移缩放+光照效果[对话框篇]

一、开发环境说明

  • 操作系统:windows
  • 开发软件:VS2017
  • 编程语言:基于MFC对话框下的opengl
  • 最终效果图:

二、配置操作

配置opengl,并搭建opnegl框架,使在MFC下能显示出绘制的图形

1、打开vs2017软件,依次点击【文件】–【新建】–【项目】,选择“Visual C++”下面的 MFC,如下图所示

2、点击【确定】–【下一步】选择【基于对话框】,点击【完成】。如图所示


3、在左侧【解决方案资源管理器】中,右键单击【project】选择【添加】–【类(C)】 如图所示

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、在【CprojectDlg.h】文件中添加代码如下

14、在【CprojectDlg.cpp】中函数OnInitDialog添加代码如下

15、 在【资源视图】下双击【Dialog】文件夹下面的【IDD_PROJECT_DIALOG】,删除文本控件和按钮,如图所示

16、 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、实现光照:启动光照
5.1 实现光照代码
void MyOpengl::light()
{
    float ambientlight0Color[] = { 0.0f,0.0f,0.0f,1.0f };
    float diffuselight0Color[] = { 1.0f,1.0f,1.0f,1.0f };
    float specularlight0Color[] = { 1.0f,1.0f,1.0f,1.0f };
    float light0Position[] = { -2.0,2.0f,2.0f,1.0f };
    float ambientM[] = { 0.11f,0.06f,0.11f,1.0f };
    float ambientD[] = { 0.43f,0.47f,0.54f,1.0f };
    float ambientS[] = { 0.33f,0.33f,0.52f,1.0f };
    float ambientE[] = { 0.0f,0.0f,0.0f,0.0f };
    float ambientSE = 10;

    glLightfv(GL_LIGHT0, GL_AMBIENT, ambientlight0Color);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuselight0Color);
    glLightfv(GL_LIGHT0, GL_SPECULAR, specularlight0Color);
    glLightfv(GL_LIGHT0, GL_POSITION, light0Position);
    //----------设置材质
    glMaterialfv(GL_FRONT, GL_AMBIENT, ambientM);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, ambientD);
    glMaterialfv(GL_FRONT, GL_SPECULAR, ambientS);
    glMaterialfv(GL_FRONT, GL_EMISSION, ambientE);
    glMaterialf(GL_FRONT, GL_SHININESS, 10.0f);
    //控制镜面反射光斑的大小 0---120
    //-----------启动光照
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHTING);
}
5.2 调用光照函数,实现光照效果

6、实现缩放:通过鼠标滚轮滚动,如果向上滚动则放大,向下滚动则缩小
//滚轮事件
BOOL MyOpengl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    // 此处添加代码
    return CWnd::OnMouseWheel(nFlags, zDelta, pt);
}
7、实现旋转:通过鼠标左键按下后移动鼠标来实现旋转角度的变化
7.1检测鼠标左键是否按下
//鼠标左键按下事件
void MyOpengl::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
     // 此处添加代码
    CWnd::OnLButtonDown(nFlags, point);
}
7.2在鼠标左键按下的情况下通过移动鼠标进行旋转
//鼠标移动事件
void MyOpengl::OnMouseMove(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
     // 此处添加代码
    CWnd::OnMouseMove(nFlags, point);
}
7.3鼠标左键弹起,结束旋转
//鼠标左键弹起事件
void MyOpengl::OnLButtonUp(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    // 此处添加代码
    CWnd::OnLButtonUp(nFlags, point);
}
8、实现平移:通过监控键盘按键,改变平移变量的值,从而平移物体
BOOL MyOpengl::PreTranslateMessage(MSG* pMsg)
{
    // TODO: 在此添加专用代码和/或调用基类
    // 此处添加代码
    return CWnd::PreTranslateMessage(pMsg);
}
9、大功告成,点击菜单栏【调试】–【开始执行】 效果图如图所示

四、工程代码下载

整个工程代码都可以下载,如果有疑惑可以留言,谢谢。

社交账号快速登录