OSG开发笔记(四十):使用OSG自绘拟合球形顶点
前言
OSG内置的几何图形并没有球面,那么绘制球面先要绘制球面的组成顶点,本篇解说绘制球面组成顶点的详细过程。
  
  组成面的时候,为了看到是否正确,取中间的几个圆环:
  
  
OSG的坐标系类似于Qt场景坐标系,场景有场景的坐标系,图元有图元的坐标系,视图有视图的坐标系。与此类似,OSG坐标系也相似,差别在于视图坐标系在OSG是相机坐标系。
世界坐标系描述的是整个场景中所有的对象,可以理解为绝对坐标系,所有对象的位置都是绝对坐标。从整体上考虑,它为所有对象的位置提供一个绝对的参考标准,从而避免了物体之间由于独立的物体坐标系而导致的坐标系混乱。
  每一个物体都有自己的坐标系,当物体发生交换时,实际上是它本身的坐标系相对于世界坐标系发生变换的过程。
物体坐标系通常描述的问题是特定物体的内部对象,主要包括物体的顶点,物体的法向量和物体的方向。
  摄像机坐标系与屏幕坐标系类似,只不过摄像机坐标系位于3D空间,而屏幕坐标系位于2D空间。
  坐标系三轴正方向
- opengl坐标系,即z轴正向朝外,y轴正向朝上,x轴正向朝右(符合软件研发标准坐标);
- osg坐标系,即z轴正向朝上,y轴正向朝内,x轴正向朝右(笛卡尔坐标系);
- Directx坐标系,即z轴正向朝里,y轴正向朝上,x轴正向朝右.(左手坐标系);
  
  平行面计算平行角度θ,其一周的x和y计算:
  
  得到了最大横截面的时候圆圈点的求解公式。
  垂直平面计算垂直的z坐标系:
  
  以上两个绘制出来就是圆柱了:
  
  纵轴的角度也要参与到之前圆圈的计算中,得到上下走的时候圆圈缩小:
  
  
  那么x和y都需要额外乘以垂直角度来缩小,按照代码的计算方式,是从y从0°开始,所以是cos,不是sin,绘制出来如下图:
  
  
// 步骤一:创建一个用户保存集合信息的对象osg::Geode
osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;
osg::ref_ptr<osg::Geometry> pGeometry = new osg::Geometry;
  
    // 步骤二:计算顶点,颜色
    osg::ref_ptr<osg::Vec3Array> pVec3ArrayVertex = new osg::Vec3Array;
    osg::ref_ptr<osg::Vec4Array> pVec4ArrayColor = new osg::Vec4Array;
    // 计算步长数量
    int xyStepTotal = qCeil(360.0f / xyCircleStepAngle);
    // 纵轴,因为只提供了z坐标,走180°即可
    int xzStepTotal = qCeil(180.0f / xzCircleStepAngle);
    {
        // 计算步长角度
        double xyStepAngle = 360.0f / xyStepTotal;
        double xzStepAngle = 180.0f / xzStepTotal;
#if 1
        // 计算顶点,颜色
        for(int xzStepIndex = 0; xzStepIndex < xzStepTotal; xzStepIndex++)
        {
            for(int xyStepIndex = 0; xyStepIndex < xyStepTotal; xyStepIndex++)
            {
//                LOG << xyStepIndex << xyStepIndex * xyStepAngle
//                    << xzStepIndex << xzStepIndex * xzStepAngle;
                LOG << radius * cos(qDegreesToRadians(xyStepIndex * xyStepAngle))
                    << radius * sin(qDegreesToRadians(xyStepIndex * xyStepAngle))
                    << radius * cos(qDegreesToRadians(xzStepIndex * xzStepAngle));
                // 绘制点
                pVec3ArrayVertex->push_back(osg::Vec3f(radius * cos(qDegreesToRadians(xyStepIndex * xyStepAngle)) * sin(qDegreesToRadians(xzStepIndex * xzStepAngle)),
                                                       radius * sin(qDegreesToRadians(xyStepIndex * xyStepAngle)) * sin(qDegreesToRadians(xzStepIndex * xzStepAngle)),
                                                       radius * cos(qDegreesToRadians(xzStepIndex * xzStepAngle))));
                // 绘制颜色
                pVec4ArrayColor->push_back(osg::Vec4f(1.0, 0.0, 0.0, 1.0));
            }
        }
#endif
    }
pGeometry->setVertexArray(pVec3ArrayVertex.get());
  
// 步骤三:设置顶点颜色
    pGeometry->setColorArray(pVec4ArrayColor.get());
pGeometry->setColorBinding(osg::Geometry::BIND_OVERALL);
  
// 步骤四:添加法线、设置法线
osg::ref_ptr<osg::Vec3Array> pVec3ArrayNormal = new osg::Vec3Array;
pVec3ArrayNormal->push_back(osg::Vec3f(0, 1, 0));
pGeometry->setNormalArray(pVec3ArrayNormal);
  
// 步骤五:设置顶点几何绘制方式
//LOG << pVec3ArrayVertex->size() << pVec4ArrayColor->size();
pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::DrawArrays::POINTS, 0, pVec3ArrayVertex->size()));
  
// 步骤六:绘制几何图形
pGeode->addDrawable(pGeometry.get());
  
#if 1
    // 步骤七:设置顶点大小
    osg::ref_ptr<osg::Point> pPoint = new osg::Point();
    pPoint->setSize(1);
    pGeometry->getOrCreateStateSet()->setAttributeAndModes(pPoint, osg::StateAttribute::ON);
#endif
osg::ref_ptr<osg::Node> OsgWidget::getSpherialSurface()
{
    // 其他demo的控件
    updateControlVisible(false);
    osg::ref_ptr<osg::Group> pGroup = new osg::Group();
    {
        // 创建球面
        osg::ref_ptr<osg::Geode> pGeode = OsgManager::createSpherialSurface(Point3F(0, 0, 0), 50, 10, 10);
        // 关闭光照
        OsgManager::setLighting(pGeode.get(), false);
        pGroup->addChild(pGeode.get());
    }
    return pGroup.get();
}
osg::ref_ptr<osg::Geode> OsgManager::createSpherialSurface(Point3F center, double radius, double xyCircleStepAngle, double xzCircleStepAngle)
{
    // 绘制球面
    // 步骤一:创建一个用户保存集合信息的对象osg::Geode
    osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;
    osg::ref_ptr<osg::Geometry> pGeometry = new osg::Geometry;
    // 步骤二:计算顶点,颜色
    osg::ref_ptr<osg::Vec3Array> pVec3ArrayVertex = new osg::Vec3Array;
    osg::ref_ptr<osg::Vec4Array> pVec4ArrayColor = new osg::Vec4Array;
    // 计算步长数量
    int xyStepTotal = qCeil(360.0f / xyCircleStepAngle);
    // 纵轴,因为只提供了z坐标,走180°即可
    int xzStepTotal = qCeil(180.0f / xzCircleStepAngle);
    {
        // 计算步长角度
        double xyStepAngle = 360.0f / xyStepTotal;
        double xzStepAngle = 180.0f / xzStepTotal;
#if 1
        // 计算顶点,颜色
        for(int xzStepIndex = 0; xzStepIndex < xzStepTotal; xzStepIndex++)
        {
            for(int xyStepIndex = 0; xyStepIndex < xyStepTotal; xyStepIndex++)
            {
//                LOG << xyStepIndex << xyStepIndex * xyStepAngle
//                    << xzStepIndex << xzStepIndex * xzStepAngle;
                LOG << radius * cos(qDegreesToRadians(xyStepIndex * xyStepAngle))
                    << radius * sin(qDegreesToRadians(xyStepIndex * xyStepAngle))
                    << radius * cos(qDegreesToRadians(xzStepIndex * xzStepAngle));
                // 绘制点
                pVec3ArrayVertex->push_back(osg::Vec3f(radius * cos(qDegreesToRadians(xyStepIndex * xyStepAngle)) * sin(qDegreesToRadians(xzStepIndex * xzStepAngle)),
                                                       radius * sin(qDegreesToRadians(xyStepIndex * xyStepAngle)) * sin(qDegreesToRadians(xzStepIndex * xzStepAngle)),
                                                       radius * cos(qDegreesToRadians(xzStepIndex * xzStepAngle))));
                // 绘制颜色
                pVec4ArrayColor->push_back(osg::Vec4f(1.0, 0.0, 0.0, 1.0));
            }
        }
#endif
    }
    pGeometry->setVertexArray(pVec3ArrayVertex.get());
    // 步骤三:设置顶点颜色
    pGeometry->setColorArray(pVec4ArrayColor.get());
    pGeometry->setColorBinding(osg::Geometry::BIND_OVERALL);
    // 步骤四:添加法线、设置法线
    osg::ref_ptr<osg 
                     
                    
                 
                    
                