fix(core): ACME cross-check fixes — normals, placement, scenery
Four fixes from the ACME StaticObjectManager cross-reference: 1. GfxObjMesh: normalize vertex normals (1d). Dat normals may not be unit-length; without normalization, lighting is wrong per-vertex. 2. SetupMesh: add third-fallback placement frame (2a). If neither Resting nor Default exists, use the first available frame from PlacementFrames. Matches ACME's GetDefaultPlacementFrame. 3. SceneryGenerator: building cell exclusion (4d). Compute which terrain vertices have buildings (from LandBlockInfo.Objects + Buildings), skip scenery spawns in those cells. Prevents trees from spawning inside building footprints. 4. SceneryGenerator: slope filter (4e). Compute terrain normal Z at each displaced position and check against ObjectDesc.MinSlope / MaxSlope bounds. Prevents trees from spawning on cliff faces. Also confirmed 4f (scenery Z=0) is NOT a bug — GameWindow's hydrator lifts scenery to terrain Z at line 1213. The Z=0 in SceneryGenerator is a placeholder correctly overridden at render time. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
05749f52e0
commit
9d4967a461
4 changed files with 61 additions and 7 deletions
|
|
@ -1154,8 +1154,30 @@ public sealed class GameWindow : IDisposable
|
|||
var region = _dats.Get<DatReaderWriter.DBObjs.Region>(0x13000000u);
|
||||
if (region is null) return result;
|
||||
|
||||
// Build a set of terrain vertex indices that have buildings on them,
|
||||
// so the scenery generator can skip those cells (ACME conformance fix 4d).
|
||||
HashSet<int>? buildingCells = null;
|
||||
var lbInfo = _dats.Get<DatReaderWriter.DBObjs.LandBlockInfo>(
|
||||
(lb.LandblockId & 0xFFFF0000u) | 0xFFFEu);
|
||||
if (lbInfo is not null)
|
||||
{
|
||||
buildingCells = new HashSet<int>();
|
||||
foreach (var stab in lbInfo.Objects)
|
||||
{
|
||||
int cx = Math.Clamp((int)(stab.Frame.Origin.X / 24f), 0, 8);
|
||||
int cy = Math.Clamp((int)(stab.Frame.Origin.Y / 24f), 0, 8);
|
||||
buildingCells.Add(cx * 9 + cy);
|
||||
}
|
||||
foreach (var bldg in lbInfo.Buildings)
|
||||
{
|
||||
int cx = Math.Clamp((int)(bldg.Frame.Origin.X / 24f), 0, 8);
|
||||
int cy = Math.Clamp((int)(bldg.Frame.Origin.Y / 24f), 0, 8);
|
||||
buildingCells.Add(cx * 9 + cy);
|
||||
}
|
||||
}
|
||||
|
||||
var spawns = AcDream.Core.World.SceneryGenerator.Generate(
|
||||
_dats, region, lb.Heightmap, lb.LandblockId);
|
||||
_dats, region, lb.Heightmap, lb.LandblockId, buildingCells, _heightTable);
|
||||
if (spawns.Count == 0) return result;
|
||||
|
||||
var lbOffset = new System.Numerics.Vector3(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue