ropa NPC palette gate + 60Hz pose-quantization root cause (boxcar filter)
This commit is contained in:
parent
e308e840b0
commit
6580ed141a
4 changed files with 959 additions and 56 deletions
|
|
@ -26,8 +26,12 @@ REXCVAR_DECLARE(bool, skate3_native_render_scene_tex_mips);
|
|||
REXCVAR_DECLARE(int32_t, skate3_native_render_scene_debug);
|
||||
// Smoothness / pacing.
|
||||
REXCVAR_DECLARE(bool, skate3_native_render_scene_smooth_camera);
|
||||
REXCVAR_DECLARE(double, skate3_native_render_scene_smooth_camera_filter_ms);
|
||||
REXCVAR_DECLARE(bool, skate3_native_render_scene_sort_opaque);
|
||||
REXCVAR_DECLARE(double, skate3_guest_fps_cap);
|
||||
REXCVAR_DECLARE(int32_t, skate3_native_render_scene_synthetic_pan);
|
||||
REXCVAR_DECLARE(double, skate3_native_render_scene_synthetic_pan_rate);
|
||||
REXCVAR_DECLARE(double, skate3_native_render_scene_synthetic_pan_amp);
|
||||
// SDK: emulated-draw suppression while the native output is active.
|
||||
REXCVAR_DECLARE(bool, native_render_suppress_emulated_draws);
|
||||
|
||||
|
|
@ -161,6 +165,20 @@ void NativeDebugDialog::OnDraw(ImGuiIO& io) {
|
|||
"sim tick; raw poses judder at high render rates. Re-times "
|
||||
"them on the host clock (1 kHz camera sampler + pose "
|
||||
"interpolation, a few ms of camera latency)."));
|
||||
{
|
||||
float w = float(REXCVAR_GET(skate3_native_render_scene_smooth_camera_filter_ms));
|
||||
if (ImGui::SliderFloat("camera filter (ms, 0 = off)", &w, 0.0f, 100.0f, "%.0f")) {
|
||||
REXCVAR_SET(skate3_native_render_scene_smooth_camera_filter_ms, double(w));
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(
|
||||
"Boxcar average over the camera pose signal. The game's camera "
|
||||
"advances in 60 Hz-quantized lumps at high fps (the measured cause "
|
||||
"of stick-pan stutter); 50 ms = three 60 Hz periods cancels it "
|
||||
"exactly for ~25 ms extra camera latency. 0 reverts to raw "
|
||||
"interpolation.");
|
||||
}
|
||||
}
|
||||
REXCVAR_SET(skate3_native_render_scene_sort_opaque,
|
||||
CvarCheckbox("Front-to-back opaque sort",
|
||||
REXCVAR_GET(skate3_native_render_scene_sort_opaque),
|
||||
|
|
@ -180,6 +198,59 @@ void NativeDebugDialog::OnDraw(ImGuiIO& io) {
|
|||
"directly).");
|
||||
}
|
||||
}
|
||||
{
|
||||
int mode = REXCVAR_GET(skate3_native_render_scene_synthetic_pan);
|
||||
const char* kPanModes[] = {"0: off", "1: time-based (build clock)",
|
||||
"2: fixed step per frame", "3: through smoother"};
|
||||
if (ImGui::Combo("Synthetic pan (P)", &mode, kPanModes, 4)) {
|
||||
REXCVAR_SET(skate3_native_render_scene_synthetic_pan, mode);
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(
|
||||
"Judder isolation probe: replaces the camera with a host-generated "
|
||||
"constant-rate 360-degree pan. AFTER ENGAGING, SWEEP THE REAL CAMERA "
|
||||
"AROUND ONCE WITH THE STICK; the game only submits what its own "
|
||||
"frustum sees; the sweep fills a static-world union so the full "
|
||||
"circle is populated.\n1 smooth = camera path is fine; 1 judders = "
|
||||
"frame pacing / present / display, not the camera.\n2 = constant "
|
||||
"angle per FRAME (smooth only if displayed frames are evenly spaced "
|
||||
", the complement of 1).\n3 = feeds synthetic ~200 Hz samples "
|
||||
"through the camera smoother and logs reconstruction error "
|
||||
"(synthetic-pan: lines).");
|
||||
}
|
||||
float rate = float(REXCVAR_GET(skate3_native_render_scene_synthetic_pan_rate));
|
||||
if (ImGui::SliderFloat("pan rate (deg/s)", &rate, 5.0f, 720.0f, "%.0f")) {
|
||||
REXCVAR_SET(skate3_native_render_scene_synthetic_pan_rate, double(rate));
|
||||
}
|
||||
float amp = float(REXCVAR_GET(skate3_native_render_scene_synthetic_pan_amp));
|
||||
if (ImGui::SliderFloat("pan amplitude (0 = full spin)", &, 0.0f, 60.0f, "%.0f")) {
|
||||
REXCVAR_SET(skate3_native_render_scene_synthetic_pan_amp, double(amp));
|
||||
}
|
||||
if (ImGui::Button("Record camera signal (8 s)")) {
|
||||
skate3::native_scene::RecordCameraSignal(8.0);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Record bone signal (6 s)")) {
|
||||
skate3::native_scene::RecordBoneSignal(6.0);
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(
|
||||
"Click, then skate at a steady speed for 6 seconds. Records every "
|
||||
"raw entity pose (bone palettes with timestamps) + the rendered "
|
||||
"interpolation output to logs\\bone_signal_<ts>.bin, so wheel-vs-"
|
||||
"deck lag/orbit can be measured and candidate fixes replayed "
|
||||
"offline against real data.");
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(
|
||||
"Click, then IMMEDIATELY pan the camera with the right stick at a "
|
||||
"steady rate for 8 seconds (synthetic pan should be OFF). Records "
|
||||
"every distinct guest camera pose with 1 kHz-sampler timestamps + "
|
||||
"the smoothed output, to logs\\cam_signal_<ts>.csv; offline "
|
||||
"analysis shows whether the game's own camera signal is jerky at "
|
||||
"the source.");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Caches (lightmap-era plumbing)");
|
||||
REXCVAR_SET(
|
||||
|
|
|
|||
|
|
@ -377,6 +377,17 @@ void OnFrameEnd(uint8_t* base) {
|
|||
}
|
||||
f10_was_down = f10_down;
|
||||
}
|
||||
// P: cycle the synthetic camera pan probe (judder isolation: a host-
|
||||
// driven constant-rate pan injected at a selectable pipeline stage; see
|
||||
// the skate3_native_render_scene_synthetic_pan cvar).
|
||||
{
|
||||
static bool p_was_down = false;
|
||||
const bool p_down = (GetAsyncKeyState('P') & 0x8000) != 0;
|
||||
if (p_down && !p_was_down) {
|
||||
skate3::native_scene::CycleSyntheticPan();
|
||||
}
|
||||
p_was_down = p_down;
|
||||
}
|
||||
// F11: paired A/B parity capture; one keypress produces
|
||||
// shot_<ts>_native.png + shot_<ts>_emulated.png (same viewpoint, ~half a
|
||||
// second apart while the renderer toggles) + an immediate F10-style
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -376,4 +376,26 @@ bool ToggleSceneEnabled();
|
|||
void FlushTextureCache();
|
||||
void FlushMeshCache();
|
||||
|
||||
// Synthetic camera pan probe (judder isolation, hotkey P): cycles
|
||||
// skate3_native_render_scene_synthetic_pan 0 -> 1 -> 2 -> 3 -> 0 and returns
|
||||
// the new mode. 1 = time-based constant-rate pan injected at scene build,
|
||||
// 2 = fixed angle step per published frame, 3 = synthetic pose samples fed
|
||||
// through the camera smoother (reconstruction error logged numerically).
|
||||
int CycleSyntheticPan();
|
||||
|
||||
// Camera-signal recorder (judder diagnosis): for `seconds`, records every
|
||||
// distinct guest camera pose (1 kHz sampler timestamps) plus the per-frame
|
||||
// raw and smoothed headings, then writes logs/cam_signal_<ts>.csv. Pan the
|
||||
// camera with the stick at a steady rate while it runs; offline analysis
|
||||
// shows whether the game's own pose sequence is irregular at the source.
|
||||
void RecordCameraSignal(double seconds);
|
||||
|
||||
// Bone-signal recorder (wheel-guard diagnosis): for `seconds`, records every
|
||||
// raw entity pose (ring pushes: bone palettes / rigid worlds, timestamps)
|
||||
// and each frame's interpolated output, then writes
|
||||
// logs/bone_signal_<ts>.bin. Skate at a steady speed while it runs;
|
||||
// offline analysis replays candidate guard strategies against the real
|
||||
// board data.
|
||||
void RecordBoneSignal(double seconds);
|
||||
|
||||
} // namespace skate3::native_scene
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue