static List <InputShadowLightData> GetInputShadowLightData(CullResults cullResults)
        {
            var shadowCasters         = new List <InputShadowLightData>();
            var lights                = cullResults.visibleLights;
            int directionalLightCount = 0;

            for (int i = 0; i < lights.Length; i++)
            {
                //@TODO: ignore baked. move this logic to c++...
                if (lights[i].light.shadows == LightShadows.None)
                {
                    continue;
                }

                // Only a single directional shadow casting light is supported
                if (lights[i].lightType == LightType.Directional)
                {
                    directionalLightCount++;
                    if (directionalLightCount != 1)
                    {
                        continue;
                    }
                }

                AdditionalLightData additionalLight = lights[i].light.GetComponent <AdditionalLightData>();

                InputShadowLightData light;
                light.lightIndex       = i;
                light.shadowResolution = AdditionalLightData.GetShadowResolution(additionalLight);

                shadowCasters.Add(light);
            }
            return(shadowCasters);
        }
        //---------------------------------------------------------------------------------------------------------------------------------------------------

        void UpdatePunctualLights(VisibleLight[] visibleLights)
        {
            var lights = new List <PunctualLightData>();

            for (int lightIndex = 0; lightIndex < Math.Min(visibleLights.Length, MaxLights); lightIndex++)
            {
                var light = visibleLights[lightIndex];
                if (light.lightType != LightType.Spot && light.lightType != LightType.Point && light.lightType != LightType.Directional)
                {
                    continue;
                }

                var l = new PunctualLightData();

                if (light.lightType == LightType.Directional)
                {
                    l.useDistanceAttenuation = 0.0f;
                    // positionWS store Light direction for directional and is opposite to the forward direction
                    l.positionWS = -light.light.transform.forward;
                    l.invSqrAttenuationRadius = 0.0f;
                }
                else
                {
                    l.useDistanceAttenuation  = 1.0f;
                    l.positionWS              = light.light.transform.position;
                    l.invSqrAttenuationRadius = 1.0f / (light.range * light.range);
                }

                // Correct intensity calculation (Different from Unity)
                var lightColorR = light.light.intensity * Mathf.GammaToLinearSpace(light.light.color.r);
                var lightColorG = light.light.intensity * Mathf.GammaToLinearSpace(light.light.color.g);
                var lightColorB = light.light.intensity * Mathf.GammaToLinearSpace(light.light.color.b);

                l.color.Set(lightColorR, lightColorG, lightColorB);

                l.forward = light.light.transform.forward; // Note: Light direction is oriented backward (-Z)
                l.up      = light.light.transform.up;
                l.right   = light.light.transform.right;

                l.diffuseScale  = 1.0f;
                l.specularScale = 1.0f;
                l.shadowDimmer  = 1.0f;

                if (light.lightType == LightType.Spot)
                {
                    var spotAngle             = light.light.spotAngle;
                    var additionalLightData   = light.light.GetComponent <AdditionalLightData>();
                    var innerConePercent      = AdditionalLightData.GetInnerSpotPercent01(additionalLightData);
                    var cosSpotOuterHalfAngle = Mathf.Clamp(Mathf.Cos(spotAngle * 0.5f * Mathf.Deg2Rad), 0.0f, 1.0f);
                    var cosSpotInnerHalfAngle = Mathf.Clamp(Mathf.Cos(spotAngle * 0.5f * innerConePercent * Mathf.Deg2Rad), 0.0f, 1.0f); // inner cone

                    var val = Mathf.Max(0.001f, (cosSpotInnerHalfAngle - cosSpotOuterHalfAngle));
                    l.angleScale  = 1.0f / val;
                    l.angleOffset = -cosSpotOuterHalfAngle * l.angleScale;
                }
                else
                {
                    // 1.0f, 2.0f are neutral value allowing GetAngleAnttenuation in shader code to return 1.0
                    l.angleScale  = 1.0f;
                    l.angleOffset = 2.0f;
                }

                lights.Add(l);
            }
            s_punctualLightList.SetData(lights.ToArray());

            Shader.SetGlobalBuffer("_PunctualLightList", s_punctualLightList);
            Shader.SetGlobalInt("_PunctualLightCount", lights.Count);
        }
        //---------------------------------------------------------------------------------------------------------------------------------------------------
        void UpdateLightConstants(VisibleLight[] visibleLights, ref ShadowOutput shadow)
        {
            var numLightsIncludingTooMany = 0;

            var numLights = 0;

            var lightColor = new Vector4[k_MaxLights];
            var lightPosition_invRadius        = new Vector4[k_MaxLights];
            var lightDirection                 = new Vector4[k_MaxLights];
            var lightShadowIndex_lightParams   = new Vector4[k_MaxLights];
            var lightFalloffParams             = new Vector4[k_MaxLights];
            var spotLightInnerOuterConeCosines = new Vector4[k_MaxLights];
            var matWorldToShadow               = new Matrix4x4[k_MaxLights * k_MaxShadowmapPerLights];
            var dirShadowSplitSpheres          = new Vector4[k_MaxDirectionalSplit];

            for (int nLight = 0; nLight < visibleLights.Length; nLight++)
            {
                numLightsIncludingTooMany++;
                if (numLightsIncludingTooMany > k_MaxLights)
                {
                    continue;
                }

                var light               = visibleLights[nLight];
                var lightType           = light.lightType;
                var position            = light.light.transform.position;
                var lightDir            = light.light.transform.forward.normalized;
                var additionalLightData = light.light.GetComponent <AdditionalLightData>();

                // Setup shadow data arrays
                var hasShadows = shadow.GetShadowSliceCountLightIndex(nLight) != 0;

                if (lightType == LightType.Directional)
                {
                    lightColor[numLights] = light.finalColor;
                    lightPosition_invRadius[numLights] = new Vector4(
                        position.x - (lightDir.x * k_DirectionalLightPullbackDistance),
                        position.y - (lightDir.y * k_DirectionalLightPullbackDistance),
                        position.z - (lightDir.z * k_DirectionalLightPullbackDistance),
                        -1.0f);
                    lightDirection[numLights] = new Vector4(lightDir.x, lightDir.y, lightDir.z);
                    lightShadowIndex_lightParams[numLights]   = new Vector4(0, 0, 1, 1);
                    lightFalloffParams[numLights]             = new Vector4(0.0f, 0.0f, float.MaxValue, (float)lightType);
                    spotLightInnerOuterConeCosines[numLights] = new Vector4(0.0f, -1.0f, 1.0f);

                    if (hasShadows)
                    {
                        for (int s = 0; s < k_MaxDirectionalSplit; ++s)
                        {
                            dirShadowSplitSpheres[s] = shadow.directionalShadowSplitSphereSqr[s];
                        }
                    }
                }
                else if (lightType == LightType.Point)
                {
                    lightColor[numLights] = light.finalColor;

                    lightPosition_invRadius[numLights]        = new Vector4(position.x, position.y, position.z, 1.0f / light.range);
                    lightDirection[numLights]                 = new Vector4(0.0f, 0.0f, 0.0f);
                    lightShadowIndex_lightParams[numLights]   = new Vector4(0, 0, 1, 1);
                    lightFalloffParams[numLights]             = new Vector4(1.0f, 0.0f, light.range * light.range, (float)lightType);
                    spotLightInnerOuterConeCosines[numLights] = new Vector4(0.0f, -1.0f, 1.0f);
                }
                else if (lightType == LightType.Spot)
                {
                    lightColor[numLights] = light.finalColor;
                    lightPosition_invRadius[numLights]      = new Vector4(position.x, position.y, position.z, 1.0f / light.range);
                    lightDirection[numLights]               = new Vector4(lightDir.x, lightDir.y, lightDir.z);
                    lightShadowIndex_lightParams[numLights] = new Vector4(0, 0, 1, 1);
                    lightFalloffParams[numLights]           = new Vector4(1.0f, 0.0f, light.range * light.range, (float)lightType);

                    var flInnerConePercent = AdditionalLightData.GetInnerSpotPercent01(additionalLightData);
                    var spotAngle          = light.light.spotAngle;
                    var flPhiDot           = Mathf.Clamp(Mathf.Cos(spotAngle * 0.5f * Mathf.Deg2Rad), 0.0f, 1.0f);                      // outer cone
                    var flThetaDot         = Mathf.Clamp(Mathf.Cos(spotAngle * 0.5f * flInnerConePercent * Mathf.Deg2Rad), 0.0f, 1.0f); // inner cone
                    spotLightInnerOuterConeCosines[numLights] = new Vector4(flThetaDot, flPhiDot, 1.0f / Mathf.Max(0.01f, flThetaDot - flPhiDot));
                }

                if (hasShadows)
                {
                    // Enable shadows
                    lightShadowIndex_lightParams[numLights].x = 1;
                    for (int s = 0; s < shadow.GetShadowSliceCountLightIndex(nLight); ++s)
                    {
                        var shadowSliceIndex = shadow.GetShadowSliceIndex(nLight, s);
                        matWorldToShadow[numLights * k_MaxShadowmapPerLights + s] = shadow.shadowSlices[shadowSliceIndex].shadowTransform.transpose;
                    }
                }

                numLights++;
            }

            // Warn if too many lights found
            if (numLightsIncludingTooMany > k_MaxLights)
            {
                if (numLightsIncludingTooMany > m_WarnedTooManyLights)
                {
                    Debug.LogError("ERROR! Found " + numLightsIncludingTooMany + " runtime lights! Valve renderer supports up to " + k_MaxLights +
                                   " active runtime lights at a time!\nDisabling " + (numLightsIncludingTooMany - k_MaxLights) + " runtime light" +
                                   ((numLightsIncludingTooMany - k_MaxLights) > 1 ? "s" : "") + "!\n");
                }
                m_WarnedTooManyLights = numLightsIncludingTooMany;
            }
            else
            {
                if (m_WarnedTooManyLights > 0)
                {
                    m_WarnedTooManyLights = 0;
                    Debug.Log("SUCCESS! Found " + numLightsIncludingTooMany + " runtime lights which is within the supported number of lights, " + k_MaxLights + ".\n\n");
                }
            }

            // Send constants to shaders
            Shader.SetGlobalInt("g_nNumLights", numLights);

            // New method for Unity 5.4 to set arrays of constants
            Shader.SetGlobalVectorArray("g_vLightPosition_flInvRadius", lightPosition_invRadius);
            Shader.SetGlobalVectorArray("g_vLightColor", lightColor);
            Shader.SetGlobalVectorArray("g_vLightDirection", lightDirection);
            Shader.SetGlobalVectorArray("g_vLightShadowIndex_vLightParams", lightShadowIndex_lightParams);
            Shader.SetGlobalVectorArray("g_vLightFalloffParams", lightFalloffParams);
            Shader.SetGlobalVectorArray("g_vSpotLightInnerOuterConeCosines", spotLightInnerOuterConeCosines);
            Shader.SetGlobalMatrixArray("g_matWorldToShadow", matWorldToShadow);
            Shader.SetGlobalVectorArray("g_vDirShadowSplitSpheres", dirShadowSplitSpheres);

            // Time
            #if (UNITY_EDITOR)
            {
                Shader.SetGlobalFloat("g_flTime", Time.realtimeSinceStartup);
                //Debug.Log( "Time " + Time.realtimeSinceStartup );
            }
            #else
            {
                Shader.SetGlobalFloat("g_flTime", Time.timeSinceLevelLoad);
                //Debug.Log( "Time " + Time.timeSinceLevelLoad );
            }
            #endif

            // PCF 3x3 Shadows
            var texelEpsilonX      = 1.0f / m_ShadowSettings.shadowAtlasWidth;
            var texelEpsilonY      = 1.0f / m_ShadowSettings.shadowAtlasHeight;
            var shadow3x3PCFTerms0 = new Vector4(20.0f / 267.0f, 33.0f / 267.0f, 55.0f / 267.0f, 0.0f);
            var shadow3x3PCFTerms1 = new Vector4(texelEpsilonX, texelEpsilonY, -texelEpsilonX, -texelEpsilonY);
            var shadow3x3PCFTerms2 = new Vector4(texelEpsilonX, texelEpsilonY, 0.0f, 0.0f);
            var shadow3x3PCFTerms3 = new Vector4(-texelEpsilonX, -texelEpsilonY, 0.0f, 0.0f);

            Shader.SetGlobalVector("g_vShadow3x3PCFTerms0", shadow3x3PCFTerms0);
            Shader.SetGlobalVector("g_vShadow3x3PCFTerms1", shadow3x3PCFTerms1);
            Shader.SetGlobalVector("g_vShadow3x3PCFTerms2", shadow3x3PCFTerms2);
            Shader.SetGlobalVector("g_vShadow3x3PCFTerms3", shadow3x3PCFTerms3);
        }