From metashape-mcp
Prevents and removes sky/tunnel mesh artifacts in Metashape road corridor photogrammetry using point cloud sourcing, height fields, classification, cropping, and post-mesh cleanup.
npx claudepluginhub jenkinsm13/claude-plugins --plugin metashape-mcpThis skill uses the workspace's default tool permissions.
Metashape's mesh generation creates "tunnel" or "dome" artifacts over road corridors. Even with proper sky masks:
Guides dense reconstruction in Metashape MCP: builds depth maps, point clouds, meshes, textures, DEMs, orthomosaics post-alignment with optimal GPU/CPU settings via blocking MCP calls.
Guides mesh processing for AEC computational design: data structures, operations, analysis, repair, UV mapping/unfolding, quad meshing, mesh-to-NURBS conversion, quality assessment.
Reconstructs 3D scenes from streaming images or video using LingBot-Map feed-forward model with Geometric Context Transformer. Outputs point clouds, camera poses, depth maps at ~20 FPS.
Share bugs, ideas, or general feedback.
Metashape's mesh generation creates "tunnel" or "dome" artifacts over road corridors. Even with proper sky masks:
This is Metashape's most well-known limitation for road corridor captures. There is no single fix — use a combination of strategies.
Five strategies, ordered by effectiveness for road corridors:
| # | Strategy | When to Apply | Effectiveness |
|---|---|---|---|
| 1 | Point cloud source | Before mesh build | Best — avoids the problem entirely |
| 2 | Height field mode | Before mesh build | Good for flat terrain, loses vertical surfaces |
| 3 | Point cloud classification | Before mesh build | Good — requires classification step |
| 4 | Region cropping | Before mesh build | Moderate — simple but crude |
| 5 | Post-mesh cleanup | After mesh build | Fallback — fixes what got through |
Recommended combination: Strategy 1 + 3 + 5 (point cloud source, with ground classification, followed by cleanup).
Why it works: Point cloud generation DOES respect masks. If sky is masked, no points exist in the sky → no mesh in the sky. Depth map interpolation is what creates the tunnel — bypassing it avoids the problem.
# Step 1: Build point cloud with masks active
build_point_cloud(
point_colors=True,
point_confidence=True
)
# Step 2: Build mesh from point cloud
build_model(
surface_type="arbitrary",
source_data="point_cloud",
interpolation="enabled",
vertex_colors=True
)
Trade-offs:
When NOT to use: When you need maximum mesh detail and will handle artifacts in post.
Why it works: Height field mode generates only the surface visible from directly above — it cannot create tunnels, domes, or enclosed spaces.
build_model(
surface_type="height_field",
source_data="depth_maps",
interpolation="enabled",
vertex_colors=True
)
Trade-offs:
Best for: Terrain/ground extraction where vertical surfaces don't matter. NOT suitable for driving simulator environments where canyon walls are important.
Why it works: Classify the point cloud to separate ground/building from vegetation/noise/sky, then build mesh from only the classes you want.
# Step 1: Build point cloud
build_point_cloud(
point_colors=True,
point_confidence=True
)
# Step 2: Classify ground
classify_ground_points(
max_angle=15.0,
max_distance=1.0,
cell_size=50.0
)
# Step 3: Build mesh from ground + building classes only
build_model(
surface_type="arbitrary",
source_data="point_cloud",
classes=[2, 6], # 2=Ground, 6=Building
interpolation="enabled",
vertex_colors=True
)
Point cloud classes (ASPRS LAS standard):
| Class | Code | Include? |
|---|---|---|
| Created/never classified | 0 | Maybe — contains unclassified real geometry |
| Unclassified | 1 | Maybe — same as above |
| Ground | 2 | YES — always include |
| Low vegetation | 3 | Depends on needs |
| Medium vegetation | 4 | Depends on needs |
| High vegetation | 5 | Usually NO for road corridors |
| Building | 6 | YES — retaining walls, structures |
| Noise | 7 | NO — sky artifacts live here |
Trade-offs:
classify_ground_points is designed for aerial data — may not perfectly classify vehicle-level capturesTuning for road corridors:
classify_ground_points(
max_angle=25.0, # Increase from 15 for steep canyon walls
max_distance=2.0, # Increase for rougher terrain
cell_size=20.0 # Decrease for finer detail in narrow corridors
)
Why it works: Limit the reconstruction volume so nothing above a certain height gets meshed.
# Get current bounds
get_chunk_bounds()
# Set tight region — limit vertical extent
set_region(
center=[x, y, z],
size=[width, length, limited_height]
)
How to determine limited_height:
Trade-offs:
Region rotation for corridors: If the corridor isn't axis-aligned, rotate the region to match:
set_region_rotation(yaw=corridor_heading)
When to use: After mesh is built, as a fallback for whatever got through.
clean_model(
criterion="component_size",
level=75
)
Removes disconnected mesh components smaller than the threshold. Sky artifacts are often disconnected from the main terrain mesh.
Level guide:
50: Conservative — only removes small fragments75: Moderate — removes medium artifacts (good default)90: Aggressive — removes everything except the largest componentIf point confidence was enabled:
# Remove low-confidence points first, then rebuild mesh
filter_points_by_confidence(min_confidence=3)
Sky interpolation artifacts tend to have low confidence scores.
For stubborn artifacts that automated cleaning misses:
execute_python to delete faces by height/normal criteriaBuilding mesh for road corridor?
├── Need full 3D (walls, rock faces)?
│ ├── YES → Strategy 1 (point cloud source)
│ │ + Strategy 3 (classify, use classes [0,1,2,6])
│ │ + Strategy 5 (cleanup remaining artifacts)
│ └── NO (terrain only) → Strategy 2 (height field)
├── Have EXR masks?
│ ├── YES → Strategy 1 is especially effective (masks respected in point cloud)
│ └── NO → Strategy 3 + 4 + 5 (classify + region crop + cleanup)
└── Already built mesh with artifacts?
└── Strategy 5 (cleanup) — then consider rebuilding with Strategy 1 or 3
This project needs full 3D (road + canyon walls), has EXR masks, and outputs to a driving simulator:
# 1. GPU off for dense operations
set_gpu_config(cpu_enable=False)
# 2. Build point cloud (masks respected here)
build_point_cloud(point_colors=True, point_confidence=True)
# 3. Classify ground — tuned for steep canyon
classify_ground_points(max_angle=25.0, max_distance=2.0, cell_size=20.0)
# 4. Build mesh from point cloud, ground + unclassified + building
build_model(
surface_type="arbitrary",
source_data="point_cloud",
classes=[0, 1, 2, 6],
interpolation="enabled",
vertex_colors=True,
vertex_confidence=True
)
# 5. Clean remaining artifacts
clean_model(criterion="component_size", level=75)
# 6. Verify — check for tunnel artifacts
get_model_stats()
capture_viewport()
If artifacts remain after step 5, increase level to 90 or apply region cropping before rebuilding.
| Mistake | Result | Fix |
|---|---|---|
| Building from depth maps with masks | Tunnel forms anyway — depth map interpolation ignores masks | Use source_data="point_cloud" instead |
| Height field on a canyon | Loses rock face walls | Use surface_type="arbitrary" with classification |
| Aggressive classification on vehicle data | Misclassifies walls as noise | Increase max_angle to 25-30 for steep terrain |
| Not cleaning after mesh build | Artifact fragments remain | Always run clean_model as final step |
| Region crop too tight | Clips legitimate tall features | Add 2-3m margin above tallest feature |