public static void AddLight(VolumetricLight light)
 {
     if (!allLights.Contains(light))
     {
         allLights.Add(light);
     }
 }
        static void SetupSpotLight(VolumetricLight light, CommandBuffer cb, Vector3 lightPos, bool drawShadows)
        {
            float angleScale = Mathf.Tan((light.spotAngle + 1) * 0.5f * Mathf.Deg2Rad) * light.range;

            Quaternion rotation = light.transform.rotation;
            Matrix4x4  world    = Matrix4x4.TRS(lightPos, rotation, new Vector3(angleScale, angleScale, light.range));
            Matrix4x4  view     = Matrix4x4.TRS(lightPos, rotation, Vector3.one).inverse;

            Vector3 fwd = light.transform.forward;
            // cosAngle, planeD,
            Vector2 extraParams = new Vector2(Mathf.Cos((light.spotAngle + 1) * 0.5f * Mathf.Deg2Rad), -Vector3.Dot((lightPos + fwd * light.lightC.range), fwd));

            cb.SetGlobalVector(_ConeAxis, fwd);

            SetNonDirectionalParams(light, cb, lightPos, ref world, drawShadows, extraParams);

            if (light.cookie != null)
            {
                Matrix4x4 proj = Matrix4x4.Perspective(light.spotAngle, 1, 0, 1);
                cb.SetGlobalMatrix(_MyLightMatrix0, spotClipNeg * proj * view);
            }

            if (drawShadows)
            {
                Matrix4x4 proj = Matrix4x4.Perspective(light.spotAngle, 1, SystemInfo.usesReversedZBuffer ? light.range : light.lightC.shadowNearPlane, SystemInfo.usesReversedZBuffer ? light.lightC.shadowNearPlane : light.range);
                Matrix4x4 m    = spotClip * proj;
                m[0, 2] *= -1; m[1, 2] *= -1; m[2, 2] *= -1; m[3, 2] *= -1;
                cb.SetGlobalMatrix(_MyWorld2Shadow, m * view);
            }

            cb.DrawMesh(VolumetricLightUtils.spotlightMesh, world, VolumetricLightUtils.GetMaterial(LightType.Spot), 0, IsCameraInSpotLightBounds(light, fwd) ? 0 : 1);
        }
        static void DrawLight(VolumetricLight light, CommandBuffer cb)
        {
            bool forceShadowsOff = light.type != LightType.Directional && light.cam2LightDist >= QualitySettings.shadowDistance;
            bool drawShadows     = light.lightC.shadows != LightShadows.None && light.lightC.shadowStrength > 0 && !forceShadowsOff;

            cb.EnableKeyword("USE_SHADOWS", drawShadows);
            light.UpdateShadowCommandBuffers(drawShadows);

            if (drawShadows)
            {
                cb.SetGlobalTexture(_CachedShadowMap, light.shadowmapCache.shadowMap);
            }

            cb.SetGlobalVector(_LightColor, new Vector4(light.lightC.color.r, light.lightC.color.g, light.lightC.color.b, light.finalIntensity));

            if (light.type == LightType.Point)
            {
                SetupPointLight(light, cb, light.transform.position, drawShadows);
            }
            else if (light.type == LightType.Spot)
            {
                SetupSpotLight(light, cb, light.transform.position, drawShadows);
            }
            else if (light.type == LightType.Directional)
            {
                SetupDirectionalLight(light, cb, drawShadows);
            }
        }
        static void SetupDirectionalLight(VolumetricLight light, CommandBuffer cb, bool drawShadows)
        {
            if (drawShadows)
            {
                cb.SetGlobalTexture(_World2ShadowTex, light.world2ShadowCache.world2ShadowTex);
            }

            cb.Blit(null as Texture, _RenderTarget, VolumetricLightUtils.GetMaterial(LightType.Directional), 0);
        }
        static void SetupPointLight(VolumetricLight light, CommandBuffer cb, Vector3 lightPos, bool drawShadows)
        {
            Matrix4x4 world = Matrix4x4.TRS(lightPos, Quaternion.identity, Vector3.one * light.range * 2.0f);

            SetNonDirectionalParams(light, cb, lightPos, ref world, drawShadows, Vector2.zero);

            //view
            if (light.cookie != null)
            {
                cb.SetGlobalMatrix(_MyLightMatrix0, Matrix4x4.TRS(lightPos, light.transform.rotation, Vector3.one).inverse);
            }

            cb.DrawMesh(RenderUtils.GetMesh(PrimitiveType.Sphere), world, VolumetricLightUtils.GetMaterial(LightType.Point), 0, IsCameraInPointLightBounds(light) ? 0 : 1);
        }
        static bool IsCameraInSpotLightBounds(VolumetricLight light, Vector3 fwd)
        {
            if (!IsCameraInPointLightBounds(light))
            {
                return(false);
            }

            Vector3 cam2LightNorm = light.cam2Light / light.cam2LightDist;

            if ((Mathf.Acos(Vector3.Dot(fwd, cam2LightNorm)) * Mathf.Rad2Deg) > (light.spotAngle + 3) * 0.5f)
            {
                return(false);
            }

            return(true);
        }
        static void SetNonDirectionalParams(VolumetricLight light, CommandBuffer cb, Vector3 lightPos, ref Matrix4x4 world, bool drawShadows, Vector2 extraParams)
        {
            float innerLimit = light.range * light.attenuationStart;

            cb.SetGlobalVector(_AttenuationParams, new Vector4(innerLimit, light.range - innerLimit, extraParams.x, extraParams.y));
            cb.SetGlobalVector(_VolumetricLight, new Vector4(1 - (light.mieG * light.mieG), 1 + (light.mieG * light.mieG), 2 * light.mieG, light.range));
            cb.SetGlobalVector(_LightPos, lightPos);
            cb.EnableKeyword("USE_COOKIE", light.cookie != null);
            if (light.cookie != null)
            {
                cb.SetGlobalTexture(_LightTexture0, light.cookie);
            }

            if (drawShadows)
            {
                light.shadowmapForcer.ForceShadows(ref world);
            }
        }
        public static bool PrepareLightsForRender(Camera cam, float maxDistance, float fadeRange)
        {
            bool    anyRendering = false;
            Vector3 camPos       = cam.transform.position;
            float   inner        = maxDistance - fadeRange;

            int c = allLights.Count;

            for (int i = 0; i < c; i++)
            {
                VolumetricLight light = allLights[i];
                if (light.lightC.intensity <= 0)
                {
                    light.finalIntensity = 0;
                    continue;
                }

                if (light.type == LightType.Directional)
                {
                    light.finalIntensity = light.maxIntensity;
                }
                else
                {
                    light.cam2Light     = camPos - light.transform.position;
                    light.cam2LightSq   = light.cam2Light.sqrMagnitude;
                    light.cam2LightDist = Mathf.Sqrt(light.cam2LightSq);

                    float t = 1.0f - Mathf.Clamp01((light.cam2LightDist - inner) / fadeRange);
                    light.finalIntensity = light.maxIntensity * t;
                }
                if (light.finalIntensity > 0)
                {
                    anyRendering = true;
                }
            }

            return(anyRendering);
        }
 public static void RemoveLight(VolumetricLight light)
 {
     allLights.Remove(light);
 }
 static bool IsCameraInPointLightBounds(VolumetricLight light)
 {
     return(light.cam2LightDist < light.range + 1);
 }