public void GenerateLightningBoltStandard(LightningBolt bolt, Vector3 start, Vector3 end, int generation, int totalGenerations, float offsetAmount, LightningBoltParameters p) { if (generation < 1) { return; } LightningBoltSegmentGroup group = bolt.AddGroup(); group.Segments.Add(new LightningBoltSegment { Start = start, End = end }); // every generation, get the percentage we have gone down and square it, this makes lines thinner float widthMultiplier = (float)generation / (float)totalGenerations; widthMultiplier *= widthMultiplier; Vector3 randomVector; group.LineWidth = p.TrunkWidth * widthMultiplier; group.Generation = generation; group.Color = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)(255.0f * widthMultiplier)); group.EndWidthMultiplier = p.EndWidthMultiplier * p.ForkEndWidthMultiplier; if (offsetAmount <= 0.0f) { offsetAmount = (end - start).magnitude * p.ChaosFactor; } while (generation-- > 0) { int previousStartIndex = group.StartIndex; group.StartIndex = group.Segments.Count; for (int i = previousStartIndex; i < group.StartIndex; i++) { start = group.Segments[i].Start; end = group.Segments[i].End; // determine a new direction for the split Vector3 midPoint = (start + end) * 0.5f; // adjust the mid point to be the new location RandomVector(bolt, ref start, ref end, offsetAmount, p.Random, out randomVector); midPoint += randomVector; // add two new segments group.Segments.Add(new LightningBoltSegment { Start = start, End = midPoint }); group.Segments.Add(new LightningBoltSegment { Start = midPoint, End = end }); CreateFork(bolt, p, generation, totalGenerations, start, midPoint); } // halve the distance the lightning can deviate for each generation down offsetAmount *= 0.5f; } }
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()); }
public LightningBoltSegmentGroup CreateGroup() { LightningBoltSegmentGroup g; if (groupCache.Count == 0) { g = new LightningBoltSegmentGroup(); } else { int index = groupCache.Count - 1; g = groupCache[index]; groupCache.RemoveAt(index); } CurrentBolt.segmentGroups.Add(g); return(g); }
public LightningBoltSegmentGroup AddGroup() { LightningBoltSegmentGroup group; lock (groupCache) { if (groupCache.Count == 0) { group = new LightningBoltSegmentGroup(); } else { int index = groupCache.Count - 1; group = groupCache[index]; group.Reset(); groupCache.RemoveAt(index); } } segmentGroups.Add(group); return(group); }
private bool AddLightToGroup(LightningBoltSegmentGroup group, LightningLightParameters lp, int segmentIndex, int nthLight, int nthShadows, ref int maxLights, ref int nthShadowCounter) { Light light = GetOrCreateLight(lp); group.Lights.Add(light); Vector3 pos = (group.Segments[segmentIndex].Start + group.Segments[segmentIndex].End) * 0.5f; if (dependencies.CameraIsOrthographic) { if (dependencies.CameraMode == CameraMode.OrthographicXZ) { pos.y = dependencies.CameraPos.y + lp.OrthographicOffset; } else { pos.z = dependencies.CameraPos.z + lp.OrthographicOffset; } } if (dependencies.UseWorldSpace) { light.gameObject.transform.position = pos; } else { light.gameObject.transform.localPosition = pos; } if (lp.LightShadowPercent == 0.0f || ++nthShadowCounter < nthShadows) { light.shadows = LightShadows.None; } else { light.shadows = LightShadows.Soft; nthShadowCounter = 0; } // return true if no more lights possible, false otherwise return(++lightCount == MaximumLightCount || --maxLights == 0); }
public void GenerateLightningBoltPath(LightningBolt bolt, Vector3 start, Vector3 end, LightningBoltParameters p) { if (p.Points.Count < 2) { Debug.LogError("Lightning path should have at least two points"); return; } int generation = p.Generations; int totalGenerations = generation; float offsetAmount, d; int smoothingFactor = p.SmoothingFactor - 1; Vector3 distance, randomVector; LightningBoltSegmentGroup group = bolt.AddGroup(); group.LineWidth = p.TrunkWidth; group.Generation = generation--; group.EndWidthMultiplier = p.EndWidthMultiplier; group.Color = Color.white; p.Start = p.Points[0] + start; p.End = p.Points[p.Points.Count - 1] + end; end = p.Start; for (int i = 1; i < p.Points.Count; i++) { start = end; end = p.Points[i]; distance = (end - start); d = PathGenerator.SquareRoot(distance.sqrMagnitude); if (p.ChaosFactor > 0.0f) { if (bolt.CameraMode == CameraMode.Perspective) { end += (d * p.ChaosFactor * RandomDirection3D(p.Random)); } else if (bolt.CameraMode == CameraMode.OrthographicXY) { end += (d * p.ChaosFactor * RandomDirection2D(p.Random)); } else { end += (d * p.ChaosFactor * RandomDirection2DXZ(p.Random)); } distance = (end - start); } group.Segments.Add(new LightningBoltSegment { Start = start, End = end }); offsetAmount = d * p.ChaosFactor; RandomVector(bolt, ref start, ref end, offsetAmount, p.Random, out randomVector); if (ShouldCreateFork(p, generation, totalGenerations)) { Vector3 branchVector = distance * p.ForkMultiplier() * smoothingFactor * 0.5f; Vector3 forkEnd = end + branchVector + randomVector; GenerateLightningBoltStandard(bolt, start, forkEnd, generation, totalGenerations, 0.0f, p); } if (--smoothingFactor == 0) { smoothingFactor = p.SmoothingFactor - 1; } } }
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 RenderGroup(LightningBoltSegmentGroup group, LightningBoltParameters p) { if (group.SegmentCount == 0) { return; } #if UNITY_WEBGL float timeOffset = 0.0f; #else float timeOffset = (dependencies.ThreadState == null ? 0.0f : (float)(DateTime.UtcNow - startTimeOffset).TotalSeconds); #endif float timeStart = timeSinceLevelLoad + group.Delay + timeOffset; Vector4 fadeLifeTime = new Vector4(timeStart, timeStart + group.PeakStart, timeStart + group.PeakEnd, timeStart + group.LifeTime); float radius = group.LineWidth * 0.5f * LightningBoltParameters.Scale; int lineCount = (group.Segments.Count - group.StartIndex); float radiusStep = (radius - (radius * group.EndWidthMultiplier)) / (float)lineCount; // growth multiplier float timeStep; if (p.GrowthMultiplier > 0.0f) { timeStep = (group.LifeTime / (float)lineCount) * p.GrowthMultiplier; timeOffset = 0.0f; } else { timeStep = 0.0f; timeOffset = 0.0f; } LineRendererMesh currentLineRenderer = (activeLineRenderers.Count == 0 ? GetOrCreateLineRenderer() : activeLineRenderers[activeLineRenderers.Count - 1]); // if we have filled up the mesh, we need to start a new line renderer if (!currentLineRenderer.PrepareForLines(lineCount)) { if (currentLineRenderer.CustomTransform != null) { // can't create multiple meshes if using a custom transform callback return; } #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(); } } currentLineRenderer.BeginLine(group.Segments[group.StartIndex].Start, group.Segments[group.StartIndex].End, radius, group.Color, p.Intensity, fadeLifeTime, p.GlowWidthMultiplier, p.GlowIntensity); for (int i = group.StartIndex + 1; i < group.Segments.Count; i++) { radius -= radiusStep; if (p.GrowthMultiplier < 1.0f) { timeOffset += timeStep; fadeLifeTime = new Vector4(timeStart + timeOffset, timeStart + group.PeakStart + timeOffset, timeStart + group.PeakEnd, timeStart + group.LifeTime); } currentLineRenderer.AppendLine(group.Segments[i].Start, group.Segments[i].End, radius, group.Color, p.Intensity, fadeLifeTime, p.GlowWidthMultiplier, p.GlowIntensity); } }
public void AddGroup(LightningBolt lightningBolt, LightningBoltSegmentGroup group, float growthMultiplier) { if (group.SegmentCount == 0) { return; } List<LineRendererMesh> lineRenderers = renderers[lightningBolt]; LineRendererMesh lineRenderer = lineRenderers[lineRenderers.Count - 1]; float timeStart = Time.timeSinceLevelLoad + group.Delay; Vector4 fadeLifeTime = new Vector4(timeStart, timeStart + group.PeakStart, timeStart + group.PeakEnd, timeStart + group.LifeTime); float radius = group.LineWidth * 0.5f * LightningBoltParameters.Scale; int lineCount = (group.Segments.Count - group.StartIndex); float radiusStep = (radius - (radius * group.EndWidthMultiplier)) / (float)lineCount; // growth multiplier float timeStep, timeOffset; if (growthMultiplier > 0.0f) { timeStep = (group.LifeTime / (float)lineCount) * growthMultiplier; timeOffset = 0.0f; } else { timeStep = 0.0f; timeOffset = 0.0f; } if (!lineRenderer.PrepareForLines(lineCount)) { Script.StartCoroutine(EnableRenderer(lineRenderer, lightningBolt)); lineRenderer = CreateLineRenderer(lightningBolt, lineRenderers); } lineRenderer.BeginLine(group.Segments[group.StartIndex].Start, group.Segments[group.StartIndex].End, radius, group.Color, fadeLifeTime, GlowWidthMultiplier, GlowIntensityMultiplier); for (int i = group.StartIndex + 1; i < group.Segments.Count; i++) { radius -= radiusStep; if (growthMultiplier < 1.0f) { timeOffset += timeStep; fadeLifeTime = new Color(timeStart + timeOffset, timeStart + group.PeakStart + timeOffset, timeStart + group.PeakEnd, timeStart + group.LifeTime); } lineRenderer.AppendLine(group.Segments[i].Start, group.Segments[i].End, radius, group.Color, fadeLifeTime, GlowWidthMultiplier, GlowIntensityMultiplier); } }
private bool AddLightToGroup(LightningBoltSegmentGroup group, LightningLightParameters lp, int segmentIndex, int nthLight, int nthShadows, ref int maxLights, ref int nthShadowCounter) { Light light = CreateLight(lp); group.Lights.Add(light); Vector3 pos = (group.Segments[segmentIndex].Start + group.Segments[segmentIndex].End) * 0.5f; if (Camera != null && Camera.orthographic) { pos.z = Camera.transform.position.z; } light.gameObject.transform.position = pos; if (lp.LightShadowPercent == 0.0f || ++nthShadowCounter < nthShadows) { light.shadows = LightShadows.None; } else { light.shadows = LightShadows.Soft; nthShadowCounter = 0; } // return true if no more lights possible, false otherwise return (++lightCount == MaximumLightCount || --maxLights == 0); }
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()); }
public LightningBoltSegmentGroup CreateGroup() { LightningBoltSegmentGroup g; if (groupCache.Count == 0) { g = new LightningBoltSegmentGroup(); } else { int index = groupCache.Count - 1; g = groupCache[index]; groupCache.RemoveAt(index); } CurrentBolt.segmentGroups.Add(g); return g; }
public static void ReturnGroupToCache(LightningBoltSegmentGroup group) { groupCache.Add(group); }