|
发表于 2009-12-10 20:58:18
|
显示全部楼层
这个程序中3D引擎采用opengl,可以通过鼠标对视角进行缩放和旋转,这里大概介绍下:
opengl中如何通过鼠标实现实体的旋转、平移、缩放控制(原创,转载时请注明出处)
绘制实体的关键代码:
1 glPushMatrix();
2 glTranslatef(m_xMove+m_dxMove,-m_yMove-m_dyMove,0.0f);
3 glRotatef( m_xRotate+m_dxRotate, 1.0f, 0.0f,0.0f);
4 glRotatef( m_yRotate+m_dyRotate, 0.0f, 1.0f,0.0f);
5 glScalef(m_scale,m_scale,m_scale);
6 glBegin(GL_LINES);
7 glColor3d(1.0,0.0,0.0);
8 glVertex3d( -200.0, 0.0, 0.0);
9 glVertex3d( 200.0, 0.0, 0.0);
10 glColor3d(0.0,1.0,0.0);
11 glVertex3d( 0.0, -200.0, 0.0);
12 glVertex3d( 0.0, 200.0, 0.0);
13 glColor3d(1.0,1.0,0.5);
14 glVertex3d( 0.0, 0.0, -200.0);
15 glVertex3d( 0.0, 0.0, 200.0);
16 glEnd();
17 glPopMatrix();
为了简化问题,这里我们将三维实体定义为笛卡尔坐标的三个轴线(代码6-16行),代码中的出现的坐标为实体坐标系(局部坐标系)的坐标,这点很关键,比如我们要绘制一个立方体(立方体的边长为a),首先针对这个立方体建立实体坐标系,假定这个坐标系的原点位于立方体的中心,并且立方体的顶面平行于XY平面,那么这个立方体的8个顶点的坐标就是(a/2,a/2,a/2),(-a/2,a/2,a/2),(a/2,-a/2,a/2),(-a/2,-a/2,a/2),(a/2,a/2,-a/2),(-a/2,a/2,-a/2),(a/2,-a/2,-a/2),(-a/2,-a/2,-a/2)。从这个简单的例子可以看出我们在规划实体坐标系时以简化描述实体为原则。复杂实体的建模一般由专业的建模软件完成,如3dMax、Multigen等,应用程序通过读取实体模型数据将其导入进来。
定义好实体后,接下来通过矩阵堆栈将实体摆放到世界坐标系中:
a. 由于实体是在局部坐标系中建立的,而局部坐标系可能与世界坐标系的单位不一致,因此需要通过比例缩放对实体的尺寸进行调整,代码第5行完成这个功能,这里X,Y,Z的调节比例一致,比例系数为m_scale;
b. 接下来对实体在世界中的姿态进行调整。通过对各轴进行旋转,可使用实体处于要求的姿态下,这里需要注意的是,这种旋转调整方式不是唯一的,做为生活常识,我们可以通过不同的旋转方式将物品摆放在同样的姿态下。代码第3,4行完成这个功能,这里首先将实体以Y为轴旋转m_yRotate+m_dyRotate角度,然后以X为轴旋转m_xRotate+m_dxRotate角度;
c. 最后,我们通过平移将实体移动到世界中的特定位置上。代码第2行完成这个功能,这里将实体移动(m_xMove+m_dxMove,-m_yMove-m_dyMove,0.0f)的位置上。
接下来,通过鼠标操作改变上述代码中的关键变量(m_scale, m_yRotate等等)来实现鼠标对实体的缩放、旋转以及平移控制。这里约定:鼠标左键实现实体的平移,鼠标滚轮实现实体的缩放,鼠标右键实现实体的旋转,鼠标右键双击实现归位处理。代码如下:
void CGlDemoCtrlCtrl::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_rotateFlag = TRUE; //右键按下时设置旋转标识
m_centerPoint = point; //记录此时鼠标的基准点,后面旋转角度的计算以此做为基值
COleControl::OnRButtonDown(nFlags, point);
}
void CGlDemoCtrlCtrl::OnRButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_rotateFlag = FALSE; //右键释放时,归位旋转标识
m_yRotate += m_dyRotate; //保存当前Y轴旋转角度
m_xRotate += m_dxRotate; //保存当前X轴旋转角度
m_dxRotate = m_dyRotate = 0.0f; //X,Y轴旋转增量回零
COleControl::OnRButtonUp(nFlags, point);
}
void CGlDemoCtrlCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_moveFlag = TRUE; //左键按下时设置平移标识
m_centerPoint = point; //记录此时鼠标的基准点,后面平移尺寸的计算以此做为基值
COleControl::OnLButtonDown(nFlags, point);
}
void CGlDemoCtrlCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_moveFlag = FALSE; //左键释放时,归位平移标识
m_xMove += m_dxMove; //保存当前X轴平移尺寸
m_yMove += m_dyMove; //保存当前Y轴平移尺寸
m_dxMove = m_dyMove = 0.0f; // X,Y轴平移增量回零
COleControl::OnLButtonUp(nFlags, point);
}
void CGlDemoCtrlCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(m_rotateFlag)
{ //在旋转模式下
//根据旋转坐标基点以及鼠标当前位置计算旋转增量
m_dyRotate = (point.x-m_centerPoint.x)*360.f/m_width;
m_dxRotate = (point.y-m_centerPoint.y)*360.f/m_height;
Invalidate();
}
if(m_moveFlag)
{ //在平移模式下
//根据平移坐标基点以及鼠标当前位置计算平移增量
m_dxMove = (point.x-m_centerPoint.x)*400.0f/m_width;
m_dyMove = (point.y-m_centerPoint.y)*400.f/m_height;
Invalidate();
}
COleControl::OnMouseMove(nFlags, point);
}
void CGlDemoCtrlCtrl::OnRButtonDblClk(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
//鼠标右键双击,归位处理
m_xRotate = m_yRotate = 0.0f;
m_dxRotate = m_dyRotate = 0.0f;
m_xMove = m_yMove = 0.0f;
m_dxMove = m_dyMove = 0.0f;
Invalidate();
COleControl::OnRButtonDblClk(nFlags, point);
}
BOOL CGlDemoCtrlCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
// TODO: Add your message handler code here and/or call default
float delta;
if(nFlags&MK_CONTROL)
delta = .5f; //按下ctrl键,进行快速缩放,缩放增量设置为0.5
else
delta = 0.01f; //普通缩放,缩放增量设置为0.01
if(zDelta>0)
{
//这里放大
m_scale += delta;
}
else
{
//这里缩小
if(m_scale > delta)
m_scale -= delta;
}
Invalidate();
return COleControl::OnMouseWheel(nFlags, zDelta, pt);
} |
|