OSG开发笔记(四十):使用OSG自绘拟合球形顶点
OSG内置的几何图形并没有球面,那么绘制球面先要绘制球面的组成顶点,本篇解说绘制球面组成顶点的详细过程。
若该文为原创文章,未经允许不得转载
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/144609131
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…
OSG开发专栏(点击传送门)
上一篇:《OSG开发笔记(三十九):OSG中模型的透明度实现、球体透明度Demo》
下一篇:持续补充中…
前言
OSG内置的几何图形并没有球面,那么绘制球面先要绘制球面的组成顶点,本篇解说绘制球面组成顶点的详细过程。
Demo
组成面的时候,为了看到是否正确,取中间的几个圆环:
回顾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
Demo源码
节点完整绘制函数
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::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 0
// 步骤七:设置顶点大小
osg::ref_ptr<osg::Point> pPoint = new osg::Point();
pPoint->setSize(1);
pGeometry->getOrCreateStateSet()->setAttributeAndModes(pPoint, osg::StateAttribute::ON);
#endif
return pGeode.get();
}
关闭光照函数
void OsgManager::setLighting(osg::Node *pNode, bool open)
{
// 步骤一:获取状态集
osg::ref_ptr<osg::StateSet> pStateSet = pNode->getOrCreateStateSet();
// 步骤二:状态集 设置深度测试开启,确保透明的物体深度测试开启
pStateSet->setMode(GL_LIGHTING, open ? osg::StateAttribute::ON : osg::StateAttribute::OFF);
}
工程模板v1.40.0
入坑
入坑一:测试绘制顶点的时候,绘制顶点不显示
问题
顶点不显示
结点代码:
尝试
改成直线后也不现实,然后拽托下变换视角,发现可以显示
所以绘制时出来了,只是看不到,关闭光照就好:
改回点即可。
解决
关闭光照即可
查看点,是为了检查点对错,上面就是少计算了一个,所以变成圆柱,下面是对的了:
上一篇:《OSG开发笔记(三十九):OSG中模型的透明度实现、球体透明度Demo》
下一篇:持续补充中…
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/144609131
更多推荐
所有评论(0)