OSG绘制视锥体

news2025/1/24 11:48:57

最近要来实现一个相机位姿态可视化的需求,不想使用pangolin,不好集成,想用osg来做可视化。以下是demo效果。

代码实现:

// Cone_of_vision.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <osgViewer/Viewer>
#include <osg/Camera>
#include <osg/Geode>
#include <osg/Geometry>

// 在创建相机视锥体时计算视锥体顶点和设置边线
osg::ref_ptr<osg::Geode> createCameraFrustum(osg::Camera* camera) {
	osg::ref_ptr<osg::Geode> geode = new osg::Geode();
	osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();

	// 获取相机的投影矩阵和视图矩阵
	osg::Matrixd projectionMatrix = camera->getProjectionMatrix();
	osg::Matrixd viewMatrix = camera->getViewMatrix();

	// 计算视锥体顶点坐标
	osg::Vec3Array* vertices = new osg::Vec3Array(9);
	double nearPlane, farPlane;
	// 获取近和远裁剪平面的值
	double fovY = 1;
	double aspectRatio = 0.5;
	projectionMatrix.getPerspective(fovY, aspectRatio, nearPlane, farPlane);
	farPlane = 1.9;
	double tanFovY = tan(fovY * 0.5);
	double tanFovX = tanFovY * aspectRatio;

	// 近裁剪平面的四个顶点
	(*vertices)[0] = osg::Vec3(0.0, 0.0, 0.0);
	(*vertices)[1] = osg::Vec3(tanFovX * nearPlane, tanFovY * nearPlane, -nearPlane);
	(*vertices)[2] = osg::Vec3(-tanFovX * nearPlane, tanFovY * nearPlane, -nearPlane);
	(*vertices)[3] = osg::Vec3(-tanFovX * nearPlane, -tanFovY * nearPlane, -nearPlane);
	(*vertices)[4] = osg::Vec3(tanFovX * nearPlane, -tanFovY * nearPlane, -nearPlane);

	// 远裁剪平面的四个顶点
	(*vertices)[5] = osg::Vec3(tanFovX * farPlane, tanFovY * farPlane, -farPlane);
	(*vertices)[6] = osg::Vec3(-tanFovX * farPlane, tanFovY * farPlane, -farPlane);
	(*vertices)[7] = osg::Vec3(-tanFovX * farPlane, -tanFovY * farPlane, -farPlane);
	(*vertices)[8] = osg::Vec3(tanFovX * farPlane, -tanFovY * farPlane, -farPlane);

	// 设置视锥体的边线
	osg::ref_ptr<osg::DrawElementsUInt> edges = new osg::DrawElementsUInt(osg::PrimitiveSet::LINES, 24);
	// 给edges数组添加顶点索引来定义边线
	edges->push_back(0); 
	edges->push_back(1);
	edges->push_back(0); 
	edges->push_back(2);
	edges->push_back(0);
	edges->push_back(3);
	edges->push_back(0);
	edges->push_back(4);

	edges->push_back(1);
	edges->push_back(2);
	edges->push_back(3);
	edges->push_back(4);

	edges->push_back(1);
	edges->push_back(4);
	edges->push_back(2);
	edges->push_back(3);


	edges->push_back(0 );
	edges->push_back(1 + 4);
	edges->push_back(0 );
	edges->push_back(2 + 4);
	edges->push_back(0 );
	edges->push_back(3 + 4);
	edges->push_back(0 );
	edges->push_back(4 + 4);
	edges->push_back(1 + 4);
	edges->push_back(2 + 4);
	edges->push_back(3 + 4);
	edges->push_back(4 + 4);

	edges->push_back(1 + 4);
	edges->push_back(4 + 4);
	edges->push_back(2 + 4);
	edges->push_back(3 + 4);

	/*edges->push_back(0);
	edges->push_back(7);
	edges->push_back(0);
	edges->push_back(8);*/

	// 其他边线的索引添加类似的操作...

	// 设置几何体属性
	geometry->setVertexArray(vertices);
	geometry->addPrimitiveSet(edges);

	geode->addDrawable(geometry);

	return geode;
}

osg::ref_ptr<osg::Geode> createPyramid() {
	osg::ref_ptr<osg::Geode> geode = new osg::Geode();
	osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();

	// 顶点数组
	osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
	vertices->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));  // 顶点
	vertices->push_back(osg::Vec3(1.0f, 0.0f, -1.0f)); // 底面顶点1
	vertices->push_back(osg::Vec3(-1.0f, 0.0f, -1.0f)); // 底面顶点2
	vertices->push_back(osg::Vec3(0.0f, 1.0f, 0.0f)); // 底面顶点3
	vertices->push_back(osg::Vec3(0.0f, -1.0f, 0.0f)); // 底面顶点4

	// 设置几何体的顶点
	geometry->setVertexArray(vertices.get());

	// 底面索引数组
	osg::ref_ptr<osg::DrawElementsUInt> baseIndices = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES);
	baseIndices->push_back(1);
	baseIndices->push_back(2);
	baseIndices->push_back(3);

	baseIndices->push_back(2);
	baseIndices->push_back(1);
	baseIndices->push_back(4);

	baseIndices->push_back(3);
	baseIndices->push_back(2);
	baseIndices->push_back(4);

	baseIndices->push_back(1);
	baseIndices->push_back(3);
	baseIndices->push_back(4);

	// 侧面索引数组
	osg::ref_ptr<osg::DrawElementsUInt> sideIndices = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES);
	sideIndices->push_back(0);
	sideIndices->push_back(1);
	sideIndices->push_back(2);

	sideIndices->push_back(0);
	sideIndices->push_back(2);
	sideIndices->push_back(3);

	sideIndices->push_back(0);
	sideIndices->push_back(3);
	sideIndices->push_back(4);

	sideIndices->push_back(0);
	sideIndices->push_back(4);
	sideIndices->push_back(1);

	// 添加底面和侧面索引
	geometry->addPrimitiveSet(baseIndices.get());
	geometry->addPrimitiveSet(sideIndices.get());

	geode->addDrawable(geometry.get());

	return geode;
}

osg::ref_ptr <osg::Geode > cteateQuad()
{
	//创建一个叶节点对象
	osg::ref_ptr <osg::Geode > geode = new osg::Geode();
	//创建一个几何体对象
	osg::ref_ptr <osg::Geometry >geom = new osg::Geometry();
	//添加顶点数据 注意顶点的添加顺序是逆时针
	osg::ref_ptr <osg::Vec3Array >v = new osg::Vec3Array();
	//添加数据
	v->push_back(osg::Vec3(0, 0, 0));
	v->push_back(osg::Vec3(1, 0, 0));
	v->push_back(osg::Vec3(1, 0, 1));
	v->push_back(osg::Vec3(0, 0, 1));

	//设置顶点数据
	geom->setVertexArray(v.get());

	//创建纹理订点数据
	osg::ref_ptr <osg::Vec2Array >vt = new osg::Vec2Array();
	//添加纹理坐标
	vt->push_back(osg::Vec2(0, 0));
	vt->push_back(osg::Vec2(1, 0));
	vt->push_back(osg::Vec2(1, 1));
	vt->push_back(osg::Vec2(0, 1));

	//设置纹理坐标
	geom->setTexCoordArray(0, vt.get());

	//创建颜色数组
	osg::ref_ptr <osg::Vec4Array >vc = new osg::Vec4Array();
	//添加数据
	vc->push_back(osg::Vec4(1, 0, 0, 1));
	vc->push_back(osg::Vec4(0, 1, 0, 1));
	vc->push_back(osg::Vec4(0, 0, 1, 1));
	vc->push_back(osg::Vec4(1, 1, 0, 1));

	//设置颜色数组
	geom->setColorArray(vc.get());
	//设置颜色的绑定方式为单个顶点
	geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);

	//创建法线数组
	osg::ref_ptr <osg::Vec3Array >nc = new osg::Vec3Array();
	//添加法线
	nc->push_back(osg::Vec3(0, -1, 0));
	//设置法线
	geom->setNormalArray(nc.get());
	//设置法绑定为全部顶点
	geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
	//添加图元
	geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));

	//添加到叶子节点
	geode->addDrawable(geom.get());

	return geode.get();
}


int main() {
	// 创建场景图和视图器
	osg::ref_ptr<osg::Group> root = new osg::Group();
	osgViewer::Viewer viewer;

	// 创建四棱锥体几何体
	osg::ref_ptr<osg::Geode> pyramid = createCameraFrustum(viewer.getCamera());
	// 将四棱锥体添加到场景图中
	root->addChild(pyramid);

	// 设置场景图到视图器并运行
	viewer.setSceneData(root);
	return viewer.run();
}

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Angular进阶之六:Progressive rendering

简介 Progressive Rendering 是一种提高 Web 应用性能的方法&#xff0c;允许页面在加载过程中逐步呈现&#xff0c;以提高用户体验。在本文中&#xff0c;我们将探讨如何在 Angular 中通过自定义指令实现 Progressive Rendering&#xff0c;特别是处理从服务器获取大量数据的…

PAT 乙级 1046 划拳

划拳是古老中国酒文化的一个有趣的组成部分。酒桌上两人划拳的方法为&#xff1a;每人口中喊出一个数字&#xff0c;同时用手比划出一个数字。如果谁比划出的数字正好等于两人喊出的数字之和&#xff0c;谁就赢了&#xff0c;输家罚一杯酒。两人同赢或两人同输则继续下一轮&…

数据预处理时,怎样处理类别型特征?

1. 序号编码 序号编码通常用于处理类别间具有大小关系的数据。例如成绩&#xff0c;可以分为低、中、高三档&#xff0c;并且存在“高>中>低”的排序关系。序号编码会按照大小关系对类别型特征赋予一个数值ID&#xff0c;例如高表示为3、中表示为2、低表示为1&#xff0…

【网络安全 | MD5截断比较】PHP、Python脚本利用

前言 在解题中&#xff0c;当遇到类似 substr(md5(a),-6,6) 7788这样的MD5截断比较的题目时&#xff0c;只有求出a的值才能进行接下来的操作。 一个一个去猜是不可能的&#xff0c;通常使用脚本解决&#xff0c;文末给出实战案例。 PHP循环脚本 <?phpfor($i1;$i<9…

机器学习(一) -- 概述

系列文章目录 机器学习&#xff08;一&#xff09; -- 概述 机器学习&#xff08;二&#xff09; -- 数据预处理 未完待续…… 目录 系列文章目录 前言 一、机器学习定义&#xff08;是什么&#xff09; 二、机器学习的应用&#xff08;能做什么&#xff09; 三、***机器…

蒙牛的京东店铺的数字化经营

1、蒙牛的京东店铺的数字化经营框架是怎样的&#xff1f; 2. 蒙牛的京东店铺是如何进行环境分析的&#xff1f; 结合波特五力模型进行分析&#xff1a;客户、供应商、企业自身、潜在竞争对手、同行业竞争对手 3.蒙牛的京东店铺采取了哪些方式进行线上引流&#xff1f; 找智商长…

2023-12-23 LeetCode每日一题(移除石子使总数最小)

2023-12-23每日一题 一、题目编号 1962. 移除石子使总数最小二、题目链接 点击跳转到题目位置 三、题目描述 给你一个整数数组 piles &#xff0c;数组 下标从 0 开始 &#xff0c;其中 piles[i] 表示第 i 堆石子中的石子数量。另给你一个整数 k &#xff0c;请你执行下述…

Zookeeper-Zookeeper应用场景实战(二)

1. Zookeeper 分布式锁实战 1.1 什么是分布式锁 在单体的应用开发场景中涉及并发同步的时候&#xff0c;大家往往采用Synchronized&#xff08;同步&#xff09;或者其他同一个 JVM内Lock机制来解决多线程间的同步问题。在分布式集群工作的开发场景中&#xff0c;就需要 一种…

Spring Cloud Gateway + Nacos 实现动态路由

