前言
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::Geodeosg::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