diff --git a/docs/formats/pmo.md b/docs/formats/pmo.md index 693b6eac..c4dec30f 100644 --- a/docs/formats/pmo.md +++ b/docs/formats/pmo.md @@ -22,7 +22,7 @@ from [mhff](https://github.com/svanheulen/mhff) by Seth VanHeulen. | 0x00 | `char[4]` | `pmo\0` | | 0x04 | `char[4]` | Version, `1.0\0` or `102\0` | | 0x08 | `u32` | Size: header, tables and geometry region. Bytes after it are the tail | -| 0x0C | `f32` | Clip distance; MHFU sets the largest scale component | +| 0x0C | `f32` | Cull-sphere radius before the entity's scale; MHFU sets the largest scale component, and 0 culls the model as a point | | 0x10 | `f32[3]` | Scale (MHFU): multiplies the dequantised positions | | 0x1C | `u16` | Mesh count | | 0x1E | `u16` | Material count | diff --git a/packages/mhfu-port/src/mhfu_port/mesh.py b/packages/mhfu-port/src/mhfu_port/mesh.py index 6b0e9a3a..c0c2f013 100644 --- a/packages/mhfu-port/src/mhfu_port/mesh.py +++ b/packages/mhfu-port/src/mhfu_port/mesh.py @@ -25,7 +25,6 @@ BLEND = 0 SHADOW = 0 COLOR = 0xFFFFFFFF -CLIP = 0.0 NO_NORMAL = (0.0, 0.0, 0.0) """Written for a donor vertex that carries no normal.""" @@ -162,7 +161,8 @@ def build(skinned: Sequence[Skinned], scale: Vec3) -> pmo.Pmo: groups = [group(s, scale, material_of[s.part.texture]) for s in skinned] mesh = pmo.Mesh(groups, list(range(len(textures))), lighting=LIGHTING, blend=BLEND) materials = [pmo.Material(color=COLOR, shadow=SHADOW, texture=t) for t in textures] - return pmo.Pmo([mesh], materials, scale, CLIP) + # the engine's cull sphere (Pmo.clip): 0 culls the model as a point near its feet + return pmo.Pmo([mesh], materials, scale, max(scale)) def group(skinned: Skinned, scale: Vec3, material: int = 0) -> pmo.Group: diff --git a/packages/mhfu-port/tests/test_build.py b/packages/mhfu-port/tests/test_build.py index 20474f01..0610115a 100644 --- a/packages/mhfu-port/tests/test_build.py +++ b/packages/mhfu-port/tests/test_build.py @@ -17,8 +17,8 @@ PORTS = Path(__file__).parents[3] / "ports" BUILT = { - "brute_tigrex": "a882bf01daf07df844a07da32fd6ff87ed10c9ecb1fec7e1eb207172e6ca5e29", - "zinogre": "3a0b11b7556678c66364d3357107a8ee130677d2c5fde9a43c7dfd5f82948f12", + "brute_tigrex": "1082b88cfaeee3086020a6b02ff59101dec4af8653ff44a4b56373a90ae87fae", + "zinogre": "830a4c15ed67a8760c0462fa8bcd5fc6548ca0b00b090089bb6d382c5e5e2256", } """sha256 of each manifest's build: changes only with an intended change to the port.""" HEAD = '[port]\nname = "t"\nhost_species = 75\npac = "t.bin"\n[source]\nmodel = 5248\n' diff --git a/packages/mhfu-port/tests/test_mesh.py b/packages/mhfu-port/tests/test_mesh.py index 1a0167e8..2c36a802 100644 --- a/packages/mhfu-port/tests/test_mesh.py +++ b/packages/mhfu-port/tests/test_mesh.py @@ -131,7 +131,7 @@ def test_build(): joint_of = {4: 1, 7: 2, 9: 3} built = mesh.build(skin.source(parts, joint_of), SCALE) back = fu.Pmo.from_bytes(built.to_bytes()) - assert back == built and back.clip == mesh.CLIP and back.scale == SCALE + assert back == built and back.clip == max(SCALE) and back.scale == SCALE assert [m.texture for m in back.materials] == [2, 6] assert {(m.color, m.shadow) for m in back.materials} == {(mesh.COLOR, mesh.SHADOW)} assert back.meshes[0].materials == [0, 1] and back.meshes[0].lighting == mesh.LIGHTING @@ -163,8 +163,8 @@ def test_palette_limit(): DONORS = { # model, geometry: groups, vertices, triangles, sha256 of our PMO on an identity map - "brute": (5248, 5249, 88, 2862, 2973, "cb0d830eb6c61a09"), - "zinogre": (5339, 5340, 181, 4336, 4426, "98b3869f594ce302"), + "brute": (5248, 5249, 88, 2862, 2973, "ccc9f32546fdfcbb"), + "zinogre": (5339, 5340, 181, 4336, 4426, "09fd2847cff33e01"), } diff --git a/packages/mhp-formats/src/mhp_formats/pmo.py b/packages/mhp-formats/src/mhp_formats/pmo.py index f466166c..e0259355 100644 --- a/packages/mhp-formats/src/mhp_formats/pmo.py +++ b/packages/mhp-formats/src/mhp_formats/pmo.py @@ -536,7 +536,8 @@ class Pmo: scale: Vec3 = (1.0, 1.0, 1.0) """Multiplies the dequantised positions.""" clip: float = 0.0 - """Clipping distance; MHFU sets it to the largest scale component.""" + """Cull-sphere radius before the entity's scale, centred half a `scale.y` up; MHFU sets it to + the largest scale component, and 0 culls the model as a point.""" tail: bytes = b"" """Bytes after the size the header declares (a standalone file pads to 0x800)."""