private Transform RenderLightningBolt(LightningBoltQualitySetting quality, int generations, int startGroupIndex, int endGroupIndex, LightningBoltParameters parameters)
        {
            if (segmentGroups.Count == 0 || startGroupIndex >= segmentGroups.Count || endGroupIndex > segmentGroups.Count)
            {
                return(null);
            }

            Transform transform         = null;
            LightningLightParameters lp = parameters.LightParameters;

            if (lp != null)
            {
                if ((hasLight |= lp.HasLight))
                {
                    lp.LightPercent       = Mathf.Clamp(lp.LightPercent, Mathf.Epsilon, 1.0f);
                    lp.LightShadowPercent = Mathf.Clamp(lp.LightShadowPercent, 0.0f, 1.0f);
                }
                else
                {
                    lp = null;
                }
            }

            LightningBoltSegmentGroup mainTrunkGroup = segmentGroups[startGroupIndex];
            Vector3 start = mainTrunkGroup.Segments[mainTrunkGroup.StartIndex].Start;
            Vector3 end   = mainTrunkGroup.Segments[mainTrunkGroup.StartIndex + mainTrunkGroup.SegmentCount - 1].End;

            parameters.FadePercent = Mathf.Clamp(parameters.FadePercent, 0.0f, 0.5f);

            // create a new line renderer mesh right now if we have a custom transform
            if (parameters.CustomTransform != null)
            {
                LineRendererMesh currentLineRenderer = (activeLineRenderers.Count == 0 || !activeLineRenderers[activeLineRenderers.Count - 1].Empty ? null : activeLineRenderers[activeLineRenderers.Count - 1]);

                if (currentLineRenderer == null)
                {
#if !UNITY_WEBGL
                    if (dependencies.ThreadState != null)
                    {
                        // we need to block until this action is run, Unity objects can only be modified and created on the main thread
                        dependencies.ThreadState.AddActionForMainThread(() =>
                        {
                            EnableCurrentLineRenderer();
                            currentLineRenderer = GetOrCreateLineRenderer();
                        }, true);
                    }
                    else
#endif

                    {
                        EnableCurrentLineRenderer();
                        currentLineRenderer = GetOrCreateLineRenderer();
                    }
                }
                if (currentLineRenderer == null)
                {
                    return(null);
                }

                currentLineRenderer.CustomTransform = parameters.CustomTransform;
                transform = currentLineRenderer.Transform;
            }

            for (int i = startGroupIndex; i < endGroupIndex; i++)
            {
                LightningBoltSegmentGroup group = segmentGroups[i];
                group.Delay     = parameters.delaySeconds;
                group.LifeTime  = parameters.LifeTime;
                group.PeakStart = group.LifeTime * parameters.FadePercent;
                group.PeakEnd   = group.LifeTime - group.PeakStart;
                float peakGap = group.PeakEnd - group.PeakStart;
                float fadeOut = group.LifeTime - group.PeakEnd;
                group.PeakStart      *= parameters.FadeInMultiplier;
                group.PeakEnd         = group.PeakStart + (peakGap * parameters.FadeFullyLitMultiplier);
                group.LifeTime        = group.PeakEnd + (fadeOut * parameters.FadeOutMultiplier);
                group.LightParameters = lp;
                RenderGroup(group, parameters);
            }

#if !UNITY_WEBGL
            if (dependencies.ThreadState != null)
            {
                dependencies.ThreadState.AddActionForMainThread(() =>
                {
                    RenderParticleSystems(start, end, parameters.TrunkWidth, parameters.LifeTime, parameters.delaySeconds);

                    // create lights only on the main trunk
                    if (lp != null)
                    {
                        CreateLightsForGroup(segmentGroups[startGroupIndex], lp, quality, parameters.maxLights);
                    }
                });
            }
            else
#endif

            {
                RenderParticleSystems(start, end, parameters.TrunkWidth, parameters.LifeTime, parameters.delaySeconds);

                // create lights only on the main trunk
                if (lp != null)
                {
                    CreateLightsForGroup(segmentGroups[startGroupIndex], lp, quality, parameters.maxLights);
                }
            }

            return(transform);
        }
        private void CreateLightsForGroup(LightningBoltSegmentGroup group, LightningLightParameters lp, LightningBoltQualitySetting quality,
            int maxLights, int groupIndex)
        {
            if (lightCount == MaximumLightCount || maxLights <= 0)
            {
                return;
            }

            segmentGroupsWithLight.Add(group);

            int segmentCount = group.SegmentCount;
            float lightPercent, lightShadowPercent;
            if (quality == LightningBoltQualitySetting.LimitToQualitySetting)
            {
                int level = QualitySettings.GetQualityLevel();
                LightningQualityMaximum maximum;
                if (LightningBoltParameters.QualityMaximums.TryGetValue(level, out maximum))
                {
                    lightPercent = Mathf.Min(lp.LightPercent, maximum.MaximumLightPercent);
                    lightShadowPercent = Mathf.Min(lp.LightShadowPercent, maximum.MaximumShadowPercent);
                }
                else
                {
                    Debug.LogError("Unable to read lightning quality for level " + level.ToString());
                    lightPercent = lp.LightPercent;
                    lightShadowPercent = lp.LightShadowPercent;
                }
            }
            else
            {
                lightPercent = lp.LightPercent;
                lightShadowPercent = lp.LightShadowPercent;
            }

            maxLights = Mathf.Max(1, Mathf.Min(maxLights, (int)(segmentCount * lightPercent)));
            int nthLight = Mathf.Max(1, (int)((segmentCount / maxLights)));
            int nthShadows = maxLights - (int)((float)maxLights * lightShadowPercent);

            int nthShadowCounter = nthShadows;

            // add lights evenly spaced
            for (int i = group.StartIndex + (int)(nthLight * 0.5f); i < group.Segments.Count; i += nthLight)
            {
                if (AddLightToGroup(group, lp, i, nthLight, nthShadows, ref maxLights, ref nthShadowCounter))
                {
                    return;
                }
            }

            // Debug.Log("Lightning light count: " + lightCount.ToString());
        }
        private void CreateLightsForGroup(LightningBoltSegmentGroup group, LightningLightParameters lp, LightningBoltQualitySetting quality, int maxLights)
        {
            if (lightCount == MaximumLightCount || maxLights <= 0)
            {
                return;
            }

            float fadeOutTime       = (lifeTime - group.PeakEnd) * lp.FadeOutMultiplier;
            float peakGap           = (group.PeakEnd - group.PeakStart) * lp.FadeFullyLitMultiplier;
            float peakStart         = group.PeakStart * lp.FadeInMultiplier;
            float peakEnd           = peakStart + peakGap;
            float maxLifeWithLights = peakEnd + fadeOutTime;

            maxLifeTime = Mathf.Max(maxLifeTime, group.Delay + maxLifeWithLights);

            segmentGroupsWithLight.Add(group);

            int   segmentCount = group.SegmentCount;
            float lightPercent, lightShadowPercent;

            if (quality == LightningBoltQualitySetting.LimitToQualitySetting)
            {
                int level = QualitySettings.GetQualityLevel();
                LightningQualityMaximum maximum;
                if (LightningBoltParameters.QualityMaximums.TryGetValue(level, out maximum))
                {
                    lightPercent       = Mathf.Min(lp.LightPercent, maximum.MaximumLightPercent);
                    lightShadowPercent = Mathf.Min(lp.LightShadowPercent, maximum.MaximumShadowPercent);
                }
                else
                {
                    Debug.LogError("Unable to read lightning quality for level " + level.ToString());
                    lightPercent       = lp.LightPercent;
                    lightShadowPercent = lp.LightShadowPercent;
                }
            }
            else
            {
                lightPercent       = lp.LightPercent;
                lightShadowPercent = lp.LightShadowPercent;
            }

            maxLights = Mathf.Max(1, Mathf.Min(maxLights, (int)(segmentCount * lightPercent)));
            int nthLight         = Mathf.Max(1, (int)((segmentCount / maxLights)));
            int nthShadows       = maxLights - (int)((float)maxLights * lightShadowPercent);
            int nthShadowCounter = nthShadows;

            // add lights evenly spaced
            for (int i = group.StartIndex + (int)(nthLight * 0.5f); i < group.Segments.Count; i += nthLight)
            {
                if (AddLightToGroup(group, lp, i, nthLight, nthShadows, ref maxLights, ref nthShadowCounter))
                {
                    return;
                }
            }

            // Debug.Log("Lightning light count: " + lightCount.ToString());
        }
        private void RenderLightningBolt(LightningBoltQualitySetting quality, int generations, Vector3 start, Vector3 end, int groupIndex,
            ParticleSystem originParticleSystem, ParticleSystem destParticleSystem, LightningBoltParameters parameters,
            LightningLightParameters lp, int maxLights)
        {
            if (parameters.Generations < 1)
            {
                CreateLightOnly(parameters, lp, start);
                return;
            }
            else if (segmentGroups.Count == 0 || groupIndex >= segmentGroups.Count)
            {
                return;
            }

            float delayBase = parameters.LifeTime / (float)segmentGroups.Count;
            float minDelayValue = delayBase * 0.9f;
            float maxDelayValue = delayBase * 1.1f;
            float delayDiff = maxDelayValue - minDelayValue;
            parameters.FadePercent = Mathf.Clamp(parameters.FadePercent, 0.0f, 0.5f);

            if (originParticleSystem != null)
            {
                // we have a strike, create a particle where the lightning is coming from
                Script.StartCoroutine(GenerateParticle(originParticleSystem, start, parameters.Delay));
            }
            if (destParticleSystem != null)
            {
                Script.StartCoroutine(GenerateParticle(destParticleSystem, end, parameters.Delay * 1.1f));
            }

            if (HasGlow)
            {
                lightningBoltRenderer.GlowIntensityMultiplier = parameters.GlowIntensity;
                lightningBoltRenderer.GlowWidthMultiplier = parameters.GlowWidthMultiplier;
            }

            float currentDelayAmount = 0.0f;
            for (int i = groupIndex; i < segmentGroups.Count; i++)
            {
                LightningBoltSegmentGroup group = segmentGroups[i];
                group.Delay = currentDelayAmount + parameters.Delay;
                group.LifeTime = parameters.LifeTime - currentDelayAmount;
                group.PeakStart = group.LifeTime * parameters.FadePercent;
                group.PeakEnd = group.LifeTime - group.PeakStart;
                group.LightParameters = lp;

                lightningBoltRenderer.AddGroup(this, group, parameters.GrowthMultiplier);
                currentDelayAmount += ((float)parameters.Random.NextDouble() * minDelayValue) + delayDiff;

                // create lights only on the main trunk
                if (lp != null && group.Generation == generations)
                {
                    CreateLightsForGroup(group, lp, quality, maxLights, groupIndex);
                }
            }
        }