// Copyright Epic Games, Inc. All Rights Reserved. #include "DatasmithSketchUpCamera.h" #include "DatasmithSketchUpCommon.h" #include "DatasmithSketchUpUtils.h" #include "DatasmithSketchUpString.h" #include "DatasmithSketchUpExportContext.h" // SketchUp SDK. #include "DatasmithSketchUpSDKBegins.h" #include "SketchUpAPI/model/camera.h" #include "SketchUpAPI/model/entity.h" #include "SketchUpAPI/model/model.h" #include "SketchUpAPI/model/scene.h" #include "DatasmithSketchUpSDKCeases.h" #include "DatasmithUtils.h" #include "DatasmithSceneFactory.h" using namespace DatasmithSketchUp; TSharedPtr FCamera::Create(FExportContext& Context, SUCameraRef InCameraRef, const FString& Name) { TSharedPtr Camera = MakeShared(InCameraRef); Camera->Name = Name; return Camera; } TSharedPtr FCamera::Create(FExportContext& Context, SUSceneRef InSceneRef) { SUCameraRef CameraRef; // Retrieve the SketchUp scene camera. SUSceneGetCamera(InSceneRef, &CameraRef); return Create(Context, CameraRef, SuGetString(SUSceneGetName, InSceneRef)); } void FCamera::Update(FExportContext& Context) { if (!DatasmithCamera) { DatasmithCamera = FDatasmithSceneFactory::CreateCameraActor(TEXT("")); Context.DatasmithScene->AddActor(DatasmithCamera); } SUPoint3D SourcePosition; SUPoint3D SourceTarget; SUVector3D SourceUpVector; // Retrieve the SketckUp camera orientation. SUCameraGetOrientation(CameraRef, &SourcePosition, &SourceTarget, &SourceUpVector); // Get the SketchUp camera aspect ratio. double CameraAspectRatio = 0.0; SUResult Result = SUCameraGetAspectRatio(CameraRef, &CameraAspectRatio); double SourceAspectRatio = 16.0 / 9.0; // Keep the default aspect ratio when the camera uses the screen aspect ratio (SU_ERROR_NO_DATA). if (Result == SU_ERROR_NONE) { SourceAspectRatio = CameraAspectRatio; } // Get the flag indicating whether or not the SketchUp scene camera is a perspective camera. bool bCameraIsPerspective = false; SUCameraGetPerspective(CameraRef, &bCameraIsPerspective); // we can ignore the returned SU_RESULT // Get the flag indicating whether or not the SketchUp scene camera is a two dimensional camera. bool bCameraIs2D = false; SUCameraGet2D(CameraRef, &bCameraIs2D); // we can ignore the returned SU_RESULT bool bSourceFOVForHeight = true; double SourceFOV(60.0); // default vertical field of view of 60 degrees double SourceImageWidth(36.0); // default image width of 36 mm (from Datasmith) if (bCameraIsPerspective && !bCameraIs2D) { // Get the flag indicating whether or not the SketchUp camera field of view value represents the camera view height. SUCameraGetFOVIsHeight(CameraRef, &bSourceFOVForHeight); // we can ignore the returned SU_RESULT // Get the SketchUp camera field of view (in degrees). SUCameraGetPerspectiveFrustumFOV(CameraRef, &SourceFOV); // we can ignore the returned SU_RESULT // Get the SketchUp camera image width (in millimeters). double CameraImageWidth = 0.0; Result = SUCameraGetImageWidth(CameraRef, &CameraImageWidth); // Keep the default image width when the camera does not have an image width. if (CameraImageWidth > 0.0) { SourceImageWidth = CameraImageWidth; } } FString ActorName = FDatasmithUtils::SanitizeObjectName(Name); FString ActorLabel = ActorName; // Create a Datasmith camera actor for the camera definition. DatasmithCamera->SetName(*ActorName); // Set the camera actor label used in the Unreal UI. DatasmithCamera->SetLabel(*ActorLabel); // Convert the SketchUp right-handed camera orientation into an Unreal left-handed look-at rotation quaternion. // To avoid perturbating X, which is forward in Unreal, the handedness conversion is done by flipping the side vector Y. SUVector3D SLookAtVector = { SourceTarget.x - SourcePosition.x, SourceTarget.y - SourcePosition.y, SourceTarget.z - SourcePosition.z }; FVector XAxis = DatasmithSketchUpUtils::FromSketchUp::ConvertDirection(SLookAtVector); FVector ZAxis = DatasmithSketchUpUtils::FromSketchUp::ConvertDirection(SourceUpVector); FQuat Rotation(FRotationMatrix::MakeFromXZ(XAxis, ZAxis)); // axis vectors do not need to be normalized // Convert the SketchUp right-handed Z-up coordinate translation into an Unreal left-handed Z-up coordinate translation. // To avoid perturbating X, which is forward in Unreal, the handedness conversion is done by flipping the side vector Y. // SketchUp uses inches as internal system unit for all 3D coordinates in the model while Unreal uses centimeters. FVector Translation = FVector(DatasmithSketchUpUtils::FromSketchUp::ConvertPosition(SourcePosition)); // Set the world transform of the Datasmith camera actor. DatasmithCamera->SetRotation(Rotation); DatasmithCamera->SetTranslation(Translation); // Set the Datasmith camera aspect ratio. DatasmithCamera->SetSensorAspectRatio(float(SourceAspectRatio)); // Set the Datasmith camera sensor width (in millimeters). DatasmithCamera->SetSensorWidth(float(SourceImageWidth)); // Set the Datasmith camera focal length (in millimeters). double FocalLength = (bSourceFOVForHeight ? (SourceImageWidth / SourceAspectRatio) : SourceImageWidth) / (2.0 * tan(FMath::DegreesToRadians(SourceFOV) / 2.0)); DatasmithCamera->SetFocalLength(float(FocalLength)); // Set the Datasmith camera focus distance (in centimeters). FVector DistanceVector = FVector(DatasmithSketchUpUtils::FromSketchUp::ConvertPosition(SourceTarget.x - SourcePosition.x, SourceTarget.y - SourcePosition.y, SourceTarget.z - SourcePosition.z)); DatasmithCamera->SetFocusDistance(DistanceVector.Size()); // Using unused 'Visibility' flag for Camera to indicate currently active camera // todo: replace someday with dedicated flag DatasmithCamera->SetVisibility(bIsActive); } FMD5Hash FCamera::GetHash() { FMD5 MD5; MD5.Update(reinterpret_cast(*Name), Name.Len() * sizeof(TCHAR)); SUPoint3D SourcePosition; SUPoint3D SourceTarget; SUVector3D SourceUpVector; // Retrieve the SketckUp camera orientation. SUCameraGetOrientation(CameraRef, &SourcePosition, &SourceTarget, &SourceUpVector); MD5.Update(reinterpret_cast(&SourcePosition), sizeof(SourcePosition)); MD5.Update(reinterpret_cast(&SourceTarget), sizeof(SourceTarget)); MD5.Update(reinterpret_cast(&SourceUpVector), sizeof(SourceUpVector)); // Get the SketchUp camera aspect ratio. double CameraAspectRatio = 0.0; SUResult Result = SUCameraGetAspectRatio(CameraRef, &CameraAspectRatio); double SourceAspectRatio = 16.0 / 9.0; // Keep the default aspect ratio when the camera uses the screen aspect ratio (SU_ERROR_NO_DATA). if (Result == SU_ERROR_NONE) { SourceAspectRatio = CameraAspectRatio; } MD5.Update(reinterpret_cast(&SourceAspectRatio), sizeof(SourceAspectRatio)); // Get the flag indicating whether or not the SketchUp scene camera is a perspective camera. bool bCameraIsPerspective = false; SUCameraGetPerspective(CameraRef, &bCameraIsPerspective); // we can ignore the returned SU_RESULT MD5.Update(reinterpret_cast(&bCameraIsPerspective), sizeof(bCameraIsPerspective)); // Get the flag indicating whether or not the SketchUp scene camera is a two dimensional camera. bool bCameraIs2D = false; SUCameraGet2D(CameraRef, &bCameraIs2D); // we can ignore the returned SU_RESULT MD5.Update(reinterpret_cast(&bCameraIs2D), sizeof(bCameraIs2D)); bool bSourceFOVForHeight = true; double SourceFOV(60.0); // default vertical field of view of 60 degrees double SourceImageWidth(36.0); // default image width of 36 mm (from Datasmith) if (bCameraIsPerspective && !bCameraIs2D) { // Get the flag indicating whether or not the SketchUp camera field of view value represents the camera view height. SUCameraGetFOVIsHeight(CameraRef, &bSourceFOVForHeight); // we can ignore the returned SU_RESULT MD5.Update(reinterpret_cast(&bSourceFOVForHeight), sizeof(bSourceFOVForHeight)); // Get the SketchUp camera field of view (in degrees). SUCameraGetPerspectiveFrustumFOV(CameraRef, &SourceFOV); // we can ignore the returned SU_RESULT MD5.Update(reinterpret_cast(&SourceFOV), sizeof(SourceFOV)); // Get the SketchUp camera image width (in millimeters). double CameraImageWidth = 0.0; Result = SUCameraGetImageWidth(CameraRef, &CameraImageWidth); // Keep the default image width when the camera does not have an image width. if (CameraImageWidth > 0.0) { SourceImageWidth = CameraImageWidth; } MD5.Update(reinterpret_cast(&SourceImageWidth), sizeof(SourceImageWidth)); } FMD5Hash Hash; Hash.Set(MD5); return Hash; } bool FViewportCamera::Update(FExportContext& InContext) { SUCameraRef camera_ref = SU_INVALID; if (SUModelGetCamera(InContext.ModelRef, &camera_ref) == SU_ERROR_NONE && SUIsValid(camera_ref)) { TSharedPtr MainCamera = FCamera::Create(InContext, camera_ref, TEXT("viewport_camera")); FMD5Hash CurrentHash = MainCamera->GetHash(); if(Hash != CurrentHash) { Hash = CurrentHash; MainCamera->Update(InContext); return true; } return false; } DatasmithSketchUpUtils::ToRuby::LogWarn(TEXT("Cannot find viewport camera.")); return false; }