ALL_ROTATION mask can be used, only target relative position should be calculated each frame by script. you can test it as Chase camera in Airshow Assistant v4 if you have it.
can’t promise this peace of code works correctly, code was extracted from my project by AI:
static const char* CAMERA_CLIENT_ID = "My Chase Camera";
static bool g_cameraRequested = false;
static bool g_cameraAcquired = false;
static bool g_gameControlled = false;
static SIMCONNECT_DATA_LATLONALT g_chasePos = {};
static bool g_chaseValid = false;
static double g_prevLat = 0.0;
static double g_prevLon = 0.0;
static double g_prevAlt = 0.0;
static bool g_prevValid = false;
static double g_dirEast = 0.0;
static double g_dirNorth = 0.0;
static double g_dirUp = 0.0;
static double degToRad(double v) { return v * 3.14159265358979323846 / 180.0; }
static double radToDeg(double v) { return v * 180.0 / 3.14159265358979323846; }
static double clamp(double v, double lo, double hi) {
return v < lo ? lo : (v > hi ? hi : v);
}
static double bearingRad(double lat1, double lon1, double lat2, double lon2) {
double y = sin(degToRad(lon2 - lon1)) * cos(degToRad(lat2));
double x =
cos(degToRad(lat1)) * sin(degToRad(lat2)) -
sin(degToRad(lat1)) * cos(degToRad(lat2)) * cos(degToRad(lon2 - lon1));
return atan2(y, x);
}
void HandleCameraStatus(SIMCONNECT_RECV_CAMERA_STATUS* msg) {
g_gameControlled = msg->bGameControlled != 0;
g_cameraAcquired = msg->acquiredState == SIMCONNECT_CAMERA_ACQUIRED;
}
void UpdateChaseCamera(
HANDLE hSimConnect,
double dt,
double aircraftLatDeg,
double aircraftLonDeg,
double aircraftAltM,
double aircraftHeadingRad,
double distanceM,
double smooth01,
double pitchOffsetDeg,
double headingOffsetDeg,
double fovDeg)
{
if (!g_cameraRequested) {
if (SimConnect_CameraAcquire(hSimConnect, CAMERA_CLIENT_ID) != S_OK)
return;
SimConnect_CameraGetStatus(hSimConnect);
g_cameraRequested = true;
return;
}
if (!g_cameraAcquired || g_gameControlled)
return;
dt = clamp(dt, 0.0, 1.0);
distanceM = max(distanceM * 0.5, 3.0);
if (g_prevValid && dt > 0.0001) {
double lonScale = 111111.0 * max(0.2, cos(degToRad(aircraftLatDeg)));
double east = (aircraftLonDeg - g_prevLon) * lonScale / dt;
double north = (aircraftLatDeg - g_prevLat) * 111111.0 / dt;
double up = (aircraftAltM - g_prevAlt) / dt;
double speed = sqrt(east * east + north * north + up * up);
if (speed > 1.0) {
g_dirEast = east / speed;
g_dirNorth = north / speed;
g_dirUp = up / speed;
}
}
if (g_dirEast == 0.0 && g_dirNorth == 0.0 && g_dirUp == 0.0) {
g_dirEast = sin(aircraftHeadingRad);
g_dirNorth = cos(aircraftHeadingRad);
}
g_prevLat = aircraftLatDeg;
g_prevLon = aircraftLonDeg;
g_prevAlt = aircraftAltM;
g_prevValid = true;
double lonScale = 111111.0 * max(0.2, cos(degToRad(aircraftLatDeg)));
double targetCamLat = aircraftLatDeg - g_dirNorth * distanceM / 111111.0;
double targetCamLon = aircraftLonDeg - g_dirEast * distanceM / lonScale;
double targetCamAlt = aircraftAltM - g_dirUp * distanceM;
if (!g_chaseValid) {
g_chasePos = { targetCamLat, targetCamLon, targetCamAlt };
g_chaseValid = true;
}
double lag = clamp(dt / (0.15 + 1.5 * clamp(smooth01, 0.0, 1.0)), 0.0, 1.0);
g_chasePos.Latitude += (targetCamLat - g_chasePos.Latitude) * lag;
g_chasePos.Longitude += (targetCamLon - g_chasePos.Longitude) * lag;
g_chasePos.Altitude += (targetCamAlt - g_chasePos.Altitude) * lag;
double horizontalM = sqrt(
pow((aircraftLatDeg - g_chasePos.Latitude) * 111111.0, 2.0) +
pow((aircraftLonDeg - g_chasePos.Longitude) * lonScale, 2.0));
double verticalM = aircraftAltM - g_chasePos.Altitude;
double aimBearing = bearingRad(g_chasePos.Latitude, g_chasePos.Longitude, aircraftLatDeg, aircraftLonDeg);
SIMCONNECT_DATA_CAMERA camera = {};
camera.PositionReferential = SIMCONNECT_POSITION_REFERENTIAL_WORLD;
camera.Position.x = g_chasePos.Latitude;
camera.Position.y = g_chasePos.Longitude;
camera.Position.z = g_chasePos.Altitude;
camera.RotationReferential = SIMCONNECT_POSITION_REFERENTIAL_WORLD;
camera.TargetedPos.x = aircraftLatDeg;
camera.TargetedPos.y = aircraftLonDeg;
camera.TargetedPos.z = aircraftAltM;
camera.Pbh.Pitch = (float)(radToDeg(atan2(-verticalM, max(horizontalM, 1e-6))) + pitchOffsetDeg);
camera.Pbh.Bank = 0.0f;
camera.Pbh.Heading = (float)(radToDeg(aimBearing) + headingOffsetDeg);
camera.Fov = degToRad(fovDeg);
SimConnect_CameraSet(
hSimConnect,
camera,
SIMCONNECT_CAMERA_DATA_MASK_ALL_ROTATION);
}
void ReleaseChaseCamera(HANDLE hSimConnect) {
if (g_cameraRequested || g_cameraAcquired)
SimConnect_CameraRelease(hSimConnect, nullptr);
g_cameraRequested = false;
g_cameraAcquired = false;
g_gameControlled = false;
g_chaseValid = false;
g_prevValid = false;
}