OSG开发笔记(四十):使用OSG自绘拟合球形顶点

摘要:OSG的坐标系类似于Qt场景坐标系,场景有场景的坐标系,图元有图元的坐标系,视图有视图的坐标系。与此类似,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::Geodeosg::ref_ptr pGeode =new osg::Geode;osg::ref_ptr pGeometry =new osg::Geometry;

  

// 步骤二:计算顶点,颜色 osg::ref_ptr pVec3ArrayVertex =new osg::Vec3Array; osg::ref_ptr 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;#if1 // 计算顶点,颜色 for(int xzStepIndex =0; xzStepIndex push_back(osg::Vec3f(radius *cos(qDegreesToRadians(xyStepIndex * xyStepAngle))*sin(qDegreesToRadians(xzStepIndex * xzStepAngle)),radius *sin(qDegreesToRadians(xyStepIndex * xyStepAngle))*sin(qDegreesToRadians(xzStepIndex * xzStepAngle)),*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 pVec3ArrayNormal =new osg::Vec3Array;pVec3ArrayNormal->push_back(osg::Vec3f(0,1,0));pGeometry->setNormalArray(pVec3ArrayNormal);

  

// 步骤五:设置顶点几何绘制方式//LOG size size;pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::DrawArrays::POINTS,0, pVec3ArrayVertex->size));

  

// 步骤六:绘制几何图形pGeode->addDrawable(pGeometry.get);

  

#if1 // 步骤七:设置顶点大小 osg::ref_ptr pPoint =new osg::Point; pPoint->setSize(1); pGeometry->getOrCreateStateSet->setAttributeAndModes(pPoint, osg::StateAttribute::ON);#endif

osg::ref_ptrOsgWidget::getSpherialSurface{ // 其他demo的控件 updateControlVisible(false); osg::ref_ptr pGroup =new osg::Group; { // 创建球面 osg::ref_ptr pGeode =OsgManager::createSpherialSurface(Point3F(0,0,0),50,10,10); // 关闭光照 OsgManager::setLighting(pGeode.get,false); pGroup->addChild(pGeode.get); } return pGroup.get;}

绘制球面点函数

osg::ref_ptrOsgManager::createSpherialSurface(Point3F center,double radius,double xyCircleStepAngle,double xzCircleStepAngle){ // 绘制球面 // 步骤一:创建一个用户保存集合信息的对象osg::Geode osg::ref_ptr pGeode =new osg::Geode; osg::ref_ptr pGeometry =new osg::Geometry; // 步骤二:计算顶点,颜色 osg::ref_ptr pVec3ArrayVertex =new osg::Vec3Array; osg::ref_ptr 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;#if1 // 计算顶点,颜色 for(int xzStepIndex =0; xzStepIndex push_back(osg::Vec3f(radius *cos(qDegreesToRadians(xyStepIndex * xyStepAngle))*sin(qDegreesToRadians(xzStepIndex * xzStepAngle)),radius *sin(qDegreesToRadians(xyStepIndex * xyStepAngle))*sin(qDegreesToRadians(xzStepIndex * xzStepAngle)),*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 pVec3ArrayNormal =new osg::Vec3Array; pVec3ArrayNormal->push_back(osg::Vec3f(0,1,0)); pGeometry->setNormalArray(pVec3ArrayNormal); // 步骤五:设置顶点几何绘制方式// LOG size size; pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::DrawArrays::POINTS,0, pVec3ArrayVertex->size)); // 步骤六:绘制几何图形 pGeode->addDrawable(pGeometry.get);#if0 // 步骤七:设置顶点大小 osg::ref_ptr pPoint =new osg::Point; pPoint->setSize(1); pGeometry->getOrCreateStateSet->setAttributeAndModes(pPoint, osg::StateAttribute::ON);#endif return pGeode.get;}

关闭光照函数

voidOsgManager::setLighting(osg::Node *pNode,bool open){ // 步骤一:获取状态集 osg::ref_ptr pStateSet = pNode->getOrCreateStateSet; // 步骤二:状态集 设置深度测试开启,确保透明的物体深度测试开启 pStateSet->setMode(GL_LIGHTING, open ? osg::StateAttribute::ON : osg::StateAttribute::OFF);}

  

  顶点不显示
  

  结点代码:
  

尝试

  改成直线后也不现实,然后拽托下变换视角,发现可以显示
  

  

  所以绘制时出来了,只是看不到,关闭光照就好:
  

  改回点即可。

解决

  关闭光照即可
  

  查看点,是为了检查点对错,上面就是少计算了一个,所以变成圆柱,下面是对的了:
  

来源:戴戴是萌娃

相关推荐