Honor provider temporal reprojection semantics

This commit is contained in:
Meta Vens 2026-07-16 20:04:19 +01:00
commit 7588763999
3 changed files with 79 additions and 2 deletions

View file

@ -28,6 +28,7 @@ namespace GameCult.Eve.UnityScene.Fields
private readonly RenderTexture?[] _historyTextures = new RenderTexture?[2];
private int _historyTextureIndex = -1;
private Matrix4x4 _previousViewProjection;
private Matrix4x4 _previousView;
private EveUnityFieldsVolumePass? _renderPass;
private string _activeNodeId = "";
private long _rasterizedFrameId = -1;
@ -160,7 +161,15 @@ namespace GameCult.Eve.UnityScene.Fields
finalCloudTexture = _historyTextures[historyWriteIndex]!;
SetTexturePort("currentSample", _raymarchTexture);
SetTexturePort("history", historyReadTexture!);
SetMatrixPort("previousViewProjection", _historyTextureIndex < 0 ? viewProjection : _previousViewProjection);
SetMatrixPort(
"previousViewProjection",
_historyTextureIndex < 0
? viewProjection
: ResolvePreviousViewProjection(
_programMetadata,
_previousViewProjection,
gpuProjection,
_previousView));
SetFloatPort("resetHistory", _historyTextureIndex < 0 ? 1f : 0f);
}
SetTexturePort("cloud", finalCloudTexture);
@ -186,6 +195,7 @@ namespace GameCult.Eve.UnityScene.Fields
{
_historyTextureIndex = historyWriteIndex;
_previousViewProjection = viewProjection;
_previousView = camera.worldToCameraMatrix;
}
CompositeCount++;
}
@ -454,6 +464,20 @@ namespace GameCult.Eve.UnityScene.Fields
{
_historyTextureIndex = -1;
_previousViewProjection = Matrix4x4.identity;
_previousView = Matrix4x4.identity;
}
public static Matrix4x4 ResolvePreviousViewProjection(
IReadOnlyDictionary<string, string>? metadata,
Matrix4x4 previousViewProjection,
Matrix4x4 currentGpuProjection,
Matrix4x4 previousView)
{
return metadata != null &&
metadata.TryGetValue("unity.volume.matrixSemantic.previousViewProjection", out var semantic) &&
string.Equals(semantic, "current-projection.previous-view.v1", StringComparison.Ordinal)
? currentGpuProjection * previousView
: previousViewProjection;
}
private bool HasTemporalProgram() => ProgramPass("temporal") >= 0;
@ -532,6 +556,10 @@ namespace GameCult.Eve.UnityScene.Fields
!ValidPort(metadata, "matrix", "previousViewProjection") ||
!ValidPort(metadata, "float", "resetHistory"))
return Fail("Native volume temporal pass is missing a required history port.", out error);
if (metadata.TryGetValue("unity.volume.matrixSemantic.previousViewProjection", out var semantic) &&
!string.Equals(semantic, "previous-view-projection.v1", StringComparison.Ordinal) &&
!string.Equals(semantic, "current-projection.previous-view.v1", StringComparison.Ordinal))
return Fail("Native volume temporal pass has an unsupported previous-view-projection semantic.", out error);
return true;
}

View file

@ -327,6 +327,55 @@ namespace GameCult.Eve.UnityScene.Tests
Assert.That(EveUnityFieldsVolumeRenderer.TryValidateProgramMetadata(metadata, out var error), Is.True, error);
}
[Test]
public void VolumeRendererUsesCurrentProjectionWithPreviousViewWhenAdvertised()
{
var metadata = RequiredVolumeProgramMetadata();
metadata["unity.volume.matrixSemantic.previousViewProjection"] =
"current-projection.previous-view.v1";
var previousViewProjection = Matrix4x4.Translate(new Vector3(1f, 2f, 3f));
var currentProjection = Matrix4x4.Scale(new Vector3(2f, 3f, 4f));
var previousView = Matrix4x4.Rotate(Quaternion.Euler(10f, 20f, 30f));
var resolved = EveUnityFieldsVolumeRenderer.ResolvePreviousViewProjection(
metadata,
previousViewProjection,
currentProjection,
previousView);
Assert.That(resolved, Is.EqualTo(currentProjection * previousView));
Assert.That(resolved, Is.Not.EqualTo(previousViewProjection));
}
[Test]
public void VolumeRendererDefaultsToTruePreviousViewProjection()
{
var previousViewProjection = Matrix4x4.Translate(new Vector3(1f, 2f, 3f));
var resolved = EveUnityFieldsVolumeRenderer.ResolvePreviousViewProjection(
RequiredVolumeProgramMetadata(),
previousViewProjection,
Matrix4x4.Scale(Vector3.one * 2f),
Matrix4x4.Rotate(Quaternion.Euler(10f, 20f, 30f)));
Assert.That(resolved, Is.EqualTo(previousViewProjection));
}
[Test]
public void VolumeProgramRejectsUnknownPreviousViewProjectionSemantic()
{
var metadata = RequiredVolumeProgramMetadata();
metadata["unity.volume.pass.temporal"] = "1";
metadata["unity.volume.texturePort.currentSample"] = "_CurrentVolume";
metadata["unity.volume.texturePort.history"] = "_HistoryVolume";
metadata["unity.volume.matrixPort.previousViewProjection"] = "_PreviousViewProjection";
metadata["unity.volume.floatPort.resetHistory"] = "_ResetHistory";
metadata["unity.volume.matrixSemantic.previousViewProjection"] = "made-up";
Assert.That(EveUnityFieldsVolumeRenderer.TryValidateProgramMetadata(metadata, out var error), Is.False);
Assert.That(error, Does.Contain("previous-view-projection semantic"));
}
[Test]
public void VolumeProgramRejectsPartialTemporalLifecycle()
{

View file

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