"""
Remeshing Tools
Tools for mesh reconstruction, optimization, and polygon reduction.
NOTE: Voxel remesh and QuadriFlow remesh implementations have been moved to
retopo_tools/remesh.py for enhanced functionality. This module now contains
only decimation and shrinkwrap operations.
"""
from mcp.server.fastmcp import Context
import logging
logger = logging.getLogger("BlenderMCPServer")
def decimate(
ctx: Context,
blender_connection,
ratio: float = 0.5,
mode: str = "COLLAPSE",
angle_limit: float = 5.0
) -> str:
"""
Reduce polygon count while preserving shape using decimation.
Parameters:
- ratio: Target ratio of faces to keep, 0-1 (default: 0.5 = 50%)
- mode: Decimation mode (default: "COLLAPSE")
* "COLLAPSE" - Edge collapse (best for general use)
* "DISSOLVE" - Planar decimation (good for flat surfaces)
* "UNSUBDIVIDE" - Reverse subdivision (for subdivided meshes)
- angle_limit: Angle limit in degrees for DISSOLVE mode (default: 5.0)
Returns success status and face count reduction.
"""
try:
result = blender_connection.send_command("decimate", {
"ratio": ratio,
"mode": mode,
"angle_limit": angle_limit
})
if "error" in result:
return f"Error: {result['error']}"
output = f"Decimation Complete ({mode} mode)!\n\n"
output += f"Target Ratio: {ratio:.2%}\n"
output += f"Old Face Count: {result.get('old_faces', 0)}\n"
output += f"New Face Count: {result.get('new_faces', 0)}\n"
output += f"Ratio Achieved: {result.get('ratio_achieved', 0):.2%}\n"
return output
except Exception as e:
logger.error(f"Error in decimate: {str(e)}")
return f"Error in decimate: {str(e)}"
def shrinkwrap_reproject(
ctx: Context,
blender_connection,
high: str,
low: str,
method: str = "NEAREST_SURFACEPOINT",
offset: float = 0.0
) -> str:
"""
Project low-poly mesh vertices onto high-poly surface to preserve silhouette.
Parameters:
- high: Name of the high-poly reference mesh
- low: Name of the low-poly mesh to project
- method: Projection method (default: "NEAREST_SURFACEPOINT")
* "NEAREST_SURFACEPOINT" - Project to nearest point on surface
* "PROJECT" - Project along axis
* "NEAREST_VERTEX" - Snap to nearest vertex
* "TARGET_PROJECT" - Project to target
- offset: Distance offset from surface (default: 0.0)
Returns success status.
"""
try:
result = blender_connection.send_command("shrinkwrap_reproject", {
"high": high,
"low": low,
"method": method,
"offset": offset
})
if "error" in result:
return f"Error: {result['error']}"
output = "Shrinkwrap Complete!\n\n"
output += f"High-poly mesh: {result.get('high_poly', high)}\n"
output += f"Low-poly mesh: {result.get('low_poly', low)}\n"
output += f"Method: {result.get('method', method)}\n"
output += f"Offset: {offset}\n"
return output
except Exception as e:
logger.error(f"Error in shrinkwrap: {str(e)}")
return f"Error in shrinkwrap: {str(e)}"