代码及注释如下:
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);
}