Files
2026-10-24 11:04:41 +02:00

33 lines
2.1 KiB
C#

using System.Numerics;
namespace SoberEsp;
public record CameraContext(int Pid,ulong Base,ulong Workspace,ulong Camera);
public static class CameraAim
{
// Engine storage is row-major, with right/up/back in columns. Numerics uses
// row vectors, so transpose the basis for quaternion interpolation.
public static float[] Rotation(float[] frame,Vector3 target,float response)
{
if(frame.Length!=Offsets.Camera.FrameFloats||frame.Any(f=>!float.IsFinite(f))||
!float.IsFinite(target.X)||!float.IsFinite(target.Y)||!float.IsFinite(target.Z)||
!float.IsFinite(response)||response<0||response>1)throw new IOException("Invalid camera aim input");
var right=new Vector3(frame[0],frame[3],frame[6]);
var up=new Vector3(frame[1],frame[4],frame[7]);
var back=new Vector3(frame[2],frame[5],frame[8]);
if(Math.Abs(right.LengthSquared()-1)>.02f||Math.Abs(up.LengthSquared()-1)>.02f||Math.Abs(back.LengthSquared()-1)>.02f||
Math.Abs(Vector3.Dot(right,up))>.02f||Math.Abs(Vector3.Dot(right,back))>.02f||Math.Abs(Vector3.Dot(up,back))>.02f||
Vector3.Dot(Vector3.Cross(right,up),back)<.98f)throw new IOException("Camera basis is not a valid rotation");
var delta=new Vector3(frame[9],frame[10],frame[11])-target;
if(delta.LengthSquared()<.0001f)throw new IOException("Target is at the camera position");
var wantedBack=Vector3.Normalize(delta);var wantedRight=Vector3.Cross(Vector3.UnitY,wantedBack);
if(wantedRight.LengthSquared()<.0001f)wantedRight=right-wantedBack*Vector3.Dot(right,wantedBack);
if(wantedRight.LengthSquared()<.0001f)wantedRight=Vector3.Cross(Vector3.UnitZ,wantedBack);
wantedRight=Vector3.Normalize(wantedRight);var wantedUp=Vector3.Normalize(Vector3.Cross(wantedBack,wantedRight));
static Quaternion Q(Vector3 r,Vector3 u,Vector3 b)=>Quaternion.Normalize(Quaternion.CreateFromRotationMatrix(
new Matrix4x4(r.X,r.Y,r.Z,0,u.X,u.Y,u.Z,0,b.X,b.Y,b.Z,0,0,0,0,1)));
var rotation=Matrix4x4.CreateFromQuaternion(Quaternion.Slerp(Q(right,up,back),Q(wantedRight,wantedUp,wantedBack),response));
return [rotation.M11,rotation.M21,rotation.M31,rotation.M12,rotation.M22,rotation.M32,rotation.M13,rotation.M23,rotation.M33];
}
}