"""
Remeshing operator tools for retopology workflows.
Provides safe, parameterized tools for voxel remesh and QuadriFlow operations.
"""
from typing import Dict, Any
from mcp.server.fastmcp import Context
import logging
logger = logging.getLogger("BlenderMCPServer")
# ============================================================================
# VOXEL REMESH (Operator)
# ============================================================================
def remesh_voxel(
ctx: Context,
blender_connection,
voxel_size: float = 0.01,
adaptivity: float = 0.0,
preserve_volume: bool = True
) -> str:
"""
Apply voxel-based remeshing to create uniform topology.
Rebuilds the mesh using a voxel grid. Good for cleanup and creating
uniform base topology. Generates geometry from scratch, ignoring modifiers.
Works on the active object in Object Mode.
Parameters:
- voxel_size: Size of voxels - smaller = more detail (default: 0.01)
- adaptivity: Adaptivity 0-1 for reducing detail in flat areas (default: 0.0)
- preserve_volume: Try to preserve mesh volume (default: true)
Returns status message with face count before/after.
"""
try:
if voxel_size <= 0:
return f"Error: Voxel size must be greater than 0."
if not 0.0 <= adaptivity <= 1.0:
return f"Error: Adaptivity must be between 0.0 and 1.0."
result = blender_connection.send_command("remesh_voxel", {
"voxel_size": voxel_size,
"adaptivity": adaptivity,
"preserve_volume": preserve_volume
})
if "error" in result:
return f"Error: {result['error']}"
output = "Voxel Remesh Complete!\n\n"
output += f"Voxel Size: {voxel_size}\n"
output += f"Adaptivity: {adaptivity}\n"
output += f"Preserve Volume: {preserve_volume}\n"
if 'old_faces' in result:
output += f"\nOld Face Count: {result['old_faces']}\n"
if 'new_faces' in result:
output += f"New Face Count: {result['new_faces']}\n"
if 'old_faces' in result and result['old_faces'] > 0:
ratio = result['new_faces'] / result['old_faces']
output += f"Change: {ratio:.1%}\n"
return output
except Exception as e:
logger.error(f"Error in voxel remesh: {str(e)}")
return f"Error in voxel remesh: {str(e)}"
# ============================================================================
# QUADRIFLOW REMESH (Operator)
# ============================================================================
def quadriflow_remesh(
ctx: Context,
blender_connection,
target_faces: int = 5000,
preserve_sharp: bool = True,
use_symmetry: bool = False
) -> str:
"""
Apply QuadriFlow remeshing to generate quad-dominant topology.
Creates high-quality quad-dominant meshes suitable for animation and
subdivision. REQUIRES manifold input with consistent normals.
Works on the active object in Object Mode.
Parameters:
- target_faces: Desired face count (default: 5000)
- preserve_sharp: Preserve sharp edges (default: true)
- use_symmetry: Detect and preserve mesh symmetry (default: false)
Returns status message with face count before/after, or error with fix suggestions.
"""
try:
if target_faces < 10:
return f"Error: Target faces must be at least 10."
result = blender_connection.send_command("quadriflow_remesh", {
"target_faces": target_faces,
"preserve_sharp": preserve_sharp,
"use_symmetry": use_symmetry
})
if "error" in result:
error_msg = f"Error: {result['error']}\n\n"
# Add helpful remediation suggestions
if "manifold" in result['error'].lower() or "non-manifold" in result['error'].lower():
error_msg += "QuadriFlow requires a manifold mesh. To fix:\n"
error_msg += "1. Use 'select_non_manifold()' to find problem areas\n"
error_msg += "2. Use 'merge_by_distance()' to remove duplicate vertices\n"
error_msg += "3. Use 'recalculate_normals()' to fix face orientations\n"
error_msg += "4. Fill any holes manually in Edit Mode (F key)\n"
error_msg += "5. Or use 'remesh_voxel()' first to create a clean manifold mesh\n"
return error_msg
output = "QuadriFlow Remesh Complete!\n\n"
output += f"Target Faces: {target_faces}\n"
output += f"Preserve Sharp: {preserve_sharp}\n"
output += f"Use Symmetry: {use_symmetry}\n"
if 'old_faces' in result:
output += f"\nOld Face Count: {result['old_faces']}\n"
if 'new_faces' in result:
output += f"New Face Count: {result['new_faces']}\n"
if 'quad_percentage' in result:
output += f"Quad Percentage: {result['quad_percentage']:.1f}%\n"
return output
except Exception as e:
logger.error(f"Error in quadriflow remesh: {str(e)}")
return f"Error in quadriflow remesh: {str(e)}"