From 6a3c8b730e9560788c01e24625f4e8c0c73c0d8c Mon Sep 17 00:00:00 2001 From: Pedro413 <44695680+Pedro413@users.noreply.github.com> Date: Wed, 15 May 2024 18:58:23 +1000 Subject: [PATCH] update reach fog conversion --- .../Porting/PortTagCommand.Scenario.cs | 56 ++++++----- TagTool/Common/MathHelper.cs | 20 ++++ TagTool/Tags/Definitions/Effect.cs | 27 ++++- TagTool/Tags/Definitions/SkyAtmParameters.cs | 98 +++++++++++++++++++ 4 files changed, 172 insertions(+), 29 deletions(-) diff --git a/TagTool/Commands/Porting/PortTagCommand.Scenario.cs b/TagTool/Commands/Porting/PortTagCommand.Scenario.cs index 3b41132f7..afd097293 100644 --- a/TagTool/Commands/Porting/PortTagCommand.Scenario.cs +++ b/TagTool/Commands/Porting/PortTagCommand.Scenario.cs @@ -708,49 +708,51 @@ public Scenario ConvertScenario(Stream cacheStream, Stream blamCacheStream, Dict { atmosphereSettings.Flags |= SkyAtmParameters.AtmosphereProperty.AtmosphereFlags.OverrideRealSunValues; atmosphereSettings.Color = fogSettings.FogColor; - atmosphereSettings.Intensity = 3.0f; // tweak? + atmosphereSettings.Intensity = 1.0f; // tweak? atmosphereSettings.SunAnglePitch = 0.0f; atmosphereSettings.SunAngleYaw = 0.0f; - // Test for direction - //if (scnr.SkyReferences.Count > 0 && scnr.SkyReferences[0].SkyObject != null) - //{ - // var skyObje = CacheContext.Deserialize(cacheStream, scnr.SkyReferences[0].SkyObject); - // var hlmt = CacheContext.Deserialize(cacheStream, skyObje.Model); - // var mode = CacheContext.Deserialize(cacheStream, hlmt.RenderModel); - // - // if (mode.LightgenLights.Count > 0) - // { - // var direction = mode.LightgenLights.Last().Direction; - // - // atmosphereSettings.SunAnglePitch = (float)(Math.Acos(direction.K) / Math.PI) * 180.0f; - // atmosphereSettings.SunAngleYaw = (float)(Math.Asin(direction.J / Math.Sin(atmosphereSettings.SunAnglePitch)) / Math.PI) * 180.0f; - // } - //} + // reach has a fog light angle but i think this better for now + if (scnr.SkyReferences.Count > 0 && scnr.SkyReferences[0].SkyObject != null) + { + var skyObje = CacheContext.Deserialize(cacheStream, scnr.SkyReferences[0].SkyObject); + var hlmt = CacheContext.Deserialize(cacheStream, skyObje.Model); + var mode = CacheContext.Deserialize(cacheStream, hlmt.RenderModel); + + if (mode.LightgenLights.Count > 0) + { + var direction = mode.LightgenLights.Last().Direction; // last light is sun + + atmosphereSettings.SunAnglePitch = (float)(Math.Asin(direction.K) * (180.0f / Math.PI)); + if (atmosphereSettings.SunAnglePitch < 0.0f) // limit to 0-90 + atmosphereSettings.SunAnglePitch = -atmosphereSettings.SunAnglePitch; + + atmosphereSettings.SunAngleYaw = (float)(Math.Atan2(direction.J, direction.I) * (180.0f / Math.PI)); + } + } atmosphereSettings.SeaLevel = fogSettings.BaseHeight; // WU, lowest height of scenario + + // these are definitely wrong atmosphereSettings.RayleignHeightScale = fogSettings.FogHeight; // WU, height above sea where atmo 30% thick atmosphereSettings.MieHeightScale = fogSettings.FogHeight; // WU, height above sea where atmo 30% thick - atmosphereSettings.MaxFogThickness = fogSettings.FogThickness * 10000.0f; + atmosphereSettings.MaxFogThickness = fogSettings.FogThickness * 65536.0f; } - atmosphereSettings.RayleighMultiplier = 0.0f; // scattering amount, small - atmosphereSettings.MieMultiplier = 0.0f; // scattering amount, large + // todo: scale these with fog thickness + atmosphereSettings.RayleighMultiplier = 0.05f; // scattering amount, small + atmosphereSettings.MieMultiplier = 0.025f; // scattering amount, large - atmosphereSettings.SunPhaseFunction = 0.2f; + atmosphereSettings.SunPhaseFunction = 0.2f; //todo atmosphereSettings.Desaturation = 0.0f; atmosphereSettings.DistanceBias = fogg.DistanceBias; - - // placeholder for now - - atmosphereSettings.BetaM = new RealVector3d(0.0002946603f, 0.0005024257f, 0.001058603f); - atmosphereSettings.BetaP = new RealVector3d(0.001434321f, 0.001849472f, 0.002627869f); - atmosphereSettings.BetaMThetaPrefix = new RealVector3d(1.788872E-05f, 3.050209E-05f, 6.426741E-05f); - atmosphereSettings.BetaPThetaPrefix = new RealVector3d(0.0003334733f, 0.0004336488f, 0.0006244543f); } } + // validate all values and recalculate atmosphere constants + skya.Postprocess(); + CachedTag skyTag = CacheContext.TagCache.AllocateTag(tagName); CacheContext.Serialize(cacheStream, skyTag, skya); diff --git a/TagTool/Common/MathHelper.cs b/TagTool/Common/MathHelper.cs index 094addaf9..9cf43ffcd 100644 --- a/TagTool/Common/MathHelper.cs +++ b/TagTool/Common/MathHelper.cs @@ -25,5 +25,25 @@ public static bool SphereIntersectsRectangle3d(RealPoint3d center, float radius, return (radius * radius) >= RealVector3d.Magnitude(d); } + + public static float Clamp(float value, float min, float max) + { + return Math.Min(Math.Max(value, min), max); + } + + public static RealRgbColor Clamp(RealRgbColor value, float min, float max) + { + return new RealRgbColor + { + Red = Math.Min(Math.Max(value.Red, min), max), + Green = Math.Min(Math.Max(value.Green, min), max), + Blue = Math.Min(Math.Max(value.Blue, min), max), + }; + } + + public static float Lerp(float a, float b, float s) + { + return ((1.0f - s) * a) + (s * b); + } } } diff --git a/TagTool/Tags/Definitions/Effect.cs b/TagTool/Tags/Definitions/Effect.cs index 121125023..159067761 100644 --- a/TagTool/Tags/Definitions/Effect.cs +++ b/TagTool/Tags/Definitions/Effect.cs @@ -8,6 +8,7 @@ using System.Linq; using TagTool.Commands.Common; using static TagTool.Effects.EditableProperty; +using System.IO; namespace TagTool.Tags.Definitions { @@ -450,8 +451,15 @@ public enum FlagsValue : byte None, Postprocessed = 1 << 0, IsCpu = 1 << 1, + // This flag is enabled (and disables IsCpu) in the following conditions: + // (Postprocessed == true && + // Emitter.ParticleMovement.Flags.HasFlag(Wind) && + // ParticleSystem.CanUpdateOnGpu()) IsGpu = 1 << 2, + // This flag is enabled if: + // (Postprocess == true && ParticleSystem.CanUpdateOnGpu()) BecomesGpuWhenAtRest = 1 << 3, + // I'm not sure what this is or why it's set. AlphaBlackPoint_Bit3 = 1 << 4, } @@ -970,6 +978,21 @@ public void GetConstantStates(out RuntimeMGpuData.ParticleProperties cppStates, cotStates |= RuntimeMGpuData.ParticleProperties.ParticleAlphaBlackPoint; } } + + public bool CanUpdateOnGpu(GameCache cache, Stream stream) + { + bool noAttachments = true; + + if (this.Particle != null) + { + var prt3 = cache.Deserialize(stream, this.Particle); + + if (!prt3.Flags.HasFlag(Definitions.Particle.FlagsValue.NoAttachments)) + noAttachments = false; + } + + return noAttachments && this.Flags.HasFlag(ParticleSystemFlags.TurnOffNearFadeOnEnhancedGraphics); + } } } @@ -1010,7 +1033,7 @@ public enum EffectFlags : int TintFromLightmap = 1 << 10, TintFromDiffuseTexture = 1 << 11, // geometry sampler HasEnvironmentRestrictedPart = 1 << 12, // parts->create_in_environment != 0 || ( part->type==beam && any(location->name==stringid(child)) ) - UnusedBit = 1 << 13, // unused + HasEnvironmentRestrictedAcceleration = 1 << 13, // unused HasEnvironmentRestrictedParticleSystem = 1 << 14, // system->environment != 0 TrackSubframeMovements = 1 << 15, UnknownHO = 1 << 16 // HO only. unknown @@ -1036,7 +1059,7 @@ public enum EffectFlagsMCC : int TintFromLightmap = 1 << 12, TintFromDiffuseTexture = 1 << 13, HasEnvironmentRestrictedPart = 1 << 14, - UnusedBit = 1 << 15, + HasEnvironmentRestrictedAcceleration = 1 << 15, HasEnvironmentRestrictedParticleSystem = 1 << 16, TrackSubframeMovements = 1 << 17 } diff --git a/TagTool/Tags/Definitions/SkyAtmParameters.cs b/TagTool/Tags/Definitions/SkyAtmParameters.cs index 8b63e0409..f728c0bea 100644 --- a/TagTool/Tags/Definitions/SkyAtmParameters.cs +++ b/TagTool/Tags/Definitions/SkyAtmParameters.cs @@ -95,6 +95,81 @@ public enum AtmosphereFlags : short PatchyFog = 1 << 2, Bit3 = 1 << 3, } + + private void PostprocessFogConstants() + { + // todo: B particle and molecular calculation according to tool. + // these are still accurate, as the only thing that changes these constants are: + // mie_multiplier, rayleigh_multiplier, desaturation + BetaM = new RealVector3d(0.000005893206f, 0.000010048514f, 0.00002117206f); + BetaP = new RealVector3d(0.00005737284f, 0.00007397888f, 0.00010511476f); + BetaMThetaPrefix = new RealVector3d(0.0000003577744f, 0.0000006100418f, 0.0000012853482f); + BetaPThetaPrefix = new RealVector3d(0.000013338932f, 0.000017345952f, 0.000024978172f); + + // apply multipliers + BetaM *= RayleighMultiplier; + BetaMThetaPrefix *= RayleighMultiplier; + BetaP *= MieMultiplier; + BetaPThetaPrefix *= MieMultiplier; + + // rescale + BetaM *= 1000.0f; + BetaMThetaPrefix *= 1000.0f; + BetaP *= 1000.0f; + BetaPThetaPrefix *= 1000.0f; + + // apply desaturation + if (Desaturation > 0.0f) + { + float pLum = (BetaP.I + BetaP.J + BetaP.K) / 3.0f; + BetaP.I = MathHelper.Lerp(BetaP.I, pLum, Desaturation); + BetaP.J = MathHelper.Lerp(BetaP.J, pLum, Desaturation); + BetaP.K = MathHelper.Lerp(BetaP.K, pLum, Desaturation); + + float mLum = (BetaM.I + BetaM.J + BetaM.K) / 3.0f; + BetaM.I = MathHelper.Lerp(BetaM.I, mLum, Desaturation); + BetaM.J = MathHelper.Lerp(BetaM.J, mLum, Desaturation); + BetaM.K = MathHelper.Lerp(BetaM.K, mLum, Desaturation); + + float pThetaLum = (BetaPThetaPrefix.I + BetaPThetaPrefix.J + BetaPThetaPrefix.K) / 3.0f; + BetaPThetaPrefix.I = MathHelper.Lerp(BetaPThetaPrefix.I, pThetaLum, Desaturation); + BetaPThetaPrefix.J = MathHelper.Lerp(BetaPThetaPrefix.J, pThetaLum, Desaturation); + BetaPThetaPrefix.K = MathHelper.Lerp(BetaPThetaPrefix.K, pThetaLum, Desaturation); + + float mThetaLum = (BetaMThetaPrefix.I + BetaMThetaPrefix.J + BetaMThetaPrefix.K) / 3.0f; + BetaMThetaPrefix.I = MathHelper.Lerp(BetaMThetaPrefix.I, mThetaLum, Desaturation); + BetaMThetaPrefix.J = MathHelper.Lerp(BetaMThetaPrefix.J, mThetaLum, Desaturation); + BetaMThetaPrefix.K = MathHelper.Lerp(BetaMThetaPrefix.K, mThetaLum, Desaturation); + } + } + + private void ClampValues() + { + SunAnglePitch = MathHelper.Clamp(SunAnglePitch, 0.0f, 90.0f); + SunAngleYaw = MathHelper.Clamp(SunAngleYaw, 0.0f, 360.0f); + Color = MathHelper.Clamp(Color, 0.0f, 1.0f); + Intensity = MathHelper.Clamp(Intensity, 0.0f, 65536.0f); + SeaLevel = MathHelper.Clamp(SeaLevel, -65536.0f, 65536.0f); + RayleignHeightScale = MathHelper.Clamp(RayleignHeightScale, 0.01f, 65536.0f); + MieHeightScale = MathHelper.Clamp(MieHeightScale, 0.01f, 65536.0f); + RayleighMultiplier = MathHelper.Clamp(RayleighMultiplier, 0.0f, 1000.0f); + MieMultiplier = MathHelper.Clamp(MieMultiplier, 0.0f, 1000.0f); + SunPhaseFunction = MathHelper.Clamp(SunPhaseFunction, 0.0f, 0.95f); + DistanceBias = MathHelper.Clamp(DistanceBias, -65536.0f, 65536.0f); + MaxFogThickness = MathHelper.Clamp(MaxFogThickness, 0.01f, 65536.0f); + Desaturation = MathHelper.Clamp(Desaturation, 0.0f, 1.0f); + SheetDensity = MathHelper.Clamp(SheetDensity, 0.0f, 10000.0f); + } + + public void Postprocess() + { + if (Math.Abs(MaxFogThickness) < 0.001f) + MaxFogThickness = 65535.0f; + RuntimeWeight = 0.0f; + + ClampValues(); + PostprocessFogConstants(); + } } // probably lots of wrong fields, unused anyway @@ -146,5 +221,28 @@ public class UnderwaterBlock : TagStructure public float Murkiness; public RealRgbColor FogColor; } + + public void Postprocess() + { + if (Math.Abs(DistanceFalloffPower) < 0.001f) + DistanceFalloffPower = 2.0f; + if (Math.Abs(FalloffStartDistance) < 0.001f) + FalloffStartDistance = 5.0f; + if (Math.Abs(ClusterSearchRadius) < 0.001f) + ClusterSearchRadius = 25.0f; + if (Math.Abs(TransparentSortDistance) < 0.001f) + TransparentSortDistance = 100.0f; + + foreach (var atmosphere in AtmosphereSettings) + atmosphere.Postprocess(); + + TextureRepeatRate = MathHelper.Clamp(TextureRepeatRate, 0.1f, 100.0f); + DistanceBetweenSheets = MathHelper.Clamp(DistanceBetweenSheets, 0.1f, 10000.0f); + DepthFadeFactor = MathHelper.Clamp(DepthFadeFactor, 0.00001f, 10.0f); + ClusterSearchRadius = MathHelper.Clamp(ClusterSearchRadius, 1.0f, 50.0f); + FalloffStartDistance = MathHelper.Clamp(FalloffStartDistance, 0.1f, 10.0f); + DistanceFalloffPower = MathHelper.Clamp(DistanceFalloffPower, 0.1f, 10.0f); + TransparentSortDistance = MathHelper.Clamp(TransparentSortDistance, 0.1f, 65535.0f); + } } } \ No newline at end of file