Render Eve volumes in the Scene view
This commit is contained in:
parent
6c73788368
commit
884b58683c
5 changed files with 91 additions and 42 deletions
|
|
@ -22,6 +22,10 @@ resource declarations; effects that sample camera color request an intermediate
|
|||
color texture and never read the back buffer. Do not schedule these effects from
|
||||
`RenderPipelineManager` callbacks. The provider owns programs, assets, and
|
||||
parameters; the Universal Renderer owns when and where they execute.
|
||||
Provider volume programs render through both Game and SceneView cameras. Each
|
||||
camera owns separate raymarch and temporal-history targets, so editor preview
|
||||
cannot resize or contaminate the playable camera's history. Presentation-only
|
||||
exposure remains bound to the leased Game camera.
|
||||
|
||||
Advertised input bindings are performed from the provider's semantic action
|
||||
catalog. Direct and chord gestures submit once per press edge; held values
|
||||
|
|
|
|||
|
|
@ -52,8 +52,11 @@ namespace GameCult.Eve.UnityScene
|
|||
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
|
||||
{
|
||||
var camera = renderingData.cameraData.camera;
|
||||
if (camera == null || renderingData.cameraData.cameraType != CameraType.Game) return;
|
||||
if (camera == null || !SupportsCamera(renderingData.cameraData.cameraType)) return;
|
||||
EveUnityRenderPassRegistry.Enqueue(camera, renderer);
|
||||
}
|
||||
|
||||
internal static bool SupportsCamera(CameraType cameraType) =>
|
||||
cameraType == CameraType.Game || cameraType == CameraType.SceneView;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,8 @@ namespace GameCult.Eve.UnityScene.Fields
|
|||
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;
|
||||
private Matrix4x4 _previousViewProjection;
|
||||
private Matrix4x4 _previousView;
|
||||
private readonly Dictionary<int, CameraRenderState> _cameraRenderStates =
|
||||
new Dictionary<int, CameraRenderState>();
|
||||
private EveUnityFieldsVolumePass? _renderPass;
|
||||
private string _activeNodeId = "";
|
||||
private long _rasterizedFrameId = -1;
|
||||
|
|
@ -118,13 +115,16 @@ namespace GameCult.Eve.UnityScene.Fields
|
|||
bool IEveUnityRenderPassSource.TryEnqueuePass(Camera camera, ScriptableRenderer renderer)
|
||||
{
|
||||
if (_host == null || _document == null || camera == null ||
|
||||
_host.ActiveCameraTransform != camera.transform)
|
||||
!CanRenderCamera(_host, camera))
|
||||
return false;
|
||||
_renderPass ??= new EveUnityFieldsVolumePass(this);
|
||||
renderer.EnqueuePass(_renderPass);
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static bool CanRenderCamera(EveUnityPlayableWorldClientHost host, Camera camera) =>
|
||||
camera.cameraType == CameraType.SceneView || host.ActiveCameraTransform == camera.transform;
|
||||
|
||||
private void RenderVolume(
|
||||
UnsafeCommandBuffer commands,
|
||||
Camera camera,
|
||||
|
|
@ -132,14 +132,15 @@ namespace GameCult.Eve.UnityScene.Fields
|
|||
TextureHandle depthTarget)
|
||||
{
|
||||
if (_host == null || _document == null || camera == null ||
|
||||
_host.ActiveCameraTransform != camera.transform)
|
||||
!CanRenderCamera(_host, camera))
|
||||
return;
|
||||
var field = ActiveField();
|
||||
if (field == null || !TryRenderLayers(_document, camera, out _)) return;
|
||||
camera.depthTextureMode |= DepthTextureMode.Depth;
|
||||
EnsureVolumeTextures(camera, field);
|
||||
if (_raymarchTexture == null || !ApplyViewportTextureScaleBindings(field, camera)) return;
|
||||
ApplyQuality(field, _historyTextureIndex < 0);
|
||||
var state = CameraState(camera);
|
||||
EnsureVolumeTextures(camera, field, state);
|
||||
if (state.RaymarchTexture == null || !ApplyViewportTextureScaleBindings(field, camera)) return;
|
||||
ApplyQuality(field, state.HistoryTextureIndex < 0);
|
||||
|
||||
var gpuProjection = GL.GetGPUProjectionMatrix(camera.projectionMatrix, true);
|
||||
var nonRenderTargetProjection = GL.GetGPUProjectionMatrix(camera.projectionMatrix, false);
|
||||
|
|
@ -154,33 +155,33 @@ namespace GameCult.Eve.UnityScene.Fields
|
|||
var temporalPass = ProgramPass("temporal");
|
||||
var useTemporalHistory = temporalPass >= 0;
|
||||
var historyWriteIndex = -1;
|
||||
RenderTexture finalCloudTexture = _raymarchTexture;
|
||||
RenderTexture finalCloudTexture = state.RaymarchTexture;
|
||||
|
||||
if (useTemporalHistory)
|
||||
{
|
||||
historyWriteIndex = _historyTextureIndex < 0 ? 0 : (_historyTextureIndex + 1) % _historyTextures.Length;
|
||||
var historyReadTexture = _historyTextureIndex < 0
|
||||
? _raymarchTexture
|
||||
: _historyTextures[_historyTextureIndex];
|
||||
finalCloudTexture = _historyTextures[historyWriteIndex]!;
|
||||
SetTexturePort("currentSample", _raymarchTexture);
|
||||
historyWriteIndex = state.HistoryTextureIndex < 0 ? 0 : (state.HistoryTextureIndex + 1) % state.HistoryTextures.Length;
|
||||
var historyReadTexture = state.HistoryTextureIndex < 0
|
||||
? state.RaymarchTexture
|
||||
: state.HistoryTextures[state.HistoryTextureIndex];
|
||||
finalCloudTexture = state.HistoryTextures[historyWriteIndex]!;
|
||||
SetTexturePort("currentSample", state.RaymarchTexture);
|
||||
SetTexturePort("history", historyReadTexture!);
|
||||
SetMatrixPort(
|
||||
"previousViewProjection",
|
||||
_historyTextureIndex < 0
|
||||
state.HistoryTextureIndex < 0
|
||||
? viewProjection
|
||||
: ResolvePreviousViewProjection(
|
||||
_programMetadata,
|
||||
_previousViewProjection,
|
||||
state.PreviousViewProjection,
|
||||
gpuProjection,
|
||||
nonRenderTargetProjection,
|
||||
_previousView));
|
||||
SetFloatPort("resetHistory", _historyTextureIndex < 0 ? 1f : 0f);
|
||||
state.PreviousView));
|
||||
SetFloatPort("resetHistory", state.HistoryTextureIndex < 0 ? 1f : 0f);
|
||||
}
|
||||
SetTexturePort("cloud", finalCloudTexture);
|
||||
|
||||
commands.SetRenderTarget(_raymarchTexture);
|
||||
commands.SetViewport(new Rect(0f, 0f, _raymarchTexture.width, _raymarchTexture.height));
|
||||
commands.SetRenderTarget(state.RaymarchTexture);
|
||||
commands.SetViewport(new Rect(0f, 0f, state.RaymarchTexture.width, state.RaymarchTexture.height));
|
||||
commands.ClearRenderTarget(false, true, Color.clear);
|
||||
commands.DrawProcedural(Matrix4x4.identity, _material!, raymarchPass, MeshTopology.Triangles, 3, 1);
|
||||
if (useTemporalHistory)
|
||||
|
|
@ -198,9 +199,9 @@ namespace GameCult.Eve.UnityScene.Fields
|
|||
commands.DrawProcedural(Matrix4x4.identity, _material!, compositePass, MeshTopology.Triangles, 3, 1);
|
||||
if (useTemporalHistory)
|
||||
{
|
||||
_historyTextureIndex = historyWriteIndex;
|
||||
_previousViewProjection = viewProjection;
|
||||
_previousView = camera.worldToCameraMatrix;
|
||||
state.HistoryTextureIndex = historyWriteIndex;
|
||||
state.PreviousViewProjection = viewProjection;
|
||||
state.PreviousView = camera.worldToCameraMatrix;
|
||||
}
|
||||
CompositeCount++;
|
||||
}
|
||||
|
|
@ -406,31 +407,51 @@ namespace GameCult.Eve.UnityScene.Fields
|
|||
if (_layers == null) _layers = gameObject.AddComponent<EveFieldsSplatLayerRenderer>();
|
||||
}
|
||||
|
||||
private void EnsureVolumeTextures(Camera camera, EveUnityFieldVolumeProjection field)
|
||||
private CameraRenderState CameraState(Camera camera)
|
||||
{
|
||||
var cameraId = camera.GetInstanceID();
|
||||
if (_cameraRenderStates.TryGetValue(cameraId, out var state)) return state;
|
||||
state = new CameraRenderState();
|
||||
_cameraRenderStates.Add(cameraId, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
private void EnsureVolumeTextures(
|
||||
Camera camera,
|
||||
EveUnityFieldVolumeProjection field,
|
||||
CameraRenderState state)
|
||||
{
|
||||
var downsample = Mathf.Clamp(NonNegativeInt(field, "downsample", 1), 0, 3);
|
||||
var width = Mathf.Max(1, camera.pixelWidth >> downsample);
|
||||
var height = Mathf.Max(1, camera.pixelHeight >> downsample);
|
||||
var resetHistory = EnsureRenderTexture(ref _raymarchTexture, width, height, "Eve Fields Volume Raymarch");
|
||||
var resetHistory = EnsureRenderTexture(
|
||||
ref state.RaymarchTexture,
|
||||
width,
|
||||
height,
|
||||
$"Eve Fields Volume Raymarch {camera.GetInstanceID()}");
|
||||
if (HasTemporalProgram())
|
||||
{
|
||||
resetHistory |= EnsureRenderTexture(ref _historyTextures[0], width, height, "Eve Fields Volume History A");
|
||||
resetHistory |= EnsureRenderTexture(ref _historyTextures[1], width, height, "Eve Fields Volume History B");
|
||||
resetHistory |= EnsureRenderTexture(ref state.HistoryTextures[0], width, height, "Eve Fields Volume History A");
|
||||
resetHistory |= EnsureRenderTexture(ref state.HistoryTextures[1], width, height, "Eve Fields Volume History B");
|
||||
}
|
||||
else
|
||||
{
|
||||
ReleaseRenderTexture(ref _historyTextures[0]);
|
||||
ReleaseRenderTexture(ref _historyTextures[1]);
|
||||
ReleaseRenderTexture(ref state.HistoryTextures[0]);
|
||||
ReleaseRenderTexture(ref state.HistoryTextures[1]);
|
||||
resetHistory = true;
|
||||
}
|
||||
if (resetHistory) ResetTemporalHistory();
|
||||
if (resetHistory) ResetTemporalHistory(state);
|
||||
}
|
||||
|
||||
private void ReleaseRenderState()
|
||||
{
|
||||
ReleaseRenderTexture(ref _raymarchTexture);
|
||||
ReleaseRenderTexture(ref _historyTextures[0]);
|
||||
ReleaseRenderTexture(ref _historyTextures[1]);
|
||||
foreach (var state in _cameraRenderStates.Values)
|
||||
{
|
||||
ReleaseRenderTexture(ref state.RaymarchTexture);
|
||||
ReleaseRenderTexture(ref state.HistoryTextures[0]);
|
||||
ReleaseRenderTexture(ref state.HistoryTextures[1]);
|
||||
}
|
||||
_cameraRenderStates.Clear();
|
||||
if (_material != null) { Destroy(_material); _material = null; }
|
||||
_sourceShader = null;
|
||||
_programMetadata = null;
|
||||
|
|
@ -467,7 +488,7 @@ namespace GameCult.Eve.UnityScene.Fields
|
|||
{
|
||||
var cameraData = frameData.Get<UniversalCameraData>();
|
||||
if (cameraData.camera == null || _owner._host == null ||
|
||||
_owner._host.ActiveCameraTransform != cameraData.camera.transform)
|
||||
!CanRenderCamera(_owner._host, cameraData.camera))
|
||||
return;
|
||||
|
||||
var resourceData = frameData.Get<UniversalResourceData>();
|
||||
|
|
@ -491,9 +512,23 @@ namespace GameCult.Eve.UnityScene.Fields
|
|||
|
||||
private void ResetTemporalHistory()
|
||||
{
|
||||
_historyTextureIndex = -1;
|
||||
_previousViewProjection = Matrix4x4.identity;
|
||||
_previousView = Matrix4x4.identity;
|
||||
foreach (var state in _cameraRenderStates.Values) ResetTemporalHistory(state);
|
||||
}
|
||||
|
||||
private static void ResetTemporalHistory(CameraRenderState state)
|
||||
{
|
||||
state.HistoryTextureIndex = -1;
|
||||
state.PreviousViewProjection = Matrix4x4.identity;
|
||||
state.PreviousView = Matrix4x4.identity;
|
||||
}
|
||||
|
||||
private sealed class CameraRenderState
|
||||
{
|
||||
internal RenderTexture? RaymarchTexture;
|
||||
internal readonly RenderTexture?[] HistoryTextures = new RenderTexture?[2];
|
||||
internal int HistoryTextureIndex = -1;
|
||||
internal Matrix4x4 PreviousViewProjection = Matrix4x4.identity;
|
||||
internal Matrix4x4 PreviousView = Matrix4x4.identity;
|
||||
}
|
||||
|
||||
public static Matrix4x4 ResolvePreviousViewProjection(
|
||||
|
|
|
|||
|
|
@ -159,6 +159,13 @@ namespace GameCult.Eve.UnityScene.Tests
|
|||
public void UrpRendererFeatureOwnsGenericWorldEffectScheduling()
|
||||
{
|
||||
Assert.That(typeof(EveUnityRendererFeature).IsSubclassOf(typeof(ScriptableRendererFeature)), Is.True);
|
||||
var supportsCamera = typeof(EveUnityRendererFeature).GetMethod(
|
||||
"SupportsCamera",
|
||||
BindingFlags.NonPublic | BindingFlags.Static);
|
||||
Assert.That(supportsCamera, Is.Not.Null);
|
||||
Assert.That(supportsCamera!.Invoke(null, new object[] { CameraType.Game }), Is.True);
|
||||
Assert.That(supportsCamera.Invoke(null, new object[] { CameraType.SceneView }), Is.True);
|
||||
Assert.That(supportsCamera.Invoke(null, new object[] { CameraType.Preview }), Is.False);
|
||||
AssertRenderOrder(typeof(EveUnityFieldsVolumeRenderer), 100);
|
||||
AssertRenderOrder(typeof(EveUnityFieldsParticleRenderer), 200);
|
||||
AssertRenderOrder(typeof(EveUnityAdaptiveExposureRenderer), 300);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "org.gamecult.eve.unity-scene",
|
||||
"displayName": "Eve Unity Scene Lowering",
|
||||
"version": "0.3.66",
|
||||
"version": "0.3.67",
|
||||
"unity": "6000.0",
|
||||
"description": "Provider-agnostic Unity scene shell for gamecult.eve.surface.v1 interactive world surfaces.",
|
||||
"dependencies": {
|
||||
|
|
|
|||
Reference in a new issue