mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-08-01 16:28:36 -04:00
* Remove DDGI border, just get the accurate direction * Try to use BC6H in place of RG16F for Indirect Light Volume depth now, we're using softer depth so we can take advantage of it no problem like Overwatch does. * softer DDGI depth integration * Blend DDGI borders nicely and simply, instead of wrapping a 6x6 probe * Update shaders * update terrain shader from rebase
105 lines
2.6 KiB
C#
105 lines
2.6 KiB
C#
namespace Sandbox;
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
/// <summary>
|
|
/// Maintains GPU data for all <see cref="IndirectLightVolume"/> instances in a scene.
|
|
/// Collects, sorts, and uploads volume parameters to the renderer.
|
|
/// </summary>
|
|
|
|
sealed class DDGIVolumeSystem : GameObjectSystem<DDGIVolumeSystem>
|
|
{
|
|
private GpuBuffer<IndirectLightVolume.DDGIVolumeGpuData> GpuBuffer;
|
|
private bool _dirty = true;
|
|
|
|
public DDGIVolumeSystem( Scene scene ) : base( scene )
|
|
{
|
|
Listen( Stage.FinishUpdate, 0, UpdateVolumes, "UpdateDDGIVolumes" );
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
ReleaseBuffer();
|
|
|
|
Scene?.RenderAttributes?.Set( "DDGI_VolumeCount", 0 );
|
|
Scene?.RenderAttributes?.Set( "DDGI_Volumes", (GpuBuffer)null );
|
|
|
|
base.Dispose();
|
|
}
|
|
|
|
internal void MarkDirty()
|
|
{
|
|
_dirty = true;
|
|
}
|
|
|
|
private void UpdateVolumes()
|
|
{
|
|
using var _ = PerformanceStats.Timings.Render.Scope();
|
|
|
|
if ( Application.IsHeadless )
|
|
return;
|
|
|
|
if ( Scene?.RenderAttributes is null )
|
|
return;
|
|
|
|
// Mark textures as used every frame, so the streaming system keeps
|
|
// them resident while the volumes are active.
|
|
foreach ( var volume in Scene.GetAll<IndirectLightVolume>().Where( v => v is { Active: true, Enabled: true } ) )
|
|
{
|
|
volume.IrradianceTexture?.MarkUsed();
|
|
volume.DistanceTexture?.MarkUsed();
|
|
volume.RelocationTexture?.MarkUsed();
|
|
}
|
|
|
|
if ( !_dirty )
|
|
return;
|
|
|
|
_dirty = false;
|
|
|
|
var orderedVolumes = Scene
|
|
.GetAll<IndirectLightVolume>()
|
|
.Where( volume => volume is { Active: true } )
|
|
.OrderBy( volume => volume.Bounds.Volume );
|
|
|
|
var volumeData = new List<IndirectLightVolume.DDGIVolumeGpuData>();
|
|
foreach ( var volume in orderedVolumes )
|
|
{
|
|
if ( volume.Enabled && volume.BuildData( out var data ) )
|
|
{
|
|
volumeData.Add( data );
|
|
}
|
|
}
|
|
|
|
if ( volumeData.Count > 0 )
|
|
{
|
|
EnsureBufferCapacity( volumeData.Count );
|
|
GpuBuffer.SetData( volumeData );
|
|
Scene.RenderAttributes.Set( "DDGI_VolumeCount", volumeData.Count );
|
|
Scene.RenderAttributes.Set( "DDGI_Volumes", GpuBuffer );
|
|
return;
|
|
}
|
|
|
|
// No valid volumes: clear renderer attributes to avoid stale data.
|
|
ReleaseBuffer();
|
|
Scene.RenderAttributes.Set( "DDGI_VolumeCount", 0 );
|
|
Scene.RenderAttributes.Set( "DDGI_Volumes", (GpuBuffer)null );
|
|
}
|
|
|
|
private void EnsureBufferCapacity( int count )
|
|
{
|
|
if ( GpuBuffer is not null && GpuBuffer.ElementCount >= count )
|
|
return;
|
|
|
|
ReleaseBuffer();
|
|
GpuBuffer = new GpuBuffer<IndirectLightVolume.DDGIVolumeGpuData>( Math.Max( count, 1 ), debugName: "DDGI_Volumes" );
|
|
}
|
|
|
|
private void ReleaseBuffer()
|
|
{
|
|
GpuBuffer?.Dispose();
|
|
GpuBuffer = null;
|
|
}
|
|
}
|