在设置并加密了飞行路径之后,就可以沿着所设置的飞行路径进行三维漫游,下面说明沿飞行路径漫游的实现。
实时动态三维漫游通常有以下两种方式。
1)视点固定目标移动显示方式
这种显示方式实现起来比较容易,只要实时改变三维场景在世界坐标系的位置或在自身坐标系中的空间状态,即通过实时改变其基本模型的变换矩阵(如平移、旋转、缩放等)相应参数即可得到实时动态显示效果。我们通过鼠标键盘实现的前、后、左、右移动就属于这种类型。
2)目标固定视点移动显示方式
视点沿着预先设定的路径移动,并采取透视投影,这样观察固定目标即会产生飞行效果。这就是沿飞行路径漫游的实现,其基本流程如图10-14所示。
目标固定视点移动方式流程图
图10-14  目标固定视点移动方式流程图
我们将这种浏览方式细分为以下两种方式:固定高度漫游和固定高差漫游,下面分别介绍其实现方法。
一、 沿固定高度漫游实现
1.概念理解
沿固定高度漫游是通过视点,即观察者的眼坐标(eyex , eyey , eyez)的坐标 eyey在浏览过程中保持不变,始终为用户漫游之前所设置的高度值,这样可以保持恒定的高度对三维场景进行浏览,可在高空总体上查看三维场景,如图10-15所示。在该方式下,需要用户在漫游之前设置高程值。

2.界面设计
在菜单“三维漫游(B)”→“飞行路径”下添加一个子菜单,名称为“沿路径漫游”,类型为“Pop_up”(弹出式)。在其下再添加一个子菜单,名称为“按固定高度漫游”,ID = ID_FLY_STATICHEIGHT,最后的菜单如图10-16所示。
添加菜单
图10-16  添加菜单
3.程序设计
1)变量添加
在T3DSystemView.h文件的代码:
#if _MSC_VER>1000
#pragma once
#endif //_MSC_VER>1000
下面添加枚举变量定义(用来标识不同的三维漫游类别):
enum {  GIS_FLY_STATICHEIGHT,   GIS_FLY_PATHHEIGHT};
在T3DSystemView.h文件中添加以下私有变量。
private:
    BYTE m_FlyHeightType; //三维漫游类型(固定高度漫游,固定高差漫游)
    int m_flypathPtIndex; //飞行路径坐标的索引号
    int m_flyPathCurrentPtIndex; //在飞行过程中记录当前路径点的索引号,用于暂停飞行器
    int m_flyspeed; //飞行时的计时器时间间隔
2)函数实现
(1)修改Init_data()函数,在最后添加m_flyspeed初始化代码。
void CT3DSystemView::Init_data()    //初始化相关变量
{
    ……
    m_flyspeed=10; //飞行时的计时器时间间隔初始值
}

 函数说明:
  
初始化飞行速度m_flyspeed值。
(2)为菜单ID = ID_FLY_STATICHEIGHT添加响应函数,按固定高度漫游。
void CT3DSystemView::OnFlyStaticheight()
{
    if(m_FlayPath.GetSize()<=0)//如果飞行路径坐标点数量≤0,即飞行路径为空
    {
        MessageBox("没有输入路径文件","飞行浏览",MB_ICONWARNING);
        return;
    }
    m_FlyHeightType=GIS_FLY_STATICHEIGHT;//设置漫游类型为固定高度漫游
    m_StaticHeight=(m_maxHeight+m_minHeight)/2.0;//取固定高度值=地形最大和最小高度和的1/2
    m_flypathPtIndex=0; //飞行路径坐标初始索引=0
    SetFLyTimer();  //设置三维漫游计时器,开始漫游
}
函数说明:
 OnFlyStaticHeight ()函数实现按固定高度方式漫游。
