using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif #if HDRP_IS_INSTALLED_FOR_UTS using UnityEngine.Rendering.HighDefinition; using Unity.Properties; namespace Misaki.HdrpToon { [ExecuteAlways] [DisallowMultipleComponent] [RequireComponent(typeof(Light))] public class BoxLightAdjustment : MonoBehaviour { private bool _initialized = false; private bool _srpCallbackInitialized = false; [SerializeField] private HDAdditionalLightData _bindingSourceLightData; [SerializeField] private HDAdditionalLightData _targetBoxLightData; [SerializeField] private uint _layerMask; [SerializeField] private Light _bindingSourceLight; [SerializeField] private Light _targetBoxLight; public Transform trackedTransform; public bool followGameObjectPosition = false; public float distanceOffset = 20.0f; [CreateProperty] public Light BindingSourceLight { get => _bindingSourceLight; set { _bindingSourceLight = value; _bindingSourceLightData = _bindingSourceLight.GetComponent(); } } [CreateProperty] public Light TargetBoxLight { get => _targetBoxLight; set { _targetBoxLight = value; _targetBoxLightData = _targetBoxLight.GetComponent(); } } [CreateProperty] public uint LayerMask { get => _layerMask; set { if (_targetBoxLight == null || _bindingSourceLight == null) { return; } UpdateShadowLayer(_bindingSourceLightData, value); UpdateShadowLayer(_targetBoxLightData, value); _layerMask = value; } } #if UNITY_EDITOR #pragma warning restore CS0414 private bool _isCompiling = false; #endif private void Reset() { OnDisable(); OnEnable(); } internal void OnValidate() { Release(); Initialize(); } private void Awake() { Initialize(); } // Update is called once per frame private void Update() { Initialize(); #if UNITY_EDITOR // handle script recompile if (EditorApplication.isCompiling && !_isCompiling) { // on compile begin _isCompiling = true; // Release(); no need return; // } else if (!EditorApplication.isCompiling && _isCompiling) { // on compile end _isCompiling = false; } #endif if (_targetBoxLight == null || _bindingSourceLight == null) { return; } _targetBoxLight.enabled = _bindingSourceLight.enabled; _targetBoxLight.intensity = _bindingSourceLight.intensity; if (trackedTransform != null && followGameObjectPosition) { var desiredPosition = trackedTransform.position - _bindingSourceLight.transform.forward * distanceOffset; _targetBoxLight.transform.position = desiredPosition; _targetBoxLight.transform.rotation = _bindingSourceLight.transform.rotation; } } private void EnableSrpCallbacks() { if (!_srpCallbackInitialized) { _srpCallbackInitialized = true; } } private void DisableSrpCallbacks() { if (_srpCallbackInitialized) { _srpCallbackInitialized = false; } } private void OnEnable() { Initialize(); EnableSrpCallbacks(); } private void OnDisable() { DisableSrpCallbacks(); Release(); } internal static GameObject CreateBoxLight(Transform transform) { if (transform == null) { Debug.LogError("Please, select a GameObject you want a Box Light to follow."); return null; } var gameObjectName = "Box Light for " + transform.name; var lightGameObject = new GameObject(gameObjectName); #if UNITY_EDITOR Undo.RegisterCreatedObjectUndo(lightGameObject, "Created Boxlight adjustment"); #endif var hdLightData = lightGameObject.AddHDLight(UnityEngine.LightType.Box); // light size hdLightData.SetBoxSpotSize(new Vector2(10.0f, 10.0f)); // Size should be culculated with more acculacy? var boxLightAdjustment = lightGameObject.GetComponent(); if (boxLightAdjustment == null) { #if UNITY_EDITOR boxLightAdjustment = Undo.AddComponent(lightGameObject); #else boxLightAdjustment = lightGameObject.AddComponent(); #endif } #if UNITY_EDITOR Undo.RecordObject(boxLightAdjustment, "target " + boxLightAdjustment.name); #endif boxLightAdjustment._targetBoxLight = hdLightData.GetComponent(); #if UNITY_EDITOR Undo.RecordObject(lightGameObject.transform, "Position " + lightGameObject.transform.name); #endif // position and rotation var goPos = lightGameObject.transform.position; goPos.y += 10.0f; lightGameObject.transform.position = goPos; var goRot = lightGameObject.transform.rotation; goRot.eulerAngles = new Vector3(90.0f, 0.0f, 0.0f); #if UNITY_EDITOR Undo.RecordObject(lightGameObject.transform, "Rotation " + lightGameObject.transform.name); #endif hdLightData.gameObject.transform.rotation = goRot; // must be put to gameObject model chain. boxLightAdjustment.trackedTransform = transform; return lightGameObject; } private void UpdateShadowLayer(HDAdditionalLightData lightData, uint newValue) { lightData.linkShadowLayers = false; var lightLayer = lightData.GetLightLayers(); var newShadowLayer = lightLayer | newValue | UnityEngine.RenderingLayerMask.defaultRenderingLayerMask; lightData.SetShadowLightLayer((UnityEngine.Rendering.HighDefinition.RenderingLayerMask)newShadowLayer); } private void Initialize() { if (_initialized) { return; } #if UNITY_EDITOR // initializing renderer can interfere GI baking. so wait until it is completed. if (EditorApplication.isCompiling) return; #endif if (trackedTransform == null) { return; } if (_targetBoxLight != null) { distanceOffset = Mathf.Abs(Vector3.Distance(_targetBoxLight.transform.position, trackedTransform.transform.position)); } _initialized = true; } private void Release() { _initialized = false; } } } #endif // HDRP_IS_INSTALLED_FOR_UTS