void OutputAnimationTransformDebugData(TArray<AnimationTransformDebug::FAnimationTransformDebugData> &TransformDebugData, int32 TotalNumKeys, const FReferenceSkeleton& RefSkeleton) { bool bShouldOutputToMessageLog = true; for(int32 Key=0; Key<TotalNumKeys; ++Key) { // go through all bones and find for(int32 BoneIndex=0; BoneIndex<TransformDebugData.Num(); ++BoneIndex) { FAnimationTransformDebugData& Data = TransformDebugData[BoneIndex]; int32 ParentIndex = RefSkeleton.GetParentIndex(Data.BoneIndex); int32 ParentTransformDebugDataIndex = 0; check(Data.RecalculatedLocalTransform.Num() == TotalNumKeys); check(Data.SourceGlobalTransform.Num() == TotalNumKeys); check(Data.SourceParentGlobalTransform.Num() == TotalNumKeys); for(; ParentTransformDebugDataIndex<BoneIndex; ++ParentTransformDebugDataIndex) { if(ParentIndex == TransformDebugData[ParentTransformDebugDataIndex].BoneIndex) { FTransform ParentTransform = TransformDebugData[ParentTransformDebugDataIndex].RecalculatedLocalTransform[Key] * TransformDebugData[ParentTransformDebugDataIndex].RecalculatedParentTransform[Key]; Data.RecalculatedParentTransform.Add(ParentTransform); break; } } // did not find Parent if(ParentTransformDebugDataIndex == BoneIndex) { Data.RecalculatedParentTransform.Add(FTransform::Identity); } check(Data.RecalculatedParentTransform.Num() == Key+1); FTransform GlobalTransform = Data.RecalculatedLocalTransform[Key] * Data.RecalculatedParentTransform[Key]; // makes more generous on the threshold. if(GlobalTransform.Equals(Data.SourceGlobalTransform[Key], 0.1f) == false) { // so that we don't spawm with this message if(bShouldOutputToMessageLog) { UnFbx::FFbxImporter* FFbxImporter = UnFbx::FFbxImporter::GetInstance(); // now print information - it doesn't match well, find out what it is FFbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Warning, FText::Format(LOCTEXT("FBXImport_TransformError", "Imported bone transform is different from original. Please check Output Log to see detail of error. "), FText::FromName(Data.BoneName), FText::AsNumber(Data.BoneIndex), FText::FromString(Data.SourceGlobalTransform[Key].ToString()), FText::FromString(GlobalTransform.ToString()))), FFbxErrors::Animation_TransformError); bShouldOutputToMessageLog = false; } // now print information - it doesn't match well, find out what it is UE_LOG(LogFbx, Warning, TEXT("IMPORT TRANSFORM ERROR : Bone (%s:%d) \r\nSource Global Transform (%s), \r\nConverted Global Transform (%s)"), *Data.BoneName.ToString(), Data.BoneIndex, *Data.SourceGlobalTransform[Key].ToString(), *GlobalTransform.ToString()); } } } }
void FLevelUtils::ApplyLevelTransform( ULevel* Level, const FTransform& LevelTransform, bool bDoPostEditMove ) { bool bTransformActors = !LevelTransform.Equals(FTransform::Identity); if (bTransformActors) { if (!LevelTransform.GetRotation().IsIdentity()) { // If there is a rotation applied, then the relative precomputed bounds become invalid. Level->bTextureStreamingRotationChanged = true; } // Iterate over all actors in the level and transform them for( int32 ActorIndex=0; ActorIndex<Level->Actors.Num(); ActorIndex++ ) { AActor* Actor = Level->Actors[ActorIndex]; // Don't want to transform children they should stay relative to there parents. if( Actor && Actor->GetAttachParentActor() == NULL ) { // Has to modify root component directly as GetActorPosition is incorrect this early USceneComponent *RootComponent = Actor->GetRootComponent(); if (RootComponent) { RootComponent->SetRelativeLocationAndRotation( LevelTransform.TransformPosition(RootComponent->RelativeLocation), (FTransform(RootComponent->RelativeRotation) * LevelTransform).Rotator()); } } } #if WITH_EDITOR if( bDoPostEditMove ) { ApplyPostEditMove( Level ); } #endif // WITH_EDITOR Level->OnApplyLevelTransform.Broadcast(LevelTransform); } }