基于OSG的全景图显示实现以及在osgearth环境下街景图正确嵌入地球经纬度位置的计算

前言

       这一部分我主要是写一下大致的思路,然后给一个我的代码,由于代码写得有点混乱,文档的思路也没有完全写清楚,大家凑和着看吧,有问题可以再讨论

问题描述

全景球如果直接画在地球上,那么效果是画在不同经纬度位置的球朝向是一致的,只要平移球心就可以完全吻合。说白了,如果全景球在北极显示的是天空朝头上,那么在南极画的时候就天空朝脚下了。如图(图中箭头指示天空的方向)因此需要有一种方法,实现针对不同的经纬度位置,对该处显示的全景球加以翻转。

根据在移动测量中通常采用的平面坐标系(北方为Y、头顶的方向为Z)的情况,建立平面坐标系XYZaxis的方式表示。XYZ坐标系表示地球坐标系。

在这里,Yaxis的定义是:北极点N和全景球心点P的连线在地平面(即通过点P与地球相切的平面)的投影。因此,问题归结为3步来解决

 

(1) 计算出地面坐标系的三个轴的方向

 

(2) 找到一个变换矩阵,使得一个点Q在地球坐标系的坐标与它经过这个变换以后的新坐标点Q’在地面坐标系中相同。

 

(3) 按照(2)的变换矩阵,对全景球面的各个点坐标做变换,那么就可以保证变换后全景球的位置在P点,朝向是天空朝头顶,且以前的XY轴对应的变换到新的Xaxis Yaxis位置。

 

计算原理:

 

(1)计算地面坐标系的三个轴的方向

 

设北极点N在过P点的切平面上的投影点为G,则必有向量NG平行于Zaxis方向,可以设G点坐标为 (N.x,N.y,N.z)+(Zaxis.x,Zaxis.y,Zaxis.z)*t 其中t是一个待定的系数,而N点坐标容易知道,Zaxis的坐标就是要放置全景球的位置,也是已知的。这个t怎么确定呢?需要再用到一个条件,即向量PG垂直于Zaxis,因为内积为0.于是有

 

( (N.x,N.y,N.z)+(Zaxis.x,Zaxis.y,Zaxis.z)*t –(Zaxis.x,Zaxis.y,Zaxis.z))  *

 

(Zaxis.x,Zaxis.y,Zaxis.z) = 0                                    1

 

据此可以计算出G点位置,进而计算Yaxis方向的单位向量,而Xaxis方向的单位向量可以通过ZaxisYaxis做外积再归一化得到。

(2)>找到一个变换矩阵,使得一个点Q在地球坐标系的坐标与它经过这个变换以后的新坐标点Q’在地面坐标系中相同。

  至于这个变换矩阵得到的原理,参考《两个直角坐标系间坐标变换关系的研究》

  另外,绘制全景球的原理,参考《基于openGL的全景图片三维浏览技术研究与实现》

基于OSG的全景图显示实现以及在osgearth环境下街景图正确嵌入地球经纬度位置的计算
osg::Node *makePanoView(osg::Vec3d  v3d ,osg::Vec3d north )

{

//输入north时北极点的三维坐标

    //输入v3d是全景球球心的坐标

    //中间变量有Xaxis Yaxis Zaxis

  double t=1-(v3d.x()*north.x()+v3d.y()*north.y()+v3d.z()*north.z())/(v3d.x()*v3d.x()+v3d.y()*v3d.y()+v3d.z()*v3d.z());

//计算Yaxis的方向

         osg::Vec3d  yAxis,zAxis(v3d);//Zaxis就是点P处的法向量,其实值就是P点的坐标//

 yAxis._v[0]=north.x()+v3d.x()*(t-1);

 yAxis._v[1]=north.y()+v3d.y()*(t-1);

 yAxis._v[2]=north.z()+v3d.z()*(t-1);

// 由公式(1)计算Yaxis

         osg::Vec3d  xAxis;

           guiyi(yAxis);guiyi(zAxis); //归一化的意思是把向量变成单位向量

   waiji(yAxis,zAxis,xAxis); //由yaxis和Zaxis计算外积,得到Xaxis的方向

              guiyi(xAxis);

             

           double trans_mat[3][3];

          for(int i=0;i<3;i++)

{

            trans_mat[0][i]=xAxis._v[i];

            trans_mat[1][i]=yAxis._v[i];

            trans_mat[2][i]=zAxis._v[i];

}  //把归一化后的 Xaxis、 yaxis和Zaxis的坐标摆成一个矩阵,就是我们想要的旋转矩阵,//我们接下来要做的,是加上平移变换

        

int ox=v3d.x(),oy=v3d.y(),oz=v3d.z(); 

    int i, j;

   float lev[] = {0.0,15.0,30.0,45.0,60.0,75.0,90.0,105.0, 120.0,135.0, 150.0, 165,180.0  };

  

float x, y, z;

    float alpha, theta;

    float radius = 100;

    int nlev = sizeof( lev )/sizeof(float);

osg::Geometry *geom = new osg::Geometry;

    osg::Vec3Array& coords = *(new osg::Vec3Array(19*nlev));

    osg::Vec4Array& colors = *(new osg::Vec4Array(19*nlev));

    osg::Vec2Array& tcoords = *(new osg::Vec2Array(19*nlev));


    int ci = 0;

for( j = 0; j <= 18; j++ )
        {

            alpha = osg::DegreesToRadians(lev[nlev-i-1]);

            theta = osg::DegreesToRadians((float)(j*20));

           double x0 = radius * sin( alpha ) * cosf( theta );

          double  z0 = radius * sin( alpha ) * sinf( theta );

          double   y0 = radius * cos( alpha );

             x=x0;

 y=z0;

 z=-y0;

           double p[3]={x,y,z};

           double d[3];

            Array_Multipy31(trans_mat,p,d); //相当于d=trans_mat*p

            coords[ci][0] = d[0]+ox;

            coords[ci][1] = d[1]+oy;

            coords[ci][2] = d[2]+oz;

            tcoords[ci][0] = (float)j/18.0;

            tcoords[ci][1] = (float)(nlev-1-i)/(float)(nlev-1);

            ci++;

        }

    }

  //省略若干行

    return geode;

}
基于OSG的全景图显示实现以及在osgearth环境下街景图正确嵌入地球经纬度位置的计算

基于OSG的全景图显示实现以及在osgearth环境下街景图正确嵌入地球经纬度位置的计算

上一篇:Photoshop简单制作魔术咖啡杯


下一篇:photoshop 鼠绘恩爱的情侣头像方法