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;
	}
};
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Epic Games今天宣布,正式发布“虚幻引擎4”(Unreal Engine 4/UE4),相关所有资源也一并放出。# h9 u6 O( p! y& D) q4 K7 P9 ~# N   只要每个月花19美元,你就能到全部资源,包括拿过来就能用的虚幻编辑器(Unreal Editor),GitHub上的完整C++代码(支持微软Visual Studio/苹果Xcode),还有完整的生态系统:论坛、维基、问答、协作。8 t8 q& _* ?7 K. D) S6 W 一大波新游戏要来了 虚幻4引擎正式发布, s! f+ v' w9 M j3 y: ^   而在虚幻引擎4游戏的销售,Epic将抽取5%的毛收入提升,也就是你的游戏赚了100万美元,就要交给Epic 5万美元。   回到技术方面,Epic号称虚幻引擎4是他们多年来心血的结晶,而且现在只是第一版,才刚刚开始。C++代码里你可以看到大量的创新,比如说支持虚拟立体偷窥Oculus VR,支持Linux操作系统,以及支持Valve SteamWorks、StreamBox,而且还可以通过HTML5在网页浏览器内开发游戏(页游)。   平台支持PC、PS4、Xbox One、iOS、Google等等。   虚幻引擎4基于DirectX 11,拥有新的材料流水线、蓝图觉化脚本、直观蓝图调试、内容浏览器、人物动画、Matinee影院级工具集、全新地形和植被、后期处理效果、热重载(Hot Reload)、模拟与沉浸式角、即时游戏预览、AI人工智能、音频、间件集成等一系列全新特性。   虚幻引擎4现已开始提供授权。 现在提供网盘下载地址,毕竟到官方下载很麻烦,还要$,呵呵,10分很值得,代码风格很好,注释很爽!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值