Publish gravity fog through generic Eve fields

This commit is contained in:
Meta Vens 2026-07-15 20:17:05 +01:00
commit 6f0375f4ad
22 changed files with 293 additions and 230 deletions

View file

@ -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();

View file

@ -871,7 +871,7 @@ static RudpCultNetSchemaServer StartClientCultMeshHost(
{
var viewportPut = node.Database.Documents.CreateRawDocumentPutMessage(
response.MessageId,
new CultRecordHandle<AetheriaRuntimeRenderSplatsViewportDocument>(
new CultRecordHandle<GameCult.Eve.PluginFields.EveFieldsSplatsDocument>(
new CultRecordKey(viewportRecordKey)),
AetheriaRuntimeGameDocuments.RenderSplatsViewport(frame, viewport),
new CultNetDocumentMessageOptions
@ -2051,10 +2051,11 @@ static EveAssetCatalogDocument BuildCoreAssetCatalog(
bundle.Hash,
bundle.Size,
unityAssetPath,
new Dictionary<string, string>(StringComparer.Ordinal)
{
["renderChannel.map.unityLayer"] = "14"
}))
new Dictionary<string, string>(
entry.Ref.Metadata
.Where(pair => pair.Key.StartsWith("unity.volume.", StringComparison.Ordinal))
.Append(new KeyValuePair<string, string>("renderChannel.map.unityLayer", "14")),
StringComparer.Ordinal)))
.ToArray(),
new Dictionary<string, string>(StringComparer.Ordinal)
{

View file

@ -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<AetheriaRuntimeObjectsViewportDocument> _objectsViewport",
"CultMeshReactiveDocument<AetheriaRuntimeRenderSplatsViewportDocument> _renderSplatsViewport",
"CultMeshReactiveDocument<EveFieldsSplatsDocument> _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<AetheriaRuntimeObjectsViewportDocument> ObjectsViewport(",
"public CultMeshDocumentHandle<AetheriaRuntimeRenderSplatsViewportDocument> RenderSplatsViewport(",
"public CultMeshDocumentHandle<EveFieldsSplatsDocument> RenderSplatsViewport(",
"public CultMeshDocumentHandle<AetheriaRuntimeZoneDetailsDocument> ZoneDetails("
};
var missingClientSymbols = requiredClientSymbols
@ -8669,7 +8671,7 @@ static void RequireUnityViewportAndMapReadsUseManagedAccessors(string root)
var forbiddenClientSymbols = new[]
{
"public CultMeshReactiveDocument<AetheriaRuntimeObjectsViewportDocument> ReactiveObjectsViewport(",
"public CultMeshReactiveDocument<AetheriaRuntimeRenderSplatsViewportDocument> ReactiveRenderSplatsViewport(",
"public CultMeshReactiveDocument<EveFieldsSplatsDocument> ReactiveRenderSplatsViewport(",
"public CultMeshReactiveDocument<AetheriaRuntimeZoneDetailsDocument> ReactiveZoneDetails("
};
var survivingClientSymbols = forbiddenClientSymbols
@ -8761,7 +8763,7 @@ static void RequireUnityViewportAndMapReadsUseManagedAccessors(string root)
string.Join(", ", missingRenderSplatViewportSourceSymbols));
}
if (renderSplatViewportSource.Contains("CultMeshReactiveDocument<AetheriaRuntimeRenderSplatsViewportDocument> _renderSplatsViewport", StringComparison.Ordinal) ||
if (renderSplatViewportSource.Contains("CultMeshReactiveDocument<EveFieldsSplatsDocument> _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<AetheriaRuntimeGameViewportDocument> GameViewport(",
"public CultMeshDocumentHandle<AetheriaRuntimeObjectsViewportDocument> ObjectsViewport(",
"public CultMeshDocumentHandle<AetheriaRuntimeGravityViewportDocument> GravityViewport(",
"public CultMeshDocumentHandle<AetheriaRuntimeRenderSplatsViewportDocument> RenderSplatsViewport(",
"public CultMeshDocumentHandle<EveFieldsSplatsDocument> RenderSplatsViewport(",
"public CultMeshDocumentHandle<AetheriaRuntimeZoneDetailsDocument> ZoneDetails(",
"public CultMeshDocumentHandle<AetheriaRuntimeSurfaceDocument> ZoneDetailsSurface(",
"public CultMeshDocumentHandle<AetheriaRuntimeSurfaceDocument> InventoryPanelSurface(",
@ -8948,7 +8950,7 @@ static void RequireAetheriaManagedStateAccessorsCoverDomainDocuments(string root
"public CultMeshReactiveDocument<AetheriaRuntimeGameViewportDocument> ReactiveGameViewport(",
"public CultMeshReactiveDocument<AetheriaRuntimeObjectsViewportDocument> ReactiveObjectsViewport(",
"public CultMeshReactiveDocument<AetheriaRuntimeGravityViewportDocument> ReactiveGravityViewport(",
"public CultMeshReactiveDocument<AetheriaRuntimeRenderSplatsViewportDocument> ReactiveRenderSplatsViewport(",
"public CultMeshReactiveDocument<EveFieldsSplatsDocument> ReactiveRenderSplatsViewport(",
"public CultMeshReactiveDocument<AetheriaRuntimeZoneDetailsDocument> ReactiveZoneDetails(",
"public CultMeshReactiveDocument<AetheriaRuntimeSurfaceDocument> ReactiveZoneDetailsSurface(",
"public CultMeshReactiveDocument<AetheriaRuntimeSurfaceDocument> 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<TDocument> Reactive<TDocument>", StringComparison.Ordinal) ||
runtimeClientProvider.Contains("public static CultMeshReactiveDocument<AetheriaRuntimeZoneContactsDocument> ReactiveZoneContacts(", StringComparison.Ordinal) ||
runtimeClientProvider.Contains("public static CultMeshReactiveDocument<AetheriaRuntimeObjectsViewportDocument> ReactiveObjectsViewport(", StringComparison.Ordinal) ||
runtimeClientProvider.Contains("public static CultMeshReactiveDocument<AetheriaRuntimeRenderSplatsViewportDocument> ReactiveRenderSplatsViewport(", StringComparison.Ordinal) ||
runtimeClientProvider.Contains("public static CultMeshReactiveDocument<EveFieldsSplatsDocument> ReactiveRenderSplatsViewport(", StringComparison.Ordinal) ||
runtimeClientProvider.Contains("public static CultMeshReactiveDocument<global::Aetheria.State.Documents.EveSurfaceState> ReactiveEveSurface(", StringComparison.Ordinal) ||
runtimeClientProvider.Contains("private static CultMeshReactiveDocument<AetheriaRuntimePlayerSettingsDocument> _playerSettingsDocument", StringComparison.Ordinal) ||
runtimeClientProvider.Contains("RuntimeState().ReactivePlayerSettingsDocument()", StringComparison.Ordinal) ||
@ -18697,7 +18698,7 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root)
"public async Task<AetheriaRuntimeGameViewportDocument> MapViewportAsync(",
"public async Task<AetheriaRuntimeObjectsViewportDocument> ObjectsViewportAsync(",
"public async Task<AetheriaRuntimeGravityViewportDocument> GravityViewportAsync(",
"public async Task<AetheriaRuntimeRenderSplatsViewportDocument> RenderSplatsViewportAsync(",
"public async Task<EveFieldsSplatsDocument> RenderSplatsViewportAsync(",
"public async Task<AetheriaRuntimeAssetManifestDocument> AssetManifestAsync()",
"public async Task<AetheriaRuntimeCurrentZoneDocument> CurrentZoneAsync()",
"public async Task<AetheriaRuntimeCurrentEntityDocument> CurrentEntityAsync()",

View file

@ -17,7 +17,8 @@
<ProjectReference Include="$(CultLibRoot)\src\GameCult.Networking\GameCult.Networking.csproj" />
<ProjectReference Include="..\..\CultMath\src\CultMath\CultMath.csproj" />
<ProjectReference Include="$(EveUnityRoot)\packages\org.gamecult.eve.surface\GameCult.Eve.Surface.csproj" />
<ProjectReference Include="..\..\EvePlugins\plugins\eve-plugin-fields\GameCult.Eve.PluginFields.csproj" />
<ProjectReference Include="..\..\EvePlugins\plugins\eve-plugin-fields\GameCult.Eve.PluginFields.csproj"
AdditionalProperties="CultLibRoot=$(CultLibRoot)" />
</ItemGroup>
<Import Project="Aetheria.State.Dependencies.targets" />

View file

@ -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"
}
}

View file

@ -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",

View file

@ -529,6 +529,12 @@ namespace Aetheria.Editor
var reflection = LoadAuthoredAsset<Cubemap>(bundle, assetNames, "Assets/Textures/studio2.hdr");
if (reflection == null)
throw new InvalidOperationException("Aetheria Eve bundle has no provider reflection cubemap.");
var gravityFog = LoadAuthoredAsset<Shader>(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<Texture2D>(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
{

View file

@ -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();

View file

@ -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<AetheriaSceneRenderSplatFixture>();
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<AetheriaSceneRenderSplatFixture>())
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(),

View file

@ -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<AetheriaRuntimeZoneContactsDocument> _contacts;
private readonly CultMeshReactiveDocument<AetheriaRuntimeObjectsViewportDocument> _objectsViewport;
private readonly CultMeshReactiveDocument<AetheriaRuntimeRenderSplatsViewportDocument> _renderSplatsViewport;
private readonly CultMeshReactiveDocument<EveFieldsSplatsDocument> _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,

View file

@ -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

View file

@ -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,

View file

@ -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<AetheriaRuntimeSectorMapZone>()).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,

View file

@ -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<AetheriaSceneRenderSplatSource>();
@ -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;

View file

@ -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
}

View file

@ -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",

View file

@ -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<AetheriaRuntimeViewportBounds, CultMeshDocumentHandle<AetheriaRuntimeGameViewportDocument>> _mapViewport;
private readonly Func<AetheriaRuntimeViewportBounds, CultMeshDocumentHandle<AetheriaRuntimeObjectsViewportDocument>> _objectsViewport;
private readonly Func<AetheriaRuntimeViewportBounds, CultMeshDocumentHandle<AetheriaRuntimeGravityViewportDocument>> _gravityViewport;
private readonly Func<AetheriaRuntimeViewportBounds, CultMeshDocumentHandle<AetheriaRuntimeRenderSplatsViewportDocument>> _renderSplatsViewport;
private readonly Func<AetheriaRuntimeViewportBounds, CultMeshDocumentHandle<EveFieldsSplatsDocument>> _renderSplatsViewport;
private readonly Func<int, CultMeshDocumentHandle<AetheriaRuntimeZoneDetailsDocument>> _zoneDetails;
private readonly Func<int, CultMeshDocumentHandle<AetheriaRuntimeSurfaceDocument>> _zoneDetailsSurface;
private readonly Func<AetheriaRuntimeInventoryPanelSurfaceRequest, CultMeshDocumentHandle<AetheriaRuntimeSurfaceDocument>> _inventoryPanelSurface;
@ -61,7 +62,7 @@ namespace GameCult.Aetheria.State.Verse
Func<AetheriaRuntimeViewportBounds, CultMeshDocumentHandle<AetheriaRuntimeGameViewportDocument>> mapViewport,
Func<AetheriaRuntimeViewportBounds, CultMeshDocumentHandle<AetheriaRuntimeObjectsViewportDocument>> objectsViewport,
Func<AetheriaRuntimeViewportBounds, CultMeshDocumentHandle<AetheriaRuntimeGravityViewportDocument>> gravityViewport,
Func<AetheriaRuntimeViewportBounds, CultMeshDocumentHandle<AetheriaRuntimeRenderSplatsViewportDocument>> renderSplatsViewport,
Func<AetheriaRuntimeViewportBounds, CultMeshDocumentHandle<EveFieldsSplatsDocument>> renderSplatsViewport,
Func<int, CultMeshDocumentHandle<AetheriaRuntimeZoneDetailsDocument>> zoneDetails,
Func<int, CultMeshDocumentHandle<AetheriaRuntimeSurfaceDocument>> zoneDetailsSurface,
Func<AetheriaRuntimeInventoryPanelSurfaceRequest, CultMeshDocumentHandle<AetheriaRuntimeSurfaceDocument>> inventoryPanelSurface,
@ -229,7 +230,7 @@ namespace GameCult.Aetheria.State.Verse
return _gravityViewport(viewport ?? new AetheriaRuntimeViewportBounds());
}
public CultMeshDocumentHandle<AetheriaRuntimeRenderSplatsViewportDocument> RenderSplatsViewport(
public CultMeshDocumentHandle<EveFieldsSplatsDocument> RenderSplatsViewport(
AetheriaRuntimeViewportBounds viewport)
{
return _renderSplatsViewport(viewport ?? new AetheriaRuntimeViewportBounds());

View file

@ -27,6 +27,8 @@ namespace GameCult.Aetheria.State.Verse
var entries = new Dictionary<string, AetheriaRuntimeAssetManifestEntry>(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<string, string>(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<string, string>(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,

View file

@ -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<string, string>(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<AetheriaRuntimeSurfaceComponent>(),
AetheriaRuntimeSurfaceStateBindings.FromProps(props));
}
private static AetheriaRuntimeSurfaceComponent? AimPresentation(
AetheriaRuntimeRunCheckpointCommit run,
AetheriaRuntimeZoneSnapshotCommit zone,

View file

@ -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<AetheriaRuntimeRenderSplatLayerDefinition> BuildDefaultRenderSplatLayers()
private static IReadOnlyList<EveFieldsSplatLayer> 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(),

View file

@ -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<AetheriaRuntimeRenderSplatLayerDefinition> Layers { get; set; } =
Array.Empty<AetheriaRuntimeRenderSplatLayerDefinition>();
[Key(9)]
public AetheriaRuntimeRenderSplatSoa Splats { get; set; } = new AetheriaRuntimeRenderSplatSoa();
IEveFieldsViewport IEveFieldsSplatsDocument.Viewport => Viewport;
IReadOnlyList<IEveFieldsSplatLayer> 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<double> CenterX { get; set; } = Array.Empty<double>();
[Key(2)]
public IReadOnlyList<double> CenterY { get; set; } = Array.Empty<double>();
[Key(3)]
public IReadOnlyList<double> HalfExtentX { get; set; } = Array.Empty<double>();
[Key(4)]
public IReadOnlyList<double> HalfExtentY { get; set; } = Array.Empty<double>();
[Key(5)]
public IReadOnlyList<double> RotationCos { get; set; } = Array.Empty<double>();
[Key(6)]
public IReadOnlyList<double> RotationSin { get; set; } = Array.Empty<double>();
[Key(7)]
public IReadOnlyList<int> Channel { get; set; } = Array.Empty<int>();
[Key(8)]
public IReadOnlyList<int> Falloff { get; set; } = Array.Empty<int>();
[Key(9)]
public IReadOnlyList<double> ValueR { get; set; } = Array.Empty<double>();
[Key(10)]
public IReadOnlyList<double> ValueG { get; set; } = Array.Empty<double>();
[Key(11)]
public IReadOnlyList<double> ValueB { get; set; } = Array.Empty<double>();
[Key(12)]
public IReadOnlyList<double> ValueA { get; set; } = Array.Empty<double>();
[Key(13)]
public IReadOnlyList<string> SourceKey { get; set; } = Array.Empty<string>();
[Key(14)]
public IReadOnlyList<int> LayerIndex { get; set; } = Array.Empty<int>();
[Key(15)]
public IReadOnlyList<int> SourceKind { get; set; } = Array.Empty<int>();
[Key(16)]
public IReadOnlyList<double> FrequencyX { get; set; } = Array.Empty<double>();
[Key(17)]
public IReadOnlyList<double> FrequencyY { get; set; } = Array.Empty<double>();
[Key(18)]
public IReadOnlyList<double> PhaseX { get; set; } = Array.Empty<double>();
[Key(19)]
public IReadOnlyList<double> PhaseY { get; set; } = Array.Empty<double>();
[Key(20)]
public IReadOnlyList<double> AnimationSpeed { get; set; } = Array.Empty<double>();
[Key(21)]
public IReadOnlyList<double> SourceFlags { get; set; } = Array.Empty<double>();
}
}

View file

@ -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": {