Warp: faithful POVTranslocateRenderable -- eye-centered, ramp color, no spin
Deep-dived the authentic engine effect (L4VIDRND.cpp POVTranslocateRenderable, T0)
and reworked our one-shot to match it, fixing the user's "blob from my own POV /
not aligned to my orientation" + "gray, not blue" reports:
1. PLACEMENT was the misalignment. The engine parents the sphere to the VTV/eye
("rotated and scaled around the VTV", L4VIDRND.cpp:1812) -- it is centered on and
oriented to the viewpoint. We world-fixed it at the mech's feet, so from your own
camera it sat off-axis and, once expanded, engulfed the eye as a shapeless blob.
Now: the own-respawn warp (BTStartWarpEffectPOV, from btplayer) uses
world = Scale(s) * inverse(view) -> centered on + carried by your eye (the tunnel
wraps you). Observing a PEER (BTStartWarpEffect from mechdmg) stays world-anchored
at the peer's point.
2. GEOMETRY SPIN was inauthentic. myRotateY/myRotateYSpeed are set in the engine
ctor but NEVER applied -- the swirl's rotation is entirely the material's texture
SCROLL (bintA, SCROLL 0.0 0.0 0.1 0.5). Dropped our world-Y geometry spin.
3. COLOR (gray) fixed at the source. The blue/white is the "sky" RAMP remapping the
grayscale bintA cloud per-texel (argb=lerp(0,0,0.6 -> .99,.99,.99, luminance),
L4D3D.cpp:480). The port bakes exactly this but GATED it off for normal-bearing
meshes; tsphere has normals so it arrived raw gray, and a MODULATE tint can't add
the blue floor (it only multiplies) -> the wash-out. Un-gate the ramp for
tsphere_mtl (bgfload.cpp) so the bound texture is already the blue-white swirl;
draw it MODULATE by white (no tint), alpha from TFACTOR.
4. SCALE to authentic 100 (collapse) / 150 (expand end) -- correct now that it's
eye-centered (you're meant to be inside it as it collapses through you and blasts
back open, the "blast off into the distance").
Still deferred (higher risk / SimulationState-coupling trap): the WaitForReincarnate
Lissajous wobble + the SetIsDead world-mask (black-out during the dead hold). Noted
for follow-up; the placement/color/motion are the parts the user flagged.
Smoke-verified 2-node: own respawn logs POV(eye), observer logs world-anchored, no
crash. BT_WARP_ADDITIVE / BT_WARP_COLOR / BT_WARP_SCALE remain as live tuning knobs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
160b78e38d
commit
a9d1534292
@@ -500,6 +500,7 @@ struct Builder {
|
||||
float currentLodBias = 0.0f; // (retained; per-batch bias now set in buildPmesh)
|
||||
bool currentPunch = false; // inside a PUNCH patch (SV_SPECIAL 0x2037, geogroup level)
|
||||
bool currentShadowMat = false; // material name contains "shadow" (baked ground-shadow quads)
|
||||
bool currentTSphere = false; // material is tsphere_mtl (translocation warp): ramp it despite normals
|
||||
bool currentHasEmissive = false;
|
||||
float currentEmissive[3] = {0,0,0};
|
||||
|
||||
@@ -561,7 +562,7 @@ struct Builder {
|
||||
// TRUECOLOR BSL slices (channel >= 6: RGB444/RGBA4444, e.g. damcolor's bdam8
|
||||
// damage sheet) are real colour images -- luminance-ramping them would
|
||||
// destroy their colour, so they take the plain textured path.
|
||||
const bool useRamp = currentHasRamp && !hasNormals(vtag) && currentTexChannel < 6;
|
||||
const bool useRamp = currentHasRamp && (!hasNormals(vtag) || currentTSphere) && currentTexChannel < 6;
|
||||
|
||||
const uint32_t base = (uint32_t)px.size();
|
||||
const uint32_t localCount = (uint32_t)lx.size();
|
||||
@@ -865,6 +866,7 @@ struct Builder {
|
||||
bool savedHasRamp = currentHasRamp;
|
||||
bool savedPunch = currentPunch;
|
||||
bool savedShadowMat = currentShadowMat;
|
||||
bool savedTSphere = currentTSphere;
|
||||
bool savedHasEmissive = currentHasEmissive;
|
||||
float savedEmissive[3] = { currentEmissive[0], currentEmissive[1], currentEmissive[2] };
|
||||
float savedRampLo[3] = { currentRampLo[0], currentRampLo[1], currentRampLo[2] };
|
||||
@@ -889,6 +891,12 @@ struct Builder {
|
||||
currentShadowMat = false;
|
||||
for (size_t si = 0; si + 6 <= full.size(); ++si)
|
||||
if (_strnicmp(full.c_str() + si, "shadow", 6) == 0) { currentShadowMat = true; break; }
|
||||
// The translocation warp sphere (tsphere_mtl): its swirl COLOUR is
|
||||
// the "sky" ramp remapping the grayscale bintA cloud, but tsphere.bgf
|
||||
// carries vertex normals so the normals-gate below would skip the ramp
|
||||
// and leave it raw gray. Flag it so the ramp bake runs anyway (the
|
||||
// authentic look; matches L4VIDRND POVTranslocateRenderable).
|
||||
currentTSphere = (full.find("tsphere_mtl") != std::string::npos);
|
||||
currentHasRamp = false;
|
||||
if (res) {
|
||||
MatInfo info = res->resolve(full);
|
||||
@@ -911,6 +919,7 @@ struct Builder {
|
||||
currentHasRamp = savedHasRamp;
|
||||
currentPunch = savedPunch;
|
||||
currentShadowMat = savedShadowMat;
|
||||
currentTSphere = savedTSphere;
|
||||
currentHasEmissive = savedHasEmissive;
|
||||
for (int i = 0; i < 3; ++i) currentEmissive[i] = savedEmissive[i];
|
||||
for (int i = 0; i < 3; ++i) { currentRampLo[i] = savedRampLo[i]; currentRampHi[i] = savedRampHi[i]; }
|
||||
|
||||
Reference in New Issue
Block a user