render: texture decode, ropa cloth timing and scene fixes
This commit is contained in:
parent
cf274e7457
commit
2ac10ead44
6 changed files with 1963 additions and 153 deletions
|
|
@ -230,6 +230,8 @@ set(SKATE3_COMMON_SOURCES
|
||||||
src/native/skate3_native_diagnostics.cpp
|
src/native/skate3_native_diagnostics.cpp
|
||||||
src/native/skate3_native_guest_read.cpp
|
src/native/skate3_native_guest_read.cpp
|
||||||
src/native/skate3_native_v3_shadow.cpp
|
src/native/skate3_native_v3_shadow.cpp
|
||||||
|
src/native/skate3_native_v3_shadow_mat.cpp
|
||||||
|
src/native/skate3_hud_tile.cpp
|
||||||
src/skate3_native_debug_dialog.cpp
|
src/skate3_native_debug_dialog.cpp
|
||||||
src/skate3_native_render.cpp
|
src/skate3_native_render.cpp
|
||||||
src/skate3_native_scene.cpp
|
src/skate3_native_scene.cpp
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@
|
||||||
// c8 the color multiplier, used exactly as staged.
|
// c8 the color multiplier, used exactly as staged.
|
||||||
cbuffer C : register(b0) {
|
cbuffer C : register(b0) {
|
||||||
float4 m[10]; // m[0..3] proj rows, m[4..7] world rows, m[8] color,
|
float4 m[10]; // m[0..3] proj rows, m[4..7] world rows, m[8] color,
|
||||||
// m[9].x = apply D3D9 half-pixel (2D ortho draws only)
|
// m[9].x = apply D3D9 half-pixel (2D ortho draws only),
|
||||||
|
// m[9].y = sharp-magnification amount (0 = plain bilinear)
|
||||||
};
|
};
|
||||||
Texture2D<float4> tex : register(t0);
|
Texture2D<float4> tex : register(t0);
|
||||||
SamplerState smp : register(s1);
|
SamplerState smp : register(s1);
|
||||||
|
|
@ -31,6 +32,67 @@ VSOut vs_main(float4 p : POSITION, float2 uv : TEXCOORD0, float4 color : COLOR0)
|
||||||
o.color = color;
|
o.color = color;
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
float4 ps_main(VSOut i) : SV_Target {
|
// Catmull-Rom reconstruction (9 bilinear fetches). Sharper interpolation
|
||||||
return tex.Sample(smp, i.uv) * m[8] * i.color;
|
// than plain bilinear for magnified art; the sharpen pass below restores
|
||||||
|
// edge contrast the source's own 1-texel antialiasing loses under
|
||||||
|
// magnification.
|
||||||
|
float4 SampleCR(float2 uv, float2 ts) {
|
||||||
|
float2 sp = uv * ts;
|
||||||
|
float2 tc = floor(sp - 0.5) + 0.5;
|
||||||
|
float2 f = sp - tc;
|
||||||
|
float2 f2 = f * f;
|
||||||
|
float2 f3 = f2 * f;
|
||||||
|
float2 w0 = f2 - 0.5 * (f3 + f);
|
||||||
|
float2 w1 = 1.5 * f3 - 2.5 * f2 + 1.0;
|
||||||
|
float2 w3 = 0.5 * (f3 - f2);
|
||||||
|
float2 w2 = 1.0 - w0 - w1 - w3;
|
||||||
|
float2 w12 = w1 + w2;
|
||||||
|
float2 t0 = (tc - 1.0) / ts;
|
||||||
|
float2 t3 = (tc + 2.0) / ts;
|
||||||
|
float2 t12 = (tc + w2 / w12) / ts;
|
||||||
|
float4 c = tex.Sample(smp, float2(t0.x, t0.y)) * (w0.x * w0.y);
|
||||||
|
c += tex.Sample(smp, float2(t12.x, t0.y)) * (w12.x * w0.y);
|
||||||
|
c += tex.Sample(smp, float2(t3.x, t0.y)) * (w3.x * w0.y);
|
||||||
|
c += tex.Sample(smp, float2(t0.x, t12.y)) * (w0.x * w12.y);
|
||||||
|
c += tex.Sample(smp, float2(t12.x, t12.y)) * (w12.x * w12.y);
|
||||||
|
c += tex.Sample(smp, float2(t3.x, t12.y)) * (w3.x * w12.y);
|
||||||
|
c += tex.Sample(smp, float2(t0.x, t3.y)) * (w0.x * w3.y);
|
||||||
|
c += tex.Sample(smp, float2(t12.x, t3.y)) * (w12.x * w3.y);
|
||||||
|
c += tex.Sample(smp, float2(t3.x, t3.y)) * (w3.x * w3.y);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
float4 ps_main(VSOut i) : SV_Target {
|
||||||
|
float4 c = tex.Sample(smp, i.uv);
|
||||||
|
// Sharp magnification (m[9].y = skate3_native_render_scene_2d_sharp):
|
||||||
|
// much of the HUD samples APT cached-bitmap tiles whose texel count
|
||||||
|
// equals their 720p display size; at 2-3x output scales they magnify
|
||||||
|
// into a soft blur under plain bilinear while atlas-glyph text (8-10
|
||||||
|
// texels per 720p pixel) stays crisp. Where the fetch is MAGNIFIED,
|
||||||
|
// reconstruct with Catmull-Rom and apply a locally-CLAMPED unsharp mask
|
||||||
|
// (no halos: the result never leaves the neighborhood's value range).
|
||||||
|
// Minified/1:1 content (density-rich atlases, replay video at 1x) is
|
||||||
|
// untouched by the magnification gate.
|
||||||
|
if (m[9].y > 0.0) {
|
||||||
|
float2 ts;
|
||||||
|
tex.GetDimensions(ts.x, ts.y);
|
||||||
|
float2 tpp = fwidth(i.uv) * ts; // texel footprint per output pixel
|
||||||
|
float mag = 1.0 / max(max(tpp.x, tpp.y), 1e-4);
|
||||||
|
if (mag > 1.25) {
|
||||||
|
float4 cr = SampleCR(i.uv, ts);
|
||||||
|
float2 px = 1.0 / ts;
|
||||||
|
float4 n0 = tex.Sample(smp, i.uv + float2(-0.5, -0.5) * px);
|
||||||
|
float4 n1 = tex.Sample(smp, i.uv + float2(0.5, -0.5) * px);
|
||||||
|
float4 n2 = tex.Sample(smp, i.uv + float2(-0.5, 0.5) * px);
|
||||||
|
float4 n3 = tex.Sample(smp, i.uv + float2(0.5, 0.5) * px);
|
||||||
|
float4 blur = (n0 + n1 + n2 + n3) * 0.25;
|
||||||
|
// Ramp in across 1.25x..2x so density-1 tiles at 2-3x output get the
|
||||||
|
// full amount while barely-magnified art is barely touched.
|
||||||
|
float amt = m[9].y * saturate((mag - 1.25) / 0.75);
|
||||||
|
float4 s = cr + (cr - blur) * amt;
|
||||||
|
float4 lo = min(min(n0, n1), min(n2, n3));
|
||||||
|
float4 hi = max(max(n0, n1), max(n2, n3));
|
||||||
|
c = clamp(s, min(lo, cr), max(hi, cr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c * m[8] * i.color;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -419,7 +419,9 @@ float4 ps_main(VSOut i) : SV_Target {
|
||||||
// proxyworld/incandescent: D^2 * scale. No shadow receive, no kd, no
|
// proxyworld/incandescent: D^2 * scale. No shadow receive, no kd, no
|
||||||
// material multiplier on the fog term.
|
// material multiplier on the fog term.
|
||||||
if (fam < 10.5) {
|
if (fam < 10.5) {
|
||||||
float3 lmg = lightmap.Sample(smp, i.uv2).rgb;
|
// Console lightmap semantics: bilinear, clamped, mip 0 (see the
|
||||||
|
// main env fetch below).
|
||||||
|
float3 lmg = lightmap.SampleLevel(smp_clamp, i.uv2, 0.0).rgb;
|
||||||
lin = dlin * max(lmg * lmg, sh_env.z) * sh_env.y;
|
lin = dlin * max(lmg * lmg, sh_env.z) * sh_env.y;
|
||||||
if (fam < 9.5) {
|
if (fam < 9.5) {
|
||||||
lin *= sh_env.w;
|
lin *= sh_env.w;
|
||||||
|
|
@ -445,7 +447,13 @@ float4 ps_main(VSOut i) : SV_Target {
|
||||||
float4 dk = overlay.w > 1.5 ? decal_art.Sample(smp, i.uv3)
|
float4 dk = overlay.w > 1.5 ? decal_art.Sample(smp, i.uv3)
|
||||||
: decal_art.Sample(smp_clamp, i.uv3);
|
: decal_art.Sample(smp_clamp, i.uv3);
|
||||||
dlin = lerp(dlin, dk.rgb * dk.rgb, dk.a);
|
dlin = lerp(dlin, dk.rgb * dk.rgb, dk.a);
|
||||||
ov = lerp(float3(1.0, 1.0, 1.0), ov, 1.0 - dk.a);
|
// The macro weathering overlay applies OVER the composited art:
|
||||||
|
// ApplyOverlay(cOverlay, ApplyDecal(...)) in the decalenvironment
|
||||||
|
// source. The previous `ov = lerp(1, ov, 1-dk.a)` fade rendered the
|
||||||
|
// paint unweathered: on the PCU Library ramp stencils the measured
|
||||||
|
// native/emulated brightness error was 1.19x at paint alpha~1,
|
||||||
|
// 1.05x at ~0.35 and 1.0x off-patch: exactly 1/ov for ov~0.84,
|
||||||
|
// the no-fade model (measured from a matched A/B capture pair).
|
||||||
}
|
}
|
||||||
float3 dcol = dlin * ov;
|
float3 dcol = dlin * ov;
|
||||||
// CSM shadow term s = sat(infront + 1 - coverage) from the native
|
// CSM shadow term s = sat(infront + 1 - coverage) from the native
|
||||||
|
|
@ -495,7 +503,12 @@ float4 ps_main(VSOut i) : SV_Target {
|
||||||
if (abs(misc.z - 9.0) < 0.5) {
|
if (abs(misc.z - 9.0) < 0.5) {
|
||||||
return float4(tint.r, 0.0, 1.0 - tint.r, 1.0);
|
return float4(tint.r, 0.0, 1.0 - tint.r, 1.0);
|
||||||
}
|
}
|
||||||
float3 lml = min(lmg * lmg, s + sh_color.rgb);
|
// tint.r == 0 = the real lightmap has not resolved yet (first-sight
|
||||||
|
// decode in flight; t1 = the white fallback). Min-clamping the
|
||||||
|
// fallback against the CSM term rendered in-shadow surfaces as BLACK
|
||||||
|
// patches for the decode window (the ramp-stencil "black square
|
||||||
|
// flash"); serve unshadowed brightness until the real page lands.
|
||||||
|
float3 lml = tint.r > 0.0 ? min(lmg * lmg, s + sh_color.rgb) : lmg * lmg;
|
||||||
// GetTangentLight with the neutral (flat) normal map:
|
// GetTangentLight with the neutral (flat) normal map:
|
||||||
// 0.39 * 2.39562 exactly. Fam 13 has no kd term at all; its body is
|
// 0.39 * 2.39562 exactly. Fam 13 has no kd term at all; its body is
|
||||||
// D^2 * lml * ALPHA, premultiplied once in the shader on top of the
|
// D^2 * lml * ALPHA, premultiplied once in the shader on top of the
|
||||||
|
|
@ -642,6 +655,24 @@ float4 ps_main(VSOut i) : SV_Target {
|
||||||
float3 cce = saturate(sqrt(max(tme * 0.5, 0.0)) * 1.41);
|
float3 cce = saturate(sqrt(max(tme * 0.5, 0.0)) * 1.41);
|
||||||
return float4(cce, out_a);
|
return float4(cce, out_a);
|
||||||
}
|
}
|
||||||
|
// environment.decal surfaces: the paint/graffiti art (t4) is composited
|
||||||
|
// over the base diffuse by ITS alpha, opaque output; these meshes ARE
|
||||||
|
// the wall/ground there. The art maps with uv3, the second half-pair of
|
||||||
|
// the packed half4 first texcoord (validated offline: sampling with the
|
||||||
|
// tiling uv0 repeats it: "Stereo Stereo Stereo"; the fmt-26 second
|
||||||
|
// element is the lightmap unwrap, not the decal's). Composited BEFORE the
|
||||||
|
// macro overlay: the weathering applies over the paint too
|
||||||
|
// (ApplyOverlay(cOverlay, ApplyDecal(...)); the old order left the paint
|
||||||
|
// unweathered, the too-white ramp stencils).
|
||||||
|
if (overlay.w > 0.0) {
|
||||||
|
// overlay.w == 2 marks environment.decal_tileable: the art tiles across
|
||||||
|
// the surface (rock/cliff faces) and must WRAP; clamp stretched the
|
||||||
|
// border texels into giant streaks. Single placements clamp (their
|
||||||
|
// transparent border keeps everything outside the placement clear).
|
||||||
|
float4 dk = overlay.w > 1.5 ? decal_art.Sample(smp, i.uv3)
|
||||||
|
: decal_art.Sample(smp_clamp, i.uv3);
|
||||||
|
albedo.rgb = lerp(albedo.rgb, dk.rgb, dk.a);
|
||||||
|
}
|
||||||
// Macro overlay: large-scale grime/cracks multiplied over the diffuse at
|
// Macro overlay: large-scale grime/cracks multiplied over the diffuse at
|
||||||
// uv * macroOverlayUVScale, faded by macroOverlayOpacity: the ground and
|
// uv * macroOverlayUVScale, faded by macroOverlayOpacity: the ground and
|
||||||
// wall weathering. WHITE is the neutral (materials without weathering
|
// wall weathering. WHITE is the neutral (materials without weathering
|
||||||
|
|
@ -653,21 +684,6 @@ float4 ps_main(VSOut i) : SV_Target {
|
||||||
float4 m = macro.Sample(smp, i.uv * overlay.x);
|
float4 m = macro.Sample(smp, i.uv * overlay.x);
|
||||||
albedo.rgb *= lerp(float3(1.0, 1.0, 1.0), sqrt(m.rgb), overlay.y * m.a);
|
albedo.rgb *= lerp(float3(1.0, 1.0, 1.0), sqrt(m.rgb), overlay.y * m.a);
|
||||||
}
|
}
|
||||||
// environment.decal surfaces: the paint/graffiti art (t4) is composited
|
|
||||||
// over the base diffuse by ITS alpha, opaque output; these meshes ARE
|
|
||||||
// the wall/ground there. The art maps with uv3, the second half-pair of
|
|
||||||
// the packed half4 first texcoord (validated offline: sampling with the
|
|
||||||
// tiling uv0 repeats it: "Stereo Stereo Stereo"; the fmt-26 second
|
|
||||||
// element is the lightmap unwrap, not the decal's).
|
|
||||||
if (overlay.w > 0.0) {
|
|
||||||
// overlay.w == 2 marks environment.decal_tileable: the art tiles across
|
|
||||||
// the surface (rock/cliff faces) and must WRAP; clamp stretched the
|
|
||||||
// border texels into giant streaks. Single placements clamp (their
|
|
||||||
// transparent border keeps everything outside the placement clear).
|
|
||||||
float4 dk = overlay.w > 1.5 ? decal_art.Sample(smp, i.uv3)
|
|
||||||
: decal_art.Sample(smp_clamp, i.uv3);
|
|
||||||
albedo.rgb = lerp(albedo.rgb, dk.rgb, dk.a);
|
|
||||||
}
|
|
||||||
// tint.r > 0 marks items with a lightmap bound (2x baked lighting);
|
// tint.r > 0 marks items with a lightmap bound (2x baked lighting);
|
||||||
// otherwise fall back to derivative face shading. The lighting term stays
|
// otherwise fall back to derivative face shading. The lighting term stays
|
||||||
// separate from the albedo so the CSM receive below can min-clamp IT, the
|
// separate from the albedo so the CSM receive below can min-clamp IT, the
|
||||||
|
|
@ -676,7 +692,10 @@ float4 ps_main(VSOut i) : SV_Target {
|
||||||
if (tint.b > 0.0) {
|
if (tint.b > 0.0) {
|
||||||
light = float3(1.0, 1.0, 1.0); // unlit (sky dome)
|
light = float3(1.0, 1.0, 1.0); // unlit (sky dome)
|
||||||
} else if (tint.r > 0.0) {
|
} else if (tint.r > 0.0) {
|
||||||
light = lightmap.Sample(smp, i.uv2).rgb * 2.0;
|
// Console lightmap semantics: bilinear, clamped, mip 0; the composed
|
||||||
|
// atlas pages are single-level; mip/wrap sampling bled neighbor cells
|
||||||
|
// and page edges (see the exact env fetch).
|
||||||
|
light = lightmap.SampleLevel(smp_clamp, i.uv2, 0.0).rgb * 2.0;
|
||||||
} else {
|
} else {
|
||||||
// Smooth per-vertex normal when the mesh has one; face normal from
|
// Smooth per-vertex normal when the mesh has one; face normal from
|
||||||
// position derivatives otherwise.
|
// position derivatives otherwise.
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,10 @@
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
// Xbox-controller capture combos (see the hotkey block): the artifacts under
|
||||||
|
// investigation are too brief to reach the keyboard from the pad.
|
||||||
|
#include <Xinput.h>
|
||||||
|
#pragma comment(lib, "xinput9_1_0.lib")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <rex/cvar.h>
|
#include <rex/cvar.h>
|
||||||
|
|
@ -366,6 +370,17 @@ void OnFrameEnd(uint8_t* base) {
|
||||||
REXLOG_INFO("native-render: F8, texture + mesh caches flushed");
|
REXLOG_INFO("native-render: F8, texture + mesh caches flushed");
|
||||||
}
|
}
|
||||||
f8_was_down = f8_down;
|
f8_was_down = f8_down;
|
||||||
|
// F7: dump the rolling scene-composition ring (last ~900 frames of
|
||||||
|
// per-item signatures); press within a few seconds of SEEING a 1-2
|
||||||
|
// frame artifact; diffing the artifact frame against neighbors in the
|
||||||
|
// CSV names the item that flashed.
|
||||||
|
static bool f7_was_down = false;
|
||||||
|
const bool f7_down = (GetAsyncKeyState(VK_F7) & 0x8000) != 0;
|
||||||
|
if (f7_down && !f7_was_down) {
|
||||||
|
skate3::native_scene::RequestSceneRingDump();
|
||||||
|
REXLOG_INFO("native-render: F7, scene ring dump requested");
|
||||||
|
}
|
||||||
|
f7_was_down = f7_down;
|
||||||
static bool f10_was_down = false;
|
static bool f10_was_down = false;
|
||||||
const bool f10_down = (GetAsyncKeyState(VK_F10) & 0x8000) != 0;
|
const bool f10_down = (GetAsyncKeyState(VK_F10) & 0x8000) != 0;
|
||||||
if (f10_down && !f10_was_down) {
|
if (f10_down && !f10_was_down) {
|
||||||
|
|
@ -377,6 +392,47 @@ void OnFrameEnd(uint8_t* base) {
|
||||||
g_frame_index);
|
g_frame_index);
|
||||||
}
|
}
|
||||||
f10_was_down = f10_down;
|
f10_was_down = f10_down;
|
||||||
|
// Xbox controller capture combos (the artifacts are too brief to reach
|
||||||
|
// the keyboard from the pad): RB+X = F10-style immediate capture,
|
||||||
|
// RB+A = F7 scene-ring dump (retroactive ~17 s, so a slightly late
|
||||||
|
// press still contains the flash frame). Pad 0; disconnected pads
|
||||||
|
// re-probe on a backoff; XInputGetState is slow for absent devices.
|
||||||
|
{
|
||||||
|
static bool combo_x_was = false;
|
||||||
|
static bool combo_a_was = false;
|
||||||
|
static uint32_t pad_retry = 0;
|
||||||
|
static bool pad_seen = true;
|
||||||
|
if (pad_seen || ++pad_retry >= 240) {
|
||||||
|
pad_retry = 0;
|
||||||
|
XINPUT_STATE xs{};
|
||||||
|
if (XInputGetState(0, &xs) == ERROR_SUCCESS) {
|
||||||
|
pad_seen = true;
|
||||||
|
const WORD b = xs.Gamepad.wButtons;
|
||||||
|
const bool rb = (b & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0;
|
||||||
|
const bool cx = rb && (b & XINPUT_GAMEPAD_X) != 0;
|
||||||
|
const bool ca = rb && (b & XINPUT_GAMEPAD_A) != 0;
|
||||||
|
if (cx && !combo_x_was) {
|
||||||
|
g_collecting = true;
|
||||||
|
g_immediate = true;
|
||||||
|
g_collect_counter = 0;
|
||||||
|
skate3::native_scene::StartRecording(1);
|
||||||
|
REXLOG_INFO(
|
||||||
|
"native-render snapshot: RB+X, immediate single-frame capture "
|
||||||
|
"at frame {}",
|
||||||
|
g_frame_index);
|
||||||
|
}
|
||||||
|
combo_x_was = cx;
|
||||||
|
if (ca && !combo_a_was) {
|
||||||
|
skate3::native_scene::RequestSceneRingDump();
|
||||||
|
REXLOG_INFO("native-render: RB+A, scene ring dump requested");
|
||||||
|
}
|
||||||
|
combo_a_was = ca;
|
||||||
|
} else {
|
||||||
|
pad_seen = false;
|
||||||
|
combo_x_was = combo_a_was = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// P: cycle the synthetic camera pan probe (judder isolation: a host-
|
// P: cycle the synthetic camera pan probe (judder isolation: a host-
|
||||||
// driven constant-rate pan injected at a selectable pipeline stage; see
|
// driven constant-rate pan injected at a selectable pipeline stage; see
|
||||||
|
|
@ -904,3 +960,42 @@ extern "C" REX_FUNC(sub_82B79FC0) {
|
||||||
skate3::native_scene::OnDrawDone(base, 2, r4, r5, r6, ctx.r3.u32 != 0 ? ctx.r3.u32 : r7);
|
skate3::native_scene::OnDrawDone(base, 2, r4, r5, r6, ctx.r3.u32 != 0 ? ctx.r3.u32 : r7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- v3 shadow-mat reader hooks (observers only; see
|
||||||
|
// native/skate3_native_v3_shadow_mat.h). Declared here instead of including
|
||||||
|
// the header so this section is a pure append.
|
||||||
|
|
||||||
|
namespace skate3::native_v3_mat {
|
||||||
|
void OnConstantTable(uint8_t* base, uint32_t table, uint32_t count);
|
||||||
|
} // namespace skate3::native_v3_mat
|
||||||
|
|
||||||
|
// renderengine::ProgramBuffer::Xbox2CreateConstantTable: builds a shader's
|
||||||
|
// 8-byte {name, register, dataType, numConstants} record array. Register
|
||||||
|
// conventions VERIFIED in generated/skate3_recomp.60.cpp:37720: ENTRY r3 =
|
||||||
|
// shader-blob holder (+16 = CTAB rel offset), r4 = destination record array
|
||||||
|
// (NULL on the sizing pass: the Initialize caller at .60.cpp:38221 passes
|
||||||
|
// ProgramBuffer + *(u32*)(PB+8) + 20 on the fill pass and stores the return
|
||||||
|
// count at PB+4), r5 = out name-bytes; EXIT r3 = record count. Firing once
|
||||||
|
// per shader table as it is built gives the reflect reader every table with
|
||||||
|
// no ProgramBuffer back-pointer needed.
|
||||||
|
extern "C" REX_FUNC(sub_82A77EA0) {
|
||||||
|
const uint32_t table = ctx.r4.u32;
|
||||||
|
__imp__sub_82A77EA0(ctx, base);
|
||||||
|
if (skate3::native_render::Enabled()) {
|
||||||
|
skate3::native_v3_mat::OnConstantTable(base, table, ctx.r3.u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LivingWorld batch pack writer (unnamed; called per entity per sim tick
|
||||||
|
// from the tail of cLivingWorldPresEntityManager::Update), the LOD-
|
||||||
|
// pedestrian skinning-palette source: fused UpdateBoneTransforms+Pack writing the
|
||||||
|
// concatenated per-mesh 4x3 palettes into cModelInstance.m_matrices. r3 =
|
||||||
|
// the cLivingWorldPresEntity-derived entity; post-call m_matrices holds the
|
||||||
|
// packed rows.
|
||||||
|
extern "C" REX_FUNC(sub_827C1D38) {
|
||||||
|
const uint32_t entity = ctx.r3.u32;
|
||||||
|
__imp__sub_827C1D38(ctx, base);
|
||||||
|
if (skate3::native_render::Enabled()) {
|
||||||
|
skate3::native_v3::OnLwPack(base, entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -139,6 +139,21 @@ struct DrawItem {
|
||||||
// Detected via the AttribulatorMaterialName channel; consumed by
|
// Detected via the AttribulatorMaterialName channel; consumed by
|
||||||
// CaptureSkinnedState.
|
// CaptureSkinnedState.
|
||||||
bool ropa;
|
bool ropa;
|
||||||
|
// ROPA shape blending (set by InterpolateDynamicItems): decoded shape
|
||||||
|
// generations (DynDecodeJob seq) + weights reproducing the SAME temporal
|
||||||
|
// kernel the body bones / garment world were evaluated with this frame:
|
||||||
|
// the 8-tap boxcar when the world took it, else the plain bracketing
|
||||||
|
// lerp. shape_count == 0 = no pairing this frame (draw the newest cached
|
||||||
|
// decode). The stepped cloth shape against the interpolated body was the
|
||||||
|
// tee jelly/clip-through (worse at LOWER fps: the excursion scales with
|
||||||
|
// the guest period); a plain 2-generation lerp against the BOXCAR-
|
||||||
|
// filtered body left the same period-scaled mismatch; the two filters
|
||||||
|
// answer the same 60 Hz limb signal with different frequency responses,
|
||||||
|
// so the kernels must match exactly.
|
||||||
|
static constexpr int kShapeGens = 10;
|
||||||
|
uint64_t shape_seq[kShapeGens] = {};
|
||||||
|
float shape_w[kShapeGens] = {};
|
||||||
|
int shape_count = 0;
|
||||||
// Exact world-material shading family, classified from
|
// Exact world-material shading family, classified from
|
||||||
// AttribulatorMaterialName (models verified against the game's own pixel
|
// AttribulatorMaterialName (models verified against the game's own pixel
|
||||||
// shaders):
|
// shaders):
|
||||||
|
|
@ -447,6 +462,13 @@ int CycleSyntheticPan();
|
||||||
// shows whether the game's own pose sequence is irregular at the source.
|
// shows whether the game's own pose sequence is irregular at the source.
|
||||||
void RecordCameraSignal(double seconds);
|
void RecordCameraSignal(double seconds);
|
||||||
|
|
||||||
|
// F7: dump the rolling per-frame scene-composition ring (one compact
|
||||||
|
// signature per item per frame for the last ~900 frames) to
|
||||||
|
// logs/scene_ring_<ts>.csv on the render thread's next frame. Diffing the
|
||||||
|
// artifact frame against its neighbors names exactly which item appeared /
|
||||||
|
// vanished / changed textures during a 1-2 frame flash no capture can catch.
|
||||||
|
void RequestSceneRingDump();
|
||||||
|
|
||||||
// Bone-signal recorder (wheel-guard diagnosis): for `seconds`, records every
|
// Bone-signal recorder (wheel-guard diagnosis): for `seconds`, records every
|
||||||
// raw entity pose (ring pushes: bone palettes / rigid worlds, timestamps)
|
// raw entity pose (ring pushes: bone palettes / rigid worlds, timestamps)
|
||||||
// and each frame's interpolated output, then writes
|
// and each frame's interpolated output, then writes
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue