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

news/2024/12/20 14:16:00/文章来源:https://www.cnblogs.com/qq21497936/p/18619168

前言

  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::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 = 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);
#endifreturn 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

  在这里插入图片描述

 

入坑

入坑一:测试绘制顶点的时候,绘制顶点不显示

问题

  顶点不显示
  在这里插入图片描述

  结点代码:
  在这里插入图片描述

尝试

  改成直线后也不现实,然后拽托下变换视角,发现可以显示
  在这里插入图片描述

  在这里插入图片描述

  所以绘制时出来了,只是看不到,关闭光照就好:
  在这里插入图片描述

  改回点即可。

解决

  关闭光照即可
  在这里插入图片描述

  查看点,是为了检查点对错,上面就是少计算了一个,所以变成圆柱,下面是对的了:
  在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/855841.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

流量治理架构对比:当Kmesh遇上Ambient Mesh

Kmesh在控制面升级时或者重启时,即使BPF程序更新,也不会导致业务的连接中断。而节点级用户态代理,天然不具备升级重启不影响业务通信的能力。本文分享自华为云社区《流量治理架构对比:当Kmesh遇上Ambient Mesh》,作者:云容器大未来。 Kmesh是业内首个内核级流量治理引擎,…

ISUP协议视频平台EasyCVR在网页端播放RTSP流对带宽有什么要求?

在现代网络监控系统中,RTSP流的播放是一个关键的技术环节,它涉及视频的实时传输和监控。然而,由于RTSP流的播放在网页端存在一定的技术挑战,需要考虑多种因素,如视频分辨率、编码格式、帧率等,这些因素都会对带宽产生影响。 本文将详细介绍这些因素如何影响带宽需求,并探…

字符串部分语法内容(更新中

字符串部分语法内容 一.字符与ASCII码 1.字符 Q:字符串的作用 A:在日常使用中,我们需要计算机帮我们处理各种各样的文字,比如写文档,写代码,各种文字记录在计算机中,就需要用到字符串或者字符数组将文字内容存储在计算机中。 字符串由字符组成,字符是单引号包含的一个字…

Java项目实战之基于springboot+vue+mysql+jpa+redis的企业网站搭建设计文档设计与实现

一、引言 1.1 项目背景 随着互联网的飞速发展,企业网站已成为企业展示形象、推广产品和服务、与客户沟通的重要窗口。为了提升企业的竞争力,需要构建一个功能完善、用户体验良好的企业网站。 1.2 项目目标 本项目旨在打造一个专业、高效、易用的企业网站,满足企业在品牌展示…

2024 新版Pycharm安装使用教程(附激活至2099年,以及常见问题处理)

Pycharm 简介 Pycharm 是一款非常强大的Python集成开发环境(IDE),由JetBrains公司开发。它提供了丰富的功能和工具,帮助开发者更高效地编写、调试和部署代码。 下面这种方式仅供交流学习,如果有能力还请支持正版 下载安装 为了方便,也可以去链接取 点击获取安装包开始安装下…

OpenCL 编程步骤 4. 创建命令队列 Command Queue

转载 https://deepinout.com/opencl/opencl-basic-tutorials/opencl-create-command-queue.html 在OpenCL上下文中,有内存、程序和内核对象,对这些对象的操作就需要使用命令队列。一条命令就是主机发送给设备的一条消息,用来告诉设备执行一个操作。这个操作包含主机与设备间…

Java线程 interrupt 方法使用异常

背景 需要在异步任务中中断任务的执行,故选择通过调用 interrupt 方法对线程设置中断信号。 在比较耗时的业务代码增加判断 Thread.currentThread().isInterrupted() 抛出异常停止任务执行,并回退任务。 问题 中断信号发出后,任务线程一直未检测到中断信号状态。 以下为测试…

人员检测视频分析服务器安装网络监控系统时有哪些常见的技术挑战?

在构建一个高效、可靠的网络监控系统时,技术人员需要面对一系列技术挑战,这些挑战覆盖了从系统集成到信息安全的各个环节。随着技术的不断进步,尤其是在人工智能和物联网技术的推动下,安防监控系统变得更加复杂和强大。以下是在安装网络监控系统时可能遇到的一些常见技术挑…

六款电脑端简单好用的时间管理app对比推荐

今天分享六款压箱底的时间管理app,简单且好用,让你从此不再拖延!因为我平时工作用Windows电脑比较多,所以主要介绍可以在Win电脑端使用的,部分app还支持在手机端实时同步! 1、微软待办todo 微软生态系统集成,“我的一天” 可将今日任务展示于首页及 Widget 小组件。 “建…

jellyfine套件登录忘记密码

1.ssh登录群晖,管理员模式,进入蓝色路径 var--config---system.xml 2. 用vim命令修改文件内容将<IsStartupWizardCompleted>true</IsStartupWizardCompleted>改成<IsStartupWizardCompleted>false</IsStartupWizardCompleted>重启jellyfin ,重新初始…

排查Java进程占用CPU高的原因

背景 一般java程序占用cpu内存都不会太高,出现占用高的情况,第一反应就是,进程在某个地方死循环了。排查top -Hp 15057 查看下进程中的线程资源占用情况由上图可见,CPU时间片主要是被15393 这个线程给吃掉了, 所以目标锁定在 15393。 执行 printf "%x\n" 15393,…

Java 项目愚蠢的分层及解决方案

《整洁架构之道》的最后一章《细节决定成败》又在讨论 Javaer 永恒的问题:分层后 DAO Service Controller 应该按功能分包还是按层分包。 按功能分包的人认为这些文件在业务上是一起的,应该放在同一个包。按层分包的人认为每个层代表了不同的技术,应该按层分包。 可以想象,…