最近项目需要把solidworks创建的设备模型导入MFC对话框中显示,并且能鼠标控制移动、缩放。
软件平台包括 solidworks 2008 、3DS-Max 7.0 、 vs 2008 sp1;
openGL配置
提供最全的openGL库,支持鼠标滚轮,配置方法
将下载的压缩包解开,将得到5个文件(glut.dll, glut32.dll, glut.lib, glut32.lib,glut.h)
(1)把glut.h复制到x:\Program Files\Microsoft\Visual Studio 10.0\VC\include\gl文件夹中,如果没有gl这个文件夹则可以自己新建一个。(x是你安装VS的盘符号)
(2)把解压得到的glut.lib和glut32.lib放到静态函数库所在文件夹(即与include并排的lib文件夹下)。
(3)把解压得到的glut.dll和glut32.dll放到操作系统目录下面的system32文件夹内。(典型的位置为:C:\Windows\System32)
(注:如在开发应用程序时用到OpenGL辅助库函数,则还需下载相应动态链接库,包含glaux.dll, glaux.lib, glaux.h,相应步骤同上)
在Visual C++中先右击项目,选择属性,找到连接器标签,最后在输入中的附加依赖库加上opengl32.lib glut32.lib glu32.lib.
3 #include<gl/glut.h>
4
5 //#include<gl/glu.h> //glut.h自动包含了glu.h 和 gl.h
6
7 //#include<gl/gl.h>
1.在solildworks中创建设备模型,编辑好纹理,这里为了方便直接为模型上的颜色,没有进行贴图(关于soildworks的使用可另外参考教程)
2.保存模型文件为 .wtl格式
3.在3DS-Max 7.0中导入上面的.wtl文件,然后导出文件为.OBJ格式,同时导出素材库即.mtl格式文件。
4.导入模型到MFC对话框
创建一个MFC对话框在OnInitDialog()中设置RC;
hrenderDC=::GetDC(this->m_hWnd);
if(SetWindowPixelFormat(hrenderDC)==FALSE)// 设置像素格式
return ;
if(CreateViewGLContext(hrenderDC)==FALSE)//创建RC并选为所用
return ;
SetWindowPixelFormat( HDC hDC )
{
PIXELFORMATDESCRIPTOR pixelDesc;
pixelDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pixelDesc.nVersion = 1;
pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER |
PFD_TYPE_RGBA;
pixelDesc.iPixelType = PFD_TYPE_RGBA;
pixelDesc.cColorBits = 32;
pixelDesc.cRedBits = 0;
pixelDesc.cRedShift = 0;
pixelDesc.cGreenBits = 0;
pixelDesc.cGreenShift = 0;
pixelDesc.cBlueBits = 0;
pixelDesc.cBlueShift = 0;
pixelDesc.cAlphaBits = 0;
pixelDesc.cAlphaShift = 0;
pixelDesc.cAccumBits = 0;
pixelDesc.cAccumRedBits = 0;
pixelDesc.cAccumGreenBits = 0;
pixelDesc.cAccumBlueBits = 0;
pixelDesc.cAccumAlphaBits = 0;
pixelDesc.cDepthBits = 0;
pixelDesc.cStencilBits = 1;
pixelDesc.cAuxBuffers = 0;
pixelDesc.iLayerType = PFD_MAIN_PLANE;
pixelDesc.bReserved = 0;
pixelDesc.dwLayerMask = 0;
pixelDesc.dwVisibleMask = 0;
pixelDesc.dwDamageMask = 0;
PixelFormat = ChoosePixelFormat(hDC,&pixelDesc);
if(PixelFormat==0) // Choose default
{
PixelFormat = 1;
if(DescribePixelFormat(hDC,PixelFormat,
sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)==0)
{
return FALSE;
}
}
if(SetPixelFormat(hDC,PixelFormat,&pixelDesc)==FALSE)
{
return FALSE;
}
return TRUE;
}
hrenderRC = wglCreateContext(hDC);
if(hrenderRC==NULL)
return FALSE;
if(wglMakeCurrent(hDC,hrenderRC)==FALSE)
return FALSE;
随后初始化openGL配置
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
CRect clirc;
GetClientRect(&clirc);
window_width = clirc.Width();
window_height = clirc.Height();
glPolygonMode(GL_FRONT,GL_FILL);
glPolygonMode(GL_BACK,GL_FILL);
glClearColor(0.0, 0.0, 0.0, 0.0);
//设置当前操作的矩阵为“模型”视图矩阵
glMatrixMode(GL_PROJECTION);
//把当前矩阵设置为单位矩阵
glLoadIdentity();
//将当前控件设置为透视投影空间
gluPerspective(45.0f, (float)window_width/(float)window_height, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glClearColor(0, 0, 0, 1);
glClearDepth(1.0f);
//把屏幕上的颜色清空
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//启动深度测试
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do 用于指定深度缓冲比较值。
//
glEnable(GL_NORMALIZE);
//启动剔除功能
glEnable(GL_CULL_FACE);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Setup other misc features.
//打开光照功能
glEnable( GL_LIGHTING );
glEnable( GL_NORMALIZE );
//设置颜色填充方式:GL_SMOOTH:平滑方式 GL_FLAT:单色方式
glShadeModel( GL_SMOOTH );
//glViewport(0,0,clirc.Width(),clirc.Height());
// Setup lighting model.
GLfloat light_model_ambient[] = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat light0_diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat light0_direction[] = {0.0f, 0.0f, 10.0f, 0.0f};
GLfloat light_specular[] = {1.0f, 1.0f, 1.0f, 1.0f};
// GL_LIGHT0 0号光源,以此类推
// 光源位置由四个值表示(X,Y,Z,W)如果第四个值W为零,则表示该光源位于无限远处,
//前三个值表示了它所在的方向。这种光源称为方向性光源,通常,太阳可以近似的被认为是方向性光源。
//如果第四个值W不为零,则X/W, Y/W, Z/W表示了光源的位置。这种光源称为位置性光源。对于位置性光源,
//设置其位置与设置多边形顶点的方式相似,各种矩阵变换函数例如:glTranslate*、glRotate*等在这里也同样有效。
//方向性光源在计算时比位置性光源快了不少,因此,在视觉效果允许的情况下,应该尽可能的使用方向性光源。
glLightfv(GL_LIGHT0, GL_POSITION, light0_direction);
//GL_AMBIENT、GL_DIFFUSE、GL_SPECULAR属性。这三个属性表示了光源所发出的光的反射特性(以及颜色)。
//每个属性由四个值表示,分别代表了颜色的R, G, B, A值。GL_AMBIENT表示该光源所发出的光,经过非常多次的反射后,最终遗留在整个光照环境中的强度(颜色)。
//GL_DIFFUSE表示该光源所发出的光,照射到粗糙表面时经过漫反射,所得到的光的强度(颜色)。
//GL_SPECULAR表示该光源所发出的光,照射到光滑表面时经过镜面反射,所得到的光的强度(颜色)。
glLightfv(GL_LIGHT0, GL_AMBIENT, light_model_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
glEnable( GL_LIGHT0 );
然后读取模型文件
// Center of the model
float modelCenter[] = {0.0f, 0.0f, 0.0f};
if ( pModel )
{
glmDelete( pModel );
pModel = NULL;
}
CString FileName;
FileName = CommonFunction::GetApplicationPath() + _T("ESR.obj");
//声明标识符
USES_CONVERSION ;
char * pFileName = T2A(FileName);
// Load the new obj model
pModel = glmReadOBJ( pFileName);
// Generate normal for the model
glmFacetNormals( pModel );
// Scale the model to fit the screen
glmUnitize( pModel, modelCenter );
// Init the modelview matrix as an identity matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glGetDoublev( GL_MODELVIEW_MATRIX, pModelViewMatrix );
绘制场景及模型
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslated( 0.0, 0.0, -5.0 );
glMultMatrixd( pModelViewMatrix );
if ( pModel )
{
glmDraw( pModel, GLM_FLAT|GLM_MATERIAL );
}
窗口改变大小时候重绘模型
OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType, cx, cy);
window_width = cx;
window_height = cy;
// Reset the viewport
//把像素绘制到窗口的哪个区域,前两个参数定义了视口的左下脚(0,0表示最左下方),后两个参数分别是宽度和高度
glViewport(0, 0, window_width, window_height);
//使用glMatrixMode来指定当前操作的究竟是模型视图矩阵还是投影矩阵。
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//为了得到透视效果,我们使用gluPerspective来设置可视空间。假定可视角为60度(如果调试时发现该角度不合适,可修改之。我在最后选择的数值是75。),
//高宽比为1.0。最近可视距离为1.0,最远可视距离为200000000*2=400000000。即:gluPerspective(60, 1, 1, 400000000);
gluPerspective(45.0f, (float)window_width/(float)window_height, 0.01f, 200.0f);
}
鼠标操作
OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
OldX = point.x;
OldY = point.y;
bLeftBntDown = true;
CDialog::OnLButtonDown(nFlags, point);
}
OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
bLeftBntDown = false;
CDialog::OnLButtonUp(nFlags, point);
}
OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if ( bLeftBntDown && pModel )
{
float fOldX = 2.0f*OldX/(float)window_width - 1.0f;
float fOldY = -2.0f*OldY/(float)window_height + 1.0f;
float fNewX = 2.0f*point.x/(float)window_width - 1.0f;
float fNewY = -2.0f*point.y/(float)window_height + 1.0f;
double pMatrix[16];
trackball_opengl_matrix( pMatrix, fOldX, fOldY, fNewX, fNewY);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glLoadMatrixd( pMatrix );
glMultMatrixd( pModelViewMatrix );
glGetDoublev( GL_MODELVIEW_MATRIX, pModelViewMatrix );
OldX = point.x;
OldY = point.y;
}
CDialog::OnMouseMove(nFlags, point);
}
滚轮操作
OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (zDelta > 0)
{
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glLoadMatrixd( pModelViewMatrix );
glScaled( 1.05, 1.05, 1.05 );
glGetDoublev( GL_MODELVIEW_MATRIX, pModelViewMatrix );
}
if (zDelta < 0)
{
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glLoadMatrixd( pModelViewMatrix );
glScaled( 0.95, 0.95, 0.95 );
glGetDoublev( GL_MODELVIEW_MATRIX, pModelViewMatrix );
}
return CDialog::OnMouseWheel(nFlags, zDelta, pt);
}
源码 源码