(3)设置菜单是否设置勾选标识“√”。
void CT3DSystemView::OnUpdateFlyStaticheight(CCmdUI*pCmdUI)
{
    pCmdUI->Enable(m_PathFlag==TRUE); //根据是否具有有效飞行路径值,设置菜单状态
    if(m_FlyHeightType==GIS_FLY_STATICHEIGHT)//如果当前是沿固定高度漫游方式
        pCmdUI->SetCheck(TRUE); //菜单前设置勾选标识"√"
    else
        pCmdUI->SetCheck(FALSE); //否则不设置   
}
(4)设置飞行计时器。
void CT3DSystemView::SetFLyTimer()
{
    SetTimer(1,m_flyspeed,0); //m_flyspeed:飞行计时器时间间隔
}
函数说明:
 
 
设置飞行漫游的计时器。
(5)计时器。
void CT3DSystemView::OnTimer(UINT nIDEvent)
{
    switch(nIDEvent)
    {
    case 1: //三维漫游
        //如果当前飞行路径坐标点索引≤路径坐标点总数-1               
        if(m_flypathPtIndex<=m_FlayPath.GetSize()-2)
        {
            //根据漫游路径相临坐标点计算相机各参数
            GetCameraCorrdinate(
                m_FlayPath.GetAt(m_flypathPtIndex)->x,\
                m_FlayPath.GetAt(m_flypathPtIndex)->y,\
                m_FlayPath.GetAt(m_flypathPtIndex)->z,\
                m_FlayPath.GetAt(m_flypathPtIndex+1)->x,\
                m_FlayPath.GetAt(m_flypathPtIndex+1)->y,\
                m_FlayPath.GetAt(m_flypathPtIndex+1)->z
                );
            OnDraw(GetDC()); //刷新三维场景
            m_flypathPtIndex++; //飞行路径当前坐标索引号+1
        }
        else
        {
            //到了飞行路径尾,将飞行路径当前坐标索引号重置为0,即从飞行路径起始点开始漫游
            m_flypathPtIndex=0;
        }
        break ;
    }
    CView :: OnTimer ( nIDEvent ) ;
}

 函数说明:
   
OnTimer()函数实现飞行态漫游。
(6)根据漫游路径相临坐标点计算相机各参数。
void CT3DSystemView::GetCameraCorrdinate(double x1,double y1,double z1,double x2,
                                     double y2,double z2)
{
    //(x1,y1,x1):飞行路径当前点坐标
    //(x2,y2,x2):飞行路径下一点坐标
    if(m_FlyHeightType==GIS_FLY_STATICHEIGHT)   //固定高度飞行方式
    {
        m_vView.x=x2;//观察点x坐标
        m_vView.y=m_StaticHeight;//观察点y坐标=始终等于固定高度值
        m_vView.z=z2;//观察点z坐标
        m_vPosition.x=x1;//视点x坐标
        m_vPosition.y=m_vView.y;//视点y坐标=观察点y坐标
        m_vPosition.z=z1;//视点z坐标
    }  
}
函数说明:
 GetCameraCorrdinate()函数主要根据漫游路径相临坐标点的三维坐标计算相机观察点和视点参数的值。
如图10-17所示为程序运行效果图。
按固定高度方式漫游效果图
图10-17  按固定高度方式漫游效果图
二、  沿相对高度漫游实现
1.概念理解
沿相对高度漫游,即视点的y坐标 eyey在浏览过程中不断地改变,始终保持与地面点固定的高度差,如图10-18所示。这就需要对三维漫游路径进行插值处理。设某一时刻视点下方的地面高程值为H,固定高差为△h,则 eyey = H + △h。在该方式下,需要用户在浏览之前设置高差。如果高差为0时,则相当驾驶模拟,即达到人或车贴在地面上行走的效果。

2.界面设计
在菜单“三维漫游(B)”→“沿路径漫游”下添加一个子菜单,名称为“按相对高度漫游”,ID = ID_FLY_ROUTINEHEIGHT,最后的菜单如图10-19所示。
添加菜单
图10-19  添加菜单
3.程序设计
1)添加变量
private:
    BOOL m_ViewUpDown;//标识漫游时视角上、下倾增量
