framegen.cs
· 4.5 KiB · C#
Brut
using System;
using System.Collections.Generic;
using System.Linq;
using Vintagestory.API.MathTools;
using VSClientOptimizer.Config;
using VSClientOptimizer.Math;
using VSClientOptimizer.Interpolation;
namespace VSClientOptimizer.Performance
{
/// <summary>
/// Frame Generation - Creates intermediate frames between real frames for smoother motion
/// Similar to AMD FSR Frame Generation or NVIDIA DLSS 3 Frame Generation
/// </summary>
public class FrameGenerator
{
private Queue<FrameSnapshot> frameHistory = new Queue<FrameSnapshot>();
private const int MaxFrameHistory = 3;
private float generationMultiplier = 2.0f;
private bool useMotionVectors = true;
public class FrameSnapshot
{
public long TimestampMs;
public Dictionary<long, EntityPositionSnapshot> EntityStates;
public FrameSnapshot(long timestamp)
{
TimestampMs = timestamp;
EntityStates = new Dictionary<long, EntityPositionSnapshot>();
}
}
public FrameGenerator(float multiplier, bool useMotion)
{
generationMultiplier = System.Math.Max(1.0f, System.Math.Min(4.0f, multiplier)); // Clamp 1-4x
useMotionVectors = useMotion;
}
public void AddFrame(long timestamp, Dictionary<long, EntityPositionSnapshot> states)
{
var snapshot = new FrameSnapshot(timestamp);
foreach (var kvp in states)
{
snapshot.EntityStates[kvp.Key] = kvp.Value;
}
frameHistory.Enqueue(snapshot);
if (frameHistory.Count > MaxFrameHistory)
frameHistory.Dequeue();
}
public List<FrameSnapshot> GenerateIntermediateFrames()
{
var generatedFrames = new List<FrameSnapshot>();
if (frameHistory.Count < 2 || generationMultiplier <= 1.0f)
return generatedFrames;
var frames = frameHistory.ToArray();
var lastFrame = frames[frames.Length - 2];
var currentFrame = frames[frames.Length - 1];
long timeDiff = currentFrame.TimestampMs - lastFrame.TimestampMs;
if (timeDiff <= 0) return generatedFrames;
// Generate intermediate frames
int intermediateCount = (int)(generationMultiplier - 1);
for (int i = 1; i <= intermediateCount; i++)
{
float t = i / generationMultiplier;
long interpTime = lastFrame.TimestampMs + (long)(timeDiff * t);
var interpFrame = new FrameSnapshot(interpTime);
// Interpolate each entity's state
foreach (var entityId in lastFrame.EntityStates.Keys)
{
if (currentFrame.EntityStates.TryGetValue(entityId, out var currentState) &&
lastFrame.EntityStates.TryGetValue(entityId, out var lastState))
{
var interpState = InterpolateEntityState(lastState, currentState, t);
interpFrame.EntityStates[entityId] = interpState;
}
}
generatedFrames.Add(interpFrame);
}
return generatedFrames;
}
private EntityPositionSnapshot InterpolateEntityState(
EntityPositionSnapshot from,
EntityPositionSnapshot to,
float t)
{
// Position interpolation
Vector3 fromPos = new Vector3(from.Position.X, from.Position.Y, from.Position.Z);
Vector3 toPos = new Vector3(to.Position.X, to.Position.Y, to.Position.Z);
Vector3 interpPos;
if (useMotionVectors && (from.Velocity.X != 0 || from.Velocity.Y != 0 || from.Velocity.Z != 0))
{
// Use motion vectors for smoother interpolation
double deltaTime = (to.TimestampMs - from.TimestampMs) / 1000.0;
Vector3 motionPredicted = fromPos + (from.Velocity * (deltaTime * t));
interpPos = Vector3.Lerp(Vector3.Lerp(fromPos, toPos, t), motionPredicted, 0.3f);
}
else
{
interpPos = Vector3.Lerp(fromPos, toPos, t);
}
// Rotation interpolation
Rotation3 fromRot = new Rotation3(from.Rotation.X, from.Rotation.Y, from.Rotation.Z);
Rotation3 toRot = new Rotation3(to.Rotation.X, to.Rotation.Y, to.Rotation.Z);
Rotation3 interpRot = Rotation3.Lerp(fromRot, toRot, t);
// Velocity interpolation
Vector3 interpVel = Vector3.Lerp(from.Velocity, to.Velocity, t);
long interpTime = from.TimestampMs + (long)((to.TimestampMs - from.TimestampMs) * t);
return new EntityPositionSnapshot(
new Vec3d(interpPos.X, interpPos.Y, interpPos.Z),
new Vec3f(interpRot.Pitch, interpRot.Yaw, interpRot.Roll),
interpTime,
interpVel
);
}
}
}
| 1 | using System; |
| 2 | using System.Collections.Generic; |
| 3 | using System.Linq; |
| 4 | using Vintagestory.API.MathTools; |
| 5 | using VSClientOptimizer.Config; |
| 6 | using VSClientOptimizer.Math; |
| 7 | using VSClientOptimizer.Interpolation; |
| 8 | |
| 9 | namespace VSClientOptimizer.Performance |
| 10 | { |
| 11 | /// <summary> |
| 12 | /// Frame Generation - Creates intermediate frames between real frames for smoother motion |
| 13 | /// Similar to AMD FSR Frame Generation or NVIDIA DLSS 3 Frame Generation |
| 14 | /// </summary> |
| 15 | public class FrameGenerator |
| 16 | { |
| 17 | private Queue<FrameSnapshot> frameHistory = new Queue<FrameSnapshot>(); |
| 18 | private const int MaxFrameHistory = 3; |
| 19 | private float generationMultiplier = 2.0f; |
| 20 | private bool useMotionVectors = true; |
| 21 | |
| 22 | public class FrameSnapshot |
| 23 | { |
| 24 | public long TimestampMs; |
| 25 | public Dictionary<long, EntityPositionSnapshot> EntityStates; |
| 26 | |
| 27 | public FrameSnapshot(long timestamp) |
| 28 | { |
| 29 | TimestampMs = timestamp; |
| 30 | EntityStates = new Dictionary<long, EntityPositionSnapshot>(); |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | public FrameGenerator(float multiplier, bool useMotion) |
| 35 | { |
| 36 | generationMultiplier = System.Math.Max(1.0f, System.Math.Min(4.0f, multiplier)); // Clamp 1-4x |
| 37 | useMotionVectors = useMotion; |
| 38 | } |
| 39 | |
| 40 | public void AddFrame(long timestamp, Dictionary<long, EntityPositionSnapshot> states) |
| 41 | { |
| 42 | var snapshot = new FrameSnapshot(timestamp); |
| 43 | foreach (var kvp in states) |
| 44 | { |
| 45 | snapshot.EntityStates[kvp.Key] = kvp.Value; |
| 46 | } |
| 47 | |
| 48 | frameHistory.Enqueue(snapshot); |
| 49 | if (frameHistory.Count > MaxFrameHistory) |
| 50 | frameHistory.Dequeue(); |
| 51 | } |
| 52 | |
| 53 | public List<FrameSnapshot> GenerateIntermediateFrames() |
| 54 | { |
| 55 | var generatedFrames = new List<FrameSnapshot>(); |
| 56 | |
| 57 | if (frameHistory.Count < 2 || generationMultiplier <= 1.0f) |
| 58 | return generatedFrames; |
| 59 | |
| 60 | var frames = frameHistory.ToArray(); |
| 61 | var lastFrame = frames[frames.Length - 2]; |
| 62 | var currentFrame = frames[frames.Length - 1]; |
| 63 | |
| 64 | long timeDiff = currentFrame.TimestampMs - lastFrame.TimestampMs; |
| 65 | if (timeDiff <= 0) return generatedFrames; |
| 66 | |
| 67 | // Generate intermediate frames |
| 68 | int intermediateCount = (int)(generationMultiplier - 1); |
| 69 | for (int i = 1; i <= intermediateCount; i++) |
| 70 | { |
| 71 | float t = i / generationMultiplier; |
| 72 | long interpTime = lastFrame.TimestampMs + (long)(timeDiff * t); |
| 73 | |
| 74 | var interpFrame = new FrameSnapshot(interpTime); |
| 75 | |
| 76 | // Interpolate each entity's state |
| 77 | foreach (var entityId in lastFrame.EntityStates.Keys) |
| 78 | { |
| 79 | if (currentFrame.EntityStates.TryGetValue(entityId, out var currentState) && |
| 80 | lastFrame.EntityStates.TryGetValue(entityId, out var lastState)) |
| 81 | { |
| 82 | var interpState = InterpolateEntityState(lastState, currentState, t); |
| 83 | interpFrame.EntityStates[entityId] = interpState; |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | generatedFrames.Add(interpFrame); |
| 88 | } |
| 89 | |
| 90 | return generatedFrames; |
| 91 | } |
| 92 | |
| 93 | private EntityPositionSnapshot InterpolateEntityState( |
| 94 | EntityPositionSnapshot from, |
| 95 | EntityPositionSnapshot to, |
| 96 | float t) |
| 97 | { |
| 98 | // Position interpolation |
| 99 | Vector3 fromPos = new Vector3(from.Position.X, from.Position.Y, from.Position.Z); |
| 100 | Vector3 toPos = new Vector3(to.Position.X, to.Position.Y, to.Position.Z); |
| 101 | |
| 102 | Vector3 interpPos; |
| 103 | if (useMotionVectors && (from.Velocity.X != 0 || from.Velocity.Y != 0 || from.Velocity.Z != 0)) |
| 104 | { |
| 105 | // Use motion vectors for smoother interpolation |
| 106 | double deltaTime = (to.TimestampMs - from.TimestampMs) / 1000.0; |
| 107 | Vector3 motionPredicted = fromPos + (from.Velocity * (deltaTime * t)); |
| 108 | interpPos = Vector3.Lerp(Vector3.Lerp(fromPos, toPos, t), motionPredicted, 0.3f); |
| 109 | } |
| 110 | else |
| 111 | { |
| 112 | interpPos = Vector3.Lerp(fromPos, toPos, t); |
| 113 | } |
| 114 | |
| 115 | // Rotation interpolation |
| 116 | Rotation3 fromRot = new Rotation3(from.Rotation.X, from.Rotation.Y, from.Rotation.Z); |
| 117 | Rotation3 toRot = new Rotation3(to.Rotation.X, to.Rotation.Y, to.Rotation.Z); |
| 118 | Rotation3 interpRot = Rotation3.Lerp(fromRot, toRot, t); |
| 119 | |
| 120 | // Velocity interpolation |
| 121 | Vector3 interpVel = Vector3.Lerp(from.Velocity, to.Velocity, t); |
| 122 | |
| 123 | long interpTime = from.TimestampMs + (long)((to.TimestampMs - from.TimestampMs) * t); |
| 124 | |
| 125 | return new EntityPositionSnapshot( |
| 126 | new Vec3d(interpPos.X, interpPos.Y, interpPos.Z), |
| 127 | new Vec3f(interpRot.Pitch, interpRot.Yaw, interpRot.Roll), |
| 128 | interpTime, |
| 129 | interpVel |
| 130 | ); |
| 131 | } |
| 132 | } |
| 133 | } |
| 134 |