관리 메뉴

기억을 위한 기록들

[UE4-CPP] FHITResult 분석 본문

UnrealEngine/UE4 - CPP

[UE4-CPP] FHITResult 분석

에드윈H 2021. 10. 7. 20:27

FHITResult는 충돌 지점(point of impact) 및 해당 point의 표면(surface) normal과 같은 trace의 한 번의 hit 정보를 포함하는 구조체입니다.

/**
 * Structure containing information about one hit of a trace, such as point of impact and surface normal at that point.
 */
USTRUCT(BlueprintType, meta = (HasNativeBreak = "Engine.GameplayStatics.BreakHitResult", HasNativeMake = "Engine.GameplayStatics.MakeHitResult"))
struct ENGINE_API FHitResult
{
	GENERATED_BODY()
    //...

 

	/** Face index we hit (for complex hits with triangle meshes). */
	UPROPERTY()
	int32 FaceIndex;

표면(face) 인덱스(삼각형 메시가 있는 complex hits의 경우).

 

 

 

	/**
	 * 'Time' of impact along trace direction (ranging from 0.0 to 1.0) if there is a hit, indicating time between TraceStart and TraceEnd.
	 * For swept movement (but not queries) this may be pulled back slightly from the actual time of impact, to prevent precision problems with adjacent geometry.
	 */
	UPROPERTY()
	float Time;

적중 시 추적 방향을 따라 영향을 미치는 '시간'(0.0~1.0 범위)이며, 이는 TraceStart와 TraceEnd 사이의 시간을 나타냅니다.

스윕 이동(쿼리가 아님)의 경우 인접 형상의 정밀도 문제를 방지하기 위해 실제 충돌 시간보다 약간 뒤로 당겨질 수 있습니다.

 

 

 

 

	/** The distance from the TraceStart to the Location in world space. This value is 0 if there was an initial overlap (trace started inside another colliding object). */
	UPROPERTY()
	float Distance;

TraceStart에서 World Space의 위치까지의 거리입니다.
초기 중첩이 있는 경우(다른 충돌 물체 내부에서 시작된 추적) 이 값은 0입니다.

 

 

 

 

	/**
	 * The location in world space where the moving shape would end up against the impacted object, if there is a hit. Equal to the point of impact for line tests.
	 * Example: for a sphere trace test, this is the point where the center of the sphere would be located when it touched the other object.
	 * For swept movement (but not queries) this may not equal the final location of the shape since hits are pulled back slightly to prevent precision issues from overlapping another surface.
	 */
	UPROPERTY()
	FVector_NetQuantize Location;

적중 시 충격을 받은 물체에 부딪혀 움직이는 모양(shape)이 끝나는 world space의 위치입니다.
line tests의 충격점(point of impact)과 같습니다.
예: 구면 추적 테스트의 경우, 이 점이 구의 중심이 위치하는 지점입니다.다른 물체에 닿았을 때요.
스윕 이동(쿼리가 아님)의 경우 정밀도 문제가 다른 표면과 겹치지 않도록 히트를 뒤로 약간 당기기 때문에 shape의 최종 위치와 동일하지 않을 수 있습니다.

 

 

 

	/**
	 * Location in world space of the actual contact of the trace shape (box, sphere, ray, etc) with the impacted object.
	 * Example: for a sphere trace test, this is the point where the surface of the sphere touches the other object.
	 * @note: In the case of initial overlap (bStartPenetrating=true), ImpactPoint will be the same as Location because there is no meaningful single impact point to report.
	 */
	UPROPERTY()
	FVector_NetQuantize ImpactPoint;

충격을 받은 물체와 trace shape(상자, 구, 광선 등)이 실제 접촉하는 world space의 위치입니다.

예: 구면 추적 테스트의 경우 구의 표면이 다른 물체와 접촉하는 지점입니다.
@참고: 초기 오버랩(bStartPenetrating=true)의 경우 보고할 의미 있는 단일 영향 지점이 없기 때문에 ImpactPoint는 Location과 동일

 

 

 

	/**
	 * Normal of the hit in world space, for the object that was swept. Equal to ImpactNormal for line tests.
	 * This is computed for capsules and spheres, otherwise it will be the same as ImpactNormal.
	 * Example: for a sphere trace test, this is a normalized vector pointing in towards the center of the sphere at the point of impact.
	 */
	UPROPERTY()
	FVector_NetQuantizeNormal Normal;

	/**
	 * Normal of the hit in world space, for the object that was hit by the sweep, if any.
	 * For example if a sphere hits a flat plane, this is a normalized vector pointing out from the plane.
	 * In the case of impact with a corner or edge of a surface, usually the "most opposing" normal (opposed to the query direction) is chosen.
	 */
	UPROPERTY()
	FVector_NetQuantizeNormal ImpactNormal;

Normal

스윕된 물체에 대한 world space에서의 hit의 Normal 입니다. 
line tests의 경우 ImpactNormal과 같습니다.

이 값은 캡슐 및 구에 대해 계산되며, 그렇지 않으면 ImpactNormal과 동일합니다.
예: 구면 추적 테스트의 경우, 이것은 충격 지점에서 구의 중심을 가리키는 정규화된 벡터입니다.

 

ImpaceNormal

스윕에 의해 hit한 물체에 대한 world space에서의 hit의 normal입니다.
예를 들어, 구가 평면에 부딪히면 평면에서 가리키는 정규화된 벡터입니다.
표면의 모서리 또는 가장자리와 충돌하는 경우 일반적으로 "가장 반대되는" 정규(쿼리 방향과 반대)가 선택됩니다.

 

 

 

 

 

	/**
	 * Start location of the trace.
	 * For example if a sphere is swept against the world, this is the starting location of the center of the sphere.
	 */
	UPROPERTY()
	FVector_NetQuantize TraceStart;

	/**
	 * End location of the trace; this is NOT where the impact occurred (if any), but the furthest point in the attempted sweep.
	 * For example if a sphere is swept against the world, this would be the center of the sphere if there was no blocking hit.
	 */
	UPROPERTY()
	FVector_NetQuantize TraceEnd;

TraceStart

추적의 시작 위치입니다.
예를 들어, 구가 세계를 향해 쓸려진다면, 이것은 구 중심부의 시작 위치입니다.

 

TraceEnd

트레이스의 끝 위치. 충격이 발생한 위치(있는 경우)가 아니라 스윕 시도에서 가장 먼 지점입니다.
예를 들어, 구가 세계를 향해 쓸려나가면, 블록이 맞지 않으면 구체의 중심이 됩니다.

 

 

	/**
	  * If this test started in penetration (bStartPenetrating is true) and a depenetration vector can be computed,
	  * this value is the distance along Normal that will result in moving out of penetration.
	  * If the distance cannot be computed, this distance will be zero.
	  */
	UPROPERTY()
	float PenetrationDepth;

이 테스트가 침투에서 시작되고(bStartPenetrating는 true이다.) 역침투(depenetration) 벡터를 계산할 수 있다면,
이 값은 정규 분포를 따른 거리로, 침투 범위를 벗어나게 됩니다.
거리를 계산할 수 없는 경우 이 거리는 0이 됩니다.

 

 

	/** Extra data about item that was hit (hit primitive specific). */
	UPROPERTY()
	int32 Item;

	/** Index to item that was hit, also hit primitive specific. */
	UPROPERTY()
	uint8 ElementIndex;

	/** Indicates if this hit was a result of blocking collision. If false, there was no hit or it was an overlap/touch instead. */
	UPROPERTY()
	uint8 bBlockingHit : 1;

item

hit한 item에 대한 추가 data(기본 항목별 히트)입니다.

 

ElementIndex

hit한 item에 대한 인덱스도 또한 기본 항목별로 히트입니다.

 

bBlockingHit

hit가 blocking collision의 결과인지 여부를 나타냅니다. 거짓일 경우, 히트하지 않았거나, 오버랩/터치 대신입니다.

 

 

 

 

	/**
	 * Whether the trace started in penetration, i.e. with an initial blocking overlap.
	 * In the case of penetration, if PenetrationDepth > 0.f, then it will represent the distance along the Normal vector that will result in
	 * minimal contact between the swept shape and the object that was hit. In this case, ImpactNormal will be the normal opposed to movement at that location
	 * (ie, Normal may not equal ImpactNormal). ImpactPoint will be the same as Location, since there is no single impact point to report.
	 */
	UPROPERTY()
	uint8 bStartPenetrating : 1;

trace가 침투(penetration)에서 시작되었는지 여부, 즉 초기 차단이 겹치는지 여부.
침투(penetration)의 경우, 침투 깊이 > 0.f일 경우, 다음과 같은 결과를 초래하는 정규 벡터(Normal Vector)를 따라 거리를 나타낸다. 스윕 모양과 부딪힌 물체 사이의 최소 접촉
이 경우 ImpactNormal(충격 노멀)은 해당 위치에서의 움직임과 반대되는 정상입니다.
(즉, 정규 분포는 충격 정규 분포와 다를 수 있습니다.)
보고할 단일 영향 지점이 없기 때문에 영향 지점은 위치와 동일합니다.

 

 

	/**
	 * Physical material that was hit.
	 * @note Must set bReturnPhysicalMaterial on the swept PrimitiveComponent or in the query params for this to be returned.
	 */
	UPROPERTY()
	TWeakObjectPtr<class UPhysicalMaterial> PhysMaterial;

	/** Actor hit by the trace. */
	UPROPERTY()
	TWeakObjectPtr<class AActor> Actor;

	/** PrimitiveComponent hit by the trace. */
	UPROPERTY()
	TWeakObjectPtr<class UPrimitiveComponent> Component;

	/** Name of bone we hit (for skeletal meshes). */
	UPROPERTY()
	FName BoneName;

	/** Name of the _my_ bone which took part in hit event (in case of two skeletal meshes colliding). */
	UPROPERTY()
	FName MyBoneName;

PhysMaterial

Physical material에 hit하였습니다.
*참고 이 값이 반환되려면 스윕된 PrimitiveComponent 또는 쿼리 매개 변수에 bReturnPhysicalMaterial을 설정해야 합니다.

 

 

Actor

trace에 맞은 actor입니다.

 

Component

trace에 맞은 PrimitiveComponent입니다.

 

BoneName

(Skeletal Mesh의 경우) 우리가 친 Bone의 이름입니다.

 

MyBoneName

(두 개의 Skeletal Mesh가 충돌하는 경우) 충돌에 참여한 나의 뼈의 이름입니다.

 

 

 

 

//...


/**
 * Structure containing information about one hit of a trace, such as point of impact and surface normal at that point.
 */
USTRUCT(BlueprintType, meta = (HasNativeBreak = "Engine.GameplayStatics.BreakHitResult", HasNativeMake = "Engine.GameplayStatics.MakeHitResult"))
struct ENGINE_API FHitResult
{
	GENERATED_BODY()

	/** Face index we hit (for complex hits with triangle meshes). */
	UPROPERTY()
	int32 FaceIndex;

	/**
	 * 'Time' of impact along trace direction (ranging from 0.0 to 1.0) if there is a hit, indicating time between TraceStart and TraceEnd.
	 * For swept movement (but not queries) this may be pulled back slightly from the actual time of impact, to prevent precision problems with adjacent geometry.
	 */
	UPROPERTY()
	float Time;
	 
	/** The distance from the TraceStart to the Location in world space. This value is 0 if there was an initial overlap (trace started inside another colliding object). */
	UPROPERTY()
	float Distance; 
	
	/**
	 * The location in world space where the moving shape would end up against the impacted object, if there is a hit. Equal to the point of impact for line tests.
	 * Example: for a sphere trace test, this is the point where the center of the sphere would be located when it touched the other object.
	 * For swept movement (but not queries) this may not equal the final location of the shape since hits are pulled back slightly to prevent precision issues from overlapping another surface.
	 */
	UPROPERTY()
	FVector_NetQuantize Location;

	/**
	 * Location in world space of the actual contact of the trace shape (box, sphere, ray, etc) with the impacted object.
	 * Example: for a sphere trace test, this is the point where the surface of the sphere touches the other object.
	 * @note: In the case of initial overlap (bStartPenetrating=true), ImpactPoint will be the same as Location because there is no meaningful single impact point to report.
	 */
	UPROPERTY()
	FVector_NetQuantize ImpactPoint;

	/**
	 * Normal of the hit in world space, for the object that was swept. Equal to ImpactNormal for line tests.
	 * This is computed for capsules and spheres, otherwise it will be the same as ImpactNormal.
	 * Example: for a sphere trace test, this is a normalized vector pointing in towards the center of the sphere at the point of impact.
	 */
	UPROPERTY()
	FVector_NetQuantizeNormal Normal;

	/**
	 * Normal of the hit in world space, for the object that was hit by the sweep, if any.
	 * For example if a sphere hits a flat plane, this is a normalized vector pointing out from the plane.
	 * In the case of impact with a corner or edge of a surface, usually the "most opposing" normal (opposed to the query direction) is chosen.
	 */
	UPROPERTY()
	FVector_NetQuantizeNormal ImpactNormal;

	/**
	 * Start location of the trace.
	 * For example if a sphere is swept against the world, this is the starting location of the center of the sphere.
	 */
	UPROPERTY()
	FVector_NetQuantize TraceStart;

	/**
	 * End location of the trace; this is NOT where the impact occurred (if any), but the furthest point in the attempted sweep.
	 * For example if a sphere is swept against the world, this would be the center of the sphere if there was no blocking hit.
	 */
	UPROPERTY()
	FVector_NetQuantize TraceEnd;

	/**
	  * If this test started in penetration (bStartPenetrating is true) and a depenetration vector can be computed,
	  * this value is the distance along Normal that will result in moving out of penetration.
	  * If the distance cannot be computed, this distance will be zero.
	  */
	UPROPERTY()
	float PenetrationDepth;

	/** Extra data about item that was hit (hit primitive specific). */
	UPROPERTY()
	int32 Item;

	/** Index to item that was hit, also hit primitive specific. */
	UPROPERTY()
	uint8 ElementIndex;

	/** Indicates if this hit was a result of blocking collision. If false, there was no hit or it was an overlap/touch instead. */
	UPROPERTY()
	uint8 bBlockingHit : 1;

	/**
	 * Whether the trace started in penetration, i.e. with an initial blocking overlap.
	 * In the case of penetration, if PenetrationDepth > 0.f, then it will represent the distance along the Normal vector that will result in
	 * minimal contact between the swept shape and the object that was hit. In this case, ImpactNormal will be the normal opposed to movement at that location
	 * (ie, Normal may not equal ImpactNormal). ImpactPoint will be the same as Location, since there is no single impact point to report.
	 */
	UPROPERTY()
	uint8 bStartPenetrating : 1;

	/**
	 * Physical material that was hit.
	 * @note Must set bReturnPhysicalMaterial on the swept PrimitiveComponent or in the query params for this to be returned.
	 */
	UPROPERTY()
	TWeakObjectPtr<class UPhysicalMaterial> PhysMaterial;

	/** Actor hit by the trace. */
	UPROPERTY()
	TWeakObjectPtr<class AActor> Actor;

	/** PrimitiveComponent hit by the trace. */
	UPROPERTY()
	TWeakObjectPtr<class UPrimitiveComponent> Component;

	/** Name of bone we hit (for skeletal meshes). */
	UPROPERTY()
	FName BoneName;

	/** Name of the _my_ bone which took part in hit event (in case of two skeletal meshes colliding). */
	UPROPERTY()
	FName MyBoneName;


	FHitResult()
	{
		Init();
	}
	
	explicit FHitResult(float InTime)
	{
		Init();
		Time = InTime;
	}

	explicit FHitResult(EForceInit InInit)
	{
		Init();
	}

	explicit FHitResult(ENoInit NoInit)
	{
	}

	explicit FHitResult(FVector Start, FVector End)
	{
		Init(Start, End);
	}

	/** Initialize empty hit result with given time. */
	FORCEINLINE void Init()
	{
		FMemory::Memzero(this, sizeof(FHitResult));
		Time = 1.f;
	}

	/** Initialize empty hit result with given time, TraceStart, and TraceEnd */
	FORCEINLINE void Init(FVector Start, FVector End)
	{
		FMemory::Memzero(this, sizeof(FHitResult));
		Time = 1.f;
		TraceStart = Start;
		TraceEnd = End;
	}

	/** Ctor for easily creating "fake" hits from limited data. */
	FHitResult(class AActor* InActor, class UPrimitiveComponent* InComponent, FVector const& HitLoc, FVector const& HitNorm);
 
	/** Reset hit result while optionally saving TraceStart and TraceEnd. */
	FORCEINLINE void Reset(float InTime = 1.f, bool bPreserveTraceData = true)
	{
		const FVector SavedTraceStart = TraceStart;
		const FVector SavedTraceEnd = TraceEnd;
		Init();
		Time = InTime;
		if (bPreserveTraceData)
		{
			TraceStart = SavedTraceStart;
			TraceEnd = SavedTraceEnd;
		}
	}

	/** Utility to return the Actor that owns the Component that was hit. */
	FORCEINLINE AActor* GetActor() const
	{
		return Actor.Get();
	}

	/** Utility to return the Component that was hit. */
	FORCEINLINE UPrimitiveComponent* GetComponent() const
	{
		return Component.Get();
	}

	/** Optimized serialize function */
	bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess);

	/** Return true if there was a blocking hit that was not caused by starting in penetration. */
	FORCEINLINE bool IsValidBlockingHit() const
	{
		return bBlockingHit && !bStartPenetrating;
	}

	/** Static utility function that returns the first 'blocking' hit in an array of results. */
	static FHitResult* GetFirstBlockingHit(TArray<FHitResult>& InHits)
	{
		for(int32 HitIdx=0; HitIdx<InHits.Num(); HitIdx++)
		{
			if(InHits[HitIdx].bBlockingHit)
			{
				return &InHits[HitIdx];
			}
		}
		return nullptr;
	}

	/** Static utility function that returns the number of blocking hits in array. */
	static int32 GetNumBlockingHits(const TArray<FHitResult>& InHits)
	{
		int32 NumBlocks = 0;
		for(int32 HitIdx=0; HitIdx<InHits.Num(); HitIdx++)
		{
			if(InHits[HitIdx].bBlockingHit)
			{
				NumBlocks++;
			}
		}
		return NumBlocks;
	}

	/** Static utility function that returns the number of overlapping hits in array. */
	static int32 GetNumOverlapHits(const TArray<FHitResult>& InHits)
	{
		return (InHits.Num() - GetNumBlockingHits(InHits));
	}

	/**
	 * Get a copy of the HitResult with relevant information reversed.
	 * For example when receiving a hit from another object, we reverse the normals.
	 */
	static FHitResult GetReversedHit(const FHitResult& Hit)
	{
		FHitResult Result(Hit);
		Result.Normal = -Result.Normal;
		Result.ImpactNormal = -Result.ImpactNormal;
		return Result;
	}

	FString ToString() const;
};



//...