2)函数实现
(1)修改Init_data()函数,在最后添加b_haveTerrainZoomroadList初始化代码。
void CT3DSystemView::Init_data()//初始化相关变量
{  
    ……
    m_ViewUpDown=0;//标识漫游时视角上、下倾增量
}

 函数说明:
 
  为Init_data()函数添加漫游时视角上、下倾增量初始值。
(2)为菜单ID = ID_FLY_STATICHEIGHT添加响应函数,按固定高度漫游。
void CT3DSystemView::OnFlyRoutineheight()//按相对高度漫游方式
{
    if(m_FlayPath.GetSize()<=0)//如果飞行路径坐标点数量≤0,即飞行路径为空
    {
        MessageBox("没有输入路径文件","飞行浏览",MB_ICONWARNING);
        return;
    }
    m_FlyHeightType=GIS_FLY_PATHHEIGHT; //设置漫游类型为相对高度漫游
    m_StaticHeight=80; //设置相对高差值
    m_flypathPtIndex=0; //飞行路径坐标初始索引=0
    SetFLyTimer();  //设置三维漫游计时器
}

 函数说明:
 
OnFlyRoutineHeight()函数实现按相对高度漫游方式,并设置相对高差值。
(3)设置菜单是否设置勾选标识“√”
void CT3DSystemView::OnUpdateFlyRoutineheight(CCmdUI*pCmdUI)
{
    pCmdUI->Enable(m_PathFlag==TRUE); //根据是否具有有效飞行路径值设置菜单状态
    if(m_FlyHeightType==GIS_FLY_PATHHEIGHT) //如果当前是沿相对高度漫游方式
        pCmdUI->SetCheck(TRUE); //菜单前设置勾选标识“√”
     else
        pCmdUI->SetCheck(FALSE); //否则不设置
}
函数说明: 
为ID_FLY_ROUTINEHEIGHT菜单设置勾选标识“√”。
(4)修改GetCameraCorrdinate()函数,添加对相对高度的支持。
void CT3DSystemView::GetCameraCorrdinate(double x1,double y1,double z1,double x2,
                    double y2,double z2)//根据漫游路径相临坐标点计算相机各参数
{
☆程序第Ⅰ部分☆《计算按固定高度漫游时的相机参数》
if(m_FlyHeightType==GIS_FLY_STATICHEIGHT)   //固定高度飞行方式
{
        ……
}
 
☆程序第Ⅱ部分☆《计算按相对高度漫游时的相机参数》
//按相对高度(即沿路径)漫游时,需计算一个基本高度
else if(m_FlyHeightType==GIS_FLY_PATHHEIGHT)
{
        m_vView.x=x2;//观察点x坐标
        m_vView.y=y2+m_StaticHeight; //观察点y坐标=y2+ m_StaticHeight固定高度值
        m_vView.z=z2;//观察点z坐标
       
        //求两点之间距离
        float distance=sqrt((x2-x1)*(x2-x1)+(z2-z1)*(z2-z1));
        //根据倾角计算高度差
        float dh=distance*tan(m_ViewUpDown*PAI_D180);
        m_vPosition.x=x1;//视点x坐标
        m_vPosition.y=m_vView.y+dh;//视点y坐标=观察点y坐标 + 高差
        m_vPosition.z=z1;//视点z坐标
    }
}
函数说明:
GetCameraCorrdinate()函数主要根据漫游路径相临坐标点的三维坐标计算相机观察点和视点参数的值,主要包括以下两个部分。
l 第1部分是计算按固定高度漫游时的相机参数。
l 第2部分是计算按相对高度漫游时的相机参数。
如图10-20所示为程序运行效果图。
按相对、固定高度方式漫游效果图
图10-20  按相对、固定高度方式漫游效果图

本文出自《实战OpenGL三维可视化系统开发与源码精解》