fix(hero): export smoothing groups; give the facade real collision
UE export hygiene (unreal-export skill checklist) plus a gameplay defect the new probe caught: - FBX export now uses mesh_smooth_type="FACE" (was OFF, which is why every import logged "No smoothing group information was found"), and the round parts are shaded with shade_smooth_by_angle(35 deg) before export, so columns and medallions read round instead of faceted. - SM_HeroFacade had complex-only collision, so capsule sweeps and line traces passed through the wall: the player could walk through the hero facade. auto_generate_collision was tried and rejected (coarse hulls bulged into the street; the QA wall probe went 0/35 -> 2/35). It now uses UseComplexAsSimple, saved on the asset, like the terrain. - New -qaselftest facade occlusion probe: 40 m traces sideways from the road centre at walking height, required only where a building is staged (explicit X spans mirroring ue_build_demo_map). Result 0/9 -> PASS, alongside transect 0 holes and wall probe 0/35. Docs: release-checks records the probe and both collision attempts; Tools/README lists the new phase; MEMORY records the smoothing/collision lessons.
This commit is contained in:
1 parent
70c6e322e2
commit
160e9144f9
32 files changed
+166
-45
No files matched your search
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -416,6 +416,81 @@ void AGigLineCharacter::StartQASelfTest()
|
||||
TEXT("GigLine QA: wall probe %d/%d traces with blocking hit inside 21 m -> %s"),
|
||||
Walls, WallSamples,
|
||||
Walls == 0 ? TEXT("PASS") : TEXT("FAIL"));
|
||||
|
||||
// Facade occlusion probe: walkable street is only half the story —
|
||||
// the player must also NOT be able to walk through the buildings.
|
||||
// From the road centre, fire 40 m sideways at walking height toward
|
||||
// each frontage and require a blocking hit. A miss means the
|
||||
// building has no collision (or only non-blocking collision) and the
|
||||
// player would pass through the wall.
|
||||
// Expect a wall only where the map actually stages a building.
|
||||
// Spans below mirror the actors placed by Tools/ue_build_demo_map.py
|
||||
// (frontage + hero) and the two north buildings; update them if
|
||||
// that list changes. Gaps between buildings are legitimate misses.
|
||||
struct FSpan { float Min, Max; };
|
||||
static const FSpan SouthSpans[] = {
|
||||
{-24276.f, -17700.f}, // 6922
|
||||
{-17749.f, -14591.f}, // 6902
|
||||
{-14638.f, -12034.f}, // 6840 hero
|
||||
{-12082.f, -8210.f}, // 6838 El Capitan Theatre
|
||||
{-7854.f, -7252.f}, // 6822 Budget
|
||||
{-6608.f, -3307.f}, // 6806-6820
|
||||
{-3320.f, -1437.f}, // 6800 Lee Drug
|
||||
};
|
||||
static const FSpan NorthSpans[] = {
|
||||
{-27071.f, -22799.f}, // Madame Tussaud's
|
||||
{-22889.f, -18442.f}, // TCL Chinese Theatre
|
||||
};
|
||||
auto InSpans = [](const FSpan* Spans, int32 Count, float X)
|
||||
{
|
||||
for (int32 i = 0; i < Count; ++i)
|
||||
{
|
||||
if (X >= Spans[i].Min && X <= Spans[i].Max) { return true; }
|
||||
}
|
||||
return false;
|
||||
};
|
||||
int32 Facades = 0, FacadeSamples = 0;
|
||||
for (float X0 = -19000.0f; X0 <= -3000.0f; X0 += 2000.0f)
|
||||
{
|
||||
for (float Dir : {1.0f, -1.0f}) // +Y south frontage, -Y north side
|
||||
{
|
||||
const bool bExpectWall = (Dir > 0.0f)
|
||||
? InSpans(SouthSpans, UE_ARRAY_COUNT(SouthSpans), X0)
|
||||
: InSpans(NorthSpans, UE_ARRAY_COUNT(NorthSpans), X0);
|
||||
if (!bExpectWall)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
FHitResult GroundHit2;
|
||||
FCollisionQueryParams GQ2(TEXT("GigLineFacadeGround"), false, this);
|
||||
if (!W->LineTraceSingleByChannel(GroundHit2,
|
||||
FVector(X0, 0.0f, 3000.f), FVector(X0, 0.0f, -1000.f),
|
||||
ECC_Visibility, GQ2))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const float ProbeZ2 = GroundHit2.ImpactPoint.Z + 160.f;
|
||||
FHitResult Hit2;
|
||||
FCollisionQueryParams Q2(TEXT("GigLineFacadeProbe"), false, this);
|
||||
const bool bHit2 = W->LineTraceSingleByChannel(Hit2,
|
||||
FVector(X0, 0.0f, ProbeZ2),
|
||||
FVector(X0, Dir * 4000.f, ProbeZ2),
|
||||
ECC_Visibility, Q2);
|
||||
++FacadeSamples;
|
||||
const bool bBlocking = bHit2 && Hit2.GetActor() != nullptr;
|
||||
if (!bBlocking)
|
||||
{
|
||||
++Facades;
|
||||
UE_LOG(LogTemp, Log,
|
||||
TEXT("GigLine QA: facade probe miss at X %.0f dir %.0f (no blocking hit in 40 m)"),
|
||||
X0, Dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
UE_LOG(LogTemp, Log,
|
||||
TEXT("GigLine QA: facade probe %d/%d directions without a blocking wall -> %s"),
|
||||
Facades, FacadeSamples,
|
||||
Facades == 0 ? TEXT("PASS") : TEXT("FAIL"));
|
||||
}
|
||||
|
||||
// 7.0: verdict, then stop ticking.
|
||||
|
||||
Reference in new issue
Block a user