app: organize the F12 debug menu into sections, add a max-quality photo mode
This commit is contained in:
parent
cb14799e47
commit
84f3f94ceb
2 changed files with 519 additions and 271 deletions
|
|
@ -45,6 +45,12 @@ REXCVAR_DECLARE(bool, skate3_native_render_scene_tex_revalidate);
|
||||||
REXCVAR_DECLARE(bool, skate3_native_render_scene_mesh_revalidate);
|
REXCVAR_DECLARE(bool, skate3_native_render_scene_mesh_revalidate);
|
||||||
REXCVAR_DECLARE(bool, skate3_native_render_scene_tex_mips);
|
REXCVAR_DECLARE(bool, skate3_native_render_scene_tex_mips);
|
||||||
REXCVAR_DECLARE(int32_t, skate3_native_render_scene_debug);
|
REXCVAR_DECLARE(int32_t, skate3_native_render_scene_debug);
|
||||||
|
// Image quality (hot; skate3_native_scene.cpp).
|
||||||
|
REXCVAR_DECLARE(int32_t, skate3_native_render_scene_msaa);
|
||||||
|
REXCVAR_DECLARE(int32_t, skate3_native_render_scene_shadow_tile);
|
||||||
|
REXCVAR_DECLARE(int32_t, skate3_native_render_scene_shadow_static_size);
|
||||||
|
REXCVAR_DECLARE(bool, skate3_native_render_scene_ssao_full_res);
|
||||||
|
REXCVAR_DECLARE(bool, skate3_native_render_scene_hdr_packed);
|
||||||
// HDR post-effect stack (hot; skate3_native_scene.cpp).
|
// HDR post-effect stack (hot; skate3_native_scene.cpp).
|
||||||
REXCVAR_DECLARE(bool, skate3_native_render_scene_hdr);
|
REXCVAR_DECLARE(bool, skate3_native_render_scene_hdr);
|
||||||
REXCVAR_DECLARE(int32_t, skate3_native_render_scene_hdr_debug);
|
REXCVAR_DECLARE(int32_t, skate3_native_render_scene_hdr_debug);
|
||||||
|
|
@ -97,6 +103,10 @@ REXCVAR_DECLARE(double, skate3_native_render_scene_freecam_speed);
|
||||||
REXCVAR_DECLARE(double, skate3_native_render_scene_freecam_look_speed);
|
REXCVAR_DECLARE(double, skate3_native_render_scene_freecam_look_speed);
|
||||||
REXCVAR_DECLARE(bool, skate3_native_render_scene_freecam_capture_input);
|
REXCVAR_DECLARE(bool, skate3_native_render_scene_freecam_capture_input);
|
||||||
REXCVAR_DECLARE(bool, skate3_native_render_scene_ssr);
|
REXCVAR_DECLARE(bool, skate3_native_render_scene_ssr);
|
||||||
|
// Draw distance (hot; skate3_draw_distance.cpp).
|
||||||
|
REXCVAR_DECLARE(double, skate3_draw_distance_scale);
|
||||||
|
REXCVAR_DECLARE(double, skate3_lod_distance_scale);
|
||||||
|
REXCVAR_DECLARE(double, skate3_draw_distance_stream_probe);
|
||||||
|
|
||||||
namespace skate3 {
|
namespace skate3 {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
@ -124,6 +134,145 @@ double CvarSlider(const char* label, double value, float lo, float hi,
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Combo over a fixed value list (for quality steps that are not a
|
||||||
|
// continuum: sample counts, map sizes). Returns the possibly-changed value;
|
||||||
|
// out-of-list current values snap to the nearest entry's label without
|
||||||
|
// writing back until the user picks one.
|
||||||
|
int32_t ValueCombo(const char* label, int32_t value, const int32_t* values,
|
||||||
|
const char* const* labels, int count,
|
||||||
|
const char* help = nullptr) {
|
||||||
|
int index = 0;
|
||||||
|
for (int i = 1; i < count; ++i) {
|
||||||
|
const int32_t di = values[i] > value ? values[i] - value : value - values[i];
|
||||||
|
const int32_t db = values[index] > value ? values[index] - value
|
||||||
|
: value - values[index];
|
||||||
|
if (di < db) {
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ImGui::Combo(label, &index, labels, count)) {
|
||||||
|
value = values[index];
|
||||||
|
}
|
||||||
|
if (help != nullptr && ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip("%s", help);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Max quality (photo mode) ---------------------------------------------
|
||||||
|
// One switch that pushes every quality knob to its maximum for
|
||||||
|
// capture/recording (showcase runs, promo footage, screenshots) and
|
||||||
|
// restores the previous values when switched off. Session-scoped: nothing
|
||||||
|
// is persisted. Aesthetic calibrations (bloom/shaft/haze strengths, SSAO
|
||||||
|
// tuning) keep their values: this maximizes fidelity, not effect strength.
|
||||||
|
// SSR stays as-is (experimental, image-quality issues) and quad-list
|
||||||
|
// particles stay off (no sprite textures).
|
||||||
|
|
||||||
|
struct MaxQualityState {
|
||||||
|
bool active = false;
|
||||||
|
// Saved values, restored on switch-off.
|
||||||
|
int32_t msaa;
|
||||||
|
int32_t shadow_tile;
|
||||||
|
int32_t static_size;
|
||||||
|
int32_t shafts_steps;
|
||||||
|
bool ssao_full_res;
|
||||||
|
bool hdr_packed;
|
||||||
|
bool hdr;
|
||||||
|
bool bloom;
|
||||||
|
bool shafts;
|
||||||
|
bool ssao;
|
||||||
|
bool shadows;
|
||||||
|
bool static_casters;
|
||||||
|
bool pcss;
|
||||||
|
double draw_scale;
|
||||||
|
double lod_scale;
|
||||||
|
double stream_probe;
|
||||||
|
};
|
||||||
|
|
||||||
|
MaxQualityState s_max_quality;
|
||||||
|
|
||||||
|
void SetMaxQuality(bool enable) {
|
||||||
|
MaxQualityState& s = s_max_quality;
|
||||||
|
if (enable == s.active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (enable) {
|
||||||
|
s.msaa = REXCVAR_GET(skate3_native_render_scene_msaa);
|
||||||
|
s.shadow_tile = REXCVAR_GET(skate3_native_render_scene_shadow_tile);
|
||||||
|
s.static_size = REXCVAR_GET(skate3_native_render_scene_shadow_static_size);
|
||||||
|
s.shafts_steps = REXCVAR_GET(skate3_native_render_scene_shafts_steps);
|
||||||
|
s.ssao_full_res = REXCVAR_GET(skate3_native_render_scene_ssao_full_res);
|
||||||
|
s.hdr_packed = REXCVAR_GET(skate3_native_render_scene_hdr_packed);
|
||||||
|
s.hdr = REXCVAR_GET(skate3_native_render_scene_hdr);
|
||||||
|
s.bloom = REXCVAR_GET(skate3_native_render_scene_bloom);
|
||||||
|
s.shafts = REXCVAR_GET(skate3_native_render_scene_shafts);
|
||||||
|
s.ssao = REXCVAR_GET(skate3_native_render_scene_ssao);
|
||||||
|
s.shadows = REXCVAR_GET(skate3_native_render_scene_shadows);
|
||||||
|
s.static_casters =
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_shadow_static_casters);
|
||||||
|
s.pcss = REXCVAR_GET(skate3_native_render_scene_shadow_pcss);
|
||||||
|
s.draw_scale = REXCVAR_GET(skate3_draw_distance_scale);
|
||||||
|
s.lod_scale = REXCVAR_GET(skate3_lod_distance_scale);
|
||||||
|
s.stream_probe = REXCVAR_GET(skate3_draw_distance_stream_probe);
|
||||||
|
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_msaa, 8);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_shadow_tile, 4096);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_shadow_static_size, 8192);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_shafts_steps, 64);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_ssao_full_res, true);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_hdr_packed, false); // RGBA16F
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_hdr, true);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_bloom, true);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_shafts, true);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_ssao, true);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_shadows, true);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_shadow_static_casters, true);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_shadow_pcss, true);
|
||||||
|
// The largest steps the settings menu offers (tested territory).
|
||||||
|
REXCVAR_SET(skate3_draw_distance_scale, 5.0);
|
||||||
|
REXCVAR_SET(skate3_lod_distance_scale, 5.0);
|
||||||
|
REXCVAR_SET(skate3_draw_distance_stream_probe, 300.0);
|
||||||
|
} else {
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_msaa, s.msaa);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_shadow_tile, s.shadow_tile);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_shadow_static_size, s.static_size);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_shafts_steps, s.shafts_steps);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_ssao_full_res, s.ssao_full_res);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_hdr_packed, s.hdr_packed);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_hdr, s.hdr);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_bloom, s.bloom);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_shafts, s.shafts);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_ssao, s.ssao);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_shadows, s.shadows);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_shadow_static_casters,
|
||||||
|
s.static_casters);
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_shadow_pcss, s.pcss);
|
||||||
|
REXCVAR_SET(skate3_draw_distance_scale, s.draw_scale);
|
||||||
|
REXCVAR_SET(skate3_lod_distance_scale, s.lod_scale);
|
||||||
|
REXCVAR_SET(skate3_draw_distance_stream_probe, s.stream_probe);
|
||||||
|
}
|
||||||
|
s.active = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawMaxQualityToggle() {
|
||||||
|
bool on = s_max_quality.active;
|
||||||
|
if (ImGui::Checkbox("MAX QUALITY (photo mode)", &on)) {
|
||||||
|
SetMaxQuality(on);
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip(
|
||||||
|
"Push every quality setting to its maximum for recording: MSAA 8x,\n"
|
||||||
|
"4096 shadow tiles, 8192 static sun map, full-res SSAO, RGBA16F\n"
|
||||||
|
"HDR, max shaft steps, 5x draw/LOD distance, 300 m streaming, all\n"
|
||||||
|
"quality features on. GPU-heavy; previous values restore when\n"
|
||||||
|
"unchecked. Applies live (a one-frame pipeline rebuild).");
|
||||||
|
}
|
||||||
|
if (s_max_quality.active) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextColored(ImVec4(1.0f, 0.85f, 0.3f, 1.0f), "ACTIVE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---- Showcase setup window ------------------------------------------------
|
// ---- Showcase setup window ------------------------------------------------
|
||||||
// Editor for skate3_native_render_scene_showcase_order: one row per build-up
|
// Editor for skate3_native_render_scene_showcase_order: one row per build-up
|
||||||
// layer, reorderable, each optionally joined to the previous row's wipe. The
|
// layer, reorderable, each optionally joined to the previous row's wipe. The
|
||||||
|
|
@ -393,99 +542,13 @@ void DrawShowcaseSetupWindow(bool* p_open) {
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
// ---- F12 menu sections ----------------------------------------------------
|
||||||
|
// One CollapsingHeader per intent group. The groups the menu is actually
|
||||||
|
// opened for (capture tools, image quality) default open; tuning and
|
||||||
|
// diagnostics stay collapsed until needed.
|
||||||
|
|
||||||
void NativeDebugDialog::Show() {
|
void DrawShowcaseCaptureSection() {
|
||||||
visible_ = true;
|
DrawMaxQualityToggle();
|
||||||
SetDrawActive(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NativeDebugDialog::Hide() {
|
|
||||||
if (!visible_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
visible_ = false;
|
|
||||||
SetDrawActive(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NativeDebugDialog::Toggle() {
|
|
||||||
if (visible_) {
|
|
||||||
Hide();
|
|
||||||
} else {
|
|
||||||
Show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NativeDebugDialog::OnDraw(ImGuiIO& io) {
|
|
||||||
(void)io;
|
|
||||||
if (!visible_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bool open = visible_;
|
|
||||||
ImGui::SetNextWindowSize(ImVec2(430.0f, 0.0f), ImGuiCond_FirstUseEver);
|
|
||||||
if (!ImGui::Begin("Native Render Debug (F12)", &open, ImGuiWindowFlags_NoCollapse)) {
|
|
||||||
ImGui::End();
|
|
||||||
if (!open) {
|
|
||||||
Hide();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!REXCVAR_GET(skate3_native_render)) {
|
|
||||||
ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.3f, 1.0f),
|
|
||||||
"skate3_native_render hook layer is OFF (boot-time)");
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SeparatorText("Renderer");
|
|
||||||
{
|
|
||||||
const bool v = CvarCheckbox("Native scene renderer (F5)",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene),
|
|
||||||
"Full native/emulated switch, same as F5");
|
|
||||||
if (v != REXCVAR_GET(skate3_native_render_scene)) {
|
|
||||||
skate3::native_scene::ToggleSceneEnabled();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
REXCVAR_SET(native_render_suppress_emulated_draws,
|
|
||||||
CvarCheckbox("Suppress emulated draws",
|
|
||||||
REXCVAR_GET(native_render_suppress_emulated_draws),
|
|
||||||
"Skip emulated GPU work for framebuffer-sized passes while "
|
|
||||||
"native output is active (perf). Small-surface passes "
|
|
||||||
"(lightmap page composition) always run."));
|
|
||||||
{
|
|
||||||
int mode = REXCVAR_GET(skate3_native_render_scene_debug);
|
|
||||||
const char* kModes[] = {"0: normal", "1: clear only", "2: solid colors",
|
|
||||||
"3: first 20 items", "4: no depth"};
|
|
||||||
if (ImGui::Combo("debug mode", &mode, kModes, 5)) {
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_debug, mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SeparatorText("World shading");
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_lightmaps,
|
|
||||||
CvarCheckbox("Lightmaps", REXCVAR_GET(skate3_native_render_scene_lightmaps),
|
|
||||||
"Baked lighting atlas sample x2 on world materials"));
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_macro,
|
|
||||||
CvarCheckbox("Macro overlay", REXCVAR_GET(skate3_native_render_scene_macro),
|
|
||||||
"Large-scale grime/crack multiply (ground/wall weathering)"));
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_decals,
|
|
||||||
CvarCheckbox("Decal art composite",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_decals),
|
|
||||||
"Graffiti/paint art lerped over environment.decal sections"));
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_transparents,
|
|
||||||
CvarCheckbox("Transparent sub-pass",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_transparents),
|
|
||||||
"environment.transparent items (mist sheets, glass, fences)"));
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_shadows,
|
|
||||||
CvarCheckbox("Dynamic shadows",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_shadows),
|
|
||||||
"Native CSM: skater/NPC/prop shadows onto the world"));
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_backface_cull,
|
|
||||||
CvarCheckbox("Backface cull (game parity)",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_backface_cull),
|
|
||||||
"World env materials cull FRONT like the game's material "
|
|
||||||
"XMLs; off = legacy cull-none (shows interior faces)"));
|
|
||||||
|
|
||||||
ImGui::SeparatorText("Graphics showcase");
|
|
||||||
{
|
{
|
||||||
const bool running = REXCVAR_GET(skate3_native_render_scene_showcase);
|
const bool running = REXCVAR_GET(skate3_native_render_scene_showcase);
|
||||||
if (ImGui::Button(running ? "Cancel showcase" : "Start showcase (Home)")) {
|
if (ImGui::Button(running ? "Cancel showcase" : "Start showcase (Home)")) {
|
||||||
|
|
@ -503,25 +566,86 @@ void NativeDebugDialog::OnDraw(ImGuiIO& io) {
|
||||||
s_showcase_setup_open = true;
|
s_showcase_setup_open = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawFreecamControls();
|
DrawFreecamControls();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::SeparatorText("HDR post effects (live)");
|
void DrawImageQualitySection() {
|
||||||
|
{
|
||||||
|
static const int32_t kMsaaValues[] = {1, 2, 4, 8};
|
||||||
|
static const char* const kMsaaLabels[] = {"Off (1x)", "2x", "4x", "8x"};
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_msaa,
|
||||||
|
ValueCombo("MSAA", REXCVAR_GET(skate3_native_render_scene_msaa),
|
||||||
|
kMsaaValues, kMsaaLabels, 4,
|
||||||
|
"Scene multisampling. Distant thin geometry "
|
||||||
|
"(railings, wires) shimmers without it. Applies "
|
||||||
|
"live (pipeline rebuild)."));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
static const int32_t kTileValues[] = {0, 512, 1024, 2048, 4096};
|
||||||
|
static const char* const kTileLabels[] = {"Auto (render scale)", "512",
|
||||||
|
"1024", "2048", "4096"};
|
||||||
|
REXCVAR_SET(
|
||||||
|
skate3_native_render_scene_shadow_tile,
|
||||||
|
ValueCombo("shadow tile size",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_shadow_tile),
|
||||||
|
kTileValues, kTileLabels, 5,
|
||||||
|
"Dynamic-shadow cascade tile resolution. Auto matches the "
|
||||||
|
"emulated renderer's crispness at the current Resolution "
|
||||||
|
"Scale; 512 = the softer original-console look."));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
static const int32_t kStaticValues[] = {1024, 2048, 4096, 8192};
|
||||||
|
static const char* const kStaticLabels[] = {"1024", "2048", "4096",
|
||||||
|
"8192"};
|
||||||
|
REXCVAR_SET(
|
||||||
|
skate3_native_render_scene_shadow_static_size,
|
||||||
|
ValueCombo("static sun map size",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_shadow_static_size),
|
||||||
|
kStaticValues, kStaticLabels, 4,
|
||||||
|
"Static sun-shadow map resolution per cascade tile (the "
|
||||||
|
"map is three tiles)."));
|
||||||
|
}
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_ssao_full_res,
|
||||||
|
CvarCheckbox("Full-res SSAO",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_ssao_full_res),
|
||||||
|
"Evaluate SSAO at full output resolution instead "
|
||||||
|
"of half. ~4x the AO cost for slightly sharper "
|
||||||
|
"contact shadows."));
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_hdr_packed,
|
||||||
|
CvarCheckbox("Packed HDR format (R11G11B10)",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_hdr_packed),
|
||||||
|
"Halves scene-pass color bandwidth vs RGBA16F at "
|
||||||
|
"slightly lower precision in very dark "
|
||||||
|
"gradients."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawLightingPostSection() {
|
||||||
REXCVAR_SET(skate3_native_render_scene_hdr,
|
REXCVAR_SET(skate3_native_render_scene_hdr,
|
||||||
CvarCheckbox("HDR intermediate",
|
CvarCheckbox("HDR intermediate",
|
||||||
REXCVAR_GET(skate3_native_render_scene_hdr),
|
REXCVAR_GET(skate3_native_render_scene_hdr),
|
||||||
"Float scene target + single host tonemap, the basis for "
|
"Float scene target + single host tonemap, the basis for "
|
||||||
"bloom, shafts and haze. Off = the classic in-material "
|
"bloom, shafts and haze. Off = the classic in-material "
|
||||||
"tonemap (parity A/B)."));
|
"tonemap (parity A/B)."));
|
||||||
{
|
REXCVAR_SET(skate3_native_render_scene_bloom,
|
||||||
int dbg = REXCVAR_GET(skate3_native_render_scene_hdr_debug);
|
CvarCheckbox("Bloom",
|
||||||
const char* kHdrDbg[] = {"0: off", "1: bloom term",
|
REXCVAR_GET(skate3_native_render_scene_bloom),
|
||||||
"2: raw pre-tonemap", "3: AO plane",
|
"Downsample/upsample pyramid driven by pre-tonemap "
|
||||||
"4: shaft plane", "5: haze term"};
|
"brightness (night lamps, neon, sun glare)."));
|
||||||
if (ImGui::Combo("HDR debug view", &dbg, kHdrDbg, 6)) {
|
REXCVAR_SET(skate3_native_render_scene_bloom_threshold,
|
||||||
REXCVAR_SET(skate3_native_render_scene_hdr_debug, dbg);
|
CvarSlider("bloom threshold",
|
||||||
}
|
REXCVAR_GET(skate3_native_render_scene_bloom_threshold),
|
||||||
}
|
0.0f, 1.5f, "%.2f",
|
||||||
|
"Pre-tonemap onset (1.0 = the tone curve's saturation "
|
||||||
|
"point). Below ~0.7 the sunlit day frame starts feeding "
|
||||||
|
"the pyramid and veils in glow."));
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_bloom_knee,
|
||||||
|
CvarSlider("bloom knee",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_bloom_knee),
|
||||||
|
0.0f, 0.5f, "%.2f"));
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_bloom_intensity,
|
||||||
|
CvarSlider("bloom intensity",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_bloom_intensity),
|
||||||
|
0.0f, 0.3f, "%.3f"));
|
||||||
REXCVAR_SET(skate3_native_render_scene_shafts,
|
REXCVAR_SET(skate3_native_render_scene_shafts,
|
||||||
CvarCheckbox("Volumetric sun shafts",
|
CvarCheckbox("Volumetric sun shafts",
|
||||||
REXCVAR_GET(skate3_native_render_scene_shafts),
|
REXCVAR_GET(skate3_native_render_scene_shafts),
|
||||||
|
|
@ -563,26 +687,6 @@ void NativeDebugDialog::OnDraw(ImGuiIO& io) {
|
||||||
0.0f, 0.02f, "%.4f",
|
0.0f, 0.02f, "%.4f",
|
||||||
"How quickly the scattering saturates with distance "
|
"How quickly the scattering saturates with distance "
|
||||||
"(0.005 reaches ~63% at 200 units)."));
|
"(0.005 reaches ~63% at 200 units)."));
|
||||||
REXCVAR_SET(skate3_native_render_scene_bloom,
|
|
||||||
CvarCheckbox("Bloom",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_bloom),
|
|
||||||
"Downsample/upsample pyramid driven by pre-tonemap "
|
|
||||||
"brightness (night lamps, neon, sun glare)."));
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_bloom_threshold,
|
|
||||||
CvarSlider("bloom threshold",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_bloom_threshold),
|
|
||||||
0.0f, 1.5f, "%.2f",
|
|
||||||
"Pre-tonemap onset (1.0 = the tone curve's saturation "
|
|
||||||
"point). Below ~0.7 the sunlit day frame starts feeding "
|
|
||||||
"the pyramid and veils in glow."));
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_bloom_knee,
|
|
||||||
CvarSlider("bloom knee",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_bloom_knee),
|
|
||||||
0.0f, 0.5f, "%.2f"));
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_bloom_intensity,
|
|
||||||
CvarSlider("bloom intensity",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_bloom_intensity),
|
|
||||||
0.0f, 0.3f, "%.3f"));
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_ssao,
|
REXCVAR_SET(skate3_native_render_scene_ssao,
|
||||||
CvarCheckbox("SSAO (GTAO)",
|
CvarCheckbox("SSAO (GTAO)",
|
||||||
REXCVAR_GET(skate3_native_render_scene_ssao),
|
REXCVAR_GET(skate3_native_render_scene_ssao),
|
||||||
|
|
@ -604,6 +708,48 @@ void NativeDebugDialog::OnDraw(ImGuiIO& io) {
|
||||||
0.0f, 3.0f, "%.2f",
|
0.0f, 3.0f, "%.2f",
|
||||||
"How strongly bright (sun-lit) surfaces resist SSAO "
|
"How strongly bright (sun-lit) surfaces resist SSAO "
|
||||||
"darkening (ambient-only approximation)."));
|
"darkening (ambient-only approximation)."));
|
||||||
|
{
|
||||||
|
const bool was_on = REXCVAR_GET(skate3_native_render_scene_sun_override);
|
||||||
|
const bool now_on =
|
||||||
|
CvarCheckbox("Sun override (lighting lab)", was_on,
|
||||||
|
"Move the sun with the sliders below: dynamic CSM "
|
||||||
|
"shadows, the static world-shadow map, shadow receivers "
|
||||||
|
"and the volumetric shafts all follow. Baked lightmap "
|
||||||
|
"shade and the sky dome's painted sun stay put (game "
|
||||||
|
"content).");
|
||||||
|
if (now_on && !was_on) {
|
||||||
|
// Seed the sliders from the captured sun so enabling the override
|
||||||
|
// starts at the true position instead of jumping.
|
||||||
|
float sun[3];
|
||||||
|
skate3::native_scene::GetCapturedSunDir(sun);
|
||||||
|
const float kRad = 57.29577951f;
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_sun_azimuth,
|
||||||
|
double(std::fmod(std::atan2(sun[0], sun[2]) * kRad + 360.0f,
|
||||||
|
360.0f)));
|
||||||
|
REXCVAR_SET(
|
||||||
|
skate3_native_render_scene_sun_elevation,
|
||||||
|
double(std::clamp(std::asin(std::clamp(sun[1], -1.0f, 1.0f)) * kRad,
|
||||||
|
2.0f, 88.0f)));
|
||||||
|
}
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_sun_override, now_on);
|
||||||
|
}
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_sun_azimuth,
|
||||||
|
CvarSlider("sun azimuth (deg)",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_sun_azimuth),
|
||||||
|
0.0f, 360.0f, "%.0f"));
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_sun_elevation,
|
||||||
|
CvarSlider("sun elevation (deg)",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_sun_elevation),
|
||||||
|
2.0f, 88.0f, "%.0f",
|
||||||
|
"Low elevations give long shadows and the most visible "
|
||||||
|
"volumetric shafts."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawShadowsSection() {
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_shadows,
|
||||||
|
CvarCheckbox("Dynamic shadows",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_shadows),
|
||||||
|
"Native CSM: skater/NPC/prop shadows onto the world"));
|
||||||
REXCVAR_SET(skate3_native_render_scene_shadow_static_casters,
|
REXCVAR_SET(skate3_native_render_scene_shadow_static_casters,
|
||||||
CvarCheckbox(
|
CvarCheckbox(
|
||||||
"Static sun shadows",
|
"Static sun shadows",
|
||||||
|
|
@ -657,41 +803,152 @@ void NativeDebugDialog::OnDraw(ImGuiIO& io) {
|
||||||
"Raise if static geometry shows self-shadow acne (stipple "
|
"Raise if static geometry shows self-shadow acne (stipple "
|
||||||
"on sunlit ground/walls); lower if static shadows visibly "
|
"on sunlit ground/walls); lower if static shadows visibly "
|
||||||
"detach from their casters."));
|
"detach from their casters."));
|
||||||
{
|
}
|
||||||
const bool was_on = REXCVAR_GET(skate3_native_render_scene_sun_override);
|
|
||||||
const bool now_on =
|
void DrawWorldShadingSection() {
|
||||||
CvarCheckbox("Sun override (lighting lab)", was_on,
|
REXCVAR_SET(skate3_native_render_scene_lightmaps,
|
||||||
"Move the sun with the sliders below: dynamic CSM "
|
CvarCheckbox("Lightmaps", REXCVAR_GET(skate3_native_render_scene_lightmaps),
|
||||||
"shadows, the static world-shadow map, shadow receivers "
|
"Baked lighting atlas sample x2 on world materials"));
|
||||||
"and the volumetric shafts all follow. Baked lightmap "
|
REXCVAR_SET(skate3_native_render_scene_macro,
|
||||||
"shade and the sky dome's painted sun stay put (game "
|
CvarCheckbox("Macro overlay", REXCVAR_GET(skate3_native_render_scene_macro),
|
||||||
"content).");
|
"Large-scale grime/crack multiply (ground/wall weathering)"));
|
||||||
if (now_on && !was_on) {
|
REXCVAR_SET(skate3_native_render_scene_decals,
|
||||||
// Seed the sliders from the captured sun so enabling the override
|
CvarCheckbox("Decal art composite",
|
||||||
// starts at the true position instead of jumping.
|
REXCVAR_GET(skate3_native_render_scene_decals),
|
||||||
float sun[3];
|
"Graffiti/paint art lerped over environment.decal sections"));
|
||||||
skate3::native_scene::GetCapturedSunDir(sun);
|
REXCVAR_SET(skate3_native_render_scene_transparents,
|
||||||
const float kRad = 57.29577951f;
|
CvarCheckbox("Transparent sub-pass",
|
||||||
REXCVAR_SET(skate3_native_render_scene_sun_azimuth,
|
REXCVAR_GET(skate3_native_render_scene_transparents),
|
||||||
double(std::fmod(std::atan2(sun[0], sun[2]) * kRad + 360.0f,
|
"environment.transparent items (mist sheets, glass, fences)"));
|
||||||
360.0f)));
|
REXCVAR_SET(skate3_native_render_scene_backface_cull,
|
||||||
|
CvarCheckbox("Backface cull (game parity)",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_backface_cull),
|
||||||
|
"World env materials cull FRONT like the game's material "
|
||||||
|
"XMLs; off = legacy cull-none (shows interior faces)"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawSceneContentSection() {
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_world_items,
|
||||||
|
CvarCheckbox("World items", REXCVAR_GET(skate3_native_render_scene_world_items),
|
||||||
|
"Static geometry from the world sort lists"));
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_dynamic_items,
|
||||||
|
CvarCheckbox("Dynamic items",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_dynamic_items),
|
||||||
|
"Characters, movable props, cloth (RenderMesh/world-path "
|
||||||
|
"captures)"));
|
||||||
REXCVAR_SET(
|
REXCVAR_SET(
|
||||||
skate3_native_render_scene_sun_elevation,
|
skate3_native_render_scene_lw_fade,
|
||||||
double(std::clamp(std::asin(std::clamp(sun[1], -1.0f, 1.0f)) * kRad,
|
CvarCheckbox("LW entity fade (store)",
|
||||||
2.0f, 88.0f)));
|
REXCVAR_GET(skate3_native_render_scene_lw_fade),
|
||||||
|
"Serve NPC/traffic fade alpha from the LivingWorld entity "
|
||||||
|
"itself (per-instance store) instead of the per-draw "
|
||||||
|
"captured constant row; fixes opaque mid-air spawns, "
|
||||||
|
"missing fade-ins and clone alpha blinks"));
|
||||||
|
REXCVAR_SET(
|
||||||
|
skate3_native_render_scene_lw_identity,
|
||||||
|
CvarCheckbox("LW entity identity (pose rings)",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_lw_identity),
|
||||||
|
"Key NPC/traffic pose-smoothing rings by the game's own "
|
||||||
|
"per-instance MeshContext instead of (mesh, occurrence) "
|
||||||
|
"pairing; clone reshuffles can no longer mispair "
|
||||||
|
"(teleport/slide class)"));
|
||||||
|
REXCVAR_SET(
|
||||||
|
skate3_native_render_scene_lw_gap_fill,
|
||||||
|
CvarCheckbox("LW gap fill (1-2 frame republish)",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_lw_gap_fill),
|
||||||
|
"Republish a live NPC whose MeshContext skipped this "
|
||||||
|
"frame's submit records (the 1-3 frame publish GAPs that "
|
||||||
|
"read as blinks/small teleports)"));
|
||||||
|
REXCVAR_SET(
|
||||||
|
skate3_native_render_scene_lw_palette,
|
||||||
|
CvarCheckbox("LW authoritative caster palettes",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_lw_palette),
|
||||||
|
"Replace GUESSED ortho caster-bank palettes on "
|
||||||
|
"edge-of-view vehicles with the entity's own packed "
|
||||||
|
"palette from the pack writer (the mangle/transform "
|
||||||
|
"class)"));
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_quadlists,
|
||||||
|
CvarCheckbox("Quad-list particles",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_quadlists),
|
||||||
|
"Non-indexed quad-list captures (particle systems; off by "
|
||||||
|
"default: render as white squares without sprite textures)"));
|
||||||
|
REXCVAR_SET(
|
||||||
|
skate3_native_render_scene_retain_offscreen,
|
||||||
|
CvarCheckbox("Retain off-screen statics",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_retain_offscreen),
|
||||||
|
"Keep recently seen statics drawn while the game view-culls "
|
||||||
|
"them: the smoothed render camera trails the guest pose, so "
|
||||||
|
"without this world geometry visibly tears down right at the "
|
||||||
|
"screen edges during pans/traversal"));
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_2d,
|
||||||
|
CvarCheckbox("2D / HUD replay", REXCVAR_GET(skate3_native_render_scene_2d),
|
||||||
|
"APT/Flash HUD + glyph text + SimpleDraw icons"));
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_splines,
|
||||||
|
CvarCheckbox("Neon splines", REXCVAR_GET(skate3_native_render_scene_splines),
|
||||||
|
"Waypoint arrows / marker beams"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawPacingSection() {
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_smooth_camera,
|
||||||
|
CvarCheckbox("Smooth camera + entity poses",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene_smooth_camera),
|
||||||
|
"The guest updates its camera/entities on its own ~200 Hz "
|
||||||
|
"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),
|
||||||
|
"Early-z rejects occluded pixels before the material shading"));
|
||||||
|
{
|
||||||
|
int cap = int(REXCVAR_GET(skate3_guest_fps_cap));
|
||||||
|
if (ImGui::InputInt("Guest fps cap (0 = off)", &cap, 10, 30)) {
|
||||||
|
if (cap < 0) cap = 0;
|
||||||
|
if (cap > 1000) cap = 1000;
|
||||||
|
REXCVAR_SET(skate3_guest_fps_cap, double(cap));
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip(
|
||||||
|
"Pace guest frames on an even beat. Set a few fps below the display "
|
||||||
|
"refresh (with G-Sync/VRR this is what makes motion read as smooth; "
|
||||||
|
"uncapped, the guest's irregular frame times drive the refresh "
|
||||||
|
"directly).");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawDiagnosticsSection() {
|
||||||
|
{
|
||||||
|
int mode = REXCVAR_GET(skate3_native_render_scene_debug);
|
||||||
|
const char* kModes[] = {"0: normal", "1: clear only", "2: solid colors",
|
||||||
|
"3: first 20 items", "4: no depth"};
|
||||||
|
if (ImGui::Combo("debug mode", &mode, kModes, 5)) {
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_debug, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int dbg = REXCVAR_GET(skate3_native_render_scene_hdr_debug);
|
||||||
|
const char* kHdrDbg[] = {"0: off", "1: bloom term",
|
||||||
|
"2: raw pre-tonemap", "3: AO plane",
|
||||||
|
"4: shaft plane", "5: haze term"};
|
||||||
|
if (ImGui::Combo("HDR debug view", &dbg, kHdrDbg, 6)) {
|
||||||
|
REXCVAR_SET(skate3_native_render_scene_hdr_debug, dbg);
|
||||||
}
|
}
|
||||||
REXCVAR_SET(skate3_native_render_scene_sun_override, now_on);
|
|
||||||
}
|
}
|
||||||
REXCVAR_SET(skate3_native_render_scene_sun_azimuth,
|
|
||||||
CvarSlider("sun azimuth (deg)",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_sun_azimuth),
|
|
||||||
0.0f, 360.0f, "%.0f"));
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_sun_elevation,
|
|
||||||
CvarSlider("sun elevation (deg)",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_sun_elevation),
|
|
||||||
2.0f, 88.0f, "%.0f",
|
|
||||||
"Low elevations give long shadows and the most visible "
|
|
||||||
"volumetric shafts."));
|
|
||||||
|
|
||||||
ImGui::SeparatorText("Reflective glass isolation (env fam 5/6/13)");
|
ImGui::SeparatorText("Reflective glass isolation (env fam 5/6/13)");
|
||||||
{
|
{
|
||||||
|
|
@ -755,108 +1012,7 @@ void NativeDebugDialog::OnDraw(ImGuiIO& io) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SeparatorText("Scene items");
|
ImGui::SeparatorText("Judder isolation");
|
||||||
REXCVAR_SET(skate3_native_render_scene_world_items,
|
|
||||||
CvarCheckbox("World items", REXCVAR_GET(skate3_native_render_scene_world_items),
|
|
||||||
"Static geometry from the world sort lists"));
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_dynamic_items,
|
|
||||||
CvarCheckbox("Dynamic items",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_dynamic_items),
|
|
||||||
"Characters, movable props, cloth (RenderMesh/world-path "
|
|
||||||
"captures)"));
|
|
||||||
REXCVAR_SET(
|
|
||||||
skate3_native_render_scene_lw_fade,
|
|
||||||
CvarCheckbox("LW entity fade (store)",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_lw_fade),
|
|
||||||
"Serve NPC/traffic fade alpha from the LivingWorld entity "
|
|
||||||
"itself (per-instance store) instead of the per-draw "
|
|
||||||
"captured constant row; fixes opaque mid-air spawns, "
|
|
||||||
"missing fade-ins and clone alpha blinks"));
|
|
||||||
REXCVAR_SET(
|
|
||||||
skate3_native_render_scene_lw_identity,
|
|
||||||
CvarCheckbox("LW entity identity (pose rings)",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_lw_identity),
|
|
||||||
"Key NPC/traffic pose-smoothing rings by the game's own "
|
|
||||||
"per-instance MeshContext instead of (mesh, occurrence) "
|
|
||||||
"pairing; clone reshuffles can no longer mispair "
|
|
||||||
"(teleport/slide class)"));
|
|
||||||
REXCVAR_SET(
|
|
||||||
skate3_native_render_scene_lw_gap_fill,
|
|
||||||
CvarCheckbox("LW gap fill (1-2 frame republish)",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_lw_gap_fill),
|
|
||||||
"Republish a live NPC whose MeshContext skipped this "
|
|
||||||
"frame's submit records (the 1-3 frame publish GAPs that "
|
|
||||||
"read as blinks/small teleports)"));
|
|
||||||
REXCVAR_SET(
|
|
||||||
skate3_native_render_scene_lw_palette,
|
|
||||||
CvarCheckbox("LW authoritative caster palettes",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_lw_palette),
|
|
||||||
"Replace GUESSED ortho caster-bank palettes on "
|
|
||||||
"edge-of-view vehicles with the entity's own packed "
|
|
||||||
"palette from the pack writer (the mangle/transform "
|
|
||||||
"class)"));
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_quadlists,
|
|
||||||
CvarCheckbox("Quad-list particles",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_quadlists),
|
|
||||||
"Non-indexed quad-list captures (particle systems; off by "
|
|
||||||
"default: render as white squares without sprite textures)"));
|
|
||||||
REXCVAR_SET(
|
|
||||||
skate3_native_render_scene_retain_offscreen,
|
|
||||||
CvarCheckbox("Retain off-screen statics",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_retain_offscreen),
|
|
||||||
"Keep recently seen statics drawn while the game view-culls "
|
|
||||||
"them: the smoothed render camera trails the guest pose, so "
|
|
||||||
"without this world geometry visibly tears down right at the "
|
|
||||||
"screen edges during pans/traversal"));
|
|
||||||
ImGui::SeparatorText("Overlays");
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_2d,
|
|
||||||
CvarCheckbox("2D / HUD replay", REXCVAR_GET(skate3_native_render_scene_2d),
|
|
||||||
"APT/Flash HUD + glyph text + SimpleDraw icons"));
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_splines,
|
|
||||||
CvarCheckbox("Neon splines", REXCVAR_GET(skate3_native_render_scene_splines),
|
|
||||||
"Waypoint arrows / marker beams"));
|
|
||||||
|
|
||||||
ImGui::SeparatorText("Smoothness / pacing");
|
|
||||||
REXCVAR_SET(skate3_native_render_scene_smooth_camera,
|
|
||||||
CvarCheckbox("Smooth camera + entity poses",
|
|
||||||
REXCVAR_GET(skate3_native_render_scene_smooth_camera),
|
|
||||||
"The guest updates its camera/entities on its own ~200 Hz "
|
|
||||||
"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),
|
|
||||||
"Early-z rejects occluded pixels before the material shading"));
|
|
||||||
{
|
|
||||||
int cap = int(REXCVAR_GET(skate3_guest_fps_cap));
|
|
||||||
if (ImGui::InputInt("Guest fps cap (0 = off)", &cap, 10, 30)) {
|
|
||||||
if (cap < 0) cap = 0;
|
|
||||||
if (cap > 1000) cap = 1000;
|
|
||||||
REXCVAR_SET(skate3_guest_fps_cap, double(cap));
|
|
||||||
}
|
|
||||||
if (ImGui::IsItemHovered()) {
|
|
||||||
ImGui::SetTooltip(
|
|
||||||
"Pace guest frames on an even beat. Set a few fps below the display "
|
|
||||||
"refresh (with G-Sync/VRR this is what makes motion read as smooth; "
|
|
||||||
"uncapped, the guest's irregular frame times drive the refresh "
|
|
||||||
"directly).");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
int mode = REXCVAR_GET(skate3_native_render_scene_synthetic_pan);
|
int mode = REXCVAR_GET(skate3_native_render_scene_synthetic_pan);
|
||||||
const char* kPanModes[] = {"0: off", "1: time-based (build clock)",
|
const char* kPanModes[] = {"0: off", "1: time-based (build clock)",
|
||||||
|
|
@ -888,6 +1044,15 @@ void NativeDebugDialog::OnDraw(ImGuiIO& io) {
|
||||||
if (ImGui::Button("Record camera signal (8 s)")) {
|
if (ImGui::Button("Record camera signal (8 s)")) {
|
||||||
skate3::native_scene::RecordCameraSignal(8.0);
|
skate3::native_scene::RecordCameraSignal(8.0);
|
||||||
}
|
}
|
||||||
|
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::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Record bone signal (6 s)")) {
|
if (ImGui::Button("Record bone signal (6 s)")) {
|
||||||
skate3::native_scene::RecordBoneSignal(6.0);
|
skate3::native_scene::RecordBoneSignal(6.0);
|
||||||
|
|
@ -900,18 +1065,10 @@ void NativeDebugDialog::OnDraw(ImGuiIO& io) {
|
||||||
"deck lag/orbit can be measured and candidate fixes replayed "
|
"deck lag/orbit can be measured and candidate fixes replayed "
|
||||||
"offline against real data.");
|
"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)");
|
void DrawCachesSection() {
|
||||||
REXCVAR_SET(
|
REXCVAR_SET(
|
||||||
skate3_native_render_scene_tex_revalidate,
|
skate3_native_render_scene_tex_revalidate,
|
||||||
CvarCheckbox("Texture payload revalidation",
|
CvarCheckbox("Texture payload revalidation",
|
||||||
|
|
@ -935,7 +1092,96 @@ void NativeDebugDialog::OnDraw(ImGuiIO& io) {
|
||||||
if (ImGui::Button("Flush mesh cache")) {
|
if (ImGui::Button("Flush mesh cache")) {
|
||||||
skate3::native_scene::FlushMeshCache();
|
skate3::native_scene::FlushMeshCache();
|
||||||
}
|
}
|
||||||
ImGui::TextDisabled("MSAA + shadow tile size are restart-only (skate3.toml).");
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void NativeDebugDialog::Show() {
|
||||||
|
visible_ = true;
|
||||||
|
SetDrawActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeDebugDialog::Hide() {
|
||||||
|
if (!visible_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
visible_ = false;
|
||||||
|
SetDrawActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeDebugDialog::Toggle() {
|
||||||
|
if (visible_) {
|
||||||
|
Hide();
|
||||||
|
} else {
|
||||||
|
Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeDebugDialog::OnDraw(ImGuiIO& io) {
|
||||||
|
(void)io;
|
||||||
|
if (!visible_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool open = visible_;
|
||||||
|
ImGui::SetNextWindowSize(ImVec2(430.0f, 0.0f), ImGuiCond_FirstUseEver);
|
||||||
|
if (!ImGui::Begin("Native Render Debug (F12)", &open, ImGuiWindowFlags_NoCollapse)) {
|
||||||
|
ImGui::End();
|
||||||
|
if (!open) {
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renderer master switches stay visible above the sections: they gate
|
||||||
|
// everything below and are the first thing checked when bisecting.
|
||||||
|
if (!REXCVAR_GET(skate3_native_render)) {
|
||||||
|
ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.3f, 1.0f),
|
||||||
|
"skate3_native_render hook layer is OFF (boot-time)");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const bool v = CvarCheckbox("Native scene renderer (F5)",
|
||||||
|
REXCVAR_GET(skate3_native_render_scene),
|
||||||
|
"Full native/emulated switch, same as F5");
|
||||||
|
if (v != REXCVAR_GET(skate3_native_render_scene)) {
|
||||||
|
skate3::native_scene::ToggleSceneEnabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
REXCVAR_SET(native_render_suppress_emulated_draws,
|
||||||
|
CvarCheckbox("Suppress emulated draws",
|
||||||
|
REXCVAR_GET(native_render_suppress_emulated_draws),
|
||||||
|
"Skip emulated GPU work for framebuffer-sized passes while "
|
||||||
|
"native output is active (perf). Small-surface passes "
|
||||||
|
"(lightmap page composition) always run."));
|
||||||
|
|
||||||
|
if (ImGui::CollapsingHeader("Showcase & capture",
|
||||||
|
ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
DrawShowcaseCaptureSection();
|
||||||
|
}
|
||||||
|
if (ImGui::CollapsingHeader("Image quality",
|
||||||
|
ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
DrawImageQualitySection();
|
||||||
|
}
|
||||||
|
if (ImGui::CollapsingHeader("Lighting & post")) {
|
||||||
|
DrawLightingPostSection();
|
||||||
|
}
|
||||||
|
if (ImGui::CollapsingHeader("Shadows")) {
|
||||||
|
DrawShadowsSection();
|
||||||
|
}
|
||||||
|
if (ImGui::CollapsingHeader("World shading")) {
|
||||||
|
DrawWorldShadingSection();
|
||||||
|
}
|
||||||
|
if (ImGui::CollapsingHeader("Scene content & overlays")) {
|
||||||
|
DrawSceneContentSection();
|
||||||
|
}
|
||||||
|
if (ImGui::CollapsingHeader("Smoothness & pacing")) {
|
||||||
|
DrawPacingSection();
|
||||||
|
}
|
||||||
|
if (ImGui::CollapsingHeader("Diagnostics")) {
|
||||||
|
DrawDiagnosticsSection();
|
||||||
|
}
|
||||||
|
if (ImGui::CollapsingHeader("Caches")) {
|
||||||
|
DrawCachesSection();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
if (s_showcase_setup_open) {
|
if (s_showcase_setup_open) {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// F12 native-render debug menu: live checkboxes for every native renderer
|
// F12 native-render debug menu: live controls for every native renderer
|
||||||
// subsystem (all hot-reload cvars), used to bisect visual regressions
|
// subsystem (all hot-reload cvars), grouped by intent (capture tools,
|
||||||
// (flicker, wrong shading) in-game without rebuilds.
|
// image quality, lighting, shadows, content, diagnostics), used to bisect
|
||||||
|
// visual regressions in-game without rebuilds. Includes the max-quality
|
||||||
|
// photo-mode toggle for showcase/promo recording.
|
||||||
|
|
||||||
#include <rex/ui/imgui_dialog.h>
|
#include <rex/ui/imgui_dialog.h>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue