diff --git a/Assets/GothicVR/Scripts/Creator/VobCreator.cs b/Assets/GothicVR/Scripts/Creator/VobCreator.cs index 5b8ac6c4b..7e4560e13 100644 --- a/Assets/GothicVR/Scripts/Creator/VobCreator.cs +++ b/Assets/GothicVR/Scripts/Creator/VobCreator.cs @@ -513,6 +513,9 @@ private static GameObject CreateLight(ZenKit.Vobs.Light vob) SetPosAndRot(vobObj, vob.Position, vob.Rotation); StationaryLight lightComp = vobObj.AddComponent(); + lightComp.ColorAnimationList = vob.ColorAnimationList.Select(color => + new Color(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f)).ToList(); + lightComp.ColorAnimationFps = vob.ColorAnimationFps; lightComp.Color = new Color(vob.Color.R / 255f, vob.Color.G / 255f, vob.Color.B / 255f, vob.Color.A / 255f); lightComp.Type = vob.LightType == ZenKit.Vobs.LightType.Point ? UnityEngine.LightType.Point diff --git a/Assets/GothicVR/Scripts/Creator/WorldCreator.cs b/Assets/GothicVR/Scripts/Creator/WorldCreator.cs index 0fd4a0d72..b8b773e37 100644 --- a/Assets/GothicVR/Scripts/Creator/WorldCreator.cs +++ b/Assets/GothicVR/Scripts/Creator/WorldCreator.cs @@ -74,6 +74,7 @@ public static async Task CreateAsync(string worldName) SkyManager.I.InitSky(); StationaryLight.InitStationaryLights(); + StationaryLightsManager.I.InitLightColorChange(); if (FeatureFlags.I.showBarrier) { diff --git a/Assets/GothicVR/Scripts/Manager/StationaryLightsManager.cs b/Assets/GothicVR/Scripts/Manager/StationaryLightsManager.cs index e4836ca10..19b65ec56 100644 --- a/Assets/GothicVR/Scripts/Manager/StationaryLightsManager.cs +++ b/Assets/GothicVR/Scripts/Manager/StationaryLightsManager.cs @@ -1,3 +1,5 @@ +using System; +using System.Collections; using System.Collections.Generic; using GVR.Util; using UnityEngine; @@ -21,10 +23,38 @@ private void LateUpdate() { UpdateRenderer(renderer); } + DirtiedMeshes.Clear(); Profiler.EndSample(); } } + + public void InitLightColorChange() + { + StartCoroutine(UpdateLightColors()); + } + + + private IEnumerator UpdateLightColors() + { + while(true) + { + var colorIndices = + Shader.GetGlobalFloatArray(StationaryLight.GlobalStationaryLightColorIndicesShaderId); + var highestTimeInterval = 0f; + foreach (var light in StationaryLight.Lights) + { + colorIndices[light.Index] = Array.IndexOf(StationaryLight.LightColors, + StationaryLight.Lights[light.Index].Color.linear); + if (highestTimeInterval < light.ColorAnimationFps) + highestTimeInterval = light.ColorAnimationFps; + } + + Shader.SetGlobalFloatArray(StationaryLight.GlobalStationaryLightColorIndicesShaderId, colorIndices); + yield return new WaitForSeconds(1 / highestTimeInterval); + } + } + public static void AddLightOnRenderer(StationaryLight light, MeshRenderer renderer) { if (!LightsPerRenderer.ContainsKey(renderer)) @@ -67,12 +97,14 @@ private void UpdateRenderer(MeshRenderer renderer) { indicesMatrix[i / 4, i % 4] = LightsPerRenderer[renderer][i].Index; } + for (int i = 0; i < NonAllocMaterials.Count; i++) { if (NonAllocMaterials[i]) { NonAllocMaterials[i].SetMatrix(StationaryLight.StationaryLightIndicesShaderId, indicesMatrix); - NonAllocMaterials[i].SetInt(StationaryLight.StationaryLightCountShaderId, LightsPerRenderer[renderer].Count); + NonAllocMaterials[i].SetInt(StationaryLight.StationaryLightCountShaderId, + LightsPerRenderer[renderer].Count); } } @@ -82,6 +114,7 @@ private void UpdateRenderer(MeshRenderer renderer) { indicesMatrix[i / 4, i % 4] = LightsPerRenderer[renderer][i + 16].Index; } + for (int i = 0; i < NonAllocMaterials.Count; i++) { if (NonAllocMaterials[i]) @@ -92,4 +125,4 @@ private void UpdateRenderer(MeshRenderer renderer) } } } -} +} \ No newline at end of file diff --git a/Assets/GothicVR/Scripts/Vob/StationaryLight.cs b/Assets/GothicVR/Scripts/Vob/StationaryLight.cs index c19623489..9e43e4cd0 100644 --- a/Assets/GothicVR/Scripts/Vob/StationaryLight.cs +++ b/Assets/GothicVR/Scripts/Vob/StationaryLight.cs @@ -1,6 +1,8 @@ using GVR.Manager; using System; +using System.Collections; using System.Collections.Generic; +using System.Linq; using GVR.Extensions; using UnityEngine; using UnityEngine.Profiling; @@ -114,6 +116,7 @@ public float SpotAngle public static readonly List Lights = new List(); public static readonly int GlobalStationaryLightPositionsAndAttenuationShaderId = Shader.PropertyToID("_GlobalStationaryLightPositionsAndAttenuation"); + public static readonly int GlobalStationaryLightColorIndicesShaderId = Shader.PropertyToID("_GlobalStationaryLightColorIndices"); public static readonly int GlobalStationaryLightColorsShaderId = Shader.PropertyToID("_GlobalStationaryLightColors"); public static readonly int StationaryLightIndicesShaderId = Shader.PropertyToID("_StationaryLightIndices"); public static readonly int StationaryLightIndices2ShaderId = Shader.PropertyToID("_StationaryLightIndices2"); @@ -124,6 +127,10 @@ public float SpotAngle private List _affectedRenderers = new List(); private Light _unityLight; private static readonly List<(Vector3 Position, float Range)> ThreadSafeLightData = new(); + internal int CurrentColorIndex; + internal float ColorAnimationFps; // change color every 1/ColorAnimationFps seconds + internal List ColorAnimationList = new(); + public static Vector4[] LightColors; private void OnDrawGizmosSelected() { @@ -151,6 +158,7 @@ private void OnDestroy() private void OnEnable() { Profiler.BeginSample("Stationary light enabled"); + StartCoroutine(ChangeColor(this)); for (int i = 0; i < _affectedRenderers.Count; i++) { StationaryLightsManager.AddLightOnRenderer(this, _affectedRenderers[i]); @@ -161,6 +169,7 @@ private void OnEnable() private void OnDisable() { Profiler.BeginSample("Stationary light disable"); + StopCoroutine(ChangeColor(this)); for (int i = 0; i < _affectedRenderers.Count; i++) { StationaryLightsManager.RemoveLightOnRenderer(this, _affectedRenderers[i]); @@ -175,23 +184,46 @@ public static void InitStationaryLights() // e.g. if we disabled Vob loading within FeatureFlags. if (Lights.IsEmpty()) return; - + List _lightColorsList = new List(); + foreach (var light in Lights) + { + _lightColorsList.Add(light.Color.linear); + _lightColorsList.AddRange(light.ColorAnimationList.Select(t => t.linear).Select(dummy => (Vector4)dummy)); + } Vector4[] _lightPositionsAndAttenuation = new Vector4[Lights.Count]; - Vector4[] _lightColors = new Vector4[Lights.Count]; + float[] _lightColorIndices = new float[Lights.Count]; + LightColors = _lightColorsList.Distinct().ToArray(); for (int i = 0; i < Lights.Count; i++) { Lights[i].Index = i; Lights[i].GatherRenderers(); _lightPositionsAndAttenuation[i] = new Vector4(Lights[i].transform.position.x, Lights[i].transform.position.y, Lights[i].transform.position.z, 1f / (Lights[i].Range * Lights[i].Range)); - _lightColors[i] = Lights[i].Color.linear; + int index = Array.IndexOf(LightColors, Lights[i].Color.linear); + _lightColorIndices[i] = index; Lights[i].gameObject.SetActive(false); Lights[i].gameObject.SetActive(true); } Shader.SetGlobalVectorArray(GlobalStationaryLightPositionsAndAttenuationShaderId, _lightPositionsAndAttenuation); - Shader.SetGlobalVectorArray(GlobalStationaryLightColorsShaderId, _lightColors); + Shader.SetGlobalFloatArray(GlobalStationaryLightColorIndicesShaderId, _lightColorIndices); + Shader.SetGlobalVectorArray(GlobalStationaryLightColorsShaderId, LightColors); ThreadSafeLightData.Clear(); // Clear the thread safe data as it is no longer needed. } + + private static IEnumerator ChangeColor(StationaryLight light) + { + yield return new WaitForSeconds(1 / light.ColorAnimationFps); + while (true) + { + yield return new WaitForSeconds(1 / light.ColorAnimationFps); + if (light.ColorAnimationList.Count == 0) continue; + light.CurrentColorIndex++; + if (light.CurrentColorIndex >= light.ColorAnimationList.Count) + light.CurrentColorIndex = 0; + + light.Color = light.ColorAnimationList[light.CurrentColorIndex]; + } + } public static int CountLightsInBounds(Bounds bounds) { diff --git a/Assets/GothicVR/Shaders/StationaryLighting.hlsl b/Assets/GothicVR/Shaders/StationaryLighting.hlsl index 52d7b88d1..d1a6237f5 100644 --- a/Assets/GothicVR/Shaders/StationaryLighting.hlsl +++ b/Assets/GothicVR/Shaders/StationaryLighting.hlsl @@ -5,6 +5,7 @@ #define MAX_AFFECTING_STATIONARY_LIGHTS 16 float4 _GlobalStationaryLightPositionsAndAttenuation[MAX_TOTAL_STATIONARY_LIGHTS]; +float _GlobalStationaryLightColorIndices[MAX_TOTAL_STATIONARY_LIGHTS]; real3 _GlobalStationaryLightColors[MAX_TOTAL_STATIONARY_LIGHTS]; half3 AdditionalStationaryDiffuse(uint lightIndex, real3 worldPos, real3 normal) @@ -15,7 +16,7 @@ half3 AdditionalStationaryDiffuse(uint lightIndex, real3 worldPos, real3 normal) half3 lightDirection = half3(lightVector * rsqrt(distanceSqr)); float diffuseDot = saturate(dot(lightDirection, normal)); - return _GlobalStationaryLightColors[lightIndex] * CustomDistanceAttenuation(distanceSqr, lightPosAndAttenuation.w) * diffuseDot * _PointLightIntensity; + return _GlobalStationaryLightColors[_GlobalStationaryLightColorIndices[lightIndex]] * CustomDistanceAttenuation(distanceSqr, lightPosAndAttenuation.w) * diffuseDot * _PointLightIntensity; } #endif \ No newline at end of file