[UE5] TIL - 30 <Socket, SpawnEmitterAttached>

ChangJin·2024년 5월 12일
0

Unreal Engine5

목록 보기
58/102
post-thumbnail

2024-05-12

깃허브!
https://github.com/ChangJin-Lee/ARproject
https://github.com/ChangJin-Lee/SimpleShooter

느낀점
SpawnEmitterAttached로 특정 Socket 위치에 파티클 이펙트를 실행하도록 만들어 보았다.

TIL

  • Socket
  • SpawnEmitterAttached

Socket

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/skeletal-mesh-sockets-in-unreal-engine?application_version=5.3


  • 스켈레탈 메시에 무기, 이펙트 등에 대한 접점으로 사용할 수 있는 위치입니다.

  • 스켈레탈 메시에서 본에 오브젝트를 어태치할 때 이 어태치먼트를 오프셋해야 하는 경우가 있습니다. 수학 연산을 사용하여 오프셋 트랜스폼을 추정하는 대신 소켓 을 생성할 수 있습니다. 소켓은 스켈레톤 계층구조 내의 전용 어태치 포인트로, 부모로 지정된 본에 상대적으로 트랜스폼할 수 있습니다. 구성한 후에는 오브젝트, 무기 및 기타 액터를 소켓에 어태치할 수 있습니다.



  • 다음처럼 원하는 위치에 Socket을 추가할 수 있습니다.


  • 다음처럼 블루프린트에서 사용할 수 있습니다.




SpawnEmitterAttached

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/API/Runtime/Engine/Kismet/UGameplayStatics/SpawnEmitterAttached/2?application_version=5.3


  • Plays the specified effect attached to and following the specified component.
  • 특정 컴포넌트에 부착된 이펙트를 실행합니다.

  • GameplayStatics.cpp에 있는 함수입니다.
  • SpawnEmitterAtLocation을 쓰지 않은 이유는?
    - UParticleSystem을 참조하기 위해서 이 매개변수가 있는 SpawnEmitterAttached 함수를 사용했습니다.

  • SpawnEmitterAtLocation 함수의 정의
UParticleSystemComponent* UGameplayStatics::SpawnEmitterAtLocation(const UObject* WorldContextObject, UParticleSystem* EmitterTemplate, FVector SpawnLocation, FRotator SpawnRotation, FVector SpawnScale, bool bAutoDestroy, EPSCPoolMethod PoolingMethod, bool bAutoActivateSystem)
{
	UParticleSystemComponent* PSC = nullptr;
	if (EmitterTemplate)
	{
		if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
		{
			PSC = InternalSpawnEmitterAtLocation(World, EmitterTemplate, SpawnLocation, SpawnRotation, SpawnScale, bAutoDestroy, PoolingMethod, bAutoActivateSystem);
		}
	}
	return PSC;
}


  • SpawnEmitterAttached의 정의
UParticleSystemComponent* UGameplayStatics::SpawnEmitterAttached(UParticleSystem* EmitterTemplate, USceneComponent* AttachToComponent, FName AttachPointName, FVector Location, FRotator Rotation, FVector Scale, EAttachLocation::Type LocationType, bool bAutoDestroy, EPSCPoolMethod PoolingMethod, bool bAutoActivateSystem)
{
	UParticleSystemComponent* PSC = nullptr;
	if (EmitterTemplate)
	{
		if (AttachToComponent == nullptr)
		{
			UE_LOG(LogScript, Warning, TEXT("UGameplayStatics::SpawnEmitterAttached: NULL AttachComponent specified!"));
		}
		else
		{
			UWorld* const World = AttachToComponent->GetWorld();
			if (World && !World->IsNetMode(NM_DedicatedServer))
			{
				PSC = CreateParticleSystem(EmitterTemplate, World, AttachToComponent->GetOwner(), bAutoDestroy, PoolingMethod);

				if (PSC != nullptr)
				{
					PSC->SetupAttachment(AttachToComponent, AttachPointName);

					if (LocationType == EAttachLocation::KeepWorldPosition)
					{
						const FTransform ParentToWorld = AttachToComponent->GetSocketTransform(AttachPointName);
						const FTransform ComponentToWorld(Rotation, Location, Scale);
						const FTransform RelativeTM = ComponentToWorld.GetRelativeTransform(ParentToWorld);
						PSC->SetRelativeLocation_Direct(RelativeTM.GetLocation());
						PSC->SetRelativeRotation_Direct(RelativeTM.GetRotation().Rotator());
						PSC->SetRelativeScale3D_Direct(RelativeTM.GetScale3D());
					}
					else
					{
						PSC->SetRelativeLocation_Direct(Location);
						PSC->SetRelativeRotation_Direct(Rotation);

						if (LocationType == EAttachLocation::SnapToTarget)
						{
							// SnapToTarget indicates we "keep world scale", this indicates we we want the inverse of the parent-to-world scale 
							// to calculate world scale at Scale 1, and then apply the passed in Scale
							const FTransform ParentToWorld = AttachToComponent->GetSocketTransform(AttachPointName);
							PSC->SetRelativeScale3D_Direct(Scale * ParentToWorld.GetSafeScaleReciprocal(ParentToWorld.GetScale3D()));
						}
						else
						{
							PSC->SetRelativeScale3D_Direct(Scale);
						}
					}

					PSC->RegisterComponentWithWorld(World);
					if(bAutoActivateSystem)
					{
						PSC->ActivateSystem(true);
					}

					// Notify the texture streamer so that PSC gets managed as a dynamic component.
					IStreamingManager::Get().NotifyPrimitiveUpdated(PSC);

#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
					if (PSC->Template && PSC->Template->IsImmortal())
					{
						const FString OnScreenMessage = FString::Printf(TEXT("SpawnEmitterAttached spawned potentially immortal particle system! %s (%s) may stay in world despite never spawning particles after burst spawning is over."), *(PSC->GetPathName()), *(PSC->Template->GetName()));
						GEngine->AddOnScreenDebugMessage((uint64)((PTRINT)AttachToComponent), 3.f, FColor::Red, OnScreenMessage);
						UE_LOG(LogParticles, Log, TEXT("GameplayStatics::SpawnEmitterAttached spawned potentially immortal particle system! %s (%s) may stay in world despite never spawning particles after burst spawning is over."),
							*(PSC->GetPathName()), *(PSC->Template->GetPathName())
						);
					}
#endif
				}
			}
		}
	}
	return PSC;
}
profile
Unreal Engine 클라이언트 개발자

0개의 댓글