mjlab/tests/test_perlin_terrain.py
Upstream Snapshot 32a241c28f
Some checks failed
nightly / Test against latest dependencies (py3.10) (push) Has been cancelled
nightly / Test against latest dependencies (py3.13) (push) Has been cancelled
tests / tests (3.13, locked) (push) Has been cancelled
tests / tests (3.13, unlocked) (push) Has been cancelled
tests / pyright (3.10) (push) Has been cancelled
tests / lint-format (push) Has been cancelled
tests / tests (3.10, locked) (push) Has been cancelled
tests / tests (3.11, locked) (push) Has been cancelled
tests / tests (3.12, locked) (push) Has been cancelled
tests / pyright (3.11) (push) Has been cancelled
tests / pyright (3.12) (push) Has been cancelled
tests / pyright (3.13) (push) Has been cancelled
tests / ty-check (3.10) (push) Has been cancelled
tests / ty-check (3.11) (push) Has been cancelled
tests / ty-check (3.12) (push) Has been cancelled
tests / ty-check (3.13) (push) Has been cancelled
tests / stubs (push) Has been cancelled
tests / smoke-test (push) Has been cancelled
Docker / check_paths (push) Has been cancelled
docs / build (push) Has been cancelled
Docker / build (push) Has been cancelled
Import upstream snapshot c19f713c415a699a79d71cd96aa13c3104a05047
Upstream: https://github.com/michaelgillett/mjlab
Upstream-Commit: c19f713c415a699a79d71cd96aa13c3104a05047
Upstream-Branch: main
2026-08-28 15:42:17 +08:00

110 lines
3.0 KiB
Python

"""Tests for Perlin noise terrain generation."""
import mujoco
import numpy as np
import pytest
from mjlab.terrains.heightfield_terrains import HfPerlinNoiseTerrainCfg
@pytest.fixture
def rng() -> np.random.Generator:
return np.random.default_rng(42)
def test_perlin_terrain_generation(rng: np.random.Generator):
"""Verify that Perlin noise terrain generates a valid TerrainOutput."""
spec = mujoco.MjSpec()
spec.worldbody.add_body(name="terrain")
cfg = HfPerlinNoiseTerrainCfg(
proportion=1.0,
size=(10.0, 10.0),
height_range=(0.1, 0.5),
octaves=4,
persistence=0.5,
lacunarity=2.0,
scale=10.0,
horizontal_scale=0.1,
resolution=0.1,
)
output = cfg.function(difficulty=0.5, spec=spec, rng=rng)
# Basic checks for TerrainOutput.
assert output.origin.shape == (3,)
assert len(output.geometries) == 1
assert output.geometries[0].geom is not None
assert output.geometries[0].hfield is not None
# Check hfield size.
# size = [x/2, y/2, max_height, base_thickness]
hfield = output.geometries[0].hfield
assert hfield.size[0] == 5.0
assert hfield.size[1] == 5.0
assert hfield.size[2] > 0 # max height should be positive
# Check hfield data.
data = np.asarray(hfield.userdata)
assert len(data) == 100 * 100 # (10.0/0.1) * (10.0/0.1)
assert np.all(data >= 0.0)
assert np.all(data <= 1.0)
assert np.max(data) > 0.0 # it should not be flat 0
# Check if height variation is present.
assert np.min(data) < np.max(data)
def test_perlin_terrain_resolution(rng: np.random.Generator):
"""Verify that higher resolution increases pixel count."""
spec = mujoco.MjSpec()
spec.worldbody.add_body(name="terrain")
cfg = HfPerlinNoiseTerrainCfg(
proportion=1.0,
size=(10.0, 10.0),
height_range=(0.1, 0.5),
horizontal_scale=0.1,
resolution=0.05, # 200 pixels
)
output = cfg.function(difficulty=0.5, spec=spec, rng=rng)
hfield = output.geometries[0].hfield
assert hfield is not None
# (10.0 / 0.05) = 200
assert hfield.nrow == 200
assert hfield.ncol == 200
assert len(hfield.userdata) == 200 * 200
def test_perlin_terrain_with_border(rng: np.random.Generator):
"""Verify Perlin noise terrain with a border."""
spec = mujoco.MjSpec()
spec.worldbody.add_body(name="terrain")
cfg = HfPerlinNoiseTerrainCfg(
proportion=1.0,
size=(10.0, 10.0),
height_range=(0.1, 0.5),
border_width=2.0,
horizontal_scale=0.1,
resolution=0.1,
)
output = cfg.function(difficulty=0.5, spec=spec, rng=rng)
hfield = output.geometries[0].hfield
assert hfield is not None
data = np.asarray(hfield.userdata).reshape(100, 100)
# Border pixels: 2.0 / 0.1 = 20
border_pixels = 20
top_border = data[:border_pixels, :]
bottom_border = data[-border_pixels:, :]
left_border = data[:, :border_pixels]
right_border = data[:, -border_pixels:]
assert np.all(top_border == top_border[0, 0])
assert np.all(bottom_border == bottom_border[0, 0])
assert np.all(left_border == left_border[0, 0])
assert np.all(right_border == right_border[0, 0])