| 250 | } |
| 251 | |
| 252 | void AMjOrbitCameraActor::Tick(float DeltaTime) |
| 253 | { |
| 254 | Super::Tick(DeltaTime); |
| 255 | |
| 256 | if (!CineCamera) |
| 257 | return; |
| 258 | |
| 259 | // --- Playback mode: read camera transforms from replay --- |
| 260 | if (bPlaybackCameraPath && ReplayMgr && ReplayMgr->bIsReplaying) |
| 261 | { |
| 262 | TArray<FMjReplayFrame>& Frames = ReplayMgr->Sessions.FindOrAdd(ReplayMgr->ActiveSessionName).Frames; |
| 263 | if (Frames.Num() > 0) |
| 264 | { |
| 265 | // Find frame at current playback time (same logic as OnReplayStep) |
| 266 | double StartTime = Frames[0].Timestamp; |
| 267 | double TargetTime = StartTime + (double)ReplayMgr->PlaybackTime; |
| 268 | |
| 269 | int32 FoundIdx = 0; |
| 270 | for (int32 i = 1; i < Frames.Num(); ++i) |
| 271 | { |
| 272 | if (Frames[i].Timestamp >= TargetTime) |
| 273 | break; |
| 274 | FoundIdx = i; |
| 275 | } |
| 276 | |
| 277 | const FMjReplayFrame& Frame = Frames[FoundIdx]; |
| 278 | if (Frame.bHasCameraData) |
| 279 | { |
| 280 | FVector TargetCamPos = Frame.CameraPosition; |
| 281 | |
| 282 | // Apply RelPos offset if the target articulation has one |
| 283 | // This shifts the camera the same way the robot position is shifted |
| 284 | if (CurrentTarget) |
| 285 | { |
| 286 | TArray<FReplayArticulationBinding>& Bindings = ReplayMgr->GetArticulationBindings(); |
| 287 | for (const FReplayArticulationBinding& B : Bindings) |
| 288 | { |
| 289 | if (B.Articulation == CurrentTarget && B.bRelativePosition && B.bInitialsCaptured) |
| 290 | { |
| 291 | FVector Offset( |
| 292 | B.InitialMjPosition.X - B.CsvStartPosition.X, |
| 293 | B.InitialMjPosition.Y - B.CsvStartPosition.Y, |
| 294 | B.InitialMjPosition.Z - B.CsvStartPosition.Z); |
| 295 | // Convert MuJoCo meters offset to Unreal cm (x100) |
| 296 | TargetCamPos += Offset * 100.0; |
| 297 | break; |
| 298 | } |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | FVector CurrentPos = CineCamera->GetComponentLocation(); |
| 303 | FRotator CurrentRot = CineCamera->GetComponentRotation(); |
| 304 | |
| 305 | FVector NewPos = FMath::VInterpTo(CurrentPos, TargetCamPos, DeltaTime, SmoothingSpeed); |
| 306 | FRotator NewRot = FMath::RInterpTo(CurrentRot, Frame.CameraRotation, DeltaTime, SmoothingSpeed); |
| 307 | |
| 308 | CineCamera->SetWorldLocationAndRotation(NewPos, NewRot); |
| 309 |
nothing calls this directly
no outgoing calls
no test coverage detected