using System.Collections.Generic; using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif using System.Linq; #if HDRP_IS_INSTALLED_FOR_UTS using UnityEngine.Rendering.HighDefinition; namespace Unity.Rendering.HighDefinition.Toon { [ExecuteAlways] [DisallowMultipleComponent] [RequireComponent(typeof(Light))] internal class BoxLightAdjustment : MonoBehaviour { private bool _initialized = false; private bool _srpCallbackInitialized = false; [SerializeField] private GameObject[] _gameObjects; [SerializeField] private Renderer[] _renderers; [SerializeField] internal HDAdditionalLightData targetBoxLight; [SerializeField] internal bool followGameObjectPosition = false; [SerializeField] internal bool followGameObjectRotation = false; [SerializeField] internal Vector3 positionOffset; [SerializeField] internal Quaternion rotationOffset; #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(); } // Start is called before the first frame update private void Start() { } // 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 (_renderers == null) { return; } if (targetBoxLight == null) { return; } // TODO: Set rendering layer mask when property changed. for (var ii = 0; ii < _renderers.Length; ii++) { _renderers[ii].renderingLayerMask &= 0xffffff00; _renderers[ii].renderingLayerMask |= (uint)targetBoxLight.lightlayersMask; } if (_gameObjects != null && _gameObjects.Length > 0 && _gameObjects[0] != null) { if (followGameObjectPosition) { targetBoxLight.transform.position = _gameObjects[0].transform.position + positionOffset; } if (followGameObjectRotation) { targetBoxLight.transform.rotation = _gameObjects[0].transform.rotation * rotationOffset; } } } private void EnableSrpCallbacks() { if (!_srpCallbackInitialized) { _srpCallbackInitialized = true; } } private void DisableSrpCallbacks() { if (_srpCallbackInitialized) { _srpCallbackInitialized = false; } } private void OnEnable() { Initialize(); EnableSrpCallbacks(); } private void OnDisable() { DisableSrpCallbacks(); Release(); } private void UpdateObjectLightLayers() { Initialize(); } internal static GameObject CreateBoxLight(GameObject[] gameObjects) { if (gameObjects == null || gameObjects[0] == null) { Debug.LogError("Please, select a GameObject you want a Box Light to follow."); return null; } var gameObjectName = "Box Light for " + gameObjects[0].name; var lightGameObject = new GameObject(gameObjectName); #if UNITY_EDITOR Undo.RegisterCreatedObjectUndo(lightGameObject, "Created Boxlight adjustment"); #endif var hdLightData = lightGameObject.AddHDLight(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; #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._gameObjects = gameObjects; return lightGameObject; } 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 (_gameObjects == null) { return; } var objCount = _gameObjects.Length; var rendererCount = 0; var rendererList = new List(); for (var ii = 0; ii < objCount; ii++) { if (_gameObjects[ii] == null) { continue; } var renderer = _gameObjects[ii].GetComponent(); if (renderer != null) { rendererCount++; rendererList.Add(renderer); } var childGameObjects = _gameObjects[ii].GetComponentsInChildren().Select(t => t.gameObject).ToArray(); var childCount = childGameObjects.Length; for (var jj = 0; jj < childCount; jj++) { if (_gameObjects[ii] == childGameObjects[jj]) { continue; } var modelToonEvAdjustment = childGameObjects[jj].GetComponent(); if (modelToonEvAdjustment != null) { break; } renderer = childGameObjects[jj].GetComponent(); if (renderer == null) { continue; }; rendererList.Add(renderer); rendererCount++; } if (rendererCount != 0) { _renderers = rendererList.ToArray(); } } if (targetBoxLight != null && objCount > 0) { positionOffset = targetBoxLight.transform.position - _gameObjects[0].transform.position; rotationOffset = Quaternion.Inverse(_gameObjects[0].transform.rotation) * targetBoxLight.transform.rotation; } _initialized = true; } private void Release() { if (_initialized) { _renderers = null; } _initialized = false; } } } #endif // HDRP_IS_INSTALLED_FOR_UTS