"""
Viewport Control Tools
Tools for controlling viewport projection, navigation, and view alignment.
"""
from mcp.server.fastmcp import Context
import logging
logger = logging.getLogger("BlenderMCPServer")
def set_view_projection(
ctx: Context,
blender_connection,
projection: str = "ORTHO"
) -> str:
"""
Toggle viewport projection between orthographic and perspective.
Parameters:
- projection: "ORTHO" for orthographic or "PERSP" for perspective (default: "ORTHO")
Orthographic: No perspective foreshortening, parallel lines stay parallel.
Perspective: Realistic depth perspective, objects farther away appear smaller.
"""
try:
result = blender_connection.send_command("set_view_projection", {
"projection": projection
})
if "error" in result:
return f"Error: {result['error']}"
output = f"Viewport Projection Set to {result.get('projection', projection)}!\n\n"
if projection == "ORTHO":
output += "Orthographic mode: No perspective distortion, ideal for precision work.\n"
else:
output += "Perspective mode: Realistic depth perception.\n"
return output
except Exception as e:
logger.error(f"Error setting view projection: {str(e)}")
return f"Error setting view projection: {str(e)}"
def align_view_to_axis(
ctx: Context,
blender_connection,
axis: str,
side: str
) -> str:
"""
Align viewport to a specific global axis and side.
Parameters:
- axis: "X", "Y", or "Z"
- side: "POS" (positive direction) or "NEG" (negative direction)
Mappings:
- Y/POS = FRONT view
- Y/NEG = BACK view
- X/POS = RIGHT view
- X/NEG = LEFT view
- Z/POS = TOP view
- Z/NEG = BOTTOM view
"""
try:
result = blender_connection.send_command("align_view_to_axis", {
"axis": axis,
"side": side
})
if "error" in result:
return f"Error: {result['error']}"
output = f"View Aligned to {result.get('view', 'Unknown')}!\n\n"
output += f"Axis: {result.get('axis', axis)}\n"
output += f"Side: {result.get('side', side)}\n"
return output
except Exception as e:
logger.error(f"Error aligning view: {str(e)}")
return f"Error aligning view: {str(e)}"
def frame_selected(
ctx: Context,
blender_connection
) -> str:
"""
Frame the currently selected objects in the viewport.
The viewport will center on and zoom to fit the selected objects.
No parameters required. Operates on current selection.
"""
try:
result = blender_connection.send_command("frame_selected", {})
if "error" in result:
return f"Error: {result['error']}"
return "Viewport framed to selected objects!"
except Exception as e:
logger.error(f"Error framing selected: {str(e)}")
return f"Error framing selected: {str(e)}"
def focus_view_on_point(
ctx: Context,
blender_connection,
x: float,
y: float,
z: float,
distance: float = None,
view_axis: str = None
) -> str:
"""
Focus viewport on a specific 3D point.
Centers the viewport on the specified coordinates with optional
distance and axis alignment. Essential for navigating to problem
areas identified by analyze_mesh_regions.
Parameters:
- x: X coordinate of the target point
- y: Y coordinate of the target point
- z: Z coordinate of the target point
- distance: Optional viewing distance from target (default: maintain current)
- view_axis: Optional axis alignment - "FRONT", "BACK", "LEFT", "RIGHT", "TOP", "BOTTOM"
Use with analyze_mesh_regions to navigate to problem zones.
"""
try:
params = {"x": x, "y": y, "z": z}
if distance is not None:
params["distance"] = distance
if view_axis is not None:
params["view_axis"] = view_axis
result = blender_connection.send_command("focus_view_on_point", params)
if "error" in result:
return f"Error: {result['error']}"
target = result.get("target", {})
output = f"Viewport focused on point ({target.get('x', x):.3f}, {target.get('y', y):.3f}, {target.get('z', z):.3f})\n"
output += f"View distance: {result.get('view_distance', 'unchanged')}\n"
if view_axis:
output += f"View aligned to: {view_axis}\n"
return output
except Exception as e:
logger.error(f"Error focusing view: {str(e)}")
return f"Error focusing view: {str(e)}"