diff --git a/Aetheria.State.Daemon.Smoke/Program.cs b/Aetheria.State.Daemon.Smoke/Program.cs index 397e6fa45..2957ec83b 100644 --- a/Aetheria.State.Daemon.Smoke/Program.cs +++ b/Aetheria.State.Daemon.Smoke/Program.cs @@ -149,6 +149,7 @@ internal sealed class AetheriaDaemonYmirSmokeChecks Action[] checks = [ PositiveGravityDepthAttractsAndProjectsAsAWell, + VolumeSurfaceKeepsNativeShaderAbiInAssetVariant, YmirMovesProjectileAndReportsStableContact, InstantWeaponRequestSurvivesLockAcquisition, ConstantWeaponRunsOnDaemonThroughYmirBeamContact, @@ -202,6 +203,32 @@ internal sealed class AetheriaDaemonYmirSmokeChecks RunCheck(check); } + private static void VolumeSurfaceKeepsNativeShaderAbiInAssetVariant() + { + var player = Entity(0, 0, "player"); + var run = new AetheriaRuntimeRunCheckpointCommit + { + RunId = "volume-program-ownership-smoke", + CurrentZoneIndex = 0, + CurrentEntityKey = "zone.0.entity.0", + Zones = [new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0, Entities = [player] }] + }; + var surface = AetheriaRuntimeDaemonGameSurfaceBuilder.Build( + new AetheriaRuntimeDaemonFrameDocument { FrameId = 1, Run = run }, + new AetheriaRuntimeDaemonHealthDocument(), + AetheriaRuntimeDaemonCommandBoundaryDocument.Create("daemon")); + var volume = Flatten(surface.Surface.Root).Single(node => node.Kind == "field.volume3d"); + Require(volume.Props.Values.All(value => value == null || !value.Contains("_Nebula", StringComparison.Ordinal)) && + volume.Props["layerBindings"].Contains("gravity.height=surfaceHeight", StringComparison.Ordinal), + "portable Eve volume surfaces must name logical ports rather than Unity shader properties"); + + var shader = AetheriaRuntimeAssets.ProjectManifest(null).Assets.Single(asset => + asset.Ref.AssetKey == "shader.environment.gravity-fog"); + Require(shader.Ref.Metadata["unity.volume.texturePort.surfaceHeight"] == "_NebulaSurfaceHeight" && + shader.Ref.Metadata["unity.volume.pass.raymarch"] == "0", + "provider asset metadata must own the concrete Unity volume-program ABI projected into runtime variants"); + } + private static AetheriaYmirWorldPhysics NewPhysics() { AetheriaYmirWorldPhysics physics = new(); diff --git a/Aetheria.State.Daemon/Program.cs b/Aetheria.State.Daemon/Program.cs index f46157044..eed967d5b 100644 --- a/Aetheria.State.Daemon/Program.cs +++ b/Aetheria.State.Daemon/Program.cs @@ -871,7 +871,7 @@ static RudpCultNetSchemaServer StartClientCultMeshHost( { var viewportPut = node.Database.Documents.CreateRawDocumentPutMessage( response.MessageId, - new CultRecordHandle( + new CultRecordHandle( new CultRecordKey(viewportRecordKey)), AetheriaRuntimeGameDocuments.RenderSplatsViewport(frame, viewport), new CultNetDocumentMessageOptions @@ -2051,10 +2051,11 @@ static EveAssetCatalogDocument BuildCoreAssetCatalog( bundle.Hash, bundle.Size, unityAssetPath, - new Dictionary(StringComparer.Ordinal) - { - ["renderChannel.map.unityLayer"] = "14" - })) + new Dictionary( + entry.Ref.Metadata + .Where(pair => pair.Key.StartsWith("unity.volume.", StringComparison.Ordinal)) + .Append(new KeyValuePair("renderChannel.map.unityLayer", "14")), + StringComparer.Ordinal))) .ToArray(), new Dictionary(StringComparer.Ordinal) { diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index 6ea173145..616ddc5aa 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -791,9 +791,10 @@ static void RequireSharedEvePackagesImportedFromEveRepo(string root) var requiredManifestSymbols = new[] { - "\"org.gamecult.cultlib\": \"https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.9\"", - "\"org.gamecult.eve.surface\": \"https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.surface#eveunity-surface-v0.2.0\"", - "\"org.gamecult.eve.unity-scene\": \"https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.2.3\"" + "\"org.gamecult.cultlib\": \"https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.13\"", + "\"org.gamecult.eve.plugin-fields\": \"https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.2.0\"", + "\"org.gamecult.eve.surface\": \"https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.surface#eveunity-surface-v0.2.2\"", + "\"org.gamecult.eve.unity-scene\": \"https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.37\"" }; var missingManifestSymbols = requiredManifestSymbols @@ -809,9 +810,10 @@ static void RequireSharedEvePackagesImportedFromEveRepo(string root) var requiredLockSymbols = new[] { - "cultlib-unity-v1.0.9", - "eveunity-surface-v0.2.0", - "eveunity-scene-v0.2.3", + "cultlib-unity-v1.0.13", + "eve-plugin-fields-unity-v0.2.0", + "eveunity-surface-v0.2.2", + "eveunity-scene-v0.3.37", "\"source\": \"git\"" }; @@ -8141,7 +8143,7 @@ static void RequireUnitySharedDocumentAccessorErgonomics(string root) var forbiddenMapRendererSharedDocumentSymbols = new[] { "CultMeshReactiveDocument _objectsViewport", - "CultMeshReactiveDocument _renderSplatsViewport", + "CultMeshReactiveDocument _renderSplatsViewport", ".ReactiveObjectsViewport(viewport, \"unity-map-renderer\")", ".ReactiveRenderSplatsViewport(viewport, \"unity-map-renderer\")", "AetheriaRuntimeObjectsViewportSession _objectsViewport", @@ -8653,7 +8655,7 @@ static void RequireUnityViewportAndMapReadsUseManagedAccessors(string root) var requiredClientSymbols = new[] { "public CultMeshDocumentHandle ObjectsViewport(", - "public CultMeshDocumentHandle RenderSplatsViewport(", + "public CultMeshDocumentHandle RenderSplatsViewport(", "public CultMeshDocumentHandle ZoneDetails(" }; var missingClientSymbols = requiredClientSymbols @@ -8669,7 +8671,7 @@ static void RequireUnityViewportAndMapReadsUseManagedAccessors(string root) var forbiddenClientSymbols = new[] { "public CultMeshReactiveDocument ReactiveObjectsViewport(", - "public CultMeshReactiveDocument ReactiveRenderSplatsViewport(", + "public CultMeshReactiveDocument ReactiveRenderSplatsViewport(", "public CultMeshReactiveDocument ReactiveZoneDetails(" }; var survivingClientSymbols = forbiddenClientSymbols @@ -8761,7 +8763,7 @@ static void RequireUnityViewportAndMapReadsUseManagedAccessors(string root) string.Join(", ", missingRenderSplatViewportSourceSymbols)); } - if (renderSplatViewportSource.Contains("CultMeshReactiveDocument _renderSplatsViewport", StringComparison.Ordinal) || + if (renderSplatViewportSource.Contains("CultMeshReactiveDocument _renderSplatsViewport", StringComparison.Ordinal) || renderSplatViewportSource.Contains(".ReactiveRenderSplatsViewport(", StringComparison.Ordinal) || renderSplatViewportSource.Contains("AetheriaRuntimeRenderSplatsViewportSession _renderSplatsViewport", StringComparison.Ordinal) || renderSplatViewportSource.Contains(".ObserveRenderSplats(viewport)", StringComparison.Ordinal)) @@ -8772,7 +8774,7 @@ static void RequireUnityViewportAndMapReadsUseManagedAccessors(string root) if (renderSplatViewportSource.Contains("_fallbackRenderSplatsViewport", StringComparison.Ordinal) || renderSplatViewportSource.Contains("EmptyRenderSplatsViewport", StringComparison.Ordinal) || - renderSplatViewportSource.Contains("new AetheriaRuntimeRenderSplatsViewportDocument", StringComparison.Ordinal)) + renderSplatViewportSource.Contains("new EveFieldsSplatsDocument", StringComparison.Ordinal)) { throw new InvalidOperationException( "AetheriaUnityRenderSplatViewportSource must not fabricate renderer-local render splat documents; daemon/CultMesh viewport documents own render fields."); @@ -8893,7 +8895,7 @@ static void RequireAetheriaManagedStateAccessorsCoverDomainDocuments(string root "public CultMeshDocumentHandle GameViewport(", "public CultMeshDocumentHandle ObjectsViewport(", "public CultMeshDocumentHandle GravityViewport(", - "public CultMeshDocumentHandle RenderSplatsViewport(", + "public CultMeshDocumentHandle RenderSplatsViewport(", "public CultMeshDocumentHandle ZoneDetails(", "public CultMeshDocumentHandle ZoneDetailsSurface(", "public CultMeshDocumentHandle InventoryPanelSurface(", @@ -8948,7 +8950,7 @@ static void RequireAetheriaManagedStateAccessorsCoverDomainDocuments(string root "public CultMeshReactiveDocument ReactiveGameViewport(", "public CultMeshReactiveDocument ReactiveObjectsViewport(", "public CultMeshReactiveDocument ReactiveGravityViewport(", - "public CultMeshReactiveDocument ReactiveRenderSplatsViewport(", + "public CultMeshReactiveDocument ReactiveRenderSplatsViewport(", "public CultMeshReactiveDocument ReactiveZoneDetails(", "public CultMeshReactiveDocument ReactiveZoneDetailsSurface(", "public CultMeshReactiveDocument ReactiveInventoryPanelSurface(", @@ -9011,7 +9013,7 @@ static void RequireAetheriaManagedStateAccessorsCoverDomainDocuments(string root "public AetheriaRuntimeGameViewportDocument CurrentGameViewport(", "public AetheriaRuntimeObjectsViewportDocument CurrentObjectsViewport(", "public AetheriaRuntimeGravityViewportDocument CurrentGravityViewport(", - "public AetheriaRuntimeRenderSplatsViewportDocument CurrentRenderSplatsViewport(", + "public EveFieldsSplatsDocument CurrentRenderSplatsViewport(", "public AetheriaRuntimeZoneDetailsDocument CurrentZoneDetails(", "public AetheriaRuntimeSurfaceDocument CurrentZoneDetailsSurface(", "public AetheriaRuntimeSurfaceDocument CurrentInventoryPanelSurface(", @@ -10998,7 +11000,6 @@ static void RequireTypedDaemonCommandPayloads(string root) ["state node"] = stateNode, ["Unity daemon observer"] = observer, ["ActionGameManager"] = actionGameManager, - ["daemon command tests"] = tests, ["daemon surface commands"] = daemonSurfaceCommands }; foreach (var source in liveSources) @@ -18293,7 +18294,7 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) if (runtimeClientProvider.Contains("public static CultMeshReactiveDocument Reactive", StringComparison.Ordinal) || runtimeClientProvider.Contains("public static CultMeshReactiveDocument ReactiveZoneContacts(", StringComparison.Ordinal) || runtimeClientProvider.Contains("public static CultMeshReactiveDocument ReactiveObjectsViewport(", StringComparison.Ordinal) || - runtimeClientProvider.Contains("public static CultMeshReactiveDocument ReactiveRenderSplatsViewport(", StringComparison.Ordinal) || + runtimeClientProvider.Contains("public static CultMeshReactiveDocument ReactiveRenderSplatsViewport(", StringComparison.Ordinal) || runtimeClientProvider.Contains("public static CultMeshReactiveDocument ReactiveEveSurface(", StringComparison.Ordinal) || runtimeClientProvider.Contains("private static CultMeshReactiveDocument _playerSettingsDocument", StringComparison.Ordinal) || runtimeClientProvider.Contains("RuntimeState().ReactivePlayerSettingsDocument()", StringComparison.Ordinal) || @@ -18697,7 +18698,7 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) "public async Task MapViewportAsync(", "public async Task ObjectsViewportAsync(", "public async Task GravityViewportAsync(", - "public async Task RenderSplatsViewportAsync(", + "public async Task RenderSplatsViewportAsync(", "public async Task AssetManifestAsync()", "public async Task CurrentZoneAsync()", "public async Task CurrentEntityAsync()", diff --git a/Aetheria.State/Aetheria.State.csproj b/Aetheria.State/Aetheria.State.csproj index f149b495d..c75f3560f 100644 --- a/Aetheria.State/Aetheria.State.csproj +++ b/Aetheria.State/Aetheria.State.csproj @@ -17,7 +17,8 @@ - + diff --git a/Aetheria.Unity/Packages/manifest.json b/Aetheria.Unity/Packages/manifest.json index 27ddefc72..fe943c3c3 100644 --- a/Aetheria.Unity/Packages/manifest.json +++ b/Aetheria.Unity/Packages/manifest.json @@ -7,8 +7,8 @@ "com.unity.modules.uielements": "1.0.0", "com.unity.render-pipelines.universal": "17.4.0", "org.gamecult.cultlib": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.13", - "org.gamecult.eve.plugin-fields": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.1.1", + "org.gamecult.eve.plugin-fields": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.2.0", "org.gamecult.eve.surface": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.surface#eveunity-surface-v0.2.2", - "org.gamecult.eve.unity-scene": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.32" + "org.gamecult.eve.unity-scene": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.37" } } diff --git a/Aetheria.Unity/Packages/packages-lock.json b/Aetheria.Unity/Packages/packages-lock.json index 32e381796..6f0044500 100644 --- a/Aetheria.Unity/Packages/packages-lock.json +++ b/Aetheria.Unity/Packages/packages-lock.json @@ -126,11 +126,13 @@ "hash": "feb5c71513e71d681699f462fe3682b3168c6f73" }, "org.gamecult.eve.plugin-fields": { - "version": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.1.1", + "version": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.2.0", "depth": 0, "source": "git", - "dependencies": {}, - "hash": "0b099274a4e2b4c301eced4322166837792f585a" + "dependencies": { + "org.gamecult.cultlib": "1.0.13" + }, + "hash": "382a23d8f8a07e4b5eef5f81f84655861a858367" }, "org.gamecult.eve.surface": { "version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.surface#eveunity-surface-v0.2.2", @@ -142,17 +144,17 @@ "hash": "140e1bd963a0033e66777a3b2c5fe6e9c97dfe32" }, "org.gamecult.eve.unity-scene": { - "version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.32", + "version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.37", "depth": 0, "source": "git", "dependencies": { "org.gamecult.cultlib": "1.0.13", - "org.gamecult.eve.plugin-fields": "0.1.1", + "org.gamecult.eve.plugin-fields": "0.2.0", "org.gamecult.eve.surface": "0.2.2", "com.unity.mathematics": "1.3.2", "com.unity.modules.particlesystem": "1.0.0" }, - "hash": "817912a041ac1911e1e27a4b88617754d90ad4b7" + "hash": "5ce654800760203154132d4b0fd1475294283ba6" }, "com.unity.modules.assetbundle": { "version": "1.0.0", diff --git a/Assets/Editor/EveAssetBundleBuilder.cs b/Assets/Editor/EveAssetBundleBuilder.cs index 6b4d7fcc7..fdefcd302 100644 --- a/Assets/Editor/EveAssetBundleBuilder.cs +++ b/Assets/Editor/EveAssetBundleBuilder.cs @@ -529,6 +529,12 @@ namespace Aetheria.Editor var reflection = LoadAuthoredAsset(bundle, assetNames, "Assets/Textures/studio2.hdr"); if (reflection == null) throw new InvalidOperationException("Aetheria Eve bundle has no provider reflection cubemap."); + var gravityFog = LoadAuthoredAsset(bundle, assetNames, "Assets/Shaders/Raymarching/CloudShader.shader"); + if (gravityFog == null || !gravityFog.isSupported) + throw new InvalidOperationException("Aetheria Eve bundle has no supported gravity-fog volume shader."); + var dither = LoadAuthoredAsset(bundle, assetNames, "Assets/Resources/LDR_LLL1_0.png"); + if (dither == null) + throw new InvalidOperationException("Aetheria Eve bundle has no pre-generated volume dither texture."); } finally { diff --git a/Assets/Scripts/Gameplay/AetheriaRenderSplatLayerRenderer.cs b/Assets/Scripts/Gameplay/AetheriaRenderSplatLayerRenderer.cs index b41151058..d86e86442 100644 --- a/Assets/Scripts/Gameplay/AetheriaRenderSplatLayerRenderer.cs +++ b/Assets/Scripts/Gameplay/AetheriaRenderSplatLayerRenderer.cs @@ -26,7 +26,7 @@ public sealed class AetheriaRenderSplatLayerRenderer : MonoBehaviour return false; } - public void Render(AetheriaRuntimeRenderSplatsViewportDocument document, int width, int height) + public void Render(EveFieldsSplatsDocument document, int width, int height) { if (document == null) return; ResolveRenderer(); diff --git a/Assets/Scripts/Gameplay/AetheriaSceneRenderSplatSource.cs b/Assets/Scripts/Gameplay/AetheriaSceneRenderSplatSource.cs index 0013fa42e..5c0689ca2 100644 --- a/Assets/Scripts/Gameplay/AetheriaSceneRenderSplatSource.cs +++ b/Assets/Scripts/Gameplay/AetheriaSceneRenderSplatSource.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using GameCult.Aetheria.State.Verse; +using GameCult.Eve.PluginFields; using UnityEngine; public sealed class AetheriaSceneRenderSplatSource : MonoBehaviour @@ -43,7 +44,7 @@ public sealed class AetheriaSceneRenderSplatSource : MonoBehaviour [SerializeField] private AetheriaSceneRenderSplatFixture[] fixtures = Array.Empty(); - public AetheriaRuntimeRenderSplatsViewportDocument BuildDocument(AetheriaRuntimeViewportBounds viewport) + public EveFieldsSplatsDocument BuildDocument(AetheriaRuntimeViewportBounds viewport) { viewport ??= new AetheriaRuntimeViewportBounds(); var normalizedViewport = Normalize(viewport); @@ -58,13 +59,19 @@ public sealed class AetheriaSceneRenderSplatSource : MonoBehaviour foreach (var fixture in fixtures ?? Array.Empty()) fixture.AddTo(builder, layerIndices); - return new AetheriaRuntimeRenderSplatsViewportDocument + return new EveFieldsSplatsDocument { PublishedAtUtc = DateTimeOffset.UtcNow.ToString("O"), SimulationTimeSeconds = Application.isPlaying ? Time.timeAsDouble : 0, RunId = "scene", ZoneName = string.IsNullOrWhiteSpace(documentName) ? gameObject.scene.name : documentName, - Viewport = normalizedViewport, + Viewport = new EveFieldsViewport + { + MinX = normalizedViewport.MinX, + MinY = normalizedViewport.MinY, + MaxX = normalizedViewport.MaxX, + MaxY = normalizedViewport.MaxY + }, Layers = layers, Splats = builder.Build() }; @@ -81,7 +88,7 @@ public sealed class AetheriaSceneRenderSplatSource : MonoBehaviour }; } - private static AetheriaRuntimeRenderSplatLayerDefinition[] BuildLayers() + private static EveFieldsSplatLayer[] BuildLayers() { return new[] { @@ -96,14 +103,14 @@ public sealed class AetheriaSceneRenderSplatSource : MonoBehaviour }; } - private static AetheriaRuntimeRenderSplatLayerDefinition Layer( + private static EveFieldsSplatLayer Layer( string key, string displayName, int channel, string blendMode = AetheriaRuntimeRenderSplatBlendModes.Add, string graphicsFormat = "R16_SFloat") { - return new AetheriaRuntimeRenderSplatLayerDefinition + return new EveFieldsSplatLayer { LayerKey = key, DisplayName = displayName, @@ -163,9 +170,9 @@ public sealed class AetheriaSceneRenderSplatSource : MonoBehaviour _sourceFlags.Add(splat.SourceFlags); } - public AetheriaRuntimeRenderSplatSoa Build() + public EveFieldsSplatSoa Build() { - return new AetheriaRuntimeRenderSplatSoa + return new EveFieldsSplatSoa { Count = _centerX.Count, CenterX = _centerX.ToArray(), diff --git a/Assets/Scripts/Gameplay/AetheriaUnityGameViewportDocuments.cs b/Assets/Scripts/Gameplay/AetheriaUnityGameViewportDocuments.cs index 653e8d3d2..8d14cd5ed 100644 --- a/Assets/Scripts/Gameplay/AetheriaUnityGameViewportDocuments.cs +++ b/Assets/Scripts/Gameplay/AetheriaUnityGameViewportDocuments.cs @@ -1,12 +1,13 @@ using System; using GameCult.Aetheria.State.Verse; +using GameCult.Eve.PluginFields; using GameCult.Mesh; public sealed class AetheriaUnityGameViewportDocuments : IDisposable { private readonly CultMeshReactiveDocument _contacts; private readonly CultMeshReactiveDocument _objectsViewport; - private readonly CultMeshReactiveDocument _renderSplatsViewport; + private readonly CultMeshReactiveDocument _renderSplatsViewport; private AetheriaUnityGameViewportDocuments( AetheriaClientState state, @@ -30,7 +31,7 @@ public sealed class AetheriaUnityGameViewportDocuments : IDisposable public AetheriaRuntimeZoneContactsDocument CurrentContacts => _contacts?.Current; public AetheriaRuntimeObjectsViewportDocument CurrentObjectsViewport => _objectsViewport?.Current; - public AetheriaRuntimeRenderSplatsViewportDocument CurrentRenderSplatsViewport => _renderSplatsViewport?.Current; + public EveFieldsSplatsDocument CurrentRenderSplatsViewport => _renderSplatsViewport?.Current; public static AetheriaUnityGameViewportDocuments OpenMap( AetheriaClientState state, diff --git a/Assets/Scripts/Gameplay/AetheriaUnityRenderSplatViewportSource.cs b/Assets/Scripts/Gameplay/AetheriaUnityRenderSplatViewportSource.cs index 606f8c360..7df995480 100644 --- a/Assets/Scripts/Gameplay/AetheriaUnityRenderSplatViewportSource.cs +++ b/Assets/Scripts/Gameplay/AetheriaUnityRenderSplatViewportSource.cs @@ -1,5 +1,6 @@ using System; using GameCult.Aetheria.State.Verse; +using GameCult.Eve.PluginFields; using UnityEngine; public sealed class AetheriaUnityRenderSplatViewportSource : MonoBehaviour @@ -40,7 +41,7 @@ public sealed class AetheriaUnityRenderSplatViewportSource : MonoBehaviour } } - public AetheriaRuntimeRenderSplatsViewportDocument CurrentDocument => + public EveFieldsSplatsDocument CurrentDocument => _viewportDocuments?.CurrentRenderSplatsViewport; public bool RenderInLateUpdate diff --git a/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs b/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs index e5f3e3bef..f94383d26 100644 --- a/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs +++ b/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs @@ -506,6 +506,13 @@ public class DaemonRuntimeDocumentTests Assert.IsTrue(ContainsSurfaceProp(surface.Surface.Root, "entityViewSchema", EveEntitySoaViewDocument.SchemaId)); Assert.IsFalse(ContainsSurfaceKind(surface.Surface.Root, "world.entity3d")); + Assert.IsTrue(ContainsSurfaceKind(surface.Surface.Root, "field.volume3d")); + Assert.IsTrue(ContainsSurfaceProp(surface.Surface.Root, "materialAssetRef", + "shader.environment.gravity-fog")); + Assert.IsTrue(ContainsSurfaceProp(surface.Surface.Root, "documentSchema", + AetheriaRuntimeDaemonSchemas.RenderSplatsViewport)); + Assert.IsFalse(ContainsSurfaceValueFragment(surface.Surface.Root, "_Nebula"), + "The semantic Eve surface must not own Unity shader property names."); Assert.AreEqual(EveEntitySoaViewDocument.SchemaId, portable.Schema); Assert.AreEqual(42, portable.Generation); Assert.AreEqual(AetheriaRuntimeDaemonSoaColumnKinds.Position, portable.Columns.Single().Semantic); @@ -708,6 +715,13 @@ public class DaemonRuntimeDocumentTests Assert.IsTrue(assetManifest.Assets.Any(asset => asset.Ref.AssetKey == "prefab.entity.ship" && asset.Ref.Kind == AetheriaRuntimeAssetKinds.Prefab)); + Assert.IsTrue(assetManifest.Assets.Any(asset => + asset.Ref.AssetKey == "shader.environment.gravity-fog" && + asset.Ref.Kind == AetheriaRuntimeAssetKinds.Shader && + asset.Ref.Metadata["unity.volume.texturePort.surfaceHeight"] == "_NebulaSurfaceHeight")); + Assert.IsTrue(assetManifest.Assets.Any(asset => + asset.Ref.AssetKey == "texture.environment.volume-dither" && + asset.Ref.Kind == AetheriaRuntimeAssetKinds.Texture)); var editorTuiSurface = result.EditorTuiSurface; Assert.AreEqual("aetheria.daemon", editorTuiSurface.ProviderId); Assert.AreEqual("editor.daemon", editorTuiSurface.ProviderKind); @@ -6224,6 +6238,14 @@ public class DaemonRuntimeDocumentTests component.Children.Any(child => ContainsSurfaceKind(child, kind)); } + private static bool ContainsSurfaceValueFragment(AetheriaRuntimeSurfaceComponent component, string fragment) + { + if (component.Props.Values.Any(value => + value != null && value.IndexOf(fragment, StringComparison.Ordinal) >= 0)) + return true; + return component.Children.Any(child => ContainsSurfaceValueFragment(child, fragment)); + } + private static bool ContainsSurfaceStateBinding( AetheriaRuntimeSurfaceComponent component, string targetProp, diff --git a/Assets/Scripts/UI/Menu/SectorMap.cs b/Assets/Scripts/UI/Menu/SectorMap.cs index 6658be9d5..edf552e89 100644 --- a/Assets/Scripts/UI/Menu/SectorMap.cs +++ b/Assets/Scripts/UI/Menu/SectorMap.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using GameCult.Aetheria.State.Verse; +using GameCult.Eve.PluginFields; using GameCult.Mesh; using TMPro; using UniRx; @@ -357,7 +358,7 @@ public class SectorMap : MonoBehaviour return InfluenceSplatRasterizer; } - private AetheriaRuntimeRenderSplatsViewportDocument BuildInfluenceSplatDocument(int factionIndex) + private EveFieldsSplatsDocument BuildInfluenceSplatDocument(int factionIndex) { var zones = (_sectorMap?.Zones ?? Array.Empty()).ToArray(); var minX = zones.Length > 0 ? zones.Min(zone => zone.X) : -1; @@ -420,10 +421,10 @@ public class SectorMap : MonoBehaviour sourceFlags.Add(0); } - return new AetheriaRuntimeRenderSplatsViewportDocument + return new EveFieldsSplatsDocument { Schema = AetheriaRuntimeDaemonSchemas.RenderSplatsViewport, - Viewport = new AetheriaRuntimeViewportBounds + Viewport = new EveFieldsViewport { MinX = minX - padding, MinY = minY - padding, @@ -432,7 +433,7 @@ public class SectorMap : MonoBehaviour }, Layers = new[] { - new AetheriaRuntimeRenderSplatLayerDefinition + new EveFieldsSplatLayer { LayerKey = AetheriaRuntimeRenderSplatLayerKeys.Influence, DisplayName = "Sector Influence", @@ -441,7 +442,7 @@ public class SectorMap : MonoBehaviour GraphicsFormat = "R16_SFloat" } }, - Splats = new AetheriaRuntimeRenderSplatSoa + Splats = new EveFieldsSplatSoa { Count = centerX.Count, CenterX = centerX, diff --git a/Assets/Scripts/Zone Display/VolumeSampling.cs b/Assets/Scripts/Zone Display/VolumeSampling.cs index 2bdd5cc91..379ab061a 100644 --- a/Assets/Scripts/Zone Display/VolumeSampling.cs +++ b/Assets/Scripts/Zone Display/VolumeSampling.cs @@ -4,6 +4,7 @@ using System; using GameCult.Aetheria.State.Verse; +using GameCult.Eve.PluginFields; using UnityEngine; using Unity.Mathematics; using UnityEngine.Experimental.Rendering; @@ -222,7 +223,7 @@ public class VolumeSampling : MonoBehaviour NebulaTint = ResolveLayerTexture(AetheriaRuntimeRenderSplatLayerKeys.FogTint, NebulaTint); } - private AetheriaRuntimeRenderSplatsViewportDocument ResolveSceneSplatDocument(Vector2 center, Vector2 size) + private EveFieldsSplatsDocument ResolveSceneSplatDocument(Vector2 center, Vector2 size) { if (SceneSplatSource == null) SceneSplatSource = GetComponent(); @@ -231,7 +232,7 @@ public class VolumeSampling : MonoBehaviour : null; } - private AetheriaRuntimeRenderSplatsViewportDocument ResolveRuntimeSplatDocument(Vector2 center, Vector2 size) + private EveFieldsSplatsDocument ResolveRuntimeSplatDocument(Vector2 center, Vector2 size) { if (SplatViewportSource == null) return null; diff --git a/Assets/Shaders/Raymarching/CloudShader.shader b/Assets/Shaders/Raymarching/CloudShader.shader index c402636c7..fef76e2ec 100644 --- a/Assets/Shaders/Raymarching/CloudShader.shader +++ b/Assets/Shaders/Raymarching/CloudShader.shader @@ -5,6 +5,13 @@ Shader "Aetheria/CloudShader" Properties { _MainTex("MainTex",2D) = "white"{} + [HideInInspector] _DitheringTex("DitheringTex", 2D) = "white" {} + [HideInInspector] _NebulaSurfaceHeight("NebulaSurfaceHeight", 2D) = "black" {} + [HideInInspector] _NebulaPatchHeight("NebulaPatchHeight", 2D) = "black" {} + [HideInInspector] _NebulaPatch("NebulaPatch", 2D) = "black" {} + [HideInInspector] _NebulaTint("NebulaTint", 2D) = "black" {} + [HideInInspector] _CloudTex("CloudTex", 2D) = "black" {} + [HideInInspector] _CompositeOpacity("CompositeOpacity", Range(0, 1)) = 1 } SubShader @@ -86,7 +93,6 @@ Shader "Aetheria/CloudShader" float density = c.a; if (density <= 0.0f) { - result.intTransmittance = 0; return; } float extinction = _ExtinctionCoefficient * density / (1-fade); @@ -94,7 +100,7 @@ Shader "Aetheria/CloudShader" float clampedExtinction = max(extinction, 1e-7); float transmittance = exp(-extinction * stepsize); - float3 luminance = c.rgb * _NebulaLuminance; + float3 luminance = c.rgb * _NebulaLuminance * density; float3 integScatt = (luminance - luminance * transmittance) / clampedExtinction; float depthWeight = result.intTransmittance * (1-transmittance); //Is it a better idea to use (1-transmittance) * intTransmittance as depth weight? @@ -168,7 +174,6 @@ Shader "Aetheria/CloudShader" //float sceneDepth = Linear01Depth(depthSample); //bool occluded = GetRaymarchEndFromSceneDepth(sceneDepth, raymarchEnd); float3 viewDir = normalize(worldPos.xyz - _WorldSpaceCameraPos); - //float blue = tex2D(_DitheringTex, screenPos * _DitheringCoords.xy + _DitheringCoords.zw).r; float dither = tex2D(_DitheringTex, screenUV * _DitheringCoords.xy).r; float offset = -fmod(_RaymarchOffset + dither, 1.0f); //final offset combined. The value will be multiplied by sample step in GetDensity. @@ -285,6 +290,7 @@ Shader "Aetheria/CloudShader" sampler2D _CloudTex; //The full resolution cloud tex we generated. sampler2D _CameraDepthTexture; float4 _ProjectionExtents; + float _CompositeOpacity; struct v2f { @@ -312,7 +318,7 @@ Shader "Aetheria/CloudShader" float distance; float density; unpack(currSample.a, distance, density); - return half4(currSample.rgb, saturate(density)); + return half4(currSample.rgb * _CompositeOpacity, saturate(density) * _CompositeOpacity); } ENDCG } diff --git a/Packages/manifest.json b/Packages/manifest.json index 64728c67c..0aeb618f4 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -23,7 +23,7 @@ "org.gamecult.cultmath": "file:../../CultMath", "org.gamecult.cultlib": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.13", "org.gamecult.eve.surface": "file:../../EveUnity/packages/org.gamecult.eve.surface", - "org.gamecult.eve.plugin-fields": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.1.1", + "org.gamecult.eve.plugin-fields": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.2.0", "org.gamecult.eve.unity-scene": "file:../../EveUnity/packages/org.gamecult.eve.unity-scene", "org.gamecult.eve.unity-uitoolkit": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-uitoolkit#eveunity-uitoolkit-v0.1.0", "com.unity.modules.accessibility": "1.0.0", diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs index 48c556985..fb481d4fd 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using GameCult.Mesh; +using GameCult.Eve.PluginFields; using MessagePack; using EveSurfaceDocument = GameCult.Eve.Surface.EveSurfaceDocument; @@ -21,7 +22,7 @@ namespace GameCult.Aetheria.State.Verse private readonly Func> _mapViewport; private readonly Func> _objectsViewport; private readonly Func> _gravityViewport; - private readonly Func> _renderSplatsViewport; + private readonly Func> _renderSplatsViewport; private readonly Func> _zoneDetails; private readonly Func> _zoneDetailsSurface; private readonly Func> _inventoryPanelSurface; @@ -61,7 +62,7 @@ namespace GameCult.Aetheria.State.Verse Func> mapViewport, Func> objectsViewport, Func> gravityViewport, - Func> renderSplatsViewport, + Func> renderSplatsViewport, Func> zoneDetails, Func> zoneDetailsSurface, Func> inventoryPanelSurface, @@ -229,7 +230,7 @@ namespace GameCult.Aetheria.State.Verse return _gravityViewport(viewport ?? new AetheriaRuntimeViewportBounds()); } - public CultMeshDocumentHandle RenderSplatsViewport( + public CultMeshDocumentHandle RenderSplatsViewport( AetheriaRuntimeViewportBounds viewport) { return _renderSplatsViewport(viewport ?? new AetheriaRuntimeViewportBounds()); diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeAssets.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeAssets.cs index 74af646ed..4f5d8a392 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeAssets.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeAssets.cs @@ -27,6 +27,8 @@ namespace GameCult.Aetheria.State.Verse var entries = new Dictionary(StringComparer.Ordinal); Add(entries, EnvironmentSkyboxMaterial()); Add(entries, EnvironmentReflectionCubemap()); + Add(entries, EnvironmentGravityFogShader()); + Add(entries, EnvironmentDitherTexture()); Add(entries, MapIcon("entity.player", "Player", "Sprites/Icons/Stroked/Ship")); Add(entries, MapIcon("entity.ship", "Ship", "Sprites/Icons/Stroked/Ship")); Add(entries, MapIcon("entity.orbital", "Orbital", "Sprites/Icons/Stroked/orbital")); @@ -207,6 +209,90 @@ namespace GameCult.Aetheria.State.Verse }; } + public static AetheriaRuntimeAssetManifestEntry EnvironmentGravityFogShader() + { + return new AetheriaRuntimeAssetManifestEntry + { + Ref = new AetheriaRuntimeAssetRef + { + AssetKey = "shader.environment.gravity-fog", + Kind = AetheriaRuntimeAssetKinds.Shader, + Uri = CultMeshAssetUri("shader.environment.gravity-fog"), + MimeType = "application/vnd.unity.shader", + Metadata = new Dictionary(StringComparer.Ordinal) + { + ["unityAssetPath"] = "Assets/Shaders/Raymarching/CloudShader.shader", + ["presentationRole"] = "environment.gravity-fog.volume", + ["unity.volume.pass.raymarch"] = "0", + ["unity.volume.pass.composite"] = "2", + ["unity.volume.quality.high.keyword"] = "HIGH_QUALITY", + ["unity.volume.quality.normal.keyword"] = "MEDIUM_QUALITY", + ["unity.volume.feature.flow.global.keyword"] = "FLOW_GLOBAL", + ["unity.volume.feature.noise.slope.keyword"] = "NOISE_SLOPE", + ["unity.volume.texturePort.surfaceHeight"] = "_NebulaSurfaceHeight", + ["unity.volume.texturePort.patchHeight"] = "_NebulaPatchHeight", + ["unity.volume.texturePort.patch"] = "_NebulaPatch", + ["unity.volume.texturePort.tint"] = "_NebulaTint", + ["unity.volume.texturePort.dither"] = "_DitheringTex", + ["unity.volume.texturePort.cloud"] = "_CloudTex", + ["unity.volume.vectorPort.viewportTransform"] = "_GridTransform", + ["unity.volume.matrixPort.cameraInverseViewProjection"] = "_CamInvProj", + ["unity.volume.vectorPort.cameraProjectionExtents"] = "_ProjectionExtents", + ["unity.volume.floatPort.raymarchOffset"] = "_RaymarchOffset", + ["unity.volume.vectorPort.ditherCoordinates"] = "_DitheringCoords", + ["unity.volume.floatPort.fillDensity"] = "_NebulaFillDensity", + ["unity.volume.floatPort.fillDistance"] = "_NebulaFillDistance", + ["unity.volume.floatPort.fillExponent"] = "_NebulaFillExponent", + ["unity.volume.floatPort.fillOffset"] = "_NebulaFillOffset", + ["unity.volume.floatPort.patchDensity"] = "_NebulaPatchDensity", + ["unity.volume.floatPort.floorOffset"] = "_NebulaFloorOffset", + ["unity.volume.floatPort.floorBlend"] = "_NebulaFloorBlend", + ["unity.volume.floatPort.patchBlend"] = "_NebulaPatchBlend", + ["unity.volume.floatPort.luminance"] = "_NebulaLuminance", + ["unity.volume.floatPort.extinction"] = "_ExtinctionCoefficient", + ["unity.volume.floatPort.tintLodExponent"] = "_TintLodExponent", + ["unity.volume.floatPort.safetyDistance"] = "_SafetyDistance", + ["unity.volume.floatPort.flowScale"] = "_FlowScale", + ["unity.volume.floatPort.flowAmplitude"] = "_FlowAmplitude", + ["unity.volume.floatPort.flowPeriod"] = "_FlowPeriod", + ["unity.volume.floatPort.flowSlopeAmplitude"] = "_FlowSlopeAmplitude", + ["unity.volume.floatPort.flowSwirlAmplitude"] = "_FlowSwirlAmplitude", + ["unity.volume.floatPort.noiseScale"] = "_NebulaNoiseScale", + ["unity.volume.floatPort.noiseAmplitude"] = "_NebulaNoiseAmplitude", + ["unity.volume.floatPort.noiseExponent"] = "_NebulaNoiseExponent", + ["unity.volume.floatPort.noiseSpeed"] = "_NebulaNoiseSpeed", + ["unity.volume.floatPort.noiseSlopeExponent"] = "_NebulaNoiseSlopeExponent", + ["unity.volume.floatPort.dynamicSkyBoost"] = "_DynamicSkyBoost", + ["unity.volume.floatPort.dynamicLodHigh"] = "_DynamicLodHigh", + ["unity.volume.floatPort.dynamicLodLow"] = "_DynamicLodLow", + ["unity.volume.floatPort.dynamicIntensity"] = "_DynamicIntensity", + ["unity.volume.floatPort.compositeOpacity"] = "_CompositeOpacity" + } + }, + Tags = new[] { "presentation", "environment", "gravity", "fog", "volume" } + }; + } + + public static AetheriaRuntimeAssetManifestEntry EnvironmentDitherTexture() + { + return new AetheriaRuntimeAssetManifestEntry + { + Ref = new AetheriaRuntimeAssetRef + { + AssetKey = "texture.environment.volume-dither", + Kind = AetheriaRuntimeAssetKinds.Texture, + Uri = CultMeshAssetUri("texture.environment.volume-dither"), + MimeType = "image/png", + Metadata = new Dictionary(StringComparer.Ordinal) + { + ["unityAssetPath"] = "Assets/Resources/LDR_LLL1_0.png", + ["presentationRole"] = "environment.volume.dither" + } + }, + Tags = new[] { "presentation", "environment", "volume", "pre-generated" } + }; + } + private static AetheriaRuntimeAssetManifestEntry MapIcon( string key, string label, diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs index e24557c80..2cd81bde9 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs @@ -655,6 +655,7 @@ namespace GameCult.Aetheria.State.Verse var aimPresentation = AimPresentation(run, zone, playerEntityId); if (aimPresentation != null) presentationChildren.Insert(0, aimPresentation); + presentationChildren.Insert(0, GravityFogVolume("aetheria.daemon.game.world.gravity-fog")); return new AetheriaRuntimeSurfaceComponent( id, @@ -677,6 +678,40 @@ namespace GameCult.Aetheria.State.Verse }); } + private static AetheriaRuntimeSurfaceComponent GravityFogVolume(string id) + { + var viewport = DefaultViewport(); + var props = new Dictionary(StringComparer.Ordinal) + { + ["label"] = "Gravity-shaped volumetric fog", + ["documentRef"] = ViewportDocumentId("aetheria.viewport.render_splats", viewport), + ["documentSchema"] = AetheriaRuntimeDaemonSchemas.RenderSplatsViewport, + ["materialAssetRef"] = "shader.environment.gravity-fog", + ["renderChannel"] = "world.transparent", + ["compositeMode"] = "premultiplied-alpha", + ["quality"] = "high", + ["features"] = "flow.global;noise.slope", + ["textureWidth"] = "1024", + ["textureHeight"] = "1024", + ["downsample"] = "0", + ["layerBindings"] = "gravity.height=surfaceHeight;fog.patch_height=patchHeight;fog.patch=patch;fog.tint=tint", + ["assetTextureBindings"] = "texture.environment.volume-dither=dither", + ["vectorParameters"] = "ditherCoordinates=0,0,0,0", + ["floatParameters"] = "fillDensity=0.000000001;fillDistance=120;fillExponent=5;fillOffset=70;" + + "patchDensity=0.35;floorOffset=-20;floorBlend=10;patchBlend=25;luminance=1;extinction=0.5;" + + "tintLodExponent=-0.45;safetyDistance=30;flowScale=512;flowAmplitude=15;flowPeriod=8;" + + "flowSlopeAmplitude=0;flowSwirlAmplitude=0;noiseScale=414.2167;noiseAmplitude=-36.17;" + + "noiseExponent=-0.25;noiseSpeed=0.0025;noiseSlopeExponent=0.15;dynamicSkyBoost=2;" + + "dynamicLodHigh=7;dynamicLodLow=2;dynamicIntensity=0.5;compositeOpacity=0.3" + }; + return new AetheriaRuntimeSurfaceComponent( + id, + "field.volume3d", + props, + Array.Empty(), + AetheriaRuntimeSurfaceStateBindings.FromProps(props)); + } + private static AetheriaRuntimeSurfaceComponent? AimPresentation( AetheriaRuntimeRunCheckpointCommit run, AetheriaRuntimeZoneSnapshotCommit zone, diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeGameDocuments.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeGameDocuments.cs index 0572e984d..1340bd8da 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeGameDocuments.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeGameDocuments.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using GameCult.Eve.PluginFields; #nullable enable @@ -110,7 +111,7 @@ namespace GameCult.Aetheria.State.Verse }; } - public static AetheriaRuntimeRenderSplatsViewportDocument RenderSplatsViewport( + public static EveFieldsSplatsDocument RenderSplatsViewport( AetheriaRuntimeDaemonFrameDocument frame, AetheriaRuntimeViewportBounds viewport) { @@ -219,7 +220,7 @@ namespace GameCult.Aetheria.State.Verse radius, radius, AetheriaRuntimeRenderSplatChannels.Gravity, - AetheriaRuntimeRenderSplatFalloffs.InverseSmooth, + AetheriaRuntimeRenderSplatFalloffs.Smooth, -body.GravityWellDepth, 0, 0, @@ -245,7 +246,9 @@ namespace GameCult.Aetheria.State.Verse if (IsBodyKind(body, "sun")) { - var tintRadius = Math.Max(radius, Math.Max(32, body.BodyRadiusMultiplier * 70) * + var tintRadius = Math.Max( + radius, + Math.Pow(Math.Max(0, body.Mass), 0.25) * 300 * Math.Max(0.01, body.SunVisual?.LightRadiusMultiplier ?? 1.0)); splats.Add( layerIndices[AetheriaRuntimeRenderSplatLayerKeys.FogTint], @@ -292,7 +295,7 @@ namespace GameCult.Aetheria.State.Verse AetheriaRuntimeRunCheckpointCommit.EntityRecordKey(context.RunId, zone.ZoneIndex, entity.EntityIndex)); } - return new AetheriaRuntimeRenderSplatsViewportDocument + return new EveFieldsSplatsDocument { FrameId = frame.FrameId, PublishedAtUtc = frame.PublishedAtUtc ?? "", @@ -300,17 +303,23 @@ namespace GameCult.Aetheria.State.Verse RunId = context.RunId, ZoneIndex = zone.ZoneIndex, ZoneName = string.IsNullOrWhiteSpace(zone.Name) ? $"Zone {zone.ZoneIndex}" : zone.Name, - Viewport = normalizedViewport, + Viewport = new EveFieldsViewport + { + MinX = normalizedViewport.MinX, + MinY = normalizedViewport.MinY, + MaxX = normalizedViewport.MaxX, + MaxY = normalizedViewport.MaxY + }, Layers = layers, Splats = splats.Build() }; } - private static IReadOnlyList BuildDefaultRenderSplatLayers() + private static IReadOnlyList BuildDefaultRenderSplatLayers() { return new[] { - new AetheriaRuntimeRenderSplatLayerDefinition + new EveFieldsSplatLayer { LayerKey = AetheriaRuntimeRenderSplatLayerKeys.GravityHeight, DisplayName = "Gravity Height", @@ -318,7 +327,7 @@ namespace GameCult.Aetheria.State.Verse BlendMode = AetheriaRuntimeRenderSplatBlendModes.Add, GraphicsFormat = "R16_SFloat" }, - new AetheriaRuntimeRenderSplatLayerDefinition + new EveFieldsSplatLayer { LayerKey = AetheriaRuntimeRenderSplatLayerKeys.GravityWave, DisplayName = "Gravity Wave", @@ -326,7 +335,7 @@ namespace GameCult.Aetheria.State.Verse BlendMode = AetheriaRuntimeRenderSplatBlendModes.Add, GraphicsFormat = "R16_SFloat" }, - new AetheriaRuntimeRenderSplatLayerDefinition + new EveFieldsSplatLayer { LayerKey = AetheriaRuntimeRenderSplatLayerKeys.Visibility, DisplayName = "Visibility Mask", @@ -334,7 +343,7 @@ namespace GameCult.Aetheria.State.Verse BlendMode = AetheriaRuntimeRenderSplatBlendModes.Max, GraphicsFormat = "R16_SFloat" }, - new AetheriaRuntimeRenderSplatLayerDefinition + new EveFieldsSplatLayer { LayerKey = AetheriaRuntimeRenderSplatLayerKeys.FogSurfaceHeight, DisplayName = "Fog Surface Height", @@ -342,7 +351,7 @@ namespace GameCult.Aetheria.State.Verse BlendMode = AetheriaRuntimeRenderSplatBlendModes.Add, GraphicsFormat = "R16_SFloat" }, - new AetheriaRuntimeRenderSplatLayerDefinition + new EveFieldsSplatLayer { LayerKey = AetheriaRuntimeRenderSplatLayerKeys.FogPatchHeight, DisplayName = "Fog Patch Height", @@ -350,7 +359,7 @@ namespace GameCult.Aetheria.State.Verse BlendMode = AetheriaRuntimeRenderSplatBlendModes.Add, GraphicsFormat = "R16_SFloat" }, - new AetheriaRuntimeRenderSplatLayerDefinition + new EveFieldsSplatLayer { LayerKey = AetheriaRuntimeRenderSplatLayerKeys.FogPatch, DisplayName = "Fog Patch", @@ -358,7 +367,7 @@ namespace GameCult.Aetheria.State.Verse BlendMode = AetheriaRuntimeRenderSplatBlendModes.Max, GraphicsFormat = "R16_SFloat" }, - new AetheriaRuntimeRenderSplatLayerDefinition + new EveFieldsSplatLayer { LayerKey = AetheriaRuntimeRenderSplatLayerKeys.FogTint, DisplayName = "Fog Tint", @@ -366,7 +375,7 @@ namespace GameCult.Aetheria.State.Verse BlendMode = AetheriaRuntimeRenderSplatBlendModes.Add, GraphicsFormat = "B10G11R11_UFloatPack32" }, - new AetheriaRuntimeRenderSplatLayerDefinition + new EveFieldsSplatLayer { LayerKey = AetheriaRuntimeRenderSplatLayerKeys.Influence, DisplayName = "Influence", @@ -1547,9 +1556,9 @@ namespace GameCult.Aetheria.State.Verse _sourceFlags.Add(sourceFlags); } - public AetheriaRuntimeRenderSplatSoa Build() + public EveFieldsSplatSoa Build() { - return new AetheriaRuntimeRenderSplatSoa + return new EveFieldsSplatSoa { Count = _centerX.Count, CenterX = _centerX.ToArray(), diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeRenderSplatDocuments.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeRenderSplatDocuments.cs index 8179ae7b3..d5d5a0ee8 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeRenderSplatDocuments.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeRenderSplatDocuments.cs @@ -1,13 +1,9 @@ -using System; -using System.Collections.Generic; -using GameCult.Caching; -using GameCult.Eve.PluginFields; -using MessagePack; - #nullable enable namespace GameCult.Aetheria.State.Verse { + // Aetheria owns how simulation state becomes splats. The persisted document, + // layer, viewport, and SoA wire types are owned by GameCult.Eve.PluginFields. public static class AetheriaRuntimeRenderSplatChannels { public const int Visibility = 0; @@ -50,148 +46,4 @@ namespace GameCult.Aetheria.State.Verse public const int Smooth = 2; public const int InverseSmooth = 3; } - - [CultDocument("gamecult.fields.splats", "gamecult.fields.splats.v1")] - [MessagePackObject] - public sealed class AetheriaRuntimeRenderSplatsViewportDocument : IEveFieldsSplatsDocument - { - [Key(0)] - public string Schema { get; set; } = AetheriaRuntimeDaemonSchemas.RenderSplatsViewport; - - [Key(1)] - public long FrameId { get; set; } - - [Key(2)] - public string PublishedAtUtc { get; set; } = ""; - - [Key(3)] - public double SimulationTimeSeconds { get; set; } - - [Key(4)] - public string RunId { get; set; } = ""; - - [Key(5)] - public int ZoneIndex { get; set; } - - [Key(6)] - public string ZoneName { get; set; } = ""; - - [Key(7)] - public AetheriaRuntimeViewportBounds Viewport { get; set; } = new AetheriaRuntimeViewportBounds(); - - [Key(8)] - public IReadOnlyList Layers { get; set; } = - Array.Empty(); - - [Key(9)] - public AetheriaRuntimeRenderSplatSoa Splats { get; set; } = new AetheriaRuntimeRenderSplatSoa(); - - IEveFieldsViewport IEveFieldsSplatsDocument.Viewport => Viewport; - IReadOnlyList IEveFieldsSplatsDocument.Layers => Layers; - IEveFieldsSplatSoa IEveFieldsSplatsDocument.Splats => Splats; - } - - [MessagePackObject] - public sealed class AetheriaRuntimeRenderSplatLayerDefinition : IEveFieldsSplatLayer - { - [Key(0)] - public string LayerKey { get; set; } = ""; - - [Key(1)] - public string DisplayName { get; set; } = ""; - - [Key(2)] - public int Channel { get; set; } - - [Key(3)] - public string BlendMode { get; set; } = AetheriaRuntimeRenderSplatBlendModes.Add; - - [Key(4)] - public string GraphicsFormat { get; set; } = "R16_SFloat"; - - [Key(5)] - public bool ClearBeforeDraw { get; set; } = true; - - [Key(6)] - public double ClearR { get; set; } - - [Key(7)] - public double ClearG { get; set; } - - [Key(8)] - public double ClearB { get; set; } - - [Key(9)] - public double ClearA { get; set; } - } - - [MessagePackObject] - public sealed class AetheriaRuntimeRenderSplatSoa : IEveFieldsSplatSoa - { - [Key(0)] - public int Count { get; set; } - - [Key(1)] - public IReadOnlyList CenterX { get; set; } = Array.Empty(); - - [Key(2)] - public IReadOnlyList CenterY { get; set; } = Array.Empty(); - - [Key(3)] - public IReadOnlyList HalfExtentX { get; set; } = Array.Empty(); - - [Key(4)] - public IReadOnlyList HalfExtentY { get; set; } = Array.Empty(); - - [Key(5)] - public IReadOnlyList RotationCos { get; set; } = Array.Empty(); - - [Key(6)] - public IReadOnlyList RotationSin { get; set; } = Array.Empty(); - - [Key(7)] - public IReadOnlyList Channel { get; set; } = Array.Empty(); - - [Key(8)] - public IReadOnlyList Falloff { get; set; } = Array.Empty(); - - [Key(9)] - public IReadOnlyList ValueR { get; set; } = Array.Empty(); - - [Key(10)] - public IReadOnlyList ValueG { get; set; } = Array.Empty(); - - [Key(11)] - public IReadOnlyList ValueB { get; set; } = Array.Empty(); - - [Key(12)] - public IReadOnlyList ValueA { get; set; } = Array.Empty(); - - [Key(13)] - public IReadOnlyList SourceKey { get; set; } = Array.Empty(); - - [Key(14)] - public IReadOnlyList LayerIndex { get; set; } = Array.Empty(); - - [Key(15)] - public IReadOnlyList SourceKind { get; set; } = Array.Empty(); - - [Key(16)] - public IReadOnlyList FrequencyX { get; set; } = Array.Empty(); - - [Key(17)] - public IReadOnlyList FrequencyY { get; set; } = Array.Empty(); - - [Key(18)] - public IReadOnlyList PhaseX { get; set; } = Array.Empty(); - - [Key(19)] - public IReadOnlyList PhaseY { get; set; } = Array.Empty(); - - [Key(20)] - public IReadOnlyList AnimationSpeed { get; set; } = Array.Empty(); - - [Key(21)] - public IReadOnlyList SourceFlags { get; set; } = Array.Empty(); - } } diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index b9a197040..b73af246a 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -324,11 +324,13 @@ "dependencies": {} }, "org.gamecult.eve.plugin-fields": { - "version": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.1.1", + "version": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.2.0", "depth": 0, "source": "git", - "dependencies": {}, - "hash": "0b099274a4e2b4c301eced4322166837792f585a" + "dependencies": { + "org.gamecult.cultlib": "1.0.13" + }, + "hash": "382a23d8f8a07e4b5eef5f81f84655861a858367" }, "org.gamecult.eve.surface": { "version": "file:../../EveUnity/packages/org.gamecult.eve.surface", @@ -344,9 +346,10 @@ "source": "local", "dependencies": { "org.gamecult.cultlib": "1.0.13", - "org.gamecult.eve.plugin-fields": "0.1.1", - "org.gamecult.eve.surface": "0.2.1", - "com.unity.mathematics": "1.3.2" + "org.gamecult.eve.plugin-fields": "0.2.0", + "org.gamecult.eve.surface": "0.2.2", + "com.unity.mathematics": "1.3.2", + "com.unity.modules.particlesystem": "1.0.0" } }, "org.gamecult.eve.unity-uitoolkit": {