1、maven 依赖 主要依赖 <!-- 网关 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>案件差不多完整主要依赖 <!--Spring boot 依赖(微服务基…

LLM之RAG实战(九)| 高级RAG 03:多文档RAG体系结构

在RAG&#xff08;检索和生成&#xff09;这样的框架内管理和处理多个文档有很大的挑战。关键不仅在于提取相关内容&#xff0c;还在于选择包含用户查询所寻求的信息的适当文档。基于用户查询对齐的多粒度特性&#xff0c;需要动态选择文档&#xff0c;本文将介绍结构化层次检索…

四种常见智能指针的介绍

一、介绍 当类中有指针成员时&#xff0c;一般有两种方式来管理指针成员&#xff1a;一是采用值型的方式管理&#xff0c;每个类对象都保留一份指针指向的对象的拷贝&#xff1b;另一种更优雅的方式是使用智能指针(smart pointer)&#xff0c;从而实现指针指向的对象的共享。 …

UDP协议基本原理

前言 本文主要讲解传输层中的UDP协议&#xff0c;我准备从UDP的特点出发&#xff0c;深入理解UDP协议&#xff0c;从UDP协议的结构推出UDP协议的特点&#xff1b; 一、理解端口号 前面我们总是说用IP加端口号的方式定位全网的唯一进程&#xff0c;通常在TCP/IP中&#xff0c;我…

gitee(码云)仓库内容更新,使用TortoiseGit同步本地仓库和远程仓库

前言&#xff1a; 网上有很多同步仓库教程&#xff0c;但都是git命令行操作。这篇使用TortoiseGit可视化操作同步本地仓库和远程仓库 克隆本地仓库&#xff0c;上传远程仓库&#xff0c;下载TortoiseGit可以看这篇使用gitee&#xff08;码云&#xff09;上传自己的代码&#xf…

电脑忘记开机密码很着急?一招搞定

前言 本教程适合没有登录微软账号的电脑哦&#xff5e; 随着手机越智能&#xff0c;人们花在电脑上的时间越来越少了。你家的电脑多久没开机了&#xff1f; 小伙伴有没有这样的经历&#xff1a;很久没有打开过电脑的你&#xff0c;突然有一天打开了电脑&#xff0c;却想不起…

继续声明 | 连声明都抄,谁抄袭谁,一目了然,现在竟然恬不知耻的反咬一口。

继续声明 | 连声明都抄&#xff0c;谁抄袭谁&#xff0c;一目了然&#xff0c;现在竟然恬不知耻的反咬一口。 一、本账号为《机器学习之心》博主CSDN唯一官方账号&#xff0c;唯一联系方式见文章底部。 二、《机器学习之心》博主未授权任何第三方账号进行模型合作、程序设计、…

harmonyOS Column组件通过space属性设置内部元素间距

例如 我们代码如下 import router from ohos.router Entry Component struct Index {build() {Row() {Column() {Text("年后")Text("一起")Text("旅游")}.width(100%)}.height(100%)} }运行之后 元素都粘连到一起 显然不太好看 我们就可以通过…

FPGA - 231227 - 5CSEMA5F31C6 - 电子万年历

TAG - F P G A 、 5 C S E M A 5 F 31 C 6 、电子万年历、 V e r i l o g FPGA、5CSEMA5F31C6、电子万年历、Verilog FPGA、5CSEMA5F31C6、电子万年历、Verilog 顶层模块 module TOP(input CLK,RST,inA,inB,inC,switch_alarm,output led,beep_led,output [41:0] dp );// 按键…

SaaS版Java基层健康卫生云HIS信息管理平台源码(springboot)

云his系统源码&#xff0c;系统采用主流成熟技术开发&#xff0c;B/S架构&#xff0c;软件结构简洁、代码规范易阅读&#xff0c;SaaS应用&#xff0c;全浏览器访问&#xff0c;前后端分离&#xff0c;多服务协同&#xff0c;服务可拆分&#xff0c;功能易扩展。多集团统一登录…

如何使用ModuleShifting测试Module Stomping和Module Overloading注入技术

关于ModuleShifting ModuleShifting是一款针对Module Stomping和Module Overloading注入技术的安全测试工具&#xff0c;该工具基于Python ctypes实现其功能&#xff0c;因此可以通过Python解释器或Pyramid在内存中完整执行&#xff0c;这样就可以避免使用编译加载器了。 需要…

Maya-UE xgen-UE 毛发导入UE流程整理

首先声明&#xff1a;maya建议用2022版本及一下&#xff0c;因为要用到Python 2 ,Maya2023以后默认是Python3不再支持Python2; 第一步&#xff1a;Xgen做好的毛发转成交互式Groom 第二步&#xff1a;导出刚生成的交互式Groom缓存&#xff0c;需要设置一下当前帧&#xff0c;和…