首页 > 其他分享 >UE4 中射线检测的简单探索

UE4 中射线检测的简单探索

时间:2024-09-01 19:14:02浏览次数:2  
标签:Hits const 探索 射线 HitBufferSync return Traits GetNumHits UE4

通过源码了解实现简单的实现原理。非常粗浅,只涉及一些基本的调用路径。
LineTrace...这个函数实际上是调用的TSceneCastCommon这个模板函数

template <typename Traits, typename TGeomInputs>
bool TSceneCastCommon(const UWorld* World, typename Traits::TOutHits& OutHits, const TGeomInputs& GeomInputs, const FVector Start, const FVector End, ECollisionChannel TraceChannel, const struct FCollisionQueryParams& Params, const struct FCollisionResponseParams& ResponseParams, const struct FCollisionObjectQueryParams& ObjectParams)

首先它是调用的RaycastSingle函数

using TCastTraits = TSQTraits<FHitRaycast, ESweepOrRay::Raycast, ESingleMultiOrTest::Single>;
return TSceneCastCommon<TCastTraits>(World, OutHit, FRaycastSQAdditionalInputs(), Start, End, TraceChannel, Params, ResponseParams, ObjectParams);

TSQTraits结构体

该结构体会存储或者设置我们检测中需要用到的变量,利用上方的using进行初始赋值
其中最主要的就是

using THitBuffer = typename TChooseClass<InSingleMultiOrTest == ESingleMultiOrTest::Multi, FDynamicHitBuffer<InHitType>, typename TChooseClass<InGeometryQuery == ESweepOrRay::Sweep, FSingleHitBuffer<FHitSweep>, FSingleHitBuffer<FHitRaycast>>::Result >::Result;

后续会出现的函数

IsRay() 检测当前的扫描类型

constexpr static bool IsRay() { return GeometryQuery == ESweepOrRay::Raycast;  }

GetNumHits() 检测命中的数量

针对multi和single有不同的检测返回

// GetNumHits - multi
template <ESingleMultiOrTest T = SingleMultiOrTest>
static typename TEnableIf<T == ESingleMultiOrTest::Multi, int32>::Type GetNumHits(const THitBuffer& HitBuffer)
{
	return HitBuffer.GetNumHits();
}

// GetNumHits - single/test
template <ESingleMultiOrTest T = SingleMultiOrTest>
static typename TEnableIf<T != ESingleMultiOrTest::Multi, int32>::Type GetNumHits(const THitBuffer& HitBuffer)
{
	return GetHasBlock(HitBuffer) ? 1 : 0;
}

HitBuffer.GetNumHits()

其调用的是根据TChooseClass选择出来的扫描类型的命中结果中的函数

	FORCEINLINE int32 GetNumHits() const
	{
		return Hits.Num();
	}

而这些实际的HitBuffer类里面存在着一个Hits成员变量

//Engine\Source\Runtime\PhysicsCore\Public\PhysXInterfaceWrapperCore.h
/** Hits encountered. Can be larger than HIT_BUFFER_SIZE */
TArray<TTypeCompatibleBytes<HitType>, TInlineAllocator<HIT_BUFFER_SIZE>> Hits;

//当发生碰撞时会执行该回调函数,向Hits数组里面加入数据
virtual PxAgain processTouches(const HitType* buffer, PxU32 nbHits) override
{
	Hits.Append((TTypeCompatibleBytes<HitType>*)buffer, nbHits);
	return true;
}

TSceneCastCommon函数

在该函数中,首先会进行射线检测距离的计算

	FVector Delta = End - Start;
	float DeltaSize = Delta.Size();
	float DeltaMag = FMath::IsNearlyZero(DeltaSize) ? 0.f : DeltaSize;
	float MinBlockingDistance = DeltaMag;

然后如果有添加了Ignore的对象,会进行处理。
接着就会开始进行检测了,Traits就是TSQTraits结构体

typename Traits::THitBuffer HitBufferSync; //HitBufferSync用来存储命中的缓存结果

bool bBlockingHit = false;
const FVector Dir = DeltaMag > 0.f ? (Delta / DeltaMag) : FVector(1, 0, 0);
const FTransform StartTM = Traits::IsRay() ? FTransform(Start) : FTransform(*GeomInputs.GetGeometryOrientation(), Start); //通过判断检测类型

接着会对当前的物理场景进行冻结,避免其他因素的影响

// Enable scene locks, in case they are required
FPhysScene& PhysScene = *World->GetPhysicsScene();

FScopedSceneReadLock SceneLocks(PhysScene);
{
	FScopedSQHitchRepeater<decltype(HitBufferSync)> HitchRepeater(HitBufferSync, QueryCallback, FHitchDetectionInfo(Start, End, TraceChannel, Params));
	do
	{
		Traits::SceneTrace(PhysScene, GeomInputs, Dir, DeltaMag, StartTM, HitchRepeater.GetBuffer(), Traits::GetHitFlags(), Traits::GetQueryFlags(), Filter, Params, &QueryCallback);
	} while (HitchRepeater.RepeatOnHitch());
}

冻结之后会进行命中检测

const int32 NumHits = Traits::GetNumHits(HitBufferSync);

通过获得的NumHits个数来判断是否成功命中,然后返回最近的命中结果

if(NumHits > 0 && GetHasBlock(HitBufferSync))
{
	bBlockingHit = true;
	MinBlockingDistance = GetDistance(Traits::GetHits(HitBufferSync)[NumHits - 1]);
}

标签:Hits,const,探索,射线,HitBufferSync,return,Traits,GetNumHits,UE4
From: https://www.cnblogs.com/XTG111/p/18391594

相关文章

  • 探索一下 Enum 优化u0
    探索一下Enum优化SV.Enums主要是探索如何让enum更高效其中涉及的优化手段并非完全自创很多内容参考于以下项目NetEscapades.EnumGeneratorsFastEnumruntime主要优化手段其实主要全是空间换时间,大量缓存封装入口方法以及source-generators生成不过本项目尝试了......
  • 探索Java的String魔法:揭秘“+”操作符的实现
    探索Java的String魔法:揭秘“+”操作符的实现在Java的世界里,String是一个无处不在的数据类型,它用于存储和操作文本数据。String的“+”操作符是连接字符串的常用方式,但你是否曾想过,这个看似简单的操作符背后隐藏着怎样的魔法?本文将深入探讨Java中String的“+”操作符是如何......
  • 探索函数式编程:纯函数 | 高阶函数 | 函数柯里化 | 组合函数
    函数式编程概述定义函数式编程(FP:Functionalprogramming)是一种范式,强调使用函数来构建程序,并且避免使用状态改变和可变数据(避免函数的执行存在副作用)→范式,用函数来"组合"以及"处理数据"(将运算过程抽象成函数)复用特点函数是第一等公民:在函数式编程语言中,函数......
  • 转载-perf-深入探索 perf CPU Profiling 实现原理
    https://mazhen.tech/p/深入探索-perf-cpu-profiling-实现原理/深入探索perfCPUProfiling实现原理perf是什么perf是由Linux官方提供的系统性能分析工具。我们通常说的perf实际上包含两部分:perf命令,用户空间的应用程序perf_events,Linux内核中的一个子系统内......
  • 探索一下 Enum 优化
    探索一下Enum优化SV.Enums主要是探索如何让enum更高效其中涉及的优化手段并非完全自创很多内容参考于以下项目NetEscapades.EnumGeneratorsFastEnumruntime主要优化手段其实主要全是空间换时间,大量缓存封装入口方法以及source-generators生成不过本项目尝试了......
  • 探索音频处理中的频率分辨率:原理、影响与应用
    目录什么是频率分辨率?频率分辨率对音频处理的影响频率分辨率的实际应用与选择结论在音频信号处理领域,频率分辨率是一个至关重要的概念,它直接影响信号的分析和处理结果。无论是在语音识别、噪声抑制、音乐信号处理,还是在更多复杂的音频处理应用中,理解和选择适当的频率......
  • 探索异步之美:aiohttp库的魔力与奥秘
    文章目录探索异步之美:aiohttp库的魔力与奥秘背景:为何选择aiohttp?什么是aiohttp?如何安装aiohttp?简单函数使用方法场景应用常见Bug及解决方案总结探索异步之美:aiohttp库的魔力与奥秘背景:为何选择aiohttp?在当今这个快速变化的技术世界中,效率和性能是开发人员追求的......
  • 探索Python中的拼音魔法:pypinyin库的奇妙之旅
    文章目录探索Python中的拼音魔法:pypinyin库的奇妙之旅背景:为何选择pypinyin?库简介:pypinyin是什么?安装指南:如何将pypinyin纳入你的项目?功能探索:pypinyin的五大核心函数实战演练:pypinyin在不同场景下的应用常见问题:使用pypinyin时的三个常见bug及解决方案总结:pypinyin-你......
  • “从手动到自动:探索Cursor编辑器和Claude-3.5-Sonnet的AI编程工具“
    Cursor情况简介AI大神AndrejKarpathy都被震惊了!他最近在试用VSCodeCursor+ClaudeSonnet3.5,结果发现这玩意儿比GitHubCopilot还好用!Cursor在短短时间内迅速成为程序员群体的顶流神器,其背后的原因在于其默认使用OpenAI投资的Claude-3.5-Sonnet模型,这一举动不仅改变......
  • list容器---深入探索STL中的双向链表
    目录一、引言二、list容器原理三、list容器的常用操作  1.创建list容器  2.添加元素  3.删除元素  4.访问元素  5.遍历list容器四、list容器的优缺点五、实际应用场景六、总结        本文将详细介绍C++STL中的list容器,包括其原理、常用......