using T3.Core.Utils; namespace Lib.render.@_; [Guid("947ad81e-47da-46c3-9b1d-8e578174d876")] internal sealed class DefineLensFlare : Instance { [Output(Guid = "B26730FF-B1FF-40A7-91AF-B10026ED4C32", DirtyFlagTrigger = DirtyFlagTrigger.Animated)] public readonly Slot OutBuffer = new(); public DefineLensFlare() { OutBuffer.UpdateAction += Update; } private void Update(EvaluationContext context) { var worldToClipSpace = Matrix4x4.Multiply(context.WorldToCamera, context.CameraToClipSpace); //Matrix worldToView = context.WorldToCamera * context.CameraProjection; //var worldToClipSpace = context.WorldToCamera //var viewToWorld = Matrix.Invert(worldToClipSpace); var brightness = Brightness.GetValue(context); var color = Color.GetValue(context); var randomizeColor = RandomizeColor.GetValue(context); var size = Size.GetValue(context); var randomizeSize = RandomizeSize.GetValue(context); var stretch = Stretch.GetValue(context); var distanceFromLight = OffsetTowardsCenter.GetValue(context); var spread = Spread.GetValue(context); var randomizeSpread = RandomizeSpread.GetValue(context); var positionFactor = DistributeSpread.GetValue(context); var randomizePosition = RandomizePosition.GetValue(context); var mixPointLightColor = MixPointLightColor.GetValue(context); var referencedLightIndex = LightIndex.GetValue(context); var innerFxZone = InnerFxZone.GetValue(context); var edgeFxZone = EdgeFxZone.GetValue(context); var zoneFxScale = FxZoneScale.GetValue(context); var zoneFxBrightness = FxZoneBrightness.GetValue(context); var matteBoxZone = MattBoxZone.GetValue(context); var rand = new Random(RandomSeed.GetValue(context)); var fxZoneMode = (ZoneFxModes)FxZoneMode.GetValue(context); var rotation = Rotation.GetValue(context); var rotationSpread = RotationSpread.GetValue(context); var rotateTowards = (Categories)RotateTowards.GetValue(context); var spriteCount = SpriteCount.GetValue(context).Clamp(0, 1000); var startLightIndex = 0; var endLightIndex = context.PointLights.Count; var textureStart = TextureIndex.GetValue(context); _tempList.Clear(); if (!(brightness > 0.00001f)) { OutBuffer.Value = null; return; } if (referencedLightIndex >= 0) { startLightIndex = referencedLightIndex; endLightIndex = referencedLightIndex + 1; } var aspectRatio = (float)context.RequestedResolution.Width / (float)context.RequestedResolution.Height; for (int lightIndex = startLightIndex; lightIndex < endLightIndex; lightIndex++) { var pointLight = context.PointLights.GetPointLight(lightIndex); var lightPosDx = new Vector4(pointLight.Position, 1); var posInViewDx = Vector4.Transform(lightPosDx, worldToClipSpace); posInViewDx /= posInViewDx.W; // Ignore light sources behind var hideFactor = posInViewDx.Z < 0 ? 0 : 1; posInViewDx /= posInViewDx.W; var lightPosInView2D = new Vector2(posInViewDx.X, posInViewDx.Y); if (spriteCount != _sprites.NumElements) { _sprites = new StructuredList(spriteCount); } // Render Planes for (var i = 0; i < spriteCount; ++i) { var f = spriteCount <= 1 ? 0 : ((float)i / (spriteCount - 1) - 0.5f); var positionOnLine = (float)((-distanceFromLight + f * spread * 2 + randomizeSpread * (rand.NextDouble() - 0.5) + 1)); Vector2 objectScreenPos = lightPosInView2D * positionOnLine * positionFactor + (new Vector2(1, 1) - positionFactor) * lightPosInView2D; objectScreenPos += new Vector2((float)(randomizePosition.X * (rand.NextDouble() - 0.5)), (float)(randomizePosition.Y * (rand.NextDouble() - 0.5))); var sizeWithRandom = size * (float)(1.0 + randomizeSize * (rand.NextDouble() - 0.5)) / 0.2f; var colorWithLight = new Vector4((color.X + randomizeColor.X * (float)(rand.NextDouble() - 0.5) * 4) * MathUtils.Lerp(1f, pointLight.Color.X, mixPointLightColor), (color.Y + randomizeColor.Y * (float)(rand.NextDouble() - 0.5) * 4) * MathUtils.Lerp(1f, pointLight.Color.Y, mixPointLightColor), (color.Z + randomizeColor.Z * (float)(rand.NextDouble() - 0.5) * 4) * MathUtils.Lerp(1f, pointLight.Color.Z, mixPointLightColor), color.W * (1 - randomizeColor.W * (float)(rand.NextDouble() * 2))); var spriteColor = Vector4.Clamp(colorWithLight, Vector4.Zero, new Vector4(100, 100, 100, 1)); var triggerPosition = fxZoneMode == ZoneFxModes.Lights ? lightPosInView2D : objectScreenPos; var d = GetDistanceToEdge(triggerPosition); var cInnerZone = MathUtils.SmootherStep(innerFxZone.Y, innerFxZone.X, 1 - d); var cEdgeZone = MathUtils.SmootherStep(edgeFxZone.X, edgeFxZone.Y, 1 - d); var cMatteBox = MathUtils.SmootherStep(matteBoxZone.Y, matteBoxZone.X, 1 - d); var totalTriggerAmount = (cInnerZone + cEdgeZone) * cMatteBox; sizeWithRandom *= (1 + zoneFxScale * totalTriggerAmount).Clamp(0, 100); var brightnessEffect = (zoneFxBrightness * totalTriggerAmount).Clamp(0, 100); spriteColor.X += brightnessEffect; spriteColor.Y += brightnessEffect; spriteColor.Z += brightnessEffect; spriteColor.W = ((spriteColor.W + brightnessEffect)).Clamp(0, 1); spriteColor.W *= cMatteBox * pointLight.Color.W; // This might actually be a good idea. Maybe we should do this later.. // Fade with incoming alpha from FlatShaders and Materials //color.W *= materialAlpha; var spriteRotation = rotation; switch (rotateTowards) { case Categories.Object: break; case Categories.Light: spriteRotation -= (float)(Math.Atan2((objectScreenPos.X - lightPosInView2D.X) * aspectRatio, objectScreenPos.Y - lightPosInView2D.Y) + MathF.PI) * (180 / MathF.PI); break; case Categories.ScreenCenter: spriteRotation -= (float)(Math.Atan2(objectScreenPos.X, objectScreenPos.Y) + MathF.PI) * 180f / MathF.PI; break; default: throw new ArgumentOutOfRangeException(); } spriteColor.W *= brightness; _tempList.Add(new Sprite { PosInClipSpace = objectScreenPos, Size = sizeWithRandom * stretch * hideFactor, Color = spriteColor, RotationDeg = spriteRotation + f * rotationSpread * 180, UvMin = Vector2.Zero, UvMax = Vector2.One, TextureIndex = (int)(rand.NextDouble() * 65535) //Fixme: implement correct number }); } } // Copy to structured array if (_tempList.Count != _sprites.NumElements) { _sprites = new StructuredList(_tempList.Count); } for (var spriteIndex = 0; spriteIndex < _tempList.Count; spriteIndex++) { _sprites.TypedElements[spriteIndex] = _tempList[spriteIndex]; } OutBuffer.Value = _sprites; } private static float GetDistanceToEdge(Vector2 posInClipSpace) { var p = (posInClipSpace / 2 + Vector2.One * 0.5f); var dToRight = 1 - p.X; var dToLeft = p.X; var dToUp = p.Y; var dToBottom = 1 - p.Y; var d = MathF.Min(dToLeft, dToRight); d = MathF.Min(d, dToUp); d = MathF.Min(d, dToBottom); d *= 2; return d; } private readonly List _tempList = new(100); [StructLayout(LayoutKind.Explicit, Size = SizeInBytes)] public struct Sprite { [FieldOffset(0 * 4)] public Vector2 PosInClipSpace; [FieldOffset(2 * 4)] public Vector2 Size; [FieldOffset(4 * 4)] public float RotationDeg; [FieldOffset(5 * 4)] public Vector4 Color; [FieldOffset(9 * 4)] public Vector2 UvMin; [FieldOffset(11 * 4)] public Vector2 UvMax; [FieldOffset(13 * 4)] public int TextureIndex; [FieldOffset(14 * 4)] public Vector2 __padding; private const int SizeInBytes = 16 * 4; } private StructuredList _sprites = new(10); private enum ZoneFxModes { Off, Objects, Lights, } [Input(Guid = "50FDA27A-BD94-4438-9CEF-0AAA16FAE12B")] public readonly InputSlot LightIndex = new(); [Input(Guid = "59BA312F-C74F-4E76-8830-57C2EFFA0FF1")] public readonly InputSlot SpriteCount = new(); [Input(Guid = "9F85D1F1-37D2-4F7E-9EFD-70CB415C4CEE")] public readonly InputSlot Brightness = new(); [Input(Guid = "792E9B7E-9094-4BF9-8AED-D8B3FCDEE358")] public readonly InputSlot Spread = new(); [Input(Guid = "F21DBEFD-EA54-4901-A806-B1A2C5EE140F")] public readonly InputSlot OffsetTowardsCenter = new(); [Input(Guid = "BC1D9FDC-EA07-4C0D-BE2D-02FA955F9E5A")] public readonly InputSlot RandomizeSpread = new(); [Input(Guid = "1C250003-CF16-44DF-9A5E-F9FCF331617C")] public readonly InputSlot DistributeSpread = new(); [Input(Guid = "D314C572-71C7-4A67-921B-DF369817DD4A")] public readonly InputSlot RandomizePosition = new(); [Input(Guid = "CCF77198-7682-4F6B-96F2-986E6827A4DF")] public readonly InputSlot Size = new(); [Input(Guid = "2A1285B1-63EA-46A5-8D96-B7BA33EDD88B")] public readonly InputSlot RandomizeSize = new(); [Input(Guid = "C8347CA9-C700-4195-A23F-0F220F5823E2")] public readonly InputSlot Stretch = new(); [Input(Guid = "000A17CA-36A2-43EF-8FDA-314366C9E204")] public readonly InputSlot Rotation = new(); [Input(Guid = "93728B1F-CBFA-4065-9DE1-BF8641FADE7E")] public readonly InputSlot RotationSpread = new(); // [Input(Guid = "7244CC40-8F0A-4381-80A3-EB818E262C88", MappedType = typeof(ColorSources))] // public readonly InputSlot ColorSource = new(); [Input(Guid = "205ED310-E01C-4B0C-9C24-E404476CE036", MappedType = typeof(Categories))] public readonly InputSlot RotateTowards = new(); [Input(Guid = "D6554B75-F320-4E8B-BCB0-6B484C29F6D3")] public readonly InputSlot MixPointLightColor = new(); [Input(Guid = "7D9DA46C-2D1F-48F8-BDC5-BB7E29C363C7")] public readonly InputSlot Color = new(); [Input(Guid = "53351CF3-71A5-4CB3-AD81-60ABC7718D4B")] public readonly InputSlot RandomizeColor = new(); // [Input(Guid = "77EAC715-D2EE-4BD5-93F5-1E9E7119A0E6")] // public readonly InputSlot TextureCells = new(); [Input(Guid = "C1B5F49F-3538-48AA-8D16-92D48FCF08CB", MappedType = typeof(ZoneFxModes))] public readonly InputSlot FxZoneMode = new(); [Input(Guid = "1C11CB25-05F8-4422-AA16-DB57E8CD2E0B")] public readonly InputSlot EdgeFxZone = new(); [Input(Guid = "00ED2D51-4CF0-43D6-ADAA-CE42E5EB8439")] public readonly InputSlot InnerFxZone = new(); [Input(Guid = "0D98C14C-3F62-47E2-8FE8-A85208D9C02D")] public readonly InputSlot FxZoneScale = new(); [Input(Guid = "520EE127-F542-4AD8-A6EA-4A24A70ADE4D")] public readonly InputSlot FxZoneBrightness = new(); [Input(Guid = "BE4366C5-9E1C-430A-8F34-F31321A7DF2C")] public readonly InputSlot MattBoxZone = new(); [Input(Guid = "9CFFFB1A-675E-410C-96DA-C02BD6B3A81A")] public readonly InputSlot RandomSeed = new(); [Input(Guid = "A5AD260C-9341-4E43-923C-86F12974DF97")] public readonly InputSlot TextureIndex = new(); private enum Categories { Object, Light, ScreenCenter, } }