HDShadowData CreateShadowData(HDShadowRequest shadowRequest, HDShadowAtlas atlas)
        {
            HDShadowData data = new HDShadowData();

            var devProj = shadowRequest.deviceProjection;
            var view    = shadowRequest.view;

            data.proj                  = new Vector4(devProj.m00, devProj.m11, devProj.m22, devProj.m23);
            data.pos                   = shadowRequest.position;
            data.rot0                  = new Vector3(view.m00, view.m01, view.m02);
            data.rot1                  = new Vector3(view.m10, view.m11, view.m12);
            data.rot2                  = new Vector3(view.m20, view.m21, view.m22);
            data.shadowToWorld         = shadowRequest.shadowToWorld;
            data.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f);

            var viewport = shadowRequest.isInCachedAtlas ? shadowRequest.cachedAtlasViewport : shadowRequest.dynamicAtlasViewport;

            // Compute the scale and offset (between 0 and 1) for the atlas coordinates
            float rWidth  = 1.0f / atlas.width;
            float rHeight = 1.0f / atlas.height;

            data.atlasOffset = Vector2.Scale(new Vector2(rWidth, rHeight), new Vector2(viewport.x, viewport.y));

            data.shadowMapSize = new Vector4(viewport.width, viewport.height, 1.0f / viewport.width, 1.0f / viewport.height);

            data.normalBias     = shadowRequest.normalBias;
            data.worldTexelSize = shadowRequest.worldTexelSize;

            data.shadowFilterParams0.x = shadowRequest.shadowSoftness;
            data.shadowFilterParams0.y = HDShadowUtils.Asfloat(shadowRequest.blockerSampleCount);
            data.shadowFilterParams0.z = HDShadowUtils.Asfloat(shadowRequest.filterSampleCount);
            data.shadowFilterParams0.w = shadowRequest.minFilterSize;

            data.zBufferParam = shadowRequest.zBufferParam;
            if (atlas.HasBlurredEVSM())
            {
                data.shadowFilterParams0 = shadowRequest.evsmParams;
            }

            data.isInCachedAtlas = shadowRequest.isInCachedAtlas ? 1.0f : 0.0f;

            return(data);
        }
        unsafe public void PrepareGPUShadowDatas(CullingResults cullResults, HDCamera camera)
        {
            if (m_MaxShadowRequests == 0)
            {
                return;
            }

            int shadowIndex = 0;

            m_ShadowDatas.Clear();

            // Create all HDShadowDatas and update them with shadow request datas
            for (int i = 0; i < m_ShadowRequestCount; i++)
            {
                Debug.Assert(m_ShadowRequests[i] != null);

                HDShadowAtlas atlas = m_Atlas;
                if (m_ShadowRequests[i].isInCachedAtlas)
                {
                    atlas = cachedShadowManager.punctualShadowAtlas;
                }

                if (m_ShadowRequests[i].shadowMapType == ShadowMapType.CascadedDirectional)
                {
                    atlas = m_CascadeAtlas;
                }
                else if (m_ShadowRequests[i].shadowMapType == ShadowMapType.AreaLightAtlas)
                {
                    atlas = m_AreaLightShadowAtlas;
                    if (m_ShadowRequests[i].isInCachedAtlas)
                    {
                        atlas = cachedShadowManager.areaShadowAtlas;
                    }
                }

                HDShadowData shadowData;
                if (m_ShadowRequests[i].shouldUseCachedShadowData)
                {
                    shadowData = m_ShadowRequests[i].cachedShadowData;
                }
                else
                {
                    shadowData = CreateShadowData(m_ShadowRequests[i], atlas);
                    m_ShadowRequests[i].cachedShadowData = shadowData;
                }

                m_ShadowDatas.Add(shadowData);
                m_ShadowRequests[i].shadowIndex = shadowIndex++;
            }

            int first = k_DirectionalShadowCascadeCount, second = k_DirectionalShadowCascadeCount;

            fixed(float *sphereBuffer = m_DirectionalShadowData.sphereCascades)
            {
                Vector4 *sphere = (Vector4 *)sphereBuffer;

                for (int i = 0; i < k_DirectionalShadowCascadeCount; i++)
                {
                    first  = (first == k_DirectionalShadowCascadeCount && sphere[i].w > 0.0f) ? i : first;
                    second = ((second == k_DirectionalShadowCascadeCount || second == first) && sphere[i].w > 0.0f) ? i : second;
                }
            }

            // Update directional datas:
            if (second != k_DirectionalShadowCascadeCount)
            {
                m_DirectionalShadowData.cascadeDirection = (GetCascadeSphereAtIndex(second) - GetCascadeSphereAtIndex(first)).normalized;
            }
            else
            {
                m_DirectionalShadowData.cascadeDirection = Vector4.zero;
            }

            m_DirectionalShadowData.cascadeDirection.w = camera.volumeStack.GetComponent <HDShadowSettings>().cascadeShadowSplitCount.value;

            if (m_ShadowRequestCount > 0)
            {
                // Upload the shadow buffers to GPU
                m_ShadowDataBuffer.SetData(m_ShadowDatas);
                m_CachedDirectionalShadowData[0] = m_DirectionalShadowData;
                m_DirectionalShadowDataBuffer.SetData(m_CachedDirectionalShadowData);
            }
        }