Files
UnrealEngine/Engine/Source/Developer/Datasmith/DatasmithFacade/Private/DatasmithFacadeActor.cpp
2025-05-18 13:04:45 +08:00

434 lines
11 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DatasmithFacadeActor.h"
#include "DatasmithFacadeActorCamera.h"
#include "DatasmithFacadeActorLight.h"
#include "DatasmithFacadeActorMesh.h"
#include "DatasmithFacadeScene.h"
// Imath third party library.
#include "Imath/ImathMatrixAlgo.h"
FDatasmithFacadeActor::FDatasmithFacadeActor(
const TCHAR* InElementName
)
: FDatasmithFacadeElement(FDatasmithSceneFactory::CreateActor(InElementName))
{
TSharedPtr<IDatasmithActorElement> ActorElement = GetDatasmithActorElement();
ActorElement->SetIsAComponent(false);
}
FDatasmithFacadeActor::FDatasmithFacadeActor(
const TSharedRef<IDatasmithActorElement>& InInternalActor
)
: FDatasmithFacadeElement(InInternalActor)
{}
void FDatasmithFacadeActor::SetWorldTransform(
const double InWorldMatrix[16],
bool bRowMajor
)
{
FTransform WorldTransform = ConvertTransform(InWorldMatrix, bRowMajor);
// Set the Datasmith actor world transform.
TSharedPtr<IDatasmithActorElement> ActorElement = GetDatasmithActorElement();
ActorElement->SetScale(WorldTransform.GetScale3D());
ActorElement->SetRotation(WorldTransform.GetRotation());
ActorElement->SetTranslation(WorldTransform.GetTranslation());
}
void FDatasmithFacadeActor::SetScale(
double X,
double Y,
double Z
)
{
GetDatasmithActorElement()->SetScale(FVector(X, Y, Z));
}
void FDatasmithFacadeActor::GetScale(
double& OutX,
double& OutY,
double& OutZ
) const
{
FVector ScaleVector(GetDatasmithActorElement()->GetScale());
OutX = ScaleVector.X;
OutY = ScaleVector.Y;
OutZ = ScaleVector.Z;
}
void FDatasmithFacadeActor::SetRotation(
double Pitch,
double Yaw,
double Roll
)
{
GetDatasmithActorElement()->SetRotation(FQuat(FRotator(Pitch, Yaw, Roll)));
}
void FDatasmithFacadeActor::GetRotation(
double& OutPitch,
double& OutYaw,
double& OutRoll
) const
{
FRotator Rotator(GetDatasmithActorElement()->GetRotation().Rotator());
OutPitch = Rotator.Pitch;
OutYaw = Rotator.Yaw;
OutRoll = Rotator.Roll;
}
void FDatasmithFacadeActor::SetRotation(
double X,
double Y,
double Z,
double W
)
{
GetDatasmithActorElement()->SetRotation(FQuat(X, Y, Z, W));
}
void FDatasmithFacadeActor::GetRotation(
double& OutX,
double& OutY,
double& OutZ,
double& OutW
) const
{
FQuat RotationQuat(GetDatasmithActorElement()->GetRotation());
OutX = RotationQuat.X;
OutY = RotationQuat.Y;
OutZ = RotationQuat.Z;
OutW = RotationQuat.W;
}
void FDatasmithFacadeActor::SetTranslation(
double X,
double Y,
double Z
)
{
GetDatasmithActorElement()->SetTranslation(FVector(X, Y, Z));
}
void FDatasmithFacadeActor::GetTranslation(
double& OutX,
double& OutY,
double& OutZ
) const
{
FVector TranslationVector(GetDatasmithActorElement()->GetTranslation());
OutX = TranslationVector.X;
OutY = TranslationVector.Y;
OutZ = TranslationVector.Z;
}
void FDatasmithFacadeActor::SetLayer(
const TCHAR* InLayerName
)
{
GetDatasmithActorElement()->SetLayer(InLayerName);
}
const TCHAR* FDatasmithFacadeActor::GetLayer() const
{
return GetDatasmithActorElement()->GetLayer();
}
void FDatasmithFacadeActor::AddTag(
const TCHAR* InTag
)
{
GetDatasmithActorElement()->AddTag(InTag);
}
void FDatasmithFacadeActor::ResetTags()
{
GetDatasmithActorElement()->ResetTags();
}
int32 FDatasmithFacadeActor::GetTagsCount() const
{
return GetDatasmithActorElement()->GetTagsCount();
}
const TCHAR* FDatasmithFacadeActor::GetTag(
int32 TagIndex
) const
{
return GetDatasmithActorElement()->GetTag(TagIndex);
}
bool FDatasmithFacadeActor::IsComponent() const
{
return GetDatasmithActorElement()->IsAComponent();
}
void FDatasmithFacadeActor::SetIsComponent(
bool bInIsComponent
)
{
GetDatasmithActorElement()->SetIsAComponent(bInIsComponent);
}
void FDatasmithFacadeActor::SetVisibility(
bool bInVisibility
)
{
GetDatasmithActorElement()->SetVisibility(bInVisibility);
}
bool FDatasmithFacadeActor::GetVisibility() const
{
return GetDatasmithActorElement()->GetVisibility();
}
void FDatasmithFacadeActor::SetCastShadow(bool bInCastShadow)
{
GetDatasmithActorElement()->SetCastShadow(bInCastShadow);
}
bool FDatasmithFacadeActor::GetCastShadow() const
{
return GetDatasmithActorElement()->GetCastShadow();
}
FDatasmithFacadeActor::EActorType FDatasmithFacadeActor::GetActorType() const
{
return FDatasmithFacadeActor::GetActorType(GetDatasmithActorElement());
}
FDatasmithFacadeActor::EActorType FDatasmithFacadeActor::GetActorType(
const TSharedPtr<const IDatasmithActorElement>& InActor
)
{
if (InActor->IsA(EDatasmithElementType::DirectionalLight))
{
return EActorType::DirectionalLight;
}
else if (InActor->IsA(EDatasmithElementType::AreaLight))
{
return EActorType::AreaLight;
}
else if (InActor->IsA(EDatasmithElementType::EnvironmentLight))
{
return EActorType::Unsupported;
}
else if (InActor->IsA(EDatasmithElementType::LightmassPortal))
{
return EActorType::LightmassPortal;
}
else if (InActor->IsA(EDatasmithElementType::PointLight))
{
return EActorType::PointLight;
}
else if (InActor->IsA(EDatasmithElementType::SpotLight))
{
return EActorType::SpotLight;
}
else if (InActor->IsA(EDatasmithElementType::Light))
{
return EActorType::Unsupported;
}
else if (InActor->IsA(EDatasmithElementType::StaticMeshActor))
{
return EActorType::StaticMeshActor;
}
else if (InActor->IsA(EDatasmithElementType::Camera))
{
return EActorType::Camera;
}
else if (InActor->IsA(EDatasmithElementType::Light
| EDatasmithElementType::HierarchicalInstanceStaticMesh
| EDatasmithElementType::CustomActor))
{
return EActorType::Unsupported;
}
else if (InActor->IsA(EDatasmithElementType::Actor))
{
return EActorType::Actor;
}
return EActorType::Unsupported;
}
FDatasmithFacadeActor* FDatasmithFacadeActor::GetNewFacadeActorFromSharedPtr(
const TSharedPtr<IDatasmithActorElement>& InActor
)
{
if (InActor)
{
EActorType ActorType = GetActorType(InActor);
TSharedRef<IDatasmithActorElement> ActorRef = InActor.ToSharedRef();
switch (ActorType)
{
case EActorType::DirectionalLight:
return new FDatasmithFacadeDirectionalLight(StaticCastSharedRef<IDatasmithDirectionalLightElement>(ActorRef));
case EActorType::AreaLight:
return new FDatasmithFacadeAreaLight(StaticCastSharedRef<IDatasmithAreaLightElement>(ActorRef));
case EActorType::LightmassPortal:
return new FDatasmithFacadeLightmassPortal(StaticCastSharedRef<IDatasmithLightmassPortalElement>(ActorRef));
case EActorType::PointLight:
return new FDatasmithFacadePointLight(StaticCastSharedRef<IDatasmithPointLightElement>(ActorRef));
case EActorType::SpotLight:
return new FDatasmithFacadeSpotLight(StaticCastSharedRef<IDatasmithSpotLightElement>(ActorRef));
case EActorType::StaticMeshActor:
return new FDatasmithFacadeActorMesh(StaticCastSharedRef<IDatasmithMeshActorElement>(ActorRef));
case EActorType::Camera:
return new FDatasmithFacadeActorCamera(StaticCastSharedRef<IDatasmithCameraActorElement>(ActorRef));
case EActorType::Actor:
return new FDatasmithFacadeActor(ActorRef);
case EActorType::Unsupported:
default:
return nullptr;
}
}
return nullptr;
}
void FDatasmithFacadeActor::AddChild(
FDatasmithFacadeActor* InChildActorPtr
)
{
if (InChildActorPtr != nullptr)
{
GetDatasmithActorElement()->AddChild(InChildActorPtr->GetDatasmithActorElement());
}
}
int32 FDatasmithFacadeActor::GetChildrenCount() const
{
return GetDatasmithActorElement()->GetChildrenCount();
}
FDatasmithFacadeActor* FDatasmithFacadeActor::GetNewChild(
int32 InIndex
)
{
TSharedPtr<IDatasmithActorElement> ChildActor = GetDatasmithActorElement()->GetChild(InIndex);
return GetNewFacadeActorFromSharedPtr(ChildActor);
}
void FDatasmithFacadeActor::RemoveChild(
FDatasmithFacadeActor* InChild
)
{
if (InChild)
{
GetDatasmithActorElement()->RemoveChild(InChild->GetDatasmithActorElement());
}
}
FTransform FDatasmithFacadeActor::ConvertTransform(
const double InSourceMatrix[16],
bool bRowMajor
) const
{
// We use Imath::extractAndRemoveScalingAndShear() because FMatrix::ExtractScaling() is deemed unreliable.
// Set up a scaling and rotation matrix.
Imath::Matrix44<double> Matrix;
if (bRowMajor)
{
Matrix = Imath::Matrix44<double>(InSourceMatrix[0], InSourceMatrix[4], InSourceMatrix[8], 0.0,
InSourceMatrix[1], InSourceMatrix[5], InSourceMatrix[9], 0.0,
InSourceMatrix[2], InSourceMatrix[6], InSourceMatrix[10], 0.0,
0.0 , 0.0 , 0.0 , 1.0);
}
else
{
Matrix = Imath::Matrix44<double>(InSourceMatrix[0], InSourceMatrix[1], InSourceMatrix[2], 0.0,
InSourceMatrix[4], InSourceMatrix[5], InSourceMatrix[6], 0.0,
InSourceMatrix[8], InSourceMatrix[9], InSourceMatrix[10], 0.0,
0.0 , 0.0 , 0.0 , 1.0);
}
// Remove any scaling from the matrix and get the scale vector that was initially present.
Imath::Vec3<double> Scale;
Imath::Vec3<double> Shear;
bool bExtracted = Imath::extractAndRemoveScalingAndShear<double>(Matrix, Scale, Shear, false);
if (!bExtracted)
{
// TODO: Append a message to the build summary.
FString Msg = FString::Printf(TEXT("WARNING: Actor %ls (%ls) has some zero scaling"), GetName(), GetLabel());
return FTransform::Identity;
}
FVector TransformScale3D;
// Initialize a rotation quaternion with the rotation matrix.
Imath::Quat<double> Quaternion = Imath::extractQuat<double>(Matrix);
switch (WorldCoordinateSystemType)
{
case ECoordinateSystemType::LeftHandedYup:
{
// Set the Datasmith actor scale.
TransformScale3D = FVector(Scale.x, Scale.z, Scale.y);
// Convert the left-handed Y-up coordinate rotation into an Unreal left-handed Z-up coordinate rotation.
// This is done by doing a 90 degree rotation about the X axis.
float Y = Quaternion.v.y;
float Z = Quaternion.v.z;
Quaternion.v.y = -Z;
Quaternion.v.z = Y;
Quaternion.normalize();
break;
}
case ECoordinateSystemType::LeftHandedZup:
{
// Set the Datasmith actor scale.
TransformScale3D = FVector(Scale.x, Scale.y, Scale.z);
break;
}
case ECoordinateSystemType::RightHandedZup:
{
// Set the Datasmith actor scale.
TransformScale3D = FVector(Scale.x, Scale.y, Scale.z);
// Convert the right-handed Z-up coordinate rotation into an Unreal left-handed Z-up coordinate rotation.
// This is done by inverting the X and Z components of the quaternion to mirror the quaternion on the XZ-plane.
Quaternion.v.x = -Quaternion.v.x;
Quaternion.v.z = -Quaternion.v.z;
Quaternion.normalize();
break;
}
}
// Make sure Unreal will be able to handle the rotation quaternion.
double Angle = Quaternion.angle();
Imath::Vec3<double> Axis = Quaternion.axis();
FQuat TransformRotation = FQuat(FVector(Axis.x, Axis.y, Axis.z), Angle);
// Scale and convert the source translation into a Datasmith actor translation.
FVector TransformTranslation = bRowMajor
? ConvertPosition(InSourceMatrix[4], InSourceMatrix[7], InSourceMatrix[11])
: ConvertPosition(InSourceMatrix[12], InSourceMatrix[13], InSourceMatrix[14]);
return FTransform(TransformRotation, TransformTranslation, TransformScale3D);
}
TSharedRef<IDatasmithActorElement> FDatasmithFacadeActor::GetDatasmithActorElement() const
{
return StaticCastSharedRef<IDatasmithActorElement>(InternalDatasmithElement);
}