443 lines
9.3 KiB
C#
443 lines
9.3 KiB
C#
|
|
using System.Diagnostics;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System;
|
|
using Godot;
|
|
using System.Linq;
|
|
|
|
|
|
namespace Rokojori
|
|
{
|
|
[Tool]
|
|
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/VirtualCameraManager.svg") ]
|
|
public partial class VirtualCamera3DManager:NetworkNode
|
|
{
|
|
[Export]
|
|
public Camera3D camera;
|
|
|
|
[Export]
|
|
public WorldEnvironment worldEnvironment;
|
|
|
|
[Export]
|
|
public bool refreshSlots = false;
|
|
|
|
[Export]
|
|
public bool active = false;
|
|
|
|
[Export]
|
|
public bool postProcess = false;
|
|
|
|
[Export]
|
|
public PostProcessVolume[] postProcessVolumes = [];
|
|
|
|
public static VirtualCamera3DManager Get()
|
|
{
|
|
return Unique<VirtualCamera3DManager>.Get();
|
|
}
|
|
|
|
public VirtualCamera3DSlot activeSlot
|
|
{
|
|
get
|
|
{
|
|
return Lists.GetWithHighestValue( _cameraSlots, c => c.priority );
|
|
}
|
|
}
|
|
|
|
[ExportGroup("Read Only" )]
|
|
[Export]
|
|
public bool lerpingCameras;
|
|
[Export]
|
|
public bool lerpingPostProcessing;
|
|
|
|
bool _lerpingCameras = false;
|
|
const int minimalLerpFrames = 100;
|
|
int _cameraLerpCounter = 0;
|
|
int _postProcessLerpCounter = 0;
|
|
|
|
|
|
bool _lerpingPostProcessVolumes = false;
|
|
|
|
|
|
public void StartLerping()
|
|
{
|
|
_lerpingCameras = true;
|
|
lerpingCameras = _lerpingCameras;
|
|
_cameraLerpCounter = minimalLerpFrames;
|
|
|
|
this.LogInfo( "Started Lerping" );
|
|
}
|
|
|
|
List<float> prios = new List<float>();
|
|
public override void _Process( double delta )
|
|
{
|
|
if ( ! active )
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
ProcessCameras( delta );
|
|
ProcessPostProcess( delta );
|
|
|
|
|
|
}
|
|
|
|
|
|
PostProcessEffectProcessor<GlowEffect> glowEffectProcessor = new PostProcessEffectProcessor<GlowEffect>();
|
|
PostProcessEffectProcessor<FogEffect> fogEffectProcessor = new PostProcessEffectProcessor<FogEffect>();
|
|
PostProcessEffectProcessor<_XX_DepthOfFieldEffect> depthOfFieldProcessor = new PostProcessEffectProcessor<_XX_DepthOfFieldEffect>();
|
|
|
|
void SetAllPostProcessors()
|
|
{
|
|
_allPostProcessors =new List<IPostProcessEffectProcessor>()
|
|
{
|
|
glowEffectProcessor,
|
|
fogEffectProcessor,
|
|
depthOfFieldProcessor
|
|
};
|
|
}
|
|
|
|
List<IPostProcessEffectProcessor> _allPostProcessors;
|
|
|
|
bool updatePostEffectStack = true;
|
|
|
|
[Export]
|
|
public bool postStackUpdate = false;
|
|
|
|
void ProcessPostProcess( double delta )
|
|
{
|
|
if ( ! postProcess || postProcessVolumes == null )
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
postProcessVolumes.ForEach(
|
|
v =>
|
|
{
|
|
if ( v == null )
|
|
{ return; }
|
|
|
|
v.UpdateEffects( this );
|
|
}
|
|
);
|
|
|
|
if ( postStackUpdate )
|
|
{
|
|
updatePostEffectStack =true;
|
|
postStackUpdate = false;
|
|
}
|
|
|
|
UpdatePostEffectStack();
|
|
|
|
|
|
|
|
_allPostProcessors.ForEach( p => p.Apply( worldEnvironment ) );
|
|
|
|
}
|
|
|
|
int _postEffectsSize = -1;
|
|
|
|
|
|
|
|
void UpdatePostEffectStack()
|
|
{
|
|
if ( _allPostProcessors == null || _allPostProcessors.Count == 0 )
|
|
{
|
|
SetAllPostProcessors();
|
|
}
|
|
|
|
if ( _postEffectsSize != postProcessVolumes.Length )
|
|
{
|
|
updatePostEffectStack = true;
|
|
}
|
|
|
|
if ( ! updatePostEffectStack )
|
|
{
|
|
return;
|
|
}
|
|
|
|
_postEffectsSize = postProcessVolumes.Length;
|
|
|
|
_allPostProcessors.ForEach( p => p.ClearForStackUpdate() );
|
|
|
|
postProcessVolumes.ForEach(
|
|
volume =>
|
|
{
|
|
var allEffects = volume.effects.ToList();
|
|
|
|
_allPostProcessors.ForEach( p => p.OnVolumeUpdate( volume, allEffects ) );
|
|
}
|
|
);
|
|
}
|
|
|
|
void ProcessCameras( double delta )
|
|
{
|
|
if ( ! _lerpingCameras )
|
|
{
|
|
RefreshSlots();
|
|
|
|
var cam = activeSlot;
|
|
|
|
if ( camera == null || cam == null || cam.camera == null )
|
|
{
|
|
return;
|
|
}
|
|
|
|
SetSingleCamera( cam );
|
|
|
|
}
|
|
else
|
|
{
|
|
LerpCameras( delta );
|
|
}
|
|
}
|
|
|
|
void SetSingleCamera( VirtualCamera3DSlot c )
|
|
{
|
|
var rotation = c.GetCameraRotation();
|
|
|
|
if ( ! rotation.IsFinite() || rotation.Length() == 0 )
|
|
{
|
|
rotation = new Quaternion();
|
|
rotation.X = 0;
|
|
rotation.Y = 0;
|
|
rotation.Z = 0;
|
|
rotation.W = 1;
|
|
rotation = rotation.Normalized();
|
|
}
|
|
|
|
|
|
var vUp = rotation * Vector3.Up;
|
|
var vForward = rotation * Vector3.Forward;
|
|
|
|
var position = c.GetCameraPosition();
|
|
var up = vUp;
|
|
var forward = vForward;
|
|
var fov = c.GetCameraFOV();
|
|
|
|
if ( forward.LengthSquared() == 0 )
|
|
{
|
|
forward = camera.Basis.Z;
|
|
}
|
|
else
|
|
{
|
|
forward = forward.Normalized();
|
|
}
|
|
|
|
if ( up.LengthSquared() == 0 )
|
|
{
|
|
up = camera.Basis.Y;
|
|
}
|
|
else
|
|
{
|
|
up = up.Normalized();
|
|
}
|
|
|
|
// RJLog.Log( "Set Cam", position );
|
|
|
|
|
|
|
|
camera.GlobalPosition = position;
|
|
camera.LookAt( position - forward, up );
|
|
camera.Fov = fov;
|
|
}
|
|
|
|
|
|
[Export]
|
|
public float CameraPrioritySmoothingCoefficient = 0.1f;
|
|
|
|
[Export]
|
|
public float CameraPrioritySmoothingStepFPS = 120;
|
|
|
|
public float smoothStepDelta => 1f / CameraPrioritySmoothingStepFPS;
|
|
public float safeSmoothing => Mathf.Max( 0, CameraPrioritySmoothingCoefficient );
|
|
|
|
List<VirtualCamera3DSlot> _cameraSlots = new List<VirtualCamera3DSlot>();
|
|
|
|
public VirtualCamera3DSlot GetSlot( int index )
|
|
{
|
|
return _cameraSlots[ index ];
|
|
}
|
|
|
|
public VirtualCamera3DSlot GetSlot( VirtualCamera3D virtualCamera3D )
|
|
{
|
|
return _cameraSlots.Find( s => s.camera == virtualCamera3D );
|
|
}
|
|
|
|
public VirtualCamera3DSlot GetSlot( SelectorFlag[] flags )
|
|
{
|
|
return _cameraSlots.Find( s => Arrays.ContainsAll( s.flags, flags ) );
|
|
}
|
|
|
|
public void SetActiveSlot( VirtualCamera3DSlot slot )
|
|
{
|
|
_cameraSlots.ForEach( c => c.priority = ( c == slot ? 1 : 0 ) );
|
|
StartLerping();
|
|
}
|
|
|
|
public void RefreshSlots( bool forceUpdate = false )
|
|
{
|
|
|
|
var needsUpdate = forceUpdate || refreshSlots || _cameraSlots == null || _cameraSlots.Count == 0;
|
|
|
|
if ( ! needsUpdate )
|
|
{
|
|
return;
|
|
}
|
|
|
|
refreshSlots = false;
|
|
_cameraSlots = Nodes.GetDirectChildren<VirtualCamera3DSlot>( this );
|
|
StartLerping();
|
|
}
|
|
|
|
|
|
|
|
public void RemoveSlot( VirtualCamera3DSlot slot )
|
|
{
|
|
if ( slot == null || slot.GetParent() != this )
|
|
{
|
|
return;
|
|
}
|
|
|
|
Nodes.RemoveAndDelete( slot );
|
|
|
|
RefreshSlots( true );
|
|
}
|
|
|
|
void LerpCameras( double delta )
|
|
{
|
|
RefreshSlots();
|
|
|
|
|
|
var sumPriority = 0f;
|
|
|
|
if ( prios.Count != _cameraSlots.Count )
|
|
{
|
|
prios = _cameraSlots.Map( c => c.smoothedPriority );
|
|
}
|
|
|
|
var numWithNonZero = 0;
|
|
|
|
|
|
_cameraSlots.ForEach(
|
|
c =>
|
|
{
|
|
c.Update( delta, this );
|
|
sumPriority += MathF.Max( 0, c.smoothedPriority );
|
|
|
|
if ( c.smoothedPriority > 0.001f )
|
|
{
|
|
numWithNonZero ++;
|
|
}
|
|
}
|
|
);
|
|
|
|
if ( _cameraLerpCounter > 0 )
|
|
{
|
|
_cameraLerpCounter --;
|
|
}
|
|
|
|
if ( _cameraLerpCounter == 0 && numWithNonZero == 1 )
|
|
{
|
|
_lerpingCameras = false;
|
|
lerpingCameras = _lerpingCameras;
|
|
|
|
// this.LogInfo( "Stopped Lerping" );
|
|
// return;
|
|
}
|
|
|
|
|
|
if ( sumPriority == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
var position = new Vector3();
|
|
var up = new Vector3();
|
|
var forward = new Vector3();
|
|
var fov = 0f;
|
|
|
|
_cameraSlots.ForEach(
|
|
c =>
|
|
{
|
|
var priority = MathF.Max( 0, c.smoothedPriority );
|
|
var rotation = c.GetCameraRotation();
|
|
|
|
if ( ! rotation.IsFinite() || rotation.Length() == 0 )
|
|
{
|
|
rotation = new Quaternion();
|
|
rotation.X = 0;
|
|
rotation.Y = 0;
|
|
rotation.Z = 0;
|
|
rotation.W = 1;
|
|
rotation = rotation.Normalized();
|
|
}
|
|
|
|
|
|
var vUp = rotation * Vector3.Up;
|
|
var vForward = rotation * Vector3.Forward;
|
|
|
|
position += priority * c.GetCameraPosition();
|
|
up += priority * vUp;
|
|
forward += priority * vForward;
|
|
fov += priority * c.GetCameraFOV();
|
|
}
|
|
);
|
|
|
|
position /= sumPriority;
|
|
fov /= sumPriority;
|
|
|
|
if ( forward.LengthSquared() == 0 )
|
|
{
|
|
forward = camera.Basis.Z;
|
|
}
|
|
else
|
|
{
|
|
forward = forward.Normalized();
|
|
}
|
|
|
|
if ( up.LengthSquared() == 0 )
|
|
{
|
|
up = camera.Basis.Y;
|
|
}
|
|
else
|
|
{
|
|
up = up.Normalized();
|
|
}
|
|
|
|
// RJLog.Log( "Set Cam", position );
|
|
|
|
|
|
|
|
camera.GlobalPosition = position;
|
|
camera.LookAt( position - forward, up );
|
|
camera.Fov = fov;
|
|
|
|
}
|
|
|
|
public VirtualCamera3D GetCamera( int index )
|
|
{
|
|
return _cameraSlots[ index ].camera;
|
|
}
|
|
|
|
public int GetCameraIndex( VirtualCamera3D camera3D )
|
|
{
|
|
return _cameraSlots.FindIndex( c => c.camera == camera3D );
|
|
}
|
|
|
|
public float GetCameraPriority( int index )
|
|
{
|
|
return _cameraSlots[ index ].priority;
|
|
}
|
|
|
|
public void SetCameraPriority( int index, float priority )
|
|
{
|
|
_cameraSlots[ index ].priority = priority;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
} |