Skip to main content
Glama
RobotCamera.cs7.58 kB
using UnityEngine; using System.Collections.Generic; using System.IO; /// <summary> /// Camera controller for virtual robots in Unity. /// Handles camera feeds, angle control, image capture, and streaming. /// Used by robotics-mcp robot_camera tool via execute_unity_method. /// </summary> public class RobotCamera : MonoBehaviour { private static Dictionary<string, RobotCamera> instances = new Dictionary<string, RobotCamera>(); [Header("Camera Settings")] public Camera robotCamera; public int captureWidth = 1920; public int captureHeight = 1080; public float fieldOfView = 60f; private bool isStreaming = false; private string streamUrl = ""; void Awake() { if (robotCamera == null) { robotCamera = GetComponentInChildren<Camera>(); if (robotCamera == null) { // Create camera if none exists GameObject cameraObj = new GameObject("RobotCamera"); cameraObj.transform.SetParent(transform); cameraObj.transform.localPosition = new Vector3(0, 0.1f, 0.1f); // Slightly forward and up robotCamera = cameraObj.AddComponent<Camera>(); robotCamera.fieldOfView = fieldOfView; } } } /// <summary> /// Get camera feed (returns base64 encoded image). /// </summary> public static Dictionary<string, object> GetCameraFeed(string robotId) { RobotCamera instance = GetInstance(robotId); if (instance == null) return null; return instance.GetCameraFeedInstance(); } private Dictionary<string, object> GetCameraFeedInstance() { if (robotCamera == null) return null; RenderTexture rt = new RenderTexture(captureWidth, captureHeight, 24); robotCamera.targetTexture = rt; Texture2D screenshot = new Texture2D(captureWidth, captureHeight, TextureFormat.RGB24, false); robotCamera.Render(); RenderTexture.active = rt; screenshot.ReadPixels(new Rect(0, 0, captureWidth, captureHeight), 0, 0); robotCamera.targetTexture = null; RenderTexture.active = null; Destroy(rt); byte[] imageBytes = screenshot.EncodeToPNG(); string base64Image = System.Convert.ToBase64String(imageBytes); Destroy(screenshot); return new Dictionary<string, object> { {"image_base64", base64Image}, {"width", captureWidth}, {"height", captureHeight}, {"format", "PNG"} }; } /// <summary> /// Set camera angle (pitch and yaw). /// </summary> public static bool SetCameraAngle(string robotId, float angleX, float angleY) { RobotCamera instance = GetInstance(robotId); if (instance == null) return false; instance.SetCameraAngleInstance(angleX, angleY); return true; } private void SetCameraAngleInstance(float angleX, float angleY) { if (robotCamera != null) { Transform camTransform = robotCamera.transform; camTransform.localRotation = Quaternion.Euler(angleX, angleY, 0); } } /// <summary> /// Capture image and save to file. /// </summary> public static Dictionary<string, object> CaptureImage(string robotId, string outputPath) { RobotCamera instance = GetInstance(robotId); if (instance == null) return null; return instance.CaptureImageInstance(outputPath); } private Dictionary<string, object> CaptureImageInstance(string outputPath) { if (robotCamera == null) return null; RenderTexture rt = new RenderTexture(captureWidth, captureHeight, 24); robotCamera.targetTexture = rt; Texture2D screenshot = new Texture2D(captureWidth, captureHeight, TextureFormat.RGB24, false); robotCamera.Render(); RenderTexture.active = rt; screenshot.ReadPixels(new Rect(0, 0, captureWidth, captureHeight), 0, 0); robotCamera.targetTexture = null; RenderTexture.active = null; Destroy(rt); byte[] imageBytes = screenshot.EncodeToPNG(); if (!string.IsNullOrEmpty(outputPath)) { string directory = Path.GetDirectoryName(outputPath); if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) { Directory.CreateDirectory(directory); } File.WriteAllBytes(outputPath, imageBytes); } string base64Image = System.Convert.ToBase64String(imageBytes); Destroy(screenshot); return new Dictionary<string, object> { {"image_base64", base64Image}, {"output_path", outputPath}, {"width", captureWidth}, {"height", captureHeight} }; } /// <summary> /// Start video streaming. /// </summary> public static bool StartStreaming(string robotId, string streamUrl) { RobotCamera instance = GetInstance(robotId); if (instance == null) return false; instance.StartStreamingInstance(streamUrl); return true; } private void StartStreamingInstance(string url) { isStreaming = true; streamUrl = url; Debug.Log($"{gameObject.name} camera streaming started: {url}"); // TODO: Implement actual streaming (WebRTC, MJPEG, etc.) } /// <summary> /// Stop video streaming. /// </summary> public static bool StopStreaming(string robotId) { RobotCamera instance = GetInstance(robotId); if (instance == null) return false; instance.StopStreamingInstance(); return true; } private void StopStreamingInstance() { isStreaming = false; streamUrl = ""; Debug.Log($"{gameObject.name} camera streaming stopped"); } /// <summary> /// Get camera status and settings. /// </summary> public static Dictionary<string, object> GetCameraStatus(string robotId) { RobotCamera instance = GetInstance(robotId); if (instance == null) return null; return instance.GetCameraStatusInstance(); } private Dictionary<string, object> GetCameraStatusInstance() { return new Dictionary<string, object> { {"isStreaming", isStreaming}, {"streamUrl", streamUrl}, {"fieldOfView", robotCamera != null ? robotCamera.fieldOfView : 0f}, {"width", captureWidth}, {"height", captureHeight}, {"hasCamera", robotCamera != null} }; } private static RobotCamera GetInstance(string robotId) { if (instances.ContainsKey(robotId)) { return instances[robotId]; } GameObject robot = GameObject.Find(robotId); if (robot == null) { Debug.LogError($"Robot with ID '{robotId}' not found in scene."); return null; } RobotCamera camera = robot.GetComponent<RobotCamera>(); if (camera == null) { camera = robot.AddComponent<RobotCamera>(); } instances[robotId] = camera; return camera; } void OnDestroy() { instances.Remove(gameObject.name); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sandraschi/robotics-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server