Files
2026-07-13 13:13:17 +08:00

141 lines
5.1 KiB
C#

using T3.Core.Animation;
using T3.Core.Rendering;
using T3.Core.Utils;
namespace Lib.render.camera;
[Guid("dfd4c912-4c4f-44b1-88aa-f27aa66b57af")]
internal sealed class ActionCamera : Instance<ActionCamera>, ICamera, ICameraPropertiesProvider
{
[Output(Guid = "66784a52-d003-4c7d-b3cf-bdca4acb041e")]
public readonly Slot<object> Reference = new();
public ActionCamera()
{
Reference.UpdateAction += UpdateCameraDefinition;
Reference.Value = this;
}
private void UpdateCameraDefinition(EvaluationContext context)
{
var time = Playback.RunTimeInSecs;
var deltaTime = (float)(time - _lastUpdateTime);
_lastUpdateTime = time;
LastObjectToWorld = context.ObjectToWorld;
if (!ReferenceCamera.HasInputConnections)
{
Log.Warning("Missing reference camera", this);
return;
}
var referenceCam = ReferenceCamera.GetValue(context) as ICamera;
if (referenceCam == null)
{
Log.Warning("Connected op is not a camera", this);
return;
}
var speed = Speed.GetValue(context);
var rotationSpeed = RotationSpeed.GetValue(context);
var reset = MathUtils.WasTriggered(TriggerReset.GetValue(context), ref _triggerReset);
var blend = BlendToReferenceCamera.GetValue(context) * deltaTime * 60;
if (reset || !_initialized)
{
TriggerReset.SetTypedInputValue(false);
_initialized = true;
blend = 1;
}
_cameraDefinition = CameraDefinition.Blend(_cameraDefinition, referenceCam.CameraDefinition, blend.Clamp(0, 1));
var forward = Forward.GetValue(context);
var sideways = Sideways.GetValue(context);
var upDown = UpDown.GetValue(context);
var yaw = Yaw.GetValue(context);
var pitch = Pitch.GetValue(context);
var roll = Roll.GetValue(context);
var fov = FOV.GetValue(context);
var viewVector = _cameraDefinition.Target - _cameraDefinition.Position;
var viewDirection = Vector3.Normalize(viewVector);
var rotYMatrix = Matrix4x4.CreateRotationY(-yaw * rotationSpeed * deltaTime);
var newViewDirection = Vector3.TransformNormal(viewDirection, rotYMatrix);
var side = Vector3.Cross(Vector3.UnitY, newViewDirection);
var rotXMatrix = Matrix4x4.CreateFromAxisAngle(side, pitch * rotationSpeed * deltaTime);
newViewDirection = Vector3.TransformNormal(newViewDirection, rotXMatrix);
_cameraDefinition.Position += viewDirection * forward * speed * deltaTime;
_cameraDefinition.Position += side * sideways * speed * deltaTime;
_cameraDefinition.Position += Vector3.UnitY * upDown * speed * deltaTime;
_cameraDefinition.Target = _cameraDefinition.Position + newViewDirection;
_cameraDefinition.Roll += roll * speed * deltaTime;
_cameraDefinition.FieldOfView += fov * deltaTime;
_cameraDefinition.BuildProjectionMatrices(out var camToClipSpace, out var worldToCamera);
CameraToClipSpace = camToClipSpace;
WorldToCamera = worldToCamera;
}
private bool _triggerReset;
private double _lastUpdateTime;
private bool _initialized;
private CameraDefinition _cameraDefinition = new CameraDefinition();
#region implement ICamera
public CameraDefinition CameraDefinition => _cameraDefinition;
public Matrix4x4 CameraToClipSpace { get; set; }
public Matrix4x4 WorldToCamera { get; set; }
public Matrix4x4 LastObjectToWorld { get; set; }
public Vector3 CameraPosition { get => _cameraDefinition.Position; set { } }
public Vector3 CameraTarget { get => _cameraDefinition.Target; set { } }
public float CameraRoll { get => _cameraDefinition.Roll; set { } }
#endregion
[Input(Guid = "D46EE53D-887B-4E37-B5BA-4EE0BA50C711")]
public readonly InputSlot<object> ReferenceCamera = new();
[Input(Guid = "3857258A-CA2D-4DAD-B926-28530E8A25B0")]
public readonly InputSlot<float> BlendToReferenceCamera = new();
[Input(Guid = "8AC6C739-3741-4816-8BAD-57BD2A226E02")]
public readonly InputSlot<bool> TriggerReset = new();
[Input(Guid = "44ED03FC-3551-4519-8B4C-DFDC1DDD1713")]
public readonly InputSlot<float> Speed = new();
[Input(Guid = "A93AA4AC-487C-4441-B501-742CD38A5F5E")]
public readonly InputSlot<float> Forward = new();
[Input(Guid = "C5DADDD7-A832-40D1-AEC3-3886803A3899")]
public readonly InputSlot<float> Sideways = new();
[Input(Guid = "37BBAF47-5985-42D7-801E-0BF099036D5F")]
public readonly InputSlot<float> UpDown = new();
[Input(Guid = "B117D2DC-EB4C-408E-9AB7-909D17AC3069")]
public readonly InputSlot<float> RotationSpeed = new();
[Input(Guid = "773F0B8F-16D4-4302-B26D-43CF4D4ADCE8")]
public readonly InputSlot<float> Yaw = new();
[Input(Guid = "832CD0D8-66BE-4F45-9AEA-6E439BE5A285")]
public readonly InputSlot<float> Pitch = new();
[Input(Guid = "C529AF20-2E52-4A29-B558-CD518BDC539D")]
public readonly InputSlot<float> Roll = new();
[Input(Guid = "CB55671F-A20D-42A3-B19C-7C8EE5D7F865")]
public readonly InputSlot<float> FOV = new();
}