您的位置:首页 > 其它

5.osg中用顶点绘制球体并贴上地球纹理

2015-07-16 20:13 393 查看
代码及注释如下:

classGeometry_sphere : public osg::Geometry
{
public:
    Geometry_sphere(double dRadius=1, intiNumPartsLongtitude_half=13,
        int iNumPartsLatitude_half=13);
 
    void InitVertices();//初始化顶点
    void AddFaces();//添加面
 
protected:
    double m_dRadius;//半径
    int m_iNumPartsLongtitude_half;//使用经线数的一半
    int m_iNumPartsLatitude_half;//纬线数的总数加1的一半
   
    osg::ref_ptr<osg::Vec3Array>m_pVertices;//绘制顶点索引
    osg::ref_ptr<osg::Vec2Array>m_pIndex;//渲染顶点索引
};
 

 

         Geometry_sphere::Geometry_sphere(doubledRadius,int iNumPartsLongtitude_half,
    int iNumPartsLatitude_half)
    :m_dRadius(dRadius),
    m_iNumPartsLongtitude_half(iNumPartsLongtitude_half),
    m_iNumPartsLatitude_half(iNumPartsLatitude_half)
{
    InitVertices();
    AddFaces();
}
 
void Geometry_sphere::InitVertices()
{
    //构成球的顶点总数为 经线数加1 * 纬线总数加2(两极点)主要是为之后渲染的封闭性考虑
    m_pVertices = newosg::Vec3Array((m_iNumPartsLongtitude_half*2+1)*
        ((m_iNumPartsLatitude_half+1)*2-1));
    //渲染顶点索引数与绘制顶点数相同
    m_pIndex = new osg::Vec2Array((m_iNumPartsLongtitude_half*2+1)*
        ((m_iNumPartsLatitude_half+1)*2-1));
 
    double dDeltaHeight =m_dRadius/m_iNumPartsLatitude_half;//纬度间高度
    double dDeltaAngle =osg::PI/m_iNumPartsLongtitude_half;//经度间夹角
 
    double dAngle,dHeight=m_dRadius,dLatitudeRadius;//角度、高度、对应纬度上的半径
 
    //初始化所有点
//x、y用于渲染顶点索引
    float y =1.0/((float)m_iNumPartsLatitude_half*2);
    float x =1.0/((float)m_iNumPartsLongtitude_half*2);
    for(int i = 0; i <(m_iNumPartsLatitude_half)*2; ++i,dHeight-=dDeltaHeight)
    {
        dLatitudeRadius =sqrt(m_dRadius*m_dRadius-fabs(dHeight)*fabs(dHeight));
        dAngle = 0;
 
        for(int k = 0; k <m_iNumPartsLongtitude_half*2+1; ++k,dAngle+=dDeltaAngle)
        {
            if(((i*(m_iNumPartsLongtitude_half*2+1)+k)+1)%(m_iNumPartsLongtitude_half*2+1)==0)
            {
                (*m_pVertices)[i*(m_iNumPartsLongtitude_half*2+1)+k]=(*m_pVertices)[i*(m_iNumPartsLongtitude_half*2+1)+k-m_iNumPartsLongtitude_half*2];
                (*m_pIndex)[i*(m_iNumPartsLongtitude_half*2+1)+k].set(k*x,1-i*y);
            }
            else
            {
                (*m_pVertices)[i*(m_iNumPartsLongtitude_half*2+1)+k].set(
                    dLatitudeRadius*cos(dAngle),dLatitudeRadius*sin(dAngle),
                    dHeight);
                (*m_pIndex)[i*(m_iNumPartsLongtitude_half*2+1)+k].set(k*x,1-i*y);
            }
        }
    }
    //初始化最后一条经线上的点(该经线与第一条经线重合,绘制顶点值相同,但渲染顶点值不同)
    for(int i = 0; i <m_iNumPartsLongtitude_half*2+1; ++i)
    {
        if(i==m_iNumPartsLongtitude_half*2)
        {
            (*m_pVertices)[(m_iNumPartsLongtitude_half*2+1)*((m_iNumPartsLatitude_half+1)*2-2)+i].set(0,0,dHeight);
            (*m_pIndex)[(m_iNumPartsLongtitude_half*2+1)*((m_iNumPartsLatitude_half+1)*2-2)+i].set(i*x,0);
        }
        else
        {
            (*m_pVertices)[(m_iNumPartsLongtitude_half*2+1)*((m_iNumPartsLatitude_half+1)*2-2)+i].set(0,0,dHeight);
            (*m_pIndex)[(m_iNumPartsLongtitude_half*2+1)*((m_iNumPartsLatitude_half+1)*2-2)+i].set(i*x,0);
        }
    }
}
 
voidGeometry_sphere::AddFaces()
{
    //设置gemoetry对象索引
    this->setVertexArray(m_pVertices.get());
    this->setTexCoordArray(0,m_pIndex.get());
 
    int iNumLongtitude =m_iNumPartsLongtitude_half*2;
    int iNumLatitude =m_iNumPartsLatitude_half*2;
 
    for(int k = 0; k < iNumLatitude; ++k)
    {
        int i;
        for(i = 0; i < iNumLongtitude; ++i)
        {
            if(((iNumLongtitude+1)*k+i+1)%(m_iNumPartsLongtitude_half*2+1)!=0)
            {
                //采用四边形的绘制方法组成球的框架
                osg::ref_ptr<osg::DrawElementsUInt>pQuads= new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS,0);
 
                pQuads->push_back((iNumLongtitude+1)*k+i);
                pQuads->push_back((iNumLongtitude+1)*k+i+1);
                pQuads->push_back((iNumLongtitude+1)*k+i+1+(iNumLongtitude+1));
                pQuads->push_back((iNumLongtitude+1)*k+i+(iNumLongtitude+1));
               
                addPrimitiveSet(pQuads.get());
            }
        }
    }
 
    //优化该对象
    osgUtil::SmoothingVisitor smv;
    smv.smooth(*this);
    //设置各点法向量
    osg::ref_ptr<osg::Vec3Array>pNormals =new osg::Vec3Array();
    for(int i = 0; i <m_pVertices->size(); ++i)
    {
        osg::Vec3 pt = (*m_pVertices)[i];
        pt.normalize();
        pNormals->push_back(pt);
    }
    this->setNormalArray(pNormals);
    this->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
    //设置各点颜色
    osg::ref_ptr<osg::Vec4Array>pColor =new osg::Vec4Array();
    for(int i = 0; i <m_pVertices->size(); ++i)
    {
        osg::Vec4 pt(1.0, 1.0, 1.0, 1.0);
        pColor->push_back(pt);
    }
    this->setColorArray(pColor);
    this->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  osg