From fa7cfcf948829b218ccc27fa7261bc61e8c4e522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=C3=AF=7E?= Date: Sun, 22 Dec 2024 22:08:18 +0100 Subject: [PATCH] Handle case where a mirror is ON: - Make object state after rendering camera more consistent: - When first-person camera finishes rendering: - rescale head back to one. - make first-person head shadow invisible. - This fixes an issue where having a mirror turned on would cause the head to be scaled to zero, which was messing the head shadow processing on the next frame. - Defensively protect access to the HeadShadowDriver field, which is null for a short time window on application load, but non-null of the time. --- .../Devices/Desktop/BasisLocalInputActions.cs | 6 ++- .../Drivers/BasisLocalCameraDriver.cs | 40 ++++++++++++++++++- .../Players/BasisHeadShadowDriver.cs | 33 ++++++++++++--- 3 files changed, 71 insertions(+), 8 deletions(-) diff --git a/Basis/Packages/Basis Framework/Device Management/Devices/Desktop/BasisLocalInputActions.cs b/Basis/Packages/Basis Framework/Device Management/Devices/Desktop/BasisLocalInputActions.cs index b7adecd93..46c3bee6e 100644 --- a/Basis/Packages/Basis Framework/Device Management/Devices/Desktop/BasisLocalInputActions.cs +++ b/Basis/Packages/Basis Framework/Device Management/Devices/Desktop/BasisLocalInputActions.cs @@ -67,7 +67,11 @@ private void OnBeforeRender() { BasisLocalPlayer.Instance.LocalBoneDriver.SimulateAndApply(Time.timeAsDouble,Time.deltaTime); AfterAvatarChanges?.Invoke(); - BasisLocalPlayer.Instance.HeadShadowDriver.PrepareThisFrame(); + + // Defensive check, this only seems to be null when the first avatar is not loaded yet. + // May be fixable by updating the prefab so that it's always defined by default. + if (BasisLocalPlayer.Instance.HeadShadowDriver) + BasisLocalPlayer.Instance.HeadShadowDriver.PrepareThisFrame(); } public void Update() diff --git a/Basis/Packages/Basis Framework/Drivers/BasisLocalCameraDriver.cs b/Basis/Packages/Basis Framework/Drivers/BasisLocalCameraDriver.cs index 8d6b0e203..876ec68ba 100644 --- a/Basis/Packages/Basis Framework/Drivers/BasisLocalCameraDriver.cs +++ b/Basis/Packages/Basis Framework/Drivers/BasisLocalCameraDriver.cs @@ -69,6 +69,7 @@ public void OnEnable() MicrophoneRecorder.MainThreadOnHasAudio += MicrophoneTransmitting; MicrophoneRecorder.MainThreadOnHasSilence += MicrophoneNotTransmitting; RenderPipelineManager.beginCameraRendering += BeginCameraRendering; + RenderPipelineManager.endCameraRendering += EndCameraRendering; BasisDeviceManagement.Instance.OnBootModeChanged += OnModeSwitch; BasisLocalPlayer.Instance.OnPlayersHeightChanged += OnHeightChanged; InstanceExists?.Invoke(); @@ -285,6 +286,7 @@ public void OnDisable() if (HasEvents) { RenderPipelineManager.beginCameraRendering -= BeginCameraRendering; + RenderPipelineManager.endCameraRendering -= BeginCameraRendering; BasisDeviceManagement.Instance.OnBootModeChanged -= OnModeSwitch; MicrophoneRecorder.MainThreadOnHasAudio -= MicrophoneTransmitting; MicrophoneRecorder.MainThreadOnHasSilence -= MicrophoneNotTransmitting; @@ -297,7 +299,11 @@ public void BeginCameraRendering(ScriptableRenderContext context, Camera Camera) { if (Camera.GetInstanceID() == CameraInstanceID) { - LocalPlayer.HeadShadowDriver.BeforeRenderFirstPerson(); + // Defensive check, this only seems to be null when the first avatar is not loaded yet. + // May be fixable by updating the prefab so that it's always defined by default. + if (LocalPlayer.HeadShadowDriver) + LocalPlayer.HeadShadowDriver.BeforeRenderFirstPerson(); + ScaleheadToZero(); if (CameraData.allowXRRendering) { @@ -311,11 +317,41 @@ public void BeginCameraRendering(ScriptableRenderContext context, Camera Camera) } else { - LocalPlayer.HeadShadowDriver.BeforeRenderThirdPerson(); + // Defensive check, this only seems to be null when the first avatar is not loaded yet. + // May be fixable by updating the prefab so that it's always defined by default. + if (LocalPlayer.HeadShadowDriver) + LocalPlayer.HeadShadowDriver.BeforeRenderThirdPerson(); + ScaleHeadToNormal(); } } } + + private void EndCameraRendering(ScriptableRenderContext context, Camera Camera) + { + if (LocalPlayer.HasAvatarDriver && LocalPlayer.AvatarDriver.References.Hashead) + { + if (Camera.GetInstanceID() == CameraInstanceID) + { + // Rescale head to avoid making the end state of the avatar + // dependent on the last rendered camera. + ScaleHeadToNormal(); + + // Defensive check, this only seems to be null when the first avatar is not loaded yet. + // May be fixable by updating the prefab so that it's always defined by default. + if (LocalPlayer.HeadShadowDriver) + LocalPlayer.HeadShadowDriver.AfterRenderFirstPerson(); + } + else + { + // Defensive check, this only seems to be null when the first avatar is not loaded yet. + // May be fixable by updating the prefab so that it's always defined by default. + if (LocalPlayer.HeadShadowDriver) + LocalPlayer.HeadShadowDriver.AfterRenderThirdPerson(); + } + } + } + public void ScaleHeadToNormal() { if (LocalPlayer.AvatarDriver.References.head.localScale != LocalPlayer.AvatarDriver.HeadScale) diff --git a/Basis/Packages/Basis Framework/Players/BasisHeadShadowDriver.cs b/Basis/Packages/Basis Framework/Players/BasisHeadShadowDriver.cs index c64ed580d..4c2540115 100644 --- a/Basis/Packages/Basis Framework/Players/BasisHeadShadowDriver.cs +++ b/Basis/Packages/Basis Framework/Players/BasisHeadShadowDriver.cs @@ -170,7 +170,33 @@ public void BeforeRenderFirstPerson() { if (!_isShadowNecessary) return; - // Made shadow visible. + MakeShadowVisible(); + } + + public void AfterRenderFirstPerson() + { + if (!_isShadowNecessary) return; + + // Make shadow invisible to avoid making the end state of the avatar + // dependent on the last rendered camera. + MakeShadowInvisible(); + } + + public void BeforeRenderThirdPerson() + { + if (!_isShadowNecessary) return; + + MakeShadowInvisible(); + } + + public void AfterRenderThirdPerson() + { + if (!_isShadowNecessary) return; + + } + + private void MakeShadowVisible() + { // There may be better ways to do this. for (var index = 0; index < _copiesOfSkinnedMeshes.Length; index++) { @@ -186,11 +212,8 @@ public void BeforeRenderFirstPerson() } } - public void BeforeRenderThirdPerson() + private void MakeShadowInvisible() { - if (!_isShadowNecessary) return; - - // Made shadow invisible, so that it doesn't cast shadow on the thing it's trying to copy. // There may be better ways to do this. foreach (var copy in _copiesOfSkinnedMeshes) {