2V2-e.5c: live smoke on c1, show the map behind the actor

The live run passed its checks, but the screenshot showed wolves floating over a
ground that ended at the actor's feet. Native heights were right (every actor
meets sample_height); two Metin2World settings written for metre units culled
the terrain in this cm-scaled scene: the .msenv depth fog (120-520) and the
terrain patch visibility_range_end (3500). The 3D surface now turns the legacy
fog off (fog belongs to the recorded D3DRS_FOG* state, off until
SetEnvironmentData is ported) and builds one mesh per tile.

The render test checks that every actor (draws grouped by world matrix) stands
on the map and that the map behind the actor shows texture. mouse.cfg, written
by 40250 uitaskbar.py at runtime, is ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-23 23:18:20 +09:00
co-authored by Claude Opus 5.5
parent 5a1df57e69
commit 157f7c3bb4
4 changed files with 43 additions and 1 deletions
+9
View File
@@ -141,6 +141,9 @@ func _load_terrain(draw: Dictionary) -> void:
terrain.set("assets_root", "pack://")
terrain.set("map_path", map_path)
terrain.set("load_radius_tiles", 1)
# One mesh per 256 m tile: split patches carry a visibility_range_end meant for metres, which in
# this cm scene culled every patch beyond 35 m (the map behind the actor vanished).
terrain.set("terrain_patches", 1)
terrain.set("objects_enabled", false)
terrain.set("water_enabled", false)
terrain.call("set_collision_enabled", false)
@@ -173,6 +176,12 @@ func _load_terrain(draw: Dictionary) -> void:
# WorldEnv from .msenv replaces the black environment created before map load.
if terrain_report.get("env_ok", false):
environment.environment = null
# Its depth fog is in legacy metres, but this scene is in cm, so it fogged everything past
# ~5 m and hid the terrain behind the actor. Fog belongs to the recorded D3DRS_FOG* state,
# which stays off until CPythonBackground::SetEnvironmentData is ported.
var map_environment := terrain.get_node_or_null("WorldEnv") as WorldEnvironment
if map_environment and map_environment.environment:
map_environment.environment.fog_enabled = false
func _map_for_position(global_cm: Vector2) -> String:
if _atlas.is_empty():
+30
View File
@@ -154,6 +154,25 @@ func run() -> void:
if p.z < actor_foot_cm:
actor_foot_cm = p.z
foot_xy = Vector2(p.x, -p.y)
# Every actor, not only the main one, stands on the map. An actor's parts (body, head, hair, teeth)
# share its world matrix; the lowest vertex over those parts meets sample_height.
var actor_low := {}
for draw in draws:
var draw_xform: Transform3D = world.d3d_transform(draw["world"])
var key := str(draw["world"])
for vertex in draw["positions"]:
var p: Vector3 = draw_xform * vertex
if not actor_low.has(key) or p.z < actor_low[key].z:
actor_low[key] = p
if world.terrain:
var worst_actor_gap_cm := 0.0
for low in actor_low.values():
var ground := float(world.terrain.call("sample_height", low.x / 100.0, -low.y / 100.0)) * 100.0
worst_actor_gap_cm = maxf(worst_actor_gap_cm, absf(low.z - ground))
report["actors"] = actor_low.size()
report["worst_actor_gap_cm"] = worst_actor_gap_cm
_check(worst_actor_gap_cm < 50.0, "every actor stands on the map (%d actors, worst gap %.1f cm)"
% [actor_low.size(), worst_actor_gap_cm])
report["native_lit_draws"] = native_lit_draws
report["view_finite"] = view_finite
_check(view_finite, "native camera view stays finite")
@@ -242,5 +261,16 @@ func run() -> void:
textured_pairs += 1
report["ground_texture_pairs"] = textured_pairs
_check(textured_pairs > 20, "textured ground visible in screenshot (%d local contrasts)" % textured_pairs)
# The camera looks 27 degrees down, so the map behind the actor fills the top of the picture
# too (legacy metre-unit fog once washed it out to flat sky colour).
var far_pairs := 0
for y in range(game_image.get_height() / 10, game_image.get_height() * 3 / 10, 13):
for x in range(30, game_image.get_width() - 35, 17):
var left := game_image.get_pixel(x, y).get_luminance()
var right := game_image.get_pixel(x + 5, y).get_luminance()
if absf(left - right) > 0.04:
far_pairs += 1
report["far_ground_texture_pairs"] = far_pairs
_check(far_pairs > 20, "map behind the actor visible (%d local contrasts)" % far_pairs)
ui.visible = true
await _finish(output, report)