// Copyright (C) 2023 Nicholas Maltbie // // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and // associated documentation files (the "Software"), to deal in the Software without restriction, // including without limitation the rights to use, copy, modify, merge, publish, distribute, // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or // substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. using nickmaltbie.OpenKCC.Utils; using nickmaltbie.TestUtilsUnity; using UnityEngine; namespace nickmaltbie.OpenKCC.cinemachine.Player { public class PlayerFade : MonoBehaviour { /// /// Unity service for testing the player fading. /// public IUnityService unityService = UnityService.Instance; /// /// Game object for fading the avatar /// public GameObject avatarBase; /// /// Object to rotate for camera to follow. /// public GameObject followTarget; /// /// If the camera is within some given units of the player, /// fade the player avatar. /// public float fadeThreshold = 1.5f; /// /// Distance to only show shadows for the player. /// public float shadowOnlyDistance = 0.25f; /// /// Camera radius /// public float cameraRadius = 0.1f; /// /// Time it takes to fade the player avatar. /// private float fadeTime = 1.0f; /// /// Previous opacity of player. /// private float PreviousOpacity { get; set; } public void Update() { // Fade avatar based on distance to player Vector3 source = Camera.main.transform.position; Vector3 target = followTarget.transform.position; Vector3 dir = target - source; bool hittingSelf = PhysicsUtils.SphereCastAllow(gameObject, source, cameraRadius, dir, dir.magnitude, ~0, QueryTriggerInteraction.Ignore, out RaycastHit selfHit); float actualDistance = hittingSelf ? selfHit.distance : dir.magnitude; if (actualDistance <= shadowOnlyDistance) { MaterialUtils.RecursiveSetShadowCastingMode(avatarBase, UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly); } else { MaterialUtils.RecursiveSetShadowCastingMode(avatarBase, UnityEngine.Rendering.ShadowCastingMode.On); } if (actualDistance > shadowOnlyDistance && actualDistance < fadeThreshold) { float newOpacity = (actualDistance - shadowOnlyDistance) / fadeThreshold; float lerpPosition = fadeTime > 0 ? unityService.deltaTime * 1 / fadeTime : 1; PreviousOpacity = Mathf.Lerp(PreviousOpacity, newOpacity, lerpPosition); // Set opacity of character based on how close the camera is MaterialUtils.RecursiveSetFloatProperty(avatarBase, "_Opacity", PreviousOpacity); } else { // Set opacity of character based on how close the camera is MaterialUtils.RecursiveSetFloatProperty(avatarBase, "_Opacity", 1); PreviousOpacity = actualDistance > shadowOnlyDistance ? 1 : 0; } } } }