diff --git a/packages/org.gamecult.eve.unity-scene/README.md b/packages/org.gamecult.eve.unity-scene/README.md index 9150c15..84f394d 100644 --- a/packages/org.gamecult.eve.unity-scene/README.md +++ b/packages/org.gamecult.eve.unity-scene/README.md @@ -72,3 +72,6 @@ out of Eve's semantic surface while allowing a provider-owned shader to consume portable Eve Fields documents. Volume composition runs as a generic URP render pass before post-processing so the provider-advertised profile grades both the native scene and the provider volume through the same camera pipeline. +Providers may advertise per-layer resolution scales, mipmap use, and filtering +through `layerTargetDescriptors`; the Unity lowerer applies those native target +requirements without assigning gameplay or product meaning to the layer keys. diff --git a/packages/org.gamecult.eve.unity-scene/Runtime/Fields/EveUnityFieldsVolumeRenderer.cs b/packages/org.gamecult.eve.unity-scene/Runtime/Fields/EveUnityFieldsVolumeRenderer.cs index 7848eb5..c7e5c2a 100644 --- a/packages/org.gamecult.eve.unity-scene/Runtime/Fields/EveUnityFieldsVolumeRenderer.cs +++ b/packages/org.gamecult.eve.unity-scene/Runtime/Fields/EveUnityFieldsVolumeRenderer.cs @@ -242,11 +242,51 @@ namespace GameCult.Eve.UnityScene.Fields private void EnsureTargets(EveUnityFieldVolumeProjection field) { var bindings = ParseBindings(Prop(field, "layerBindings")); + var descriptors = ParseBindings(Prop(field, "layerTargetDescriptors")); if (string.Equals(_activeNodeId, field.NodeId, StringComparison.Ordinal) && - _targets.Count == bindings.Count) return; + _targets.Count == bindings.Count && + _targets.All(target => bindings.ContainsKey(target.LayerKey))) + { + foreach (var target in _targets) + ApplyLayerTargetDescriptor(target, descriptors); + return; + } _targets.Clear(); foreach (var binding in bindings) - _targets.Add(new EveFieldsSplatLayerTarget { LayerKey = binding.Key, UseMipMaps = true }); + { + var target = new EveFieldsSplatLayerTarget { LayerKey = binding.Key }; + ApplyLayerTargetDescriptor(target, descriptors); + _targets.Add(target); + } + } + + private static void ApplyLayerTargetDescriptor( + EveFieldsSplatLayerTarget target, + IReadOnlyDictionary descriptors) + { + target.WidthScale = 1f; + target.HeightScale = 1f; + target.UseMipMaps = false; + target.FilterMode = FilterMode.Bilinear; + if (descriptors.TryGetValue(target.LayerKey, out var descriptor)) + TryApplyLayerTargetDescriptor(target, descriptor); + } + + public static bool TryApplyLayerTargetDescriptor(EveFieldsSplatLayerTarget? target, string descriptor) + { + if (target == null) return false; + var values = (descriptor ?? "").Split(','); + if (values.Length != 4 || + !TryFloat(values[0].Trim(), out var widthScale) || widthScale <= 0 || + !TryFloat(values[1].Trim(), out var heightScale) || heightScale <= 0 || + !bool.TryParse(values[2].Trim(), out var useMipMaps) || + !Enum.TryParse(values[3].Trim(), true, out FilterMode filterMode)) + return false; + target.WidthScale = widthScale; + target.HeightScale = heightScale; + target.UseMipMaps = useMipMaps; + target.FilterMode = filterMode; + return true; } private void EnsureLayerRenderer() diff --git a/packages/org.gamecult.eve.unity-scene/Tests/Editor/EveFieldsUnitySceneProjectionTests.cs b/packages/org.gamecult.eve.unity-scene/Tests/Editor/EveFieldsUnitySceneProjectionTests.cs index a2b5398..1268480 100644 --- a/packages/org.gamecult.eve.unity-scene/Tests/Editor/EveFieldsUnitySceneProjectionTests.cs +++ b/packages/org.gamecult.eve.unity-scene/Tests/Editor/EveFieldsUnitySceneProjectionTests.cs @@ -101,6 +101,42 @@ namespace GameCult.Eve.UnityScene.Tests } } + [Test] + public void VolumeRendererAppliesProviderAdvertisedLayerTargetShape() + { + var target = new EveFieldsSplatLayerTarget { LayerKey = "fog.tint" }; + + Assert.That( + EveUnityFieldsVolumeRenderer.TryApplyLayerTargetDescriptor( + target, + "0.5,0.25,true,trilinear"), + Is.True); + Assert.That(target.WidthScale, Is.EqualTo(0.5f)); + Assert.That(target.HeightScale, Is.EqualTo(0.25f)); + Assert.That(target.UseMipMaps, Is.True); + Assert.That(target.FilterMode, Is.EqualTo(FilterMode.Trilinear)); + } + + [Test] + public void VolumeRendererRejectsMalformedLayerTargetShape() + { + var target = new EveFieldsSplatLayerTarget + { + WidthScale = 2f, + HeightScale = 2f, + UseMipMaps = true, + FilterMode = FilterMode.Trilinear + }; + + Assert.That( + EveUnityFieldsVolumeRenderer.TryApplyLayerTargetDescriptor(target, "0,1,true,bilinear"), + Is.False); + Assert.That(target.WidthScale, Is.EqualTo(2f)); + Assert.That(target.HeightScale, Is.EqualTo(2f)); + Assert.That(target.UseMipMaps, Is.True); + Assert.That(target.FilterMode, Is.EqualTo(FilterMode.Trilinear)); + } + [Test] public void PackageContainsGenericFieldsShader() { diff --git a/packages/org.gamecult.eve.unity-scene/package.json b/packages/org.gamecult.eve.unity-scene/package.json index e4f7449..5f43b5f 100644 --- a/packages/org.gamecult.eve.unity-scene/package.json +++ b/packages/org.gamecult.eve.unity-scene/package.json @@ -1,7 +1,7 @@ { "name": "org.gamecult.eve.unity-scene", "displayName": "Eve Unity Scene Lowering", - "version": "0.3.46", + "version": "0.3.47", "unity": "6000.0", "description": "Provider-agnostic Unity scene shell for gamecult.eve.surface.v1 interactive world surfaces.", "dependencies": {