Esempio n. 1
0
        /// <summary>
        /// Effective Job of drawing the set of Lens Flare registered
        /// </summary>
        /// <param name="lensFlareShader">Lens Flare material (HDRP or URP shader)</param>
        /// <param name="lensFlares">Set of Lens Flare</param>
        /// <param name="cam">Camera</param>
        /// <param name="actualWidth">Width actually used for rendering after dynamic resolution and XR is applied.</param>
        /// <param name="actualHeight">Height actually used for rendering after dynamic resolution and XR is applied.</param>
        /// <param name="usePanini">Set if use Panani Projection</param>
        /// <param name="paniniDistance">Distance used for Panini projection</param>
        /// <param name="paniniCropToFit">CropToFit parameter used for Panini projection</param>
        /// <param name="cmd">Command Buffer</param>
        /// <param name="colorBuffer">Source Render Target which contains the Color Buffer</param>
        /// <param name="GetLensFlareLightAttenuation">Delegate to which return return the Attenuation of the light based on their shape which uses the functions ShapeAttenuation...(...), must reimplemented per SRP</param>
        /// <param name="_FlareTex">ShaderID for the FlareTex</param>
        /// <param name="_FlareColorValue">ShaderID for the FlareColor</param>
        /// <param name="_FlareData0">ShaderID for the FlareData0</param>
        /// <param name="_FlareData1">ShaderID for the FlareData1</param>
        /// <param name="_FlareData2">ShaderID for the FlareData2</param>
        /// <param name="_FlareData3">ShaderID for the FlareData3</param>
        /// <param name="_FlareData4">ShaderID for the FlareData4</param>
        /// <param name="_FlareData5">ShaderID for the FlareData5</param>
        /// <param name="debugView">Debug View which setup black background to see only Lens Flare</param>
        static public void DoLensFlareDataDrivenCommon(Material lensFlareShader, LensFlareCommonSRP lensFlares, Camera cam, float actualWidth, float actualHeight,
                                                       bool usePanini, float paniniDistance, float paniniCropToFit,
                                                       Rendering.CommandBuffer cmd,
                                                       Rendering.RenderTargetIdentifier colorBuffer,
                                                       System.Func <Light, Camera, Vector3, float> GetLensFlareLightAttenuation,
                                                       int _FlareTex, int _FlareColorValue, int _FlareData0, int _FlareData1, int _FlareData2, int _FlareData3, int _FlareData4, int _FlareData5, bool debugView)
        {
            Vector2 vScreenRatio;

            if (lensFlares.IsEmpty())
            {
                return;
            }

            Vector2 screenSize  = new Vector2(actualWidth, actualHeight);
            float   screenRatio = screenSize.x / screenSize.y;

            vScreenRatio = new Vector2(screenRatio, 1.0f);

            Rendering.CoreUtils.SetRenderTarget(cmd, colorBuffer);
            if (debugView)
            {
                // Background pitch black to see only the Flares
                cmd.ClearRenderTarget(false, true, Color.black);
            }

            foreach (LensFlareComponentSRP comp in lensFlares.GetData())
            {
                if (comp == null)
                {
                    continue;
                }

                LensFlareDataSRP data = comp.lensFlareData;

                if (!comp.enabled ||
                    !comp.gameObject.activeSelf ||
                    !comp.gameObject.activeInHierarchy ||
                    data == null ||
                    data.elements == null ||
                    data.elements.Length == 0)
                {
                    continue;
                }

                Light light = comp.GetComponent <Light>();

                Vector3 positionWS;
                Vector3 viewportPos;

                bool isDirLight = false;
                if (light != null && light.type == LightType.Directional)
                {
                    positionWS = -light.transform.forward * cam.farClipPlane;
                    isDirLight = true;
                }
                else
                {
                    positionWS = comp.transform.position;
                }
                viewportPos = cam.WorldToViewportPoint(positionWS);
                if (usePanini && cam == Camera.main)
                {
                    viewportPos = DoPaniniProjection(viewportPos, actualWidth, actualHeight, cam.fieldOfView, paniniCropToFit, paniniDistance);
                }

                if (viewportPos.z < 0.0f)
                {
                    continue;
                }

                if (!comp.allowOffScreen)
                {
                    if (viewportPos.x < 0.0f || viewportPos.x > 1.0f ||
                        viewportPos.y < 0.0f || viewportPos.y > 1.0f)
                    {
                        continue;
                    }
                }

                Vector4 modulationByColor     = Vector4.one;
                Vector4 modulationAttenuation = Vector4.one;
                Vector3 diffToObject          = positionWS - cam.transform.position;
                float   distToObject          = diffToObject.magnitude;
                float   coefDistSample        = distToObject / comp.maxAttenuationDistance;
                float   coefScaleSample       = distToObject / comp.maxAttenuationScale;
                float   distanceAttenuation   = !isDirLight && comp.distanceAttenuationCurve.length > 0 ? comp.distanceAttenuationCurve.Evaluate(coefDistSample) : 1.0f;
                float   scaleByDistance       = !isDirLight && comp.scaleByDistanceCurve.length >= 1 ? comp.scaleByDistanceCurve.Evaluate(coefScaleSample) : 1.0f;

                Color globalColorModulation = Color.white;

                if (light != null)
                {
                    if (comp.attenuationByLightShape)
                    {
                        globalColorModulation *= GetLensFlareLightAttenuation(light, cam, -diffToObject.normalized);
                    }
                }

                globalColorModulation *= distanceAttenuation;

                Vector3 dir        = (cam.transform.position - comp.transform.position).normalized;
                Vector3 screenPosZ = cam.WorldToViewportPoint(positionWS + dir * comp.occlusionOffset);
                Vector2 occlusionRadiusEdgeScreenPos0 = (Vector2)cam.WorldToViewportPoint(positionWS);
                Vector2 occlusionRadiusEdgeScreenPos1 = (Vector2)cam.WorldToViewportPoint(positionWS + cam.transform.up * comp.occlusionRadius);
                float   occlusionRadius = (occlusionRadiusEdgeScreenPos1 - occlusionRadiusEdgeScreenPos0).magnitude;
                cmd.SetGlobalVector(_FlareData1, new Vector4(occlusionRadius, comp.sampleCount, screenPosZ.z, actualHeight / actualWidth));

                if (comp.useOcclusion)
                {
                    cmd.EnableShaderKeyword("FLARE_OCCLUSION");
                }
                else
                {
                    cmd.DisableShaderKeyword("FLARE_OCCLUSION");
                }

                foreach (LensFlareDataElementSRP element in data.elements)
                {
                    if (element == null ||
                        (element.lensFlareTexture == null && element.flareType == SRPLensFlareType.Image) ||
                        element.localIntensity <= 0.0f ||
                        element.count <= 0)
                    {
                        continue;
                    }

                    Color colorModulation = globalColorModulation;
                    if (light != null && element.modulateByLightColor)
                    {
                        if (light.useColorTemperature)
                        {
                            colorModulation *= light.color * Mathf.CorrelatedColorTemperatureToRGB(light.colorTemperature);
                        }
                        else
                        {
                            colorModulation *= light.color;
                        }
                    }

                    Color   curColor         = colorModulation;
                    Vector2 screenPos        = new Vector2(2.0f * viewportPos.x - 1.0f, 1.0f - 2.0f * viewportPos.y);
                    Vector2 translationScale = new Vector2(element.translationScale.x, element.translationScale.y);
                    Texture texture          = element.lensFlareTexture;
                    float   elemAspectRatio  = element.sizeXY.x / element.sizeXY.y;
                    float   usedAspectRatio;
                    if (element.flareType == SRPLensFlareType.Image)
                    {
                        usedAspectRatio = element.preserveAspectRatio ? ((((float)texture.height) / (float)texture.width)) : 1.0f;
                    }
                    else
                    {
                        usedAspectRatio = 1.0f;
                    }

                    float   rotation           = element.rotation;
                    Vector4 tint               = Vector4.Scale(element.tint, curColor);
                    Vector2 radPos             = new Vector2(Mathf.Abs(screenPos.x), Mathf.Abs(screenPos.y));
                    float   radius             = Mathf.Max(radPos.x, radPos.y); // l1 norm (instead of l2 norm)
                    float   radialsScaleRadius = comp.radialScreenAttenuationCurve.length > 0 ? comp.radialScreenAttenuationCurve.Evaluate(radius) : 1.0f;

                    Vector2 elemSizeXY;
                    if (element.preserveAspectRatio)
                    {
                        if (usedAspectRatio >= 1.0f)
                        {
                            elemSizeXY = new Vector2(element.sizeXY.x / usedAspectRatio, element.sizeXY.y);
                        }
                        else
                        {
                            elemSizeXY = new Vector2(element.sizeXY.x, element.sizeXY.y * usedAspectRatio);
                        }
                    }
                    else
                    {
                        elemSizeXY = new Vector2(element.sizeXY.x, element.sizeXY.y);
                    }
                    float   scaleSize     = 0.1f; // Arbitrary value
                    Vector2 size          = new Vector2(elemSizeXY.x, elemSizeXY.y);
                    float   combinedScale = scaleByDistance * scaleSize * element.uniformScale * comp.scale;
                    size *= combinedScale;

                    Vector4 gradientModulation = new Vector4(1.0f, 1.0f, 1.0f, 1.0f);

                    float currentIntensity = comp.intensity * element.localIntensity * radialsScaleRadius * distanceAttenuation;

                    if (currentIntensity <= 0.0f)
                    {
                        continue;
                    }

                    curColor *= element.tint;
                    curColor *= currentIntensity;

                    float globalCos0 = Mathf.Cos(-element.angularOffset * Mathf.Deg2Rad);
                    float globalSin0 = Mathf.Sin(-element.angularOffset * Mathf.Deg2Rad);

                    float position = 2.0f * element.position;

                    SRPLensFlareBlendMode blendMode = element.blendMode;
                    int materialPass;
                    if (blendMode == SRPLensFlareBlendMode.Additive)
                    {
                        materialPass = 0;
                    }
                    else if (blendMode == SRPLensFlareBlendMode.Screen)
                    {
                        materialPass = 1;
                    }
                    else if (blendMode == SRPLensFlareBlendMode.Premultiply)
                    {
                        materialPass = 2;
                    }
                    else if (blendMode == SRPLensFlareBlendMode.Lerp)
                    {
                        materialPass = 3;
                    }
                    else
                    {
                        materialPass = 0;
                    }

                    if (element.flareType == SRPLensFlareType.Image)
                    {
                        cmd.DisableShaderKeyword("FLARE_CIRCLE");
                        cmd.DisableShaderKeyword("FLARE_POLYGON");
                    }
                    else if (element.flareType == SRPLensFlareType.Circle)
                    {
                        cmd.EnableShaderKeyword("FLARE_CIRCLE");
                        cmd.DisableShaderKeyword("FLARE_POLYGON");
                    }
                    else if (element.flareType == SRPLensFlareType.Polygon)
                    {
                        cmd.DisableShaderKeyword("FLARE_CIRCLE");
                        cmd.EnableShaderKeyword("FLARE_POLYGON");
                    }

                    if (element.flareType == SRPLensFlareType.Circle ||
                        element.flareType == SRPLensFlareType.Polygon)
                    {
                        if (element.inverseSDF)
                        {
                            cmd.EnableShaderKeyword("FLARE_INVERSE_SDF");
                        }
                        else
                        {
                            cmd.DisableShaderKeyword("FLARE_INVERSE_SDF");
                        }
                    }
                    else
                    {
                        cmd.DisableShaderKeyword("FLARE_INVERSE_SDF");
                    }

                    if (element.lensFlareTexture != null)
                    {
                        cmd.SetGlobalTexture(_FlareTex, element.lensFlareTexture);
                    }

                    float usedGradientPosition = Mathf.Clamp01((1.0f - element.edgeOffset) - 1e-6f);
                    if (element.flareType == SRPLensFlareType.Polygon)
                    {
                        usedGradientPosition = Mathf.Pow(usedGradientPosition + 1.0f, 5);
                    }

                    Vector2 ComputeLocalSize(Vector2 rayOff, Vector2 rayOff0, Vector2 curSize, AnimationCurve distortionCurve)
                    {
                        Vector2 rayOffZ = GetLensFlareRayOffset(screenPos, position, globalCos0, globalSin0);
                        Vector2 localRadPos;
                        float   localRadius;

                        if (!element.distortionRelativeToCenter)
                        {
                            localRadPos = (rayOff - rayOff0) * 0.5f;
                            localRadius = Mathf.Clamp01(Mathf.Max(Mathf.Abs(localRadPos.x), Mathf.Abs(localRadPos.y))); // l1 norm (instead of l2 norm)
                        }
                        else
                        {
                            localRadPos = screenPos + (rayOff + new Vector2(element.positionOffset.x, -element.positionOffset.y)) * element.translationScale;
                            localRadius = Mathf.Clamp01(localRadPos.magnitude); // l2 norm (instead of l1 norm)
                        }

                        float localLerpValue = Mathf.Clamp01(distortionCurve.Evaluate(localRadius));

                        return(new Vector2(Mathf.Lerp(curSize.x, element.targetSizeDistortion.x * combinedScale / usedAspectRatio, localLerpValue),
                                           Mathf.Lerp(curSize.y, element.targetSizeDistortion.y * combinedScale, localLerpValue)));
                    }

                    float usedSDFRoundness = element.sdfRoundness;

                    cmd.SetGlobalVector(_FlareData5, new Vector4(comp.allowOffScreen ? 1.0f : -1.0f, usedGradientPosition, Mathf.Exp(Mathf.Lerp(0.0f, 4.0f, Mathf.Clamp01(1.0f - element.fallOff))), 0.0f));
                    if (element.flareType == SRPLensFlareType.Polygon)
                    {
                        float invSide    = 1.0f / (float)element.sideCount;
                        float rCos       = Mathf.Cos(Mathf.PI * invSide);
                        float roundValue = rCos * usedSDFRoundness;
                        float r          = rCos - roundValue;
                        float an         = 2.0f * Mathf.PI * invSide;
                        float he         = r * Mathf.Tan(0.5f * an);
                        cmd.SetGlobalVector(_FlareData4, new Vector4(usedSDFRoundness, r, an, he));
                    }
                    else
                    {
                        cmd.SetGlobalVector(_FlareData4, new Vector4(usedSDFRoundness, 0.0f, 0.0f, 0.0f));
                    }

                    if (!element.allowMultipleElement || element.count == 1)
                    {
                        Vector4 flareData0 = GetFlareData0(screenPos, element.translationScale, vScreenRatio, element.rotation, position, element.angularOffset, element.positionOffset, element.autoRotate);

                        Vector2 rayOff    = GetLensFlareRayOffset(screenPos, position, globalCos0, globalSin0);
                        Vector2 localSize = size;

                        if (element.enableRadialDistortion)
                        {
                            Vector2 rayOff0 = GetLensFlareRayOffset(screenPos, 0.0f, globalCos0, globalSin0);
                            localSize = ComputeLocalSize(rayOff, rayOff0, localSize, element.distortionCurve);
                        }

                        cmd.SetGlobalVector(_FlareData0, flareData0);
                        cmd.SetGlobalVector(_FlareData2, new Vector4(screenPos.x, screenPos.y, localSize.x, localSize.y));
                        cmd.SetGlobalVector(_FlareData3, new Vector4(rayOff.x * element.translationScale.x, rayOff.y * element.translationScale.y, 1.0f / (float)element.sideCount, 0.0f));
                        cmd.SetGlobalVector(_FlareColorValue, curColor);

                        UnityEngine.Rendering.Blitter.DrawQuad(cmd, lensFlareShader, materialPass);
                    }
                    else
                    {
                        float dLength = 2.0f * element.lengthSpread / ((float)(element.count - 1));

                        if (element.distribution == SRPLensFlareDistribution.Uniform)
                        {
                            for (int elemIdx = 0; elemIdx < element.count; ++elemIdx)
                            {
                                Vector2 rayOff = GetLensFlareRayOffset(screenPos, position, globalCos0, globalSin0);

                                Vector2 localSize = size;
                                if (element.enableRadialDistortion)
                                {
                                    Vector2 rayOff0 = GetLensFlareRayOffset(screenPos, 0.0f, globalCos0, globalSin0);
                                    localSize = ComputeLocalSize(rayOff, rayOff0, localSize, element.distortionCurve);
                                }

                                float timeScale = element.count >= 2 ? ((float)elemIdx) / ((float)(element.count - 1)) : 0.5f;

                                Color col = element.colorGradient.Evaluate(timeScale);

                                Vector4 flareData0 = GetFlareData0(screenPos, element.translationScale, vScreenRatio, element.rotation, position, element.angularOffset, element.positionOffset, element.autoRotate);
                                cmd.SetGlobalVector(_FlareData0, flareData0);
                                cmd.SetGlobalVector(_FlareData2, new Vector4(screenPos.x, screenPos.y, localSize.x, localSize.y));
                                cmd.SetGlobalVector(_FlareData3, new Vector4(rayOff.x * element.translationScale.x, rayOff.y * element.translationScale.y, 1.0f / (float)element.sideCount, 0.0f));
                                cmd.SetGlobalVector(_FlareColorValue, curColor * col);

                                UnityEngine.Rendering.Blitter.DrawQuad(cmd, lensFlareShader, materialPass);
                                position += dLength;
                            }
                        }
                        else if (element.distribution == SRPLensFlareDistribution.Random)
                        {
                            Random.State backupRandState = UnityEngine.Random.state;
                            Random.InitState(element.seed);
                            Vector2 side = new Vector2(Mathf.Sin(-element.angularOffset * Mathf.Deg2Rad), Mathf.Cos(-element.angularOffset * Mathf.Deg2Rad));
                            side *= element.positionVariation.y;
                            float RandomRange(float min, float max)
                            {
                                return(Random.Range(min, max));
                            }

                            for (int elemIdx = 0; elemIdx < element.count; ++elemIdx)
                            {
                                float localIntensity = RandomRange(-1.0f, 1.0f) * element.intensityVariation + 1.0f;

                                Vector2 rayOff    = GetLensFlareRayOffset(screenPos, position, globalCos0, globalSin0);
                                Vector2 localSize = size;
                                if (element.enableRadialDistortion)
                                {
                                    Vector2 rayOff0 = GetLensFlareRayOffset(screenPos, 0.0f, globalCos0, globalSin0);
                                    localSize = ComputeLocalSize(rayOff, rayOff0, localSize, element.distortionCurve);
                                }

                                localSize += localSize * (element.scaleVariation * RandomRange(-1.0f, 1.0f));

                                Color randCol = element.colorGradient.Evaluate(RandomRange(0.0f, 1.0f));

                                Vector2 localPositionOffset = element.positionOffset + RandomRange(-1.0f, 1.0f) * side;

                                float localRotation = element.rotation + RandomRange(-Mathf.PI, Mathf.PI) * element.rotationVariation;

                                if (localIntensity > 0.0f)
                                {
                                    Vector4 flareData0 = GetFlareData0(screenPos, element.translationScale, vScreenRatio, localRotation, position, element.angularOffset, localPositionOffset, element.autoRotate);
                                    cmd.SetGlobalVector(_FlareData0, flareData0);
                                    cmd.SetGlobalVector(_FlareData2, new Vector4(screenPos.x, screenPos.y, localSize.x, localSize.y));
                                    cmd.SetGlobalVector(_FlareData3, new Vector4(rayOff.x * element.translationScale.x, rayOff.y * element.translationScale.y, 1.0f / (float)element.sideCount, 0.0f));
                                    cmd.SetGlobalVector(_FlareColorValue, curColor * randCol * localIntensity);

                                    UnityEngine.Rendering.Blitter.DrawQuad(cmd, lensFlareShader, materialPass);
                                }

                                position += dLength;
                                position += 0.5f * dLength * RandomRange(-1.0f, 1.0f) * element.positionVariation.x;
                            }
                            Random.state = backupRandState;
                        }
                        else if (element.distribution == SRPLensFlareDistribution.Curve)
                        {
                            for (int elemIdx = 0; elemIdx < element.count; ++elemIdx)
                            {
                                float timeScale = element.count >= 2 ? ((float)elemIdx) / ((float)(element.count - 1)) : 0.5f;

                                Color col = element.colorGradient.Evaluate(timeScale);

                                float positionSpacing = element.positionCurve.length > 0 ? element.positionCurve.Evaluate(timeScale) : 1.0f;

                                float   localPos  = position + 2.0f * element.lengthSpread * positionSpacing;
                                Vector2 rayOff    = GetLensFlareRayOffset(screenPos, localPos, globalCos0, globalSin0);
                                Vector2 localSize = size;
                                if (element.enableRadialDistortion)
                                {
                                    Vector2 rayOff0 = GetLensFlareRayOffset(screenPos, 0.0f, globalCos0, globalSin0);
                                    localSize = ComputeLocalSize(rayOff, rayOff0, localSize, element.distortionCurve);
                                }
                                float sizeCurveValue = element.scaleCurve.length > 0 ? element.scaleCurve.Evaluate(timeScale) : 1.0f;
                                localSize *= sizeCurveValue;

                                Vector4 flareData0 = GetFlareData0(screenPos, element.translationScale, vScreenRatio, element.rotation, localPos, element.angularOffset, element.positionOffset, element.autoRotate);
                                cmd.SetGlobalVector(_FlareData0, flareData0);
                                cmd.SetGlobalVector(_FlareData2, new Vector4(screenPos.x, screenPos.y, localSize.x, localSize.y));
                                cmd.SetGlobalVector(_FlareData3, new Vector4(rayOff.x * element.translationScale.x, rayOff.y * element.translationScale.y, 1.0f / (float)element.sideCount, 0.0f));
                                cmd.SetGlobalVector(_FlareColorValue, curColor * col);

                                UnityEngine.Rendering.Blitter.DrawQuad(cmd, lensFlareShader, materialPass);
                            }
                        }
                    }
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Override this method to make your own IMGUI based GUI for the property.
        /// Draw for one element one the list of SRPLensFlareElement
        /// </summary>
        /// <param name="position">Rectangle on the screen to use for the property GUI</param>
        /// <param name="property">The SerializedProperty to make the custom GUI for.</param>
        /// <param name="label">The label of this property.</param>
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            float originX      = position.x;
            float offsetHeight = 1.75f * (EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing);

            InitFirstRect(position);

            SerializedProperty intensityProp            = property.FindPropertyRelative("localIntensity");
            SerializedProperty positionProp             = property.FindPropertyRelative("position");
            SerializedProperty positionOffsetProp       = property.FindPropertyRelative("positionOffset");
            SerializedProperty angularOffsetProp        = property.FindPropertyRelative("angularOffset");
            SerializedProperty translationScaleProp     = property.FindPropertyRelative("translationScale");
            SerializedProperty lensFlareProp            = property.FindPropertyRelative("lensFlareTexture");
            SerializedProperty tintProp                 = property.FindPropertyRelative("tint");
            SerializedProperty blendModeProp            = property.FindPropertyRelative("blendMode");
            SerializedProperty countProp                = property.FindPropertyRelative("count");
            SerializedProperty allowMultipleElementProp = property.FindPropertyRelative("allowMultipleElement");
            SerializedProperty rotationProp             = property.FindPropertyRelative("rotation");
            SerializedProperty speedProp                = property.FindPropertyRelative("speed");
            SerializedProperty autoRotateProp           = property.FindPropertyRelative("autoRotate");
            SerializedProperty preserveAspectRatioProp  = property.FindPropertyRelative("preserveAspectRatio");
            SerializedProperty modulateByLightColor     = property.FindPropertyRelative("modulateByLightColor");
            SerializedProperty isFoldOpenedProp         = property.FindPropertyRelative("isFoldOpened");
            SerializedProperty flareTypeProp            = property.FindPropertyRelative("flareType");

            SerializedProperty uniformScaleProp = property.FindPropertyRelative("uniformScale");
            SerializedProperty sizeXYProp       = property.FindPropertyRelative("sizeXY");

            //
            SerializedProperty distributionProp = property.FindPropertyRelative("distribution");

            SerializedProperty lengthSpreadProp  = property.FindPropertyRelative("lengthSpread");
            SerializedProperty colorGradientProp = property.FindPropertyRelative("colorGradient");
            SerializedProperty positionCurveProp = property.FindPropertyRelative("positionCurve");
            SerializedProperty scaleCurveProp    = property.FindPropertyRelative("scaleCurve");

            // Random
            SerializedProperty seedProp = property.FindPropertyRelative("seed");
            SerializedProperty intensityVariationProp = property.FindPropertyRelative("intensityVariation");
            SerializedProperty positionVariationProp  = property.FindPropertyRelative("positionVariation");
            SerializedProperty scaleVariationProp     = property.FindPropertyRelative("scaleVariation");
            SerializedProperty sizeVariationProp      = property.FindPropertyRelative("sizeVariation");
            SerializedProperty rotationVariationProp  = property.FindPropertyRelative("rotationVariation");

            // Distortion
            SerializedProperty enableDistortionProp           = property.FindPropertyRelative("enableRadialDistortion");
            SerializedProperty targetSizeDistortionProp       = property.FindPropertyRelative("targetSizeDistortion");
            SerializedProperty distortionCurveProp            = property.FindPropertyRelative("distortionCurve");
            SerializedProperty distortionRelativeToCenterProp = property.FindPropertyRelative("distortionRelativeToCenter");

            SRPLensFlareType flareType        = (UnityEngine.SRPLensFlareType)flareTypeProp.enumValueIndex;
            Texture          texture          = lensFlareProp.objectReferenceValue ? lensFlareProp.objectReferenceValue as Texture : null;
            float            localAspectRatio = sizeXYProp.vector2Value.x / Mathf.Max(sizeXYProp.vector2Value.y, 1e-6f);
            float            imgWidth         = 1.5f * 35.0f;
            float            usedAspectRatio;

            if (flareType == SRPLensFlareType.Image)
            {
                usedAspectRatio = (lensFlareProp.objectReferenceValue && preserveAspectRatioProp.boolValue) ? (((float)texture.width) / ((float)texture.height)) : localAspectRatio;
            }
            else
            {
                usedAspectRatio = 1.0f;
            }
            if (isFoldOpenedProp.boolValue)
            {
                Rect imgRect = new Rect(m_CurrentRect.x + 0.5f * (position.width - imgWidth), m_CurrentRect.y + GUIStyle.none.lineHeight + 5.0f, imgWidth, imgWidth);
                if (flareType == SRPLensFlareType.Image)
                {
                    EditorGUI.DrawTextureTransparent(imgRect, lensFlareProp.objectReferenceValue as Texture, ScaleMode.ScaleToFit, usedAspectRatio);
                    m_CurrentRect.y += 1.5f * 35.0f;
                }
            }
            else
            {
                float imgOffY = 0.5f * (GetPropertyHeight(property, label) - imgWidth - GUIStyle.none.lineHeight);
                Rect  imgRect = new Rect(position.x - 35.0f + 15.0f, position.y + imgOffY + GUIStyle.none.lineHeight, imgWidth, imgWidth);
                if (flareType == SRPLensFlareType.Image)
                {
                    EditorGUI.DrawTextureTransparent(imgRect, lensFlareProp.objectReferenceValue as Texture, ScaleMode.ScaleToFit, usedAspectRatio);
                }
                else if (flareType == SRPLensFlareType.Circle)
                {
                    EditorGUI.DrawTextureTransparent(imgRect, Styles.circleIcon.image, ScaleMode.ScaleToFit, usedAspectRatio);
                }
                else //if (flareType != SRPLensFlareType.Polygon)
                {
                    EditorGUI.DrawTextureTransparent(imgRect, Styles.polygonIcon.image, ScaleMode.ScaleToFit, usedAspectRatio);
                }
            }
            Rect rect = m_CurrentRect;

            EditorGUI.BeginProperty(new Rect(rect.x, rect.y, rect.width, 2.0f * rect.height), label, property);

            float lineHeight = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;

            Color   tmpCol;
            bool    tmpBool;
            float   tmp;
            int     iTmp;
            Vector2 tmpVec2;
            Rect    localRect = new Rect(position.x, position.y, position.width, GUIStyle.none.lineHeight);

            if (EditorGUI.BeginFoldoutHeaderGroup(localRect, isFoldOpenedProp.boolValue, Styles.lensFlareElement))
            {
                rect = GetNextRect();
                EditorGUI.TextArea(rect, Styles.typeElement.text, style: EditorStyles.boldLabel);
                {
                    rect = GetNextRect();
                    SRPLensFlareType newType;
                    SRPLensFlareType typeValue = (UnityEngine.SRPLensFlareType)flareTypeProp.enumValueIndex;
                    if ((newType = ((SRPLensFlareType)(EditorGUI.EnumPopup(rect, Styles.flareType, typeValue)))) != typeValue)
                    {
                        flareTypeProp.enumValueIndex = (int)newType;
                    }

                    if (newType == SRPLensFlareType.Image)
                    {
                        Texture tmpTex;
                        rect = GetNextRect();
                        if ((tmpTex = (EditorGUI.ObjectField(rect, Styles.flareTexture, lensFlareProp.objectReferenceValue, typeof(Texture), false) as Texture)) != (lensFlareProp.objectReferenceValue as Texture))
                        {
                            lensFlareProp.objectReferenceValue = tmpTex;
                            lensFlareProp.serializedObject.ApplyModifiedProperties();
                        }

                        rect = GetNextRect();
                        if ((tmpBool = EditorGUI.Toggle(rect, Styles.preserveAspectRatio, preserveAspectRatioProp.boolValue)) != preserveAspectRatioProp.boolValue)
                        {
                            preserveAspectRatioProp.boolValue = tmpBool;
                        }
                    }
                    else if (newType == SRPLensFlareType.Circle || newType == SRPLensFlareType.Polygon)
                    {
                        SerializedProperty fallOffProp      = property.FindPropertyRelative("fallOff");
                        SerializedProperty edgeOffsetProp   = property.FindPropertyRelative("edgeOffset");
                        SerializedProperty sdfRoundnessProp = property.FindPropertyRelative("sdfRoundness");
                        SerializedProperty sideCountProp    = property.FindPropertyRelative("sideCount");
                        SerializedProperty inverseSDFProp   = property.FindPropertyRelative("inverseSDF");

                        rect = GetNextRect();
                        if ((tmp = EditorGUI.Slider(rect, Styles.edgeOffset, edgeOffsetProp.floatValue, 0.0f, 1.0f)) != edgeOffsetProp.floatValue)
                        {
                            edgeOffsetProp.floatValue = Mathf.Clamp01(tmp);
                        }

                        rect = GetNextRect();
                        if ((tmp = EditorGUI.Slider(rect, Styles.fallOff, fallOffProp.floatValue, 0.0f, 1.0f)) != fallOffProp.floatValue)
                        {
                            fallOffProp.floatValue = Mathf.Max(tmp, 0.0f);
                        }

                        if (newType == SRPLensFlareType.Polygon)
                        {
                            rect = GetNextRect();
                            if ((tmp = EditorGUI.IntSlider(rect, Styles.sideCount, sideCountProp.intValue, 3, 32)) != sideCountProp.intValue)
                            {
                                sideCountProp.intValue = (int)Mathf.Max(tmp, 0);
                            }

                            rect = GetNextRect();
                            if ((tmp = EditorGUI.Slider(rect, Styles.sdfRoundness, sdfRoundnessProp.floatValue, 0.0f, 1.0f)) != sdfRoundnessProp.floatValue)
                            {
                                sdfRoundnessProp.floatValue = Mathf.Clamp01(tmp);
                            }
                        }

                        rect = GetNextRect();
                        if ((tmpBool = EditorGUI.Toggle(rect, Styles.inverseSDF, inverseSDFProp.boolValue)) != inverseSDFProp.boolValue)
                        {
                            inverseSDFProp.boolValue = tmpBool;
                        }
                    }
                }

                rect = GetNextRect();
                EditorGUI.TextArea(rect, Styles.colorElement.text, EditorStyles.boldLabel);
                {
                    rect = GetNextRect();
                    if ((tmpCol = EditorGUI.ColorField(rect, Styles.tint, tintProp.colorValue)) != tintProp.colorValue)
                    {
                        tintProp.colorValue = tmpCol;
                    }
                    rect = GetNextRect();
                    if ((tmpBool = EditorGUI.Toggle(rect, Styles.modulateByLightColor, modulateByLightColor.boolValue)) != modulateByLightColor.boolValue)
                    {
                        modulateByLightColor.boolValue = tmpBool;
                    }
                    rect = GetNextRect();
                    if ((tmp = EditorGUI.FloatField(rect, Styles.intensity, intensityProp.floatValue)) != intensityProp.floatValue)
                    {
                        intensityProp.floatValue = Mathf.Max(tmp, 0.0f);
                    }
                    rect = GetNextRect();
                    SRPLensFlareBlendMode newBlendMode;
                    SRPLensFlareBlendMode blendModeValue = (UnityEngine.SRPLensFlareBlendMode)blendModeProp.enumValueIndex;
                    if ((newBlendMode = ((SRPLensFlareBlendMode)(EditorGUI.EnumPopup(rect, Styles.blendMode, blendModeValue)))) != blendModeValue)
                    {
                        blendModeProp.enumValueIndex = (int)newBlendMode;
                    }
                }

                rect = GetNextRect();
                EditorGUI.TextArea(rect, Styles.transformElement.text, EditorStyles.boldLabel);
                {
                    rect = GetNextRect();
                    if ((tmpVec2 = EditorGUI.Vector2Field(rect, Styles.positionOffset, positionOffsetProp.vector2Value)) != positionOffsetProp.vector2Value)
                    {
                        positionOffsetProp.vector2Value = tmpVec2;
                    }
                    rect = GetNextRect();
                    if ((tmpBool = EditorGUI.Toggle(rect, Styles.autoRotate, autoRotateProp.boolValue)) != autoRotateProp.boolValue)
                    {
                        autoRotateProp.boolValue = tmpBool;
                    }
                    rect = GetNextRect();
                    if ((tmp = EditorGUI.FloatField(rect, Styles.rotation, rotationProp.floatValue)) != rotationProp.floatValue)
                    {
                        rotationProp.floatValue = tmp;
                    }
                    rect = GetNextRect();
                    if ((tmpVec2 = EditorGUI.Vector2Field(rect, Styles.sizeXY, sizeXYProp.vector2Value)) != sizeXYProp.vector2Value)
                    {
                        sizeXYProp.vector2Value = new Vector2(Mathf.Max(tmpVec2.x, 1e-6f), Mathf.Max(tmpVec2.y, 1e-6f));
                    }
                    rect = GetNextRect();
                    if ((tmp = EditorGUI.FloatField(rect, Styles.uniformScale, uniformScaleProp.floatValue)) != uniformScaleProp.floatValue)
                    {
                        uniformScaleProp.floatValue = Mathf.Max(tmp, 0.0f);
                    }
                }

                rect = GetNextRect();
                EditorGUI.TextArea(rect, Styles.axisTransformElement.text, EditorStyles.boldLabel);
                {
                    rect = GetNextRect();
                    if ((tmp = EditorGUI.FloatField(rect, Styles.position, positionProp.floatValue)) != positionProp.floatValue)
                    {
                        positionProp.floatValue = tmp;
                    }
                    rect = GetNextRect();
                    if ((tmp = EditorGUI.FloatField(rect, Styles.angularOffset, angularOffsetProp.floatValue)) != angularOffsetProp.floatValue)
                    {
                        angularOffsetProp.floatValue = tmp;
                    }
                    rect = GetNextRect();
                    if ((tmpVec2 = EditorGUI.Vector2Field(rect, Styles.translationScale, translationScaleProp.vector2Value)) != translationScaleProp.vector2Value)
                    {
                        translationScaleProp.vector2Value = tmpVec2;
                    }
                }

                rect = GetNextRect();
                EditorGUI.TextArea(rect, Styles.radialDistortionElement.text, EditorStyles.boldLabel);
                {
                    rect = GetNextRect();
                    if ((tmpBool = EditorGUI.Toggle(rect, Styles.enableDistortion, enableDistortionProp.boolValue)) != enableDistortionProp.boolValue)
                    {
                        enableDistortionProp.boolValue = tmpBool;
                    }
                    if (enableDistortionProp.boolValue == true)
                    {
                        rect = GetNextRect();
                        if ((tmpVec2 = EditorGUI.Vector2Field(rect, Styles.targetSizeDistortion, targetSizeDistortionProp.vector2Value)) != targetSizeDistortionProp.vector2Value)
                        {
                            targetSizeDistortionProp.vector2Value = tmpVec2;
                        }
                        rect = GetNextRect();
                        EditorGUI.PropertyField(rect, distortionCurveProp, Styles.distortionCurve);
                        rect = GetNextRect();
                        if ((tmpBool = EditorGUI.Toggle(rect, Styles.distortionRelativeToCenter, distortionRelativeToCenterProp.boolValue)) != distortionRelativeToCenterProp.boolValue)
                        {
                            distortionRelativeToCenterProp.boolValue = tmpBool;
                        }
                    }
                }

                rect = GetNextRect();
                EditorGUI.TextArea(rect, Styles.multipleElementsElement.text, EditorStyles.boldLabel);
                {
                    rect = GetNextRect();
                    if ((tmpBool = EditorGUI.Toggle(rect, Styles.allowMultipleElement, allowMultipleElementProp.boolValue)) != allowMultipleElementProp.boolValue)
                    {
                        allowMultipleElementProp.boolValue = tmpBool;
                    }

                    if (allowMultipleElementProp.boolValue)
                    {
                        rect = GetNextRect();
                        if ((iTmp = EditorGUI.IntField(rect, Styles.count, countProp.intValue)) != countProp.intValue)
                        {
                            countProp.intValue = Mathf.Clamp(iTmp, 2, 4096); // 4096 is large enough for all imaginable use case (I hope)
                        }
                    }
                    if (allowMultipleElementProp.boolValue)
                    {
                        rect = GetNextRect();
                        SRPLensFlareDistribution newDistribution;
                        SRPLensFlareDistribution distributionValue = (UnityEngine.SRPLensFlareDistribution)distributionProp.enumValueIndex;
                        if ((newDistribution = ((SRPLensFlareDistribution)(EditorGUI.EnumPopup(rect, Styles.distribution, distributionValue)))) != distributionValue)
                        {
                            distributionProp.enumValueIndex = (int)newDistribution;
                        }

                        rect = GetNextRect();
                        if ((tmp = EditorGUI.FloatField(rect, Styles.lengthSpread, lengthSpreadProp.floatValue)) != lengthSpreadProp.floatValue)
                        {
                            lengthSpreadProp.floatValue = tmp;
                        }

                        if (newDistribution == SRPLensFlareDistribution.Uniform)
                        {
                            rect = GetNextRect();
                            EditorGUI.PropertyField(rect, colorGradientProp, Styles.colors);
                        }
                        else if (newDistribution == SRPLensFlareDistribution.Random)
                        {
                            rect = GetNextRect();
                            if ((iTmp = EditorGUI.IntField(rect, Styles.seed, seedProp.intValue)) != seedProp.intValue)
                            {
                                seedProp.intValue = Mathf.Max(iTmp, 0);
                            }

                            rect = GetNextRect();
                            if ((tmp = EditorGUI.FloatField(rect, Styles.intensityVariation, intensityVariationProp.floatValue)) != intensityVariationProp.floatValue)
                            {
                                intensityVariationProp.floatValue = Mathf.Clamp01(tmp);
                            }

                            rect = GetNextRect();
                            EditorGUI.PropertyField(rect, colorGradientProp, Styles.colors);

                            rect = GetNextRect();
                            if ((tmpVec2 = EditorGUI.Vector2Field(rect, Styles.positionVariation, positionVariationProp.vector2Value)) != positionVariationProp.vector2Value)
                            {
                                positionVariationProp.vector2Value = tmpVec2;
                            }

                            rect = GetNextRect();
                            if ((tmp = EditorGUI.FloatField(rect, Styles.rotationVariation, rotationVariationProp.floatValue)) != rotationVariationProp.floatValue)
                            {
                                rotationVariationProp.floatValue = Mathf.Max(tmp, 0.0f);
                            }

                            rect = GetNextRect();
                            if ((tmp = EditorGUI.FloatField(rect, Styles.scaleVariation, scaleVariationProp.floatValue)) != scaleVariationProp.floatValue)
                            {
                                scaleVariationProp.floatValue = Mathf.Max(tmp, 0.0f);
                            }
                        }
                        else if (newDistribution == SRPLensFlareDistribution.Curve)
                        {
                            rect = GetNextRect();
                            EditorGUI.PropertyField(rect, colorGradientProp, Styles.colors);
                            rect = GetNextRect();
                            EditorGUI.PropertyField(rect, positionCurveProp, Styles.positionCurve);
                            rect = GetNextRect();
                            EditorGUI.PropertyField(rect, scaleCurveProp, Styles.scaleCurve);
                        }
                    }
                }

                isFoldOpenedProp.boolValue = true;
            }
            else
            {
                rect = GetNextRect(35.0f);
                SRPLensFlareType newType;
                SRPLensFlareType typeValue = (UnityEngine.SRPLensFlareType)flareTypeProp.enumValueIndex;
                if ((newType = ((SRPLensFlareType)(EditorGUI.EnumPopup(rect, Styles.flareType, typeValue)))) != typeValue)
                {
                    flareTypeProp.enumValueIndex = (int)newType;
                }
                rect = GetNextRect();
                if ((tmpCol = EditorGUI.ColorField(rect, Styles.tint, tintProp.colorValue)) != tintProp.colorValue)
                {
                    tintProp.colorValue = tmpCol;
                }

                rect = GetNextRect();
                if ((tmp = EditorGUI.FloatField(rect, Styles.intensity, intensityProp.floatValue)) != intensityProp.floatValue)
                {
                    intensityProp.floatValue = Mathf.Max(tmp, 0.0f);
                }


                if (allowMultipleElementProp.boolValue)
                {
                    rect = GetNextRect();
                    if ((iTmp = EditorGUI.IntField(rect, Styles.count, countProp.intValue)) != countProp.intValue)
                    {
                        countProp.intValue = Mathf.Max(iTmp, 2);
                    }
                }

                isFoldOpenedProp.boolValue = false;
            }
            EditorGUI.EndFoldoutHeaderGroup();
            EditorGUI.EndProperty();
        }