7、虚幻引擎在c++代码中获取视椎体平面、fov、视点和视椎体剔除

1、获取fov

const double fov = UGameplayStatics::GetPlayerCameraManager(this, 0)->GetFOVAngle();

2、获取视点坐标(世界坐标系)和视口高度

if (auto world = this->GetWorld()) {
	if (auto gameView = world->GetGameViewport())
	{
		if (auto viewport = gameView->Viewport)
		{
			//获取视口高度
			const int32 viewportHeight = viewport->GetSizeXY().Y;
			//视点的屏幕坐标
			FVector2D viewportScreenCoord= FVector2D(viewport->GetSizeXY().X / 2, viewportHeight / 2);
			FVector viewportWorldCoord, direction;
			//viewportWorldCoord就是视点在世界坐标下的坐标
			UGameplayStatics::DeprojectScreenToWorld(world->GetFirstPlayerController(), viewportScreenCoord, viewportWorldCoord, direction);
		}
	}
}

3、获取视椎体的near、top、bottom、left、right的平面(透视相机)
为什么没有far平面呢,跟踪源码可知,远平面并不是固定的是动态计算的,我目前的需求也不需要获取远平面。而且远平面也可以根据自己的需要动态指定

/// <summary>
/// 获取屏幕四个角点的屏幕坐标
/// </summary>
/// <param name="OutTopLeft">左上角</param>
/// <param name="OutTopRight">右上角</param>
/// <param name="OutBottomLeft">左下角</param>
/// <param name="OutBottomRight">右下角</param>
void getViewportCorners(FVector2D& OutTopLeft, FVector2D& OutTopRight, FVector2D& OutBottomLeft, FVector2D& OutBottomRight)
{
	if (UWorld* world = GetWorld()) {
		if (APlayerController* PlayerController = world->GetFirstPlayerController())
		{
			int32 sizeX, sizeY;
			PlayerController->GetViewportSize(sizeX, sizeY);
			OutTopLeft = FVector2D(0.0, 0.0);
			OutTopRight = FVector2D(sizeX, 0);
			OutBottomLeft = FVector2D(0, sizeY);
			OutBottomRight = FVector2D(sizeX, sizeY);

		}
	}
}
/// <summary>
/// 根据屏幕坐标获取射线(射线方向是从视点到输入的屏幕坐标)
/// </summary>
/// <param name="InScreenPosition">屏幕坐标</param>
/// <param name="OutLineStartpoint">屏幕坐标点在世界坐标系下的坐标</param>
/// <param name="OutLineEndpoint">沿着射线方向一定距离的点</param>
void getFrustumEdgeEndpoint(FVector2D InScreenPosition, FVector& OutLineStartpoint, FVector& OutLineEndpoint)
{
	if (UWorld* world = GetWorld()) {
		FVector worldPosition, worldDirection;
		UGameplayStatics::DeprojectScreenToWorld(world->GetFirstPlayerController(), InScreenPosition, worldPosition, worldDirection);
		UCameraComponent* CameraComponent = world->GetFirstPlayerController()->GetPawn()->FindComponentByClass<UCameraComponent>();
		FMinimalViewInfo CaptureView;
		CameraComponent->GetCameraView(0, CaptureView);
		const float farPlaneDistance = 0.0;
		const float nearPlaneDistance = CaptureView.PerspectiveNearClipPlane > 0.0 ? CaptureView.PerspectiveNearClipPlane : GNearClippingPlane;
		OutLineEndpoint = worldPosition + worldDirection * 100000;
		OutLineStartpoint = worldPosition;

	}

}
/// <summary>
/// 获取视椎体平面(平面法向量方向指向视椎体内部)
/// </summary>
/// <param name="OutLeftPlane"></param>
/// <param name="OutRightPlane"></param>
/// <param name="OutTopPlane"></param>
/// <param name="OutBottomPlane"></param>
/// <param name="OutNearPlane"></param>
void getViewFrustumPlanes(FPlane4d& OutLeftPlane, FPlane4d& OutRightPlane, FPlane4d& OutTopPlane, FPlane4d& OutBottomPlane, FPlane4d& OutNearPlane)
{
	FVector2D topLeft, topRight, bottomLeft, bottomRight;
	_getViewportCorners(topLeft, topRight, bottomLeft, bottomRight);
	FVector topLeftStartpoint, topLeftEndpoint;
	_getFrustumEdgeEndpoint(topLeft, topLeftStartpoint, topLeftEndpoint);
	FVector topRightStartpoint, topRightEndpoint;
	_getFrustumEdgeEndpoint(topRight, topRightStartpoint, topRightEndpoint);
	FVector bottomLeftStartpoint, bottomLeftEndpoint;
	_getFrustumEdgeEndpoint(bottomLeft, bottomLeftStartpoint, bottomLeftEndpoint);
	FVector bottomRightStartpoint, bottomRightEndpoint;
	_getFrustumEdgeEndpoint(bottomRight, bottomRightStartpoint, bottomRightEndpoint);

	FVector leftPlaneNoraml = -FVector::CrossProduct((topLeftStartpoint - topLeftEndpoint), (bottomLeftEndpoint - topLeftEndpoint));
	leftPlaneNoraml.Normalize();
	OutLeftPlane = FPlane4d(topLeftEndpoint, leftPlaneNoraml);

	FVector rightPlaneNoraml = -FVector::CrossProduct((topRightEndpoint - topRightStartpoint), (bottomRightStartpoint - topRightStartpoint));
	rightPlaneNoraml.Normalize();
	OutRightPlane = FPlane4d(topRightStartpoint, rightPlaneNoraml);

	FVector topPlaneNoraml = FVector::CrossProduct((topLeftStartpoint - topLeftEndpoint), (topRightEndpoint - topLeftEndpoint));
	topPlaneNoraml.Normalize();
	OutTopPlane = FPlane4d(topLeftEndpoint, topPlaneNoraml);

	FVector bottomPlaneNoraml = -FVector::CrossProduct((bottomLeftStartpoint - bottomLeftEndpoint), (bottomRightEndpoint - bottomLeftEndpoint));
	bottomPlaneNoraml.Normalize();
	OutBottomPlane = FPlane4d(bottomLeftEndpoint, bottomPlaneNoraml);

	FVector nearPlaneNoraml = FVector::CrossProduct((topLeftStartpoint - topRightStartpoint), (bottomRightStartpoint - topRightStartpoint));
	nearPlaneNoraml.Normalize();
	OutNearPlane = FPlane4d(topRightStartpoint, nearPlaneNoraml);
}
/// <summary>
/// 获取osg坐标系下的视椎体平面(平面法向量方向指向视椎体内部)
/// </summary>
/// <param name="OutLeftPlane"></param>
/// <param name="OutRightPlane"></param>
/// <param name="OutTopPlane"></param>
/// <param name="OutBottomPlane"></param>
/// <param name="OutNearPlane"></param>
void getViewFrustumPlanes(osg::Plane& OutLeftPlane, osg::Plane& OutRightPlane, osg::Plane& OutTopPlane, osg::Plane& OutBottomPlane, osg::Plane& OutNearPlane)
{
	FVector2D topLeft, topRight, bottomLeft, bottomRight;
	_getViewportCorners(topLeft, topRight, bottomLeft, bottomRight);
	FVector topLeftStartpoint, topLeftEndpoint;
	_getFrustumEdgeEndpoint(topLeft, topLeftStartpoint, topLeftEndpoint);
	FVector topRightStartpoint, topRightEndpoint;
	_getFrustumEdgeEndpoint(topRight, topRightStartpoint, topRightEndpoint);
	FVector bottomLeftStartpoint, bottomLeftEndpoint;
	_getFrustumEdgeEndpoint(bottomLeft, bottomLeftStartpoint, bottomLeftEndpoint);
	FVector bottomRightStartpoint, bottomRightEndpoint;
	_getFrustumEdgeEndpoint(bottomRight, bottomRightStartpoint, bottomRightEndpoint);

	auto ConvertCoordinate = [](FVector point) {
		double X = point.X / 100.0;
		double Y = -point.Y / 100.0;
		double Z = point.Z / 100.0;
		return osg::Vec3f(X, Y, Z);
		};

	osg::Vec3f leftPlaneNormalOsg = (ConvertCoordinate(topLeftStartpoint) - ConvertCoordinate(topLeftEndpoint)) ^ (ConvertCoordinate(bottomLeftEndpoint) - ConvertCoordinate(topLeftEndpoint));
	leftPlaneNormalOsg.normalize();
	OutLeftPlane = osg::Plane(leftPlaneNormalOsg, ConvertCoordinate(topLeftEndpoint));

	osg::Vec3f rightPlaneNormalOsg = (ConvertCoordinate(topRightEndpoint) - ConvertCoordinate(topRightStartpoint)) ^ (ConvertCoordinate(bottomRightStartpoint) - ConvertCoordinate(topRightStartpoint));
	rightPlaneNormalOsg.normalize();
	OutRightPlane = osg::Plane(rightPlaneNormalOsg, ConvertCoordinate(topRightStartpoint));

	osg::Vec3f topPlaneNormalOsg = -(ConvertCoordinate(topLeftStartpoint) - ConvertCoordinate(topLeftEndpoint)) ^ (ConvertCoordinate(topRightEndpoint) - ConvertCoordinate(topLeftEndpoint));
	topPlaneNormalOsg.normalize();
	OutTopPlane = osg::Plane(topPlaneNormalOsg, ConvertCoordinate(topLeftEndpoint));

	osg::Vec3f bottomPlaneNormalOsg = (ConvertCoordinate(bottomLeftStartpoint) - ConvertCoordinate(bottomLeftEndpoint)) ^ (ConvertCoordinate(bottomRightEndpoint) - ConvertCoordinate(bottomLeftEndpoint));
	bottomPlaneNormalOsg.normalize();
	OutBottomPlane = osg::Plane(bottomPlaneNormalOsg, ConvertCoordinate(bottomLeftEndpoint));

	osg::Vec3f nearPlaneNormalOsg = -(ConvertCoordinate(topLeftStartpoint) - ConvertCoordinate(topRightStartpoint)) ^ (ConvertCoordinate(bottomRightStartpoint) - ConvertCoordinate(topRightStartpoint));
	nearPlaneNormalOsg.normalize();
	OutNearPlane = osg::Plane(nearPlaneNormalOsg, ConvertCoordinate(topRightStartpoint));

}


4、视椎体剔除(在osg坐标系下进行剔除(我把虚幻坐标转换为osg坐标了,我的需求就是这样,也可以在虚幻坐标系下进行剔除))

struct Frustum {
	osg::Plane leftPlane, rightPlane, topPlane, bottomPlane, nearPlane;
	Frustum() {}
	Frustum(const osg::Plane leftPlane, const osg::Plane rightPlane, const osg::Plane topPlane, const osg::Plane bottomPlane, const osg::Plane nearPlane) {
		//要求视椎体的各个平面的法向量方向是指向视椎体内部的
		this->leftPlane = leftPlane;
		this->rightPlane = rightPlane;
		this->topPlane = topPlane;
		this->bottomPlane = bottomPlane;
		this->nearPlane = nearPlane;
		ExpandFrustum(5000.0);//扩大视椎体范围,将五个平面后移5000米
	}
	void ExpandFrustum(float distance) {
		//沿着法向量反方向平移平面(向视椎体外部平移)
		leftPlane[3] += distance;
		rightPlane[3] += distance;
		topPlane[3] += distance;
		bottomPlane[3] += distance;
		nearPlane[3] += distance;
	}
	bool IsInFrustum(const osg::BoundingBox InBoundingBox)
	{

		if (leftPlane.intersect(InBoundingBox) > -1 && rightPlane.intersect(InBoundingBox) > -1 && topPlane.intersect(InBoundingBox) > -1 && bottomPlane.intersect(InBoundingBox) > -1 && nearPlane.intersect(InBoundingBox) > -1) {
			return true;
		}
		return false;
	}

	bool IsInFrustum(const osg::BoundingSphere InBoundingSphere)
	{
		if (leftPlane.intersect(InBoundingSphere) > -1 && rightPlane.intersect(InBoundingSphere) > -1 && topPlane.intersect(InBoundingSphere) > -1 && bottomPlane.intersect(InBoundingSphere) > -1 && nearPlane.intersect(InBoundingSphere) > -1) {
			return true;
		}
		return false;
	}
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Junit 历史-ApiHug准备-测试篇-008

&#x1f917; ApiHug {Postman|Swagger|Api...} 快↑ 准√ 省↓ GitHub - apihug/apihug.com: All abou the Apihug apihug.com: 有爱&#xff0c;有温度&#xff0c;有质量&#xff0c;有信任ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace 背景 J…

【人工智能书籍】一本书读懂AIGC:ChatGPT、AI绘画、智能文明与生产力变革(PDF分享)

今天又来给大家推荐一本人工智能方面的书籍<一本书读懂AIGC&#xff1a;ChatGPT、AI绘画、智能文明与生产力变革>。本书以通俗易懂的方式从各个层面介绍了AIGC的基础知识&#xff0c;并辅以大量案例引领读者了解AIGC的应用实践&#xff0c;让读者可以更快速地利用AIGC改善…

02节-51单片机-LED模块

文章目录 1.点亮一个LED灯2.LED闪烁3.LED流水灯 1.点亮一个LED灯 #include <REGX52.H> void main() {P20xFE; //1111 1110while(1){} }2.LED闪烁 增加延时&#xff0c;控制LED的亮灭间隙 延时函数的添加依靠STC-ISP软件的延时函数功能代码自动生成&#xff0c;如图 #i…

递归 python

↵一、简单理解 解决问题的一种方法&#xff0c;它将问题不断的分成更小的子问题&#xff0c;直到子问题可以用普通的方法解决。通常情况下&#xff0c;递归会使用一个不停调用自己的函数。 【注】&#xff1a;每一次递归调用都是在解决一个更小的问题&#xff0c;如此进行下…

数据库管理-第171期 Oracle是用这种方式确保读一致的(20240418)

数据库管理171期 2024-04-18 数据库管理-第171期 Oracle是用这种方式确保读一致的&#xff08;20240418&#xff09;1 基本概念2 用处3 注意事项总结 数据库管理-第171期 Oracle是用这种方式确保读一致的&#xff08;20240418&#xff09; 作者&#xff1a;胖头鱼的鱼缸&#x…

Docker文档阅读笔记-How to Run GUI Based Applications inside Docker?

以后的文档阅读笔记不在一一介绍。以后只总结干货和重点。 Step 1 使用Systemctl命令启动docker服务&#xff1a; systemctl start docker // to start the docker service. systemctl status docker // to check the status . systemctl restart docke…

mybatis创建入门流程体验

mysql数据库中建表 drop table if exists tb_user;create table tb_user(id int primary key auto_increment,username varchar(20),password varchar(20),gender char(1),addr varchar(30) );INSERT INTO tb_user VALUES (1, zhangsan, 123, 男, 北京); INSERT INTO tb_user …

四川易点慧电子商务抖音小店:安全先行,购物无忧

随着互联网的飞速发展&#xff0c;电子商务已成为人们日常购物的重要渠道。抖音小店作为新兴的电商平台&#xff0c;凭借其独特的社交属性和庞大的用户基础&#xff0c;迅速崛起并吸引了众多商家的入驻。在这个背景下&#xff0c;四川易点慧电子商务有限公司&#xff08;以下简…

Android11应用安装未知来源的权限改动

最近开发的App需要下载安装另一个App。这就涉及到了app的安装代码。关于App的安装代码&#xff0c;写了不少&#xff0c;所以这一块觉得不是问题&#xff1a; 判断版本&#xff0c;Android8.0判断是否有未知来源安装全选&#xff0c;没有则打开未知来源安装权限设置界面去开启…

Linux并发程序设计(1):进程的创建和回收

目录 1、基本概念概念 1.1 程序 1.2 进程 1.3 进程的内容 1.4 进程类型 1.5 进程状态 2、常用命令 2.1 查看进程信息 2.2 改变进程优先级 2.2.1 按用户指定的优先级运行进程 2.2.2 改变正在运行进程的优先级 2.3 其他相关指令 3、进程的创建和结束 3.1 子进程创建 3.1.1 …

Odoo讨论+聊天模块:一体化内部协作平台,赋能高效沟通与业务流程协作

Odoo讨论聊天模块&#xff1a;一体化内部协作平台&#xff0c;赋能高效沟通与业务流程协作 Odoo 讨论模块是一个集成了即时通讯、文件共享、业务关联、权限控制等功能于一体的内部协作工具&#xff0c;允许用户通过跨模块的聊天窗口或通过专用的“讨论”面板互相发送消息、分享…

Golang(一):基础、数组、map、struct

目录 hello world 变量 常量&#xff0c;iota 函数 init函数和导包过程 指针 defer 数组和动态数组 固定长度数组 遍历数组 动态数组 len 和 cap 截取 切片的追加 map 四种声明方式 遍历map 删除 查看键是否存在 结构体 声明 作为形参 方法 封装 继承…

笔记软件功能多样的是哪款?做笔记的软件哪个好用

在快节奏的现代生活中&#xff0c;笔记软件已成为我们提高工作效率、记录生活点滴的重要工具。想象一下&#xff0c;在繁忙的工作中&#xff0c;你能够快速记录下关键信息&#xff0c;或在灵感迸发时及时捕捉&#xff0c;这是多么方便高效。 一款功能多样的笔记软件&#xff0…

Syncovery for Mac:高效文件备份和同步工具

Syncovery for Mac是一款专为Mac用户设计的文件备份和同步工具&#xff0c;凭借其高效、安全和易用的特点&#xff0c;深受用户好评。 Syncovery for Mac v10.14.2激活版下载 该软件具备强大的备份功能&#xff0c;支持多种备份方案和数据格式&#xff0c;用户可以根据需求轻松…

Python教学入门:函数

在 Python 中&#xff0c;def 关键字用于定义函数。函数是一段可重用的代码块&#xff0c;用于执行特定的任务或操作。通过定义函数&#xff0c;可以将一段代码封装起来&#xff0c;使其可以在程序中被多次调用&#xff0c;提高代码的复用性和可维护性。 下面是 def 函数定义的…

pandas/python 一个实战小案例

上次写坦克游戏的时候&#xff0c;接触了一点pandas&#xff0c;当时只是简单了解了一下如何遍历行和列并获取值来替换图片&#xff0c;想更多了解pandas。正好有一些数据需要筛选&#xff0c;试试能不能用通过代码实现。虽然总的来说不复杂&#xff0c;但由于原始数据在命名、…

如何训练猫出门不害怕:耐心做好这些训练,轻松get能溜的小猫

一般我们外出见到的都是遛狗的&#xff0c;溜猫的相对少见&#xff0c;一方面是因为猫咪是喜欢安静独处的小动物&#xff0c;另一方面是糟乱的环境也容易引起猫咪的应激。对于是否应该“溜猫”&#xff0c;有两个极端的阵营。一些铲屎官认为应尊重猫的天性&#xff0c;胆小不爱…

如何使用AI写作扩写文章?看完这篇学会扩写

如何使用AI写作扩写文章&#xff1f;在数字化时代的浪潮下&#xff0c;人工智能&#xff08;AI&#xff09;已经深入渗透到我们生活的各个领域&#xff0c;其中&#xff0c;AI写作扩写技术更是以其高效、便捷的特点受到了广大用户的青睐。它不仅极大提升了写作效率&#xff0c;…

Leetcode算法训练日记 | day29

一、递增子序列 1.题目 Leetcode&#xff1a;第 491 题 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 数组中可能含有重复元素&#xff0c;如出现两个整数相等&…

硬件?、嘉立创EDA画PCB规则设计

1、打开规则设计 设置单位为mil 点击全部 将安全距离设置为8mil&#xff0c;这个8mil是目前很多生产PCB的工厂可以做的&#xff0c;如果距离设置的更小也就是性能要求更高&#xff0c;相应的生产成本也高元件到元件的距离设置为20mil 2、设置导线的宽度规则&#xff0c;可以对v…