# TsScreenPlayerTextureRenderer    - MultiViewActor: UE.MultiViewActor;// 用于渲染pvw/pgm画面 - ReceiveBeginPlay() => - this.RegisterLocalEventListener(); => - this.ChangeCameraTask(TaskData); ## RegisterLocalEventListener ```ts private RegisterLocalEventListener(): void { this.PVWCameraChangeFunc = (TaskData: UE.CamTaskDataRPC) => { if (this.CurTag == DirectorMode.PVWCameraRenderer) { this.ChangeCameraTask(TaskData); } } this.PGMCameraChangeFunc = (TaskData: UE.CamTaskDataRPC) => { if (this.CurTag == DirectorMode.PGMCameraRenderer) { this.ChangeCameraTask(TaskData); } } this.SwitchDirectorNetTagFunc = (oldTag: UE.GameplayTag, newTag: UE.GameplayTag) => { this.SwitchDirectorNetTagCallback(oldTag, newTag); } DirectorEventSystem.RegisterEventListener(this, DirectorEvent.OnPVWTaskRequested, this.PVWCameraChangeFunc); DirectorEventSystem.RegisterEventListener(this, DirectorEvent.OnPGMTaskRequested, this.PGMCameraChangeFunc); DirectorEventSystem.RegisterEventListener(this, DirectorEvent.SwitchDirectorMode, this.SwitchDirectorNetTagFunc) } ``` ## ChangeCameraTask ```ts ChangeCameraTask(TaskData: UE.CamTaskDataRPC) { if(!this.bStarted){ return; } if(this.DirectorCamManagerActor == null){ this.DirectorCamManagerActor = this.GetCameraManagerActor(); } // double check if(this.DirectorCamManagerActor == null){ return; } if (this.Task) { this.Task.Stop(); } this.Task = DirectorCamUtil.CreateCamTask(this, TaskData, CamTaskType.FullStream, this.DirectorCamManagerActor.droneCamera, null, this.DirectorCamManagerActor.handHeldCamera) if (this.Task) { this.Task.Start() this.BindCamera(this.Task.TryGetBindedMainCamera()); } } ``` # DirectorCamGroup.cpp ```c++ UDirectorSequencePlayer* UDirectorCamGroup::GetDirectorSequencePlayerFromPool(int CamIndex, bool IsPreview) { TargetPlayer = NewObject(this); TargetPlayer->SetCamSequence(CamIndex, SequenceActor); if(IsPreview) { CachedPreviewingPlayer.AddUnique(TargetPlayer); } else { CachedStreamingPlayer.AddUnique(TargetPlayer); } } ``` # PVW & PGM红框效果代码 TsDirectorCamManagerActor.ts ``` //客户机加入流程: //连接Server->同步当前场景->场景加载完成后收到本地事�?->初始化workShop //->确认机器身份,执行本机任务(异步任务处理流程) //异步处理流程:根据机器的性能,加入时间不同,状态差异自适应处理任务逻辑 // 服务端收到任务请�?->确保服务端的workShop初始化完�?->处理数据及同�?? // ->客户机收到同步数据后->等待自己的workshop初始化完�?->处理自己的逻辑 // 同一种任务只处理最近一�? ``` ## HandlePreStreamTaskByNetTag() 相关切区域与切镜代码会调用RequestPVWTaskServer() RequestPVWTaskServer() => RequestPVWTask() => HandlePreStreamTaskDataMulticast() => HandlePreStreamTaskByNetTag() ```ts HandlePreStreamTaskByNetTag(): void { if (this.prestreamTaskData) { switch (Utils.GetDirectorMode(this).TagName) { case DirectorMode.PVWAndPGM: if(!DirectorCamUtil.SubmitNewCommandIfDataNotChanged(this.preStreamTask, this.prestreamTaskData)){ if (this.preStreamTask) { this.preStreamTask.Stop() } this.preStreamTask = DirectorCamUtil.CreateCamTask(this, this.prestreamTaskData, CamTaskType.FullStream, this.droneCamera, this.PVWWindow, this.handHeldCamera) if (this.preStreamTask) { this.preStreamTask.Start() if (this.PVWWindow) { this.PVWWindow.SetViewBorderColor(0, new UE.LinearColor(0, 1, 0, 1)) } console.log('PVW Task:' + this.preStreamTask.workShop.BindPlacement.Title + " " + this.preStreamTask.groupName + " " + this.preStreamTask.camName) } } break case DirectorMode.Preview: this.RefreshWindowViewBorderColor() break case DirectorMode.PVW: this.HandlePVWTask() break; default: break } } } ``` # 130mm Bug日志 ```c++ [2024.08.06-05.08.09:625][373]Puerts: (0x00000703D1DF42D0) request PVW: WorkShop:3F855CF84C91BBD9207C0FAF5273586C, CamGroup:9223AA8A478BA88F1217CD86911EDAE1, Index=0, StartFrame:0 [2024.08.06-05.08.09:626][373]LogLevelSequence: Starting new camera cut: 'Cam_TalkShowZuo_ZhuJiWei24mm_1' [2024.08.06-05.08.09:626][373]Puerts: (0x00000703D1DF42D0) 设置相机目标: [2024.08.06-05.08.09:626][373]Puerts: (0x00000703D1DF42D0) PVW Task: 线下 站\n4 ZhuJiWei24mm [2024.08.06-05.08.11:550][487]Puerts: Warning: (0x00000703D1DF42D0) PauseOrResumeAllFxProp ,true [2024.08.06-05.08.11:551][487]Puerts: Warning: (0x00000703D1DF42D0) PauseOrResumeAllFxProp ,false [2024.08.06-05.08.11:551][487]LogChaosBone: Display: ResetDynamics: 1, ChaosBoneAssets Name: CBA_SK_JiaRan_Costume_BHair [2024.08.06-05.08.11:551][487]LogChaosBone: Display: ResetDynamics: 1, ChaosBoneAssets Name: CBA_SK_JiaRan_Costume_dress [2024.08.06-05.08.11:602][490]Puerts: Warning: (0x00000703D1DF42D0) BP_JiaRan_Costume_C_0 set visible false [2024.08.06-05.08.11:602][490]Puerts: Warning: (0x00000703D1DF42D0) teleport to livearea 031D1C1742D7EB4C76F6B397FF404FD8 [2024.08.06-05.08.11:602][490]Puerts: Warning: (0x00000703D1DF42D0) PauseOrResumeAllFxProp ,true [2024.08.06-05.08.11:602][490]Puerts: (0x00000703D1DF42D0) X=0.000 Y=0.000 Z=0.000 [2024.08.06-05.08.11:602][490]Puerts: Warning: (0x00000703D1DF42D0) PauseOrResumeAllFxProp ,false [2024.08.06-05.08.11:602][490]Puerts: (0x00000703D1DF42D0) BP_JiaRan_Costume_C_0,attach prop ,玩具水枪A [2024.08.06-05.08.11:603][490]Puerts: Warning: (0x00000703D1DF42D0) get socket of JiaRan: RightHandSocket [2024.08.06-05.08.11:604][490]Puerts: (0x00000703D1DF42D0) Attach prop 玩具水枪A [2024.08.06-05.08.11:604][490]Puerts: (0x00000703D1DF42D0) Idol.JiaRan successfully switch to 031D1C1742D7EB4C76F6B397FF404FD8 [2024.08.06-05.08.12:085][519]Puerts: Error: (0x00000703D1DF42D0) OnFinishDisappearFx(), but the idol visibility is true!!BP_JiaRan_Costume_C_0 [2024.08.06-05.08.12:107][520]Puerts: Warning: (0x00000703D1DF42D0) BP_JiaRan_Costume_C_0 set visible true [2024.08.06-05.08.12:108][520]LogBlueprintUserMessages: [BP_JiaRan_Costume_C_0] Apply Material. Oringinal Material: false [2024.08.06-05.08.12:108][520]Puerts: (0x00000703D1DF42D0) RefreshSceneCaptureShowList [2024.08.06-05.08.12:109][520]Puerts: (0x00000703D1DF42D0) CheckItemFxPool, size 0 [2024.08.06-05.08.12:109][520]Puerts: (0x00000703D1DF42D0) TriggerHandPose [2024.08.06-05.08.12:109][520]Puerts: (0x00000703D1DF42D0) TriggerHandPose [2024.08.06-05.08.12:109][520]Puerts: Warning: (0x00000703D1DF42D0) Disable instrument pose [2024.08.06-05.08.12:109][520]Puerts: (0x00000703D1DF42D0) Detect hand pose ToyGun [2024.08.06-05.08.12:109][520]Puerts: (0x00000703D1DF42D0) TriggerHandPose ToyGun [2024.08.06-05.08.12:455][541]Puerts: (0x00000703D1DF42D0) request PGM: WorkShop:3F855CF84C91BBD9207C0FAF5273586C, CamGroup:9223AA8A478BA88F1217CD86911EDAE1, Index=0, StartFrame:0 , PushMethod =0 [2024.08.06-05.08.12:805][562]Puerts: (0x00000703D1DF42D0) request PGM: WorkShop:3F855CF84C91BBD9207C0FAF5273586C, CamGroup:9223AA8A478BA88F1217CD86911EDAE1, Index=0, StartFrame:0 , PushMethod =0 [2024.08.06-05.08.14:606][670]LogBlueprintUserMessages: [BP_JiaRan_Costume_C_0] Apply Material. Oringinal Material: true [2024.08.06-05.08.15:822][743]Puerts: (0x00000703D1DF42D0) request PVW: WorkShop:3F855CF84C91BBD9207C0FAF5273586C, CamGroup:DDB1F27A44E7E5B312830A828EB55464, Index=0, StartFrame:0 [2024.08.06-05.08.15:823][743]LogLevelSequence: Starting new camera cut: 'Cine_Camera_Actor_1' [2024.08.06-05.08.15:823][743]Puerts: (0x00000703D1DF42D0) 设置相机目标: [2024.08.06-05.08.15:824][743]Puerts: (0x00000703D1DF42D0) PVW Task: 线下 贝拉2024生日 lengthtest [2024.08.06-05.08.15:824][743]LogBlueprintUserMessages: [BP_Cine_Cam_FOV_1] 35.0 [2024.08.06-05.08.16:256][769]LogBlueprintUserMessages: [BP_Cine_Cam_FOV_1] 35.002922 ``` 相关Log顺序: - request PVW: WorkShop:3F855CF84C91BBD9207C0FAF5273586C, CamGroup:DDB1F27A44E7E5B312830A828EB55464, Index=0, StartFrame:0 - LogLevelSequence: Starting new camera cut: 'Cine_Camera_Actor_1' - Puerts: 设置相机目标: - Puerts: PVW Task: 线下 贝拉2024生日 lengthtest - PrintString BP_Cine_Cam_FOV_1 35.0 ***HandlePVWTask中的prestreamTaskData 不对*** ## 日志 ``` Puerts: (0x000009E309FB5E30) request PVW: WorkShop:3F855CF84C91BBD9207C0FAF5273586C, CamGroup:B3441B7649E66555CCB558B2C0FD2872, Index=0, StartFrame:0 LogLevelSequence: Starting new camera cut: 'ZhuJiwei_Zheng16-24mm_5' Puerts: (0x000009E309FB5E30) 130mm bug用log:,其他相机1 bindingCam逻辑,ZhuJiwei_Zheng16-24mm_5 Puerts: (0x000009E309FB5E30) 130mm bug用log:,其他相机2 bindingCam逻辑,ZhuJiwei_Zheng16-24mm_5 Puerts: (0x000009E309FB5E30) 130mm bug用log:,ChangeSequenceCamTarget FullStream Other Puerts: (0x000009E309FB5E30) 设置相机目标: Idol.BeiLa 0 Puerts: (0x000009E309FB5E30) PVW Task: 线下 单唱站\nFastRhythm ZhuJiwei_Zheng16-24mm Puerts: (0x000009E309FB5E30) request PVW: WorkShop:3F855CF84C91BBD9207C0FAF5273586C, CamGroup:DDB1F27A44E7E5B312830A828EB55464, Index=0, StartFrame:0 Puerts: (0x000009E309FB5E30) Nice Playing Sequence:LevelSequenceActor_2:BP_lengthtest_1 Puerts: (0x000009E309FB5E30) RebindTarget: BP_BeiLa_Costume_C_0 PIE: Warning: Sequence did not contain any bindings with the tag 'Beila' LevelSequenceActor_2 LogLevelSequence: Starting new camera cut: 'CineCameraActor_Focus130MMTest_1' Puerts: (0x000009E309FB5E30) 130mm bug用log:,其他相机1 bindingCam逻辑,CineCameraActor_Focus130MMTest_1 Puerts: (0x000009E309FB5E30) 130mm bug用log:,其他相机2 bindingCam逻辑,CineCameraActor_Focus130MMTest_1 Puerts: (0x000009E309FB5E30) 130mm bug用log:,ChangeSequenceCamTarget FullStream Other Puerts: (0x000009E309FB5E30) 设置相机目标: Idol.BeiLa 0 Puerts: (0x000009E309FB5E30) PVW Task: 线下 贝拉2024生日 BP_lengthtest_1 LogBlueprintUserMessages: [BP_Cine_Cam_FOV_1] 35.0 ``` ## 可能的相关代码 ```c // 播放指定相机到PVW. @ufunction.ufunction(ufunction.ServerAPI, ufunction.Reliable) PlayCamSequenceOnPVWServer(camGroupId:UE.Guid, camIndex:number):void{ let shotExists = this.directorCamSubSystem.ShotExistInGroup(this.prestreamTaskData.WorkShopId, camGroupId, camIndex) if (shotExists || camIndex == DirectorCamUtil.DRONE_CAM_INDEX || camIndex == DirectorCamUtil.HANDHELD_CAM_INDEX) { let newPVWTaskData = DirectorCamUtil.CopyTaskData(this.prestreamTaskData) newPVWTaskData.CamGroupId = camGroupId newPVWTaskData.CamIndex = camIndex newPVWTaskData.StartFrame = 0 newPVWTaskData.bPreviewOneFrame = false this.RequestPVWTaskServer(newPVWTaskData) } else { console.warn('当前镜头不存�?,切换无效!index=' + camIndex) } } class TsDirectorCamSequencePlayBridge extends UE.Actor {     PlayCamSequence(camGroupId:UE.Guid, camIndex:number): void {         let camManager = TsDirectorCamManagerActor.Get(this);         if (camManager) {             camManager.PlayCamSequenceOnPVWServer(camGroupId, camIndex);         }     } } ``` ```c++ // 切换到当前直播区域中的多个workShop SwitchWorkShopInAreaServer(index: number): void { // [Server]监听到场景模块切换了直播区域后,自动切换�?0个workshop,当前切换事件用来切换当前直播区域中的多个workshop let levelControl = this.GetLevelAreaManager() let liveArea = levelControl.GetCurrentLiveArea() if (!liveArea) { console.error('DirectorCamManager@ cannot find LiveAreaBy id') return } let placement = DirectorCamUtil.GetPlacementInCurLiveArea(index, liveArea) if (!placement) { console.error('DirectorCamManager@SwitchWorkShopEvent:GetPlacementInCurLiveArea failed') return } let GroupData = DirectorCamUtil.GetDefaultGroupData(this, placement.UUID) if (GroupData) { // 预览:切换workShop后播放第一个分�? let newPreviewTaskData = new UE.CamTaskDataRPC() newPreviewTaskData.WorkShopId = DirectorCamUtil.CopyGuid(placement.UUID) newPreviewTaskData.CamGroupId = DirectorCamUtil.CopyGuid(GroupData.UUID) newPreviewTaskData.CamIndex = 0 newPreviewTaskData.OperationId = this.previewTaskData.OperationId + 1 newPreviewTaskData.StartFrame = 0 newPreviewTaskData.bPreviewOneFrame = false this.HandlePreviewTaskDataMulticast(newPreviewTaskData); // 预推流:切换workShop后,播放第一个分组的第一个镜头 let newPVWTaskData = new UE.CamTaskDataRPC() newPVWTaskData.WorkShopId = DirectorCamUtil.CopyGuid(placement.UUID) newPVWTaskData.CamGroupId = DirectorCamUtil.CopyGuid(GroupData.UUID) newPVWTaskData.CamIndex = 0 newPVWTaskData.StartFrame = 0 newPVWTaskData.bPreviewOneFrame = false this.RequestPVWTaskServer(newPVWTaskData); } } ```