Derive native volume texture scale from viewport

This commit is contained in:
Meta Vens 2026-07-15 21:47:50 +01:00
commit 3c8d127ef8
4 changed files with 68 additions and 3 deletions

View file

@ -19,6 +19,7 @@ drivers, asset-provider hooks, package release, runtime tests, and captures.
- provider asset-manifest documents
- runtime-selected asset-variant metadata, including native rendering-program bindings
- generic field-volume lifecycle declarations and logical texture/scalar/matrix ports
- generic viewport-to-texture scale bindings between logical vector and texture ports
- provider command receipts
- semantic render-channel inclusion and exclusion policy
- Unity input and local presentation assets
@ -51,6 +52,13 @@ temporal pass must also advertise its current-sample, history,
previous-view-projection, and reset-history ports; partial temporal programs fail
closed.
Viewport-sized shader inputs are likewise presentation state. A provider may
relate a logical vector port to a logical native texture port through
`viewportTextureScaleBindings`; EveUnity derives the vector from the active
camera viewport and resolved texture dimensions on every render. A provider
literal is not allowed to impersonate those runtime dimensions, and an
unresolvable relation fails closed.
The provider selects camera semantics and framing from its authoritative mode.
`planar.top-down-follow.v1` derives a downward presentation from the advertised
target and framing values. `perspective.entity-forward-follow.v1` derives its

View file

@ -20,6 +20,8 @@ namespace GameCult.Eve.UnityScene.Fields
private Material? _material;
private Shader? _sourceShader;
private IReadOnlyDictionary<string, string>? _programMetadata;
private readonly Dictionary<string, Texture> _assetTexturesByPort =
new Dictionary<string, Texture>(StringComparer.Ordinal);
private RenderTexture? _raymarchTexture;
private readonly RenderTexture?[] _historyTextures = new RenderTexture?[2];
private int _historyTextureIndex = -1;
@ -89,7 +91,7 @@ namespace GameCult.Eve.UnityScene.Fields
ApplyFieldBindings(field, _document);
camera.depthTextureMode |= DepthTextureMode.Depth;
EnsureVolumeTextures(camera, field);
if (_raymarchTexture == null) return;
if (_raymarchTexture == null || !ApplyViewportTextureScaleBindings(field, camera)) return;
var gpuProjection = GL.GetGPUProjectionMatrix(camera.projectionMatrix, true);
var viewProjection = gpuProjection * camera.worldToCameraMatrix;
@ -168,6 +170,7 @@ namespace GameCult.Eve.UnityScene.Fields
_sourceShader = shader;
_activeNodeId = field.NodeId;
_material = new Material(shader) { hideFlags = HideFlags.DontSave };
_assetTexturesByPort.Clear();
ResetTemporalHistory();
foreach (var parameter in ParseBindings(Prop(field, "floatParameters")))
{
@ -180,7 +183,11 @@ namespace GameCult.Eve.UnityScene.Fields
var texture = provider.ResolveAsset(
new EveUnityPlayableWorldAssetBinding(binding.Key, "", "provider-asset-ref"),
typeof(Texture)) as Texture;
if (texture != null) SetTexturePort(binding.Value, texture);
if (texture != null)
{
_assetTexturesByPort[binding.Value] = texture;
SetTexturePort(binding.Value, texture);
}
}
var quality = Prop(field, "quality").Trim().ToLowerInvariant();
if (TryProgramValue($"unity.volume.quality.{quality}.keyword", out var keyword) &&
@ -262,6 +269,7 @@ namespace GameCult.Eve.UnityScene.Fields
if (_material != null) { Destroy(_material); _material = null; }
_sourceShader = null;
_programMetadata = null;
_assetTexturesByPort.Clear();
_activeNodeId = "";
PresentedFrameId = -1;
CompositeCount = 0;
@ -276,6 +284,36 @@ namespace GameCult.Eve.UnityScene.Fields
private bool HasTemporalProgram() => ProgramPass("temporal") >= 0;
private bool ApplyViewportTextureScaleBindings(EveUnityFieldVolumeProjection field, Camera camera)
{
foreach (var binding in ParseBindings(Prop(field, "viewportTextureScaleBindings")))
{
if (string.IsNullOrWhiteSpace(ProgramPort("vector", binding.Key)) ||
string.IsNullOrWhiteSpace(ProgramPort("texture", binding.Value)) ||
!_assetTexturesByPort.TryGetValue(binding.Value, out var texture) ||
!TryComputeViewportTextureScale(camera.pixelWidth, camera.pixelHeight, texture, out var scale))
return false;
SetVectorPort(binding.Key, scale);
}
return true;
}
public static bool TryComputeViewportTextureScale(
int viewportWidth,
int viewportHeight,
Texture? texture,
out Vector4 scale)
{
scale = default;
if (texture == null || texture.width <= 0 || texture.height <= 0) return false;
scale = new Vector4(
(float)Math.Max(1, viewportWidth) / texture.width,
(float)Math.Max(1, viewportHeight) / texture.height,
0f,
0f);
return true;
}
private static bool EnsureRenderTexture(ref RenderTexture? texture, int width, int height, string name)
{
if (texture != null && texture.width == width && texture.height == height) return false;

View file

@ -73,6 +73,25 @@ namespace GameCult.Eve.UnityScene.Tests
Assert.That(error, Does.Contain("history port"));
}
[Test]
public void VolumeRendererDerivesViewportTextureScaleFromNativeDimensions()
{
var texture = new Texture2D(128, 64, TextureFormat.RGBA32, false);
try
{
Assert.That(EveUnityFieldsVolumeRenderer.TryComputeViewportTextureScale(
640,
360,
texture,
out var scale), Is.True);
Assert.That(scale, Is.EqualTo(new Vector4(5f, 5.625f, 0f, 0f)));
}
finally
{
UnityEngine.Object.DestroyImmediate(texture);
}
}
[Test]
public void PackageContainsGenericFieldsShader()
{

View file

@ -1,7 +1,7 @@
{
"name": "org.gamecult.eve.unity-scene",
"displayName": "Eve Unity Scene Lowering",
"version": "0.3.39",
"version": "0.3.40",
"unity": "2021.3",
"description": "Provider-agnostic Unity scene shell for gamecult.eve.surface.v1 interactive world surfaces.",
"dependencies": {