修改提交
This commit is contained in:
@@ -0,0 +1,662 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Codely.Newtonsoft.Json.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityTcp.Editor.Helpers; // For Response class
|
||||
|
||||
namespace UnityTcp.Editor.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles screenshot capture operations within Unity Editor.
|
||||
/// </summary>
|
||||
public static class ManageScreenshot
|
||||
{
|
||||
// --- Main Handler ---
|
||||
|
||||
// Define the list of valid actions
|
||||
private static readonly List<string> ValidActions = new List<string>
|
||||
{
|
||||
"capture",
|
||||
"capture_main_camera",
|
||||
"capture_specific_camera",
|
||||
"capture_scene_camera"
|
||||
};
|
||||
|
||||
public static object HandleCommand(JObject @params)
|
||||
{
|
||||
string action = @params["action"]?.ToString().ToLower();
|
||||
if (string.IsNullOrEmpty(action))
|
||||
{
|
||||
return Response.Error("Action parameter is required.");
|
||||
}
|
||||
|
||||
// Check if the action is valid before switching
|
||||
if (!ValidActions.Contains(action))
|
||||
{
|
||||
string validActionsList = string.Join(", ", ValidActions);
|
||||
return Response.Error(
|
||||
$"Unknown action: '{action}'. Valid actions are: {validActionsList}"
|
||||
);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case "capture":
|
||||
return CaptureGameView(@params);
|
||||
case "capture_main_camera":
|
||||
return CaptureMainCamera(@params);
|
||||
case "capture_specific_camera":
|
||||
return CaptureSpecificCamera(@params);
|
||||
case "capture_scene_camera":
|
||||
return CaptureSceneCamera(@params);
|
||||
|
||||
default:
|
||||
string validActionsListDefault = string.Join(", ", ValidActions);
|
||||
return Response.Error(
|
||||
$"Unknown action: '{action}'. Valid actions are: {validActionsListDefault}"
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[ManageScreenshot] Action '{action}' failed: {e}");
|
||||
return Response.Error(
|
||||
$"Internal error processing action '{action}': {e.Message}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Action Implementations ---
|
||||
|
||||
/// <summary>
|
||||
/// Menu item to capture screenshot from game view
|
||||
/// </summary>
|
||||
public static void CaptureScreenshotMenuItem()
|
||||
{
|
||||
CaptureGameViewAndSave();
|
||||
}
|
||||
|
||||
private static object CaptureGameView(JObject @params)
|
||||
{
|
||||
string customPath = @params["path"]?.ToString();
|
||||
string customFilename = @params["filename"]?.ToString();
|
||||
int? width = @params["width"]?.ToObject<int?>();
|
||||
int? height = @params["height"]?.ToObject<int?>();
|
||||
|
||||
try
|
||||
{
|
||||
string savedPath = CaptureGameViewAndSave(customPath, customFilename, width, height);
|
||||
if (savedPath != null)
|
||||
{
|
||||
return Response.Success(
|
||||
"Screenshot captured successfully from Game view.",
|
||||
new { path = savedPath, camera = "Game View" }
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Response.Error("Failed to capture screenshot from Game view.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return Response.Error($"Failed to capture screenshot from Game view: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static object CaptureMainCamera(JObject @params)
|
||||
{
|
||||
string customPath = @params["path"]?.ToString();
|
||||
string customFilename = @params["filename"]?.ToString();
|
||||
int? width = @params["width"]?.ToObject<int?>();
|
||||
int? height = @params["height"]?.ToObject<int?>();
|
||||
|
||||
try
|
||||
{
|
||||
string savedPath = CaptureAndSave(customPath, customFilename, width, height);
|
||||
if (savedPath != null)
|
||||
{
|
||||
return Response.Success(
|
||||
"Screenshot captured successfully from main camera.",
|
||||
new { path = savedPath, camera = "Main Camera" }
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Response.Error("Failed to capture screenshot from main camera.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return Response.Error($"Failed to capture screenshot: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static object CaptureSpecificCamera(JObject @params)
|
||||
{
|
||||
string cameraName = @params["cameraName"]?.ToString();
|
||||
string customPath = @params["path"]?.ToString();
|
||||
string customFilename = @params["filename"]?.ToString();
|
||||
int? width = @params["width"]?.ToObject<int?>();
|
||||
int? height = @params["height"]?.ToObject<int?>();
|
||||
|
||||
if (string.IsNullOrEmpty(cameraName))
|
||||
{
|
||||
return Response.Error("'cameraName' parameter is required for capture_specific_camera action.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Camera targetCamera = GameObject.Find(cameraName)?.GetComponent<Camera>();
|
||||
if (targetCamera == null)
|
||||
{
|
||||
// Try finding by name in all cameras
|
||||
Camera[] cameras = UnityEngine.Object.FindObjectsOfType<Camera>();
|
||||
foreach (Camera cam in cameras)
|
||||
{
|
||||
if (cam.name.Equals(cameraName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
targetCamera = cam;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (targetCamera == null)
|
||||
{
|
||||
return Response.Error($"Camera '{cameraName}' not found in the scene.");
|
||||
}
|
||||
|
||||
string savedPath = CaptureAndSave(customPath, customFilename, width, height, targetCamera);
|
||||
if (savedPath != null)
|
||||
{
|
||||
return Response.Success(
|
||||
$"Screenshot captured successfully from camera '{cameraName}'.",
|
||||
new { path = savedPath, camera = cameraName }
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Response.Error($"Failed to capture screenshot from camera '{cameraName}'.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return Response.Error($"Failed to capture screenshot from camera '{cameraName}': {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static object CaptureSceneCamera(JObject @params)
|
||||
{
|
||||
string customPath = @params["path"]?.ToString();
|
||||
string customFilename = @params["filename"]?.ToString();
|
||||
int? width = @params["width"]?.ToObject<int?>();
|
||||
int? height = @params["height"]?.ToObject<int?>();
|
||||
|
||||
try
|
||||
{
|
||||
// Get the active scene view camera
|
||||
SceneView sceneView = SceneView.lastActiveSceneView;
|
||||
if (sceneView == null)
|
||||
{
|
||||
return Response.Error("No active Scene view found. Please ensure a Scene view is open.");
|
||||
}
|
||||
|
||||
Camera sceneCamera = sceneView.camera;
|
||||
if (sceneCamera == null)
|
||||
{
|
||||
return Response.Error("Scene view camera not found.");
|
||||
}
|
||||
|
||||
string savedPath = CaptureAndSave(customPath, customFilename, width, height, sceneCamera, "SceneCamera");
|
||||
if (savedPath != null)
|
||||
{
|
||||
return Response.Success(
|
||||
"Screenshot captured successfully from Scene camera.",
|
||||
new { path = savedPath, camera = "Scene Camera" }
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Response.Error("Failed to capture screenshot from Scene camera.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return Response.Error($"Failed to capture screenshot from Scene camera: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Function to capture Game view screenshot and save to file
|
||||
/// </summary>
|
||||
public static string CaptureGameViewAndSave(string customPath = null, string customFilename = null, int? width = null, int? height = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Generate filename with GameView prefix
|
||||
string filename;
|
||||
if (!string.IsNullOrEmpty(customFilename))
|
||||
{
|
||||
filename = customFilename.EndsWith(".png") ? customFilename : customFilename + ".png";
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = $"GameView-{System.DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.png";
|
||||
}
|
||||
|
||||
// Determine save path
|
||||
string savePath;
|
||||
if (!string.IsNullOrEmpty(customPath))
|
||||
{
|
||||
// Ensure directory exists
|
||||
Directory.CreateDirectory(customPath);
|
||||
savePath = Path.Combine(customPath, filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use project path with Screenshots folder
|
||||
string projectPath = Path.GetDirectoryName(Application.dataPath); // Get project root (parent of Assets)
|
||||
string screenshotsFolder = Path.Combine(projectPath, "Screenshots");
|
||||
|
||||
// Create Screenshots folder if it doesn't exist
|
||||
if (!Directory.Exists(screenshotsFolder))
|
||||
{
|
||||
Directory.CreateDirectory(screenshotsFolder);
|
||||
Debug.Log($"Created Screenshots folder at: {screenshotsFolder}");
|
||||
}
|
||||
|
||||
savePath = Path.Combine(screenshotsFolder, filename);
|
||||
}
|
||||
|
||||
// Try different capture methods based on mode and availability
|
||||
Texture2D screenshot = null;
|
||||
|
||||
// Always prioritize GameView reflection to capture what user actually sees
|
||||
// This ensures screenshots match the GameView dimensions, multi-camera setups, and post-processing
|
||||
screenshot = CaptureGameViewInEditMode(width, height);
|
||||
|
||||
if (screenshot == null)
|
||||
{
|
||||
// Fallback to main camera rendering if GameView is not accessible
|
||||
Camera mainCamera = Camera.main;
|
||||
if (mainCamera != null)
|
||||
{
|
||||
screenshot = CaptureScreenByRenderTexture(mainCamera, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
if (screenshot == null)
|
||||
{
|
||||
Debug.LogError("Failed to capture screenshot using all available methods!");
|
||||
return null;
|
||||
}
|
||||
|
||||
// ReadPixels from RenderTexture often returns bottom-up (OpenGL origin); flip so saved PNG is top-down
|
||||
FlipTextureVertically(screenshot);
|
||||
|
||||
// Encode to PNG and save
|
||||
byte[] bytes = screenshot.EncodeToPNG();
|
||||
UnityEngine.Object.DestroyImmediate(screenshot); // Free GPU memory (must use DestroyImmediate in edit mode)
|
||||
|
||||
File.WriteAllBytes(savePath, bytes);
|
||||
Debug.Log("Game view screenshot saved to: " + savePath);
|
||||
return savePath;
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"Failed to capture game view screenshot: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Capture screenshot from camera using RenderTexture approach
|
||||
/// </summary>
|
||||
private static Texture2D CaptureScreenByRenderTexture(Camera camera, int? width = null, int? height = null)
|
||||
{
|
||||
if (camera == null)
|
||||
{
|
||||
Debug.LogError("Camera is null!");
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Use custom dimensions or default to reasonable size
|
||||
int captureWidth = width ?? 1920;
|
||||
int captureHeight = height ?? 1080;
|
||||
|
||||
Rect rect = new Rect(0, 0, captureWidth, captureHeight);
|
||||
|
||||
// Create a RenderTexture object
|
||||
RenderTexture rt = new RenderTexture((int)rect.width, (int)rect.height, 24);
|
||||
|
||||
// Store original target texture to restore later
|
||||
RenderTexture originalTarget = camera.targetTexture;
|
||||
|
||||
// Temporarily set the camera's targetTexture to rt, and manually render the camera
|
||||
camera.targetTexture = rt;
|
||||
camera.Render();
|
||||
|
||||
// Activate this rt, and read pixels from it.
|
||||
RenderTexture previousActive = RenderTexture.active;
|
||||
RenderTexture.active = rt;
|
||||
|
||||
Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24, false);
|
||||
// Note: At this time, it reads pixels from RenderTexture.active
|
||||
screenShot.ReadPixels(rect, 0, 0);
|
||||
screenShot.Apply();
|
||||
|
||||
// Reset related parameters so the camera continues to display on screen
|
||||
camera.targetTexture = originalTarget;
|
||||
RenderTexture.active = previousActive;
|
||||
UnityEngine.Object.DestroyImmediate(rt);
|
||||
|
||||
return screenShot;
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"Failed to capture screenshot using RenderTexture: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flips the texture vertically in-place. Use before saving when the image is upside-down.
|
||||
/// ReadPixels from RenderTexture uses bottom-left origin (e.g. OpenGL); PNG expects top-left,
|
||||
/// so screenshots from GameView/camera RT can appear flipped. Call this before EncodeToPNG to correct.
|
||||
/// </summary>
|
||||
private static void FlipTextureVertically(Texture2D tex)
|
||||
{
|
||||
if (tex == null || tex.height <= 1) return;
|
||||
int w = tex.width;
|
||||
int h = tex.height;
|
||||
Color[] pixels = tex.GetPixels();
|
||||
for (int y = 0; y < h / 2; y++)
|
||||
{
|
||||
int top = y * w;
|
||||
int bottom = (h - 1 - y) * w;
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
Color tmp = pixels[top + x];
|
||||
pixels[top + x] = pixels[bottom + x];
|
||||
pixels[bottom + x] = tmp;
|
||||
}
|
||||
}
|
||||
tex.SetPixels(pixels);
|
||||
tex.Apply();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Capture Game view using GameView's internal render texture via reflection
|
||||
/// Works in both Edit and Play modes to capture what the user actually sees.
|
||||
/// Note: ReadPixels from RT may yield bottom-up image (OpenGL); save path flips vertically before PNG.
|
||||
/// </summary>
|
||||
private static Texture2D CaptureGameViewInEditMode(int? width = null, int? height = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get active GameView
|
||||
var gameView = GetActiveGameView();
|
||||
if (gameView == null)
|
||||
{
|
||||
Debug.LogWarning("Game View not found. Falling back to camera rendering.");
|
||||
return CaptureWithCameraRenderingFallback(width, height);
|
||||
}
|
||||
|
||||
// Try to get GameView's internal render texture via reflection
|
||||
// Different Unity versions may use different property/field names
|
||||
RenderTexture gameViewRT = null;
|
||||
var gameViewType = gameView.GetType();
|
||||
|
||||
// Try property "targetTexture" (some Unity versions)
|
||||
var textureProperty = gameViewType.GetProperty("targetTexture",
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
if (textureProperty != null)
|
||||
{
|
||||
gameViewRT = textureProperty.GetValue(gameView, null) as RenderTexture;
|
||||
}
|
||||
|
||||
// Try field "m_TargetTexture" (some Unity versions)
|
||||
if (gameViewRT == null)
|
||||
{
|
||||
var textureField = gameViewType.GetField("m_TargetTexture",
|
||||
BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (textureField != null)
|
||||
{
|
||||
gameViewRT = textureField.GetValue(gameView) as RenderTexture;
|
||||
}
|
||||
}
|
||||
|
||||
// Try method "GetMainPlayModeView" or similar approaches
|
||||
if (gameViewRT == null)
|
||||
{
|
||||
var renderDocField = gameViewType.GetField("m_RenderTexture",
|
||||
BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (renderDocField != null)
|
||||
{
|
||||
gameViewRT = renderDocField.GetValue(gameView) as RenderTexture;
|
||||
}
|
||||
}
|
||||
|
||||
if (gameViewRT == null)
|
||||
{
|
||||
Debug.LogWarning("GameView render texture not accessible. Falling back to camera rendering.");
|
||||
return CaptureWithCameraRenderingFallback(width, height);
|
||||
}
|
||||
|
||||
RenderTexture activeRT = RenderTexture.active;
|
||||
|
||||
// Determine final dimensions
|
||||
int finalWidth = width ?? gameViewRT.width;
|
||||
int finalHeight = height ?? gameViewRT.height;
|
||||
|
||||
// Create temporary RenderTexture to read pixels
|
||||
RenderTexture tempRT;
|
||||
|
||||
// If custom dimensions are specified and different from game view, resize
|
||||
if ((width.HasValue || height.HasValue) && (finalWidth != gameViewRT.width || finalHeight != gameViewRT.height))
|
||||
{
|
||||
tempRT = RenderTexture.GetTemporary(finalWidth, finalHeight, 0, gameViewRT.format);
|
||||
// Scale the game view texture to the desired size
|
||||
Graphics.Blit(gameViewRT, tempRT);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use game view dimensions
|
||||
tempRT = RenderTexture.GetTemporary(gameViewRT.width, gameViewRT.height, 0, gameViewRT.format);
|
||||
Graphics.Blit(gameViewRT, tempRT);
|
||||
}
|
||||
|
||||
RenderTexture.active = tempRT;
|
||||
Texture2D screenshot = new Texture2D(tempRT.width, tempRT.height, TextureFormat.RGB24, false);
|
||||
screenshot.ReadPixels(new Rect(0, 0, tempRT.width, tempRT.height), 0, 0);
|
||||
screenshot.Apply();
|
||||
|
||||
RenderTexture.active = activeRT;
|
||||
RenderTexture.ReleaseTemporary(tempRT);
|
||||
|
||||
return screenshot;
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"Failed to capture game view using reflection: {e.Message}. Falling back to camera rendering.");
|
||||
return CaptureWithCameraRenderingFallback(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the active Game View window using reflection
|
||||
/// </summary>
|
||||
private static EditorWindow GetActiveGameView()
|
||||
{
|
||||
try
|
||||
{
|
||||
System.Type gameViewType = System.Type.GetType("UnityEditor.GameView,UnityEditor");
|
||||
if (gameViewType == null)
|
||||
return null;
|
||||
|
||||
// Try to get the focused game view first
|
||||
EditorWindow focusedWindow = EditorWindow.focusedWindow;
|
||||
if (focusedWindow != null && focusedWindow.GetType() == gameViewType)
|
||||
return focusedWindow;
|
||||
|
||||
// If no focused game view, get any game view that exists
|
||||
EditorWindow[] gameViews = Resources.FindObjectsOfTypeAll(gameViewType) as EditorWindow[];
|
||||
if (gameViews != null && gameViews.Length > 0)
|
||||
return gameViews[0];
|
||||
|
||||
return null;
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogWarning($"Could not get Game View: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fallback method using camera rendering when GameView access fails
|
||||
/// </summary>
|
||||
private static Texture2D CaptureWithCameraRenderingFallback(int? width = null, int? height = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
int captureWidth = width ?? Screen.width;
|
||||
int captureHeight = height ?? Screen.height;
|
||||
|
||||
// Create render texture
|
||||
RenderTexture rt = new RenderTexture(captureWidth, captureHeight, 24);
|
||||
|
||||
// Get all cameras and render them to the render texture
|
||||
Camera[] cameras = Camera.allCameras;
|
||||
RenderTexture previousActive = RenderTexture.active;
|
||||
RenderTexture.active = rt;
|
||||
|
||||
// Clear the render texture
|
||||
GL.Clear(true, true, Color.black);
|
||||
|
||||
// Render all active cameras to the render texture in order
|
||||
foreach (Camera cam in cameras)
|
||||
{
|
||||
if (cam != null && cam.enabled && cam.gameObject.activeInHierarchy)
|
||||
{
|
||||
RenderTexture prevTarget = cam.targetTexture;
|
||||
cam.targetTexture = rt;
|
||||
cam.Render();
|
||||
cam.targetTexture = prevTarget;
|
||||
}
|
||||
}
|
||||
|
||||
// Read pixels from render texture
|
||||
Texture2D screenshot = new Texture2D(captureWidth, captureHeight, TextureFormat.RGB24, false);
|
||||
screenshot.ReadPixels(new Rect(0, 0, captureWidth, captureHeight), 0, 0);
|
||||
screenshot.Apply();
|
||||
|
||||
// Cleanup
|
||||
RenderTexture.active = previousActive;
|
||||
UnityEngine.Object.DestroyImmediate(rt);
|
||||
|
||||
return screenshot;
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"Camera rendering fallback failed: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to resize a texture
|
||||
/// </summary>
|
||||
private static Texture2D ResizeTexture(Texture2D source, int targetWidth, int targetHeight)
|
||||
{
|
||||
RenderTexture rt = RenderTexture.GetTemporary(targetWidth, targetHeight);
|
||||
RenderTexture.active = rt;
|
||||
Graphics.Blit(source, rt);
|
||||
|
||||
Texture2D result = new Texture2D(targetWidth, targetHeight);
|
||||
result.ReadPixels(new Rect(0, 0, targetWidth, targetHeight), 0, 0);
|
||||
result.Apply();
|
||||
|
||||
RenderTexture.active = null;
|
||||
RenderTexture.ReleaseTemporary(rt);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Function to capture screenshot and save to file
|
||||
/// </summary>
|
||||
public static string CaptureAndSave(string customPath = null, string customFilename = null, int? width = null, int? height = null, Camera specificCamera = null, string cameraPrefix = null)
|
||||
{
|
||||
// Get the camera to use
|
||||
Camera cam = specificCamera ?? Camera.main;
|
||||
if (cam == null)
|
||||
{
|
||||
Debug.LogError("No main camera found!");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Use the new RenderTexture approach
|
||||
Texture2D screenshot = CaptureScreenByRenderTexture(cam, width, height);
|
||||
if (screenshot == null)
|
||||
{
|
||||
Debug.LogError("Failed to capture screenshot using RenderTexture!");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Encode to PNG
|
||||
byte[] bytes = screenshot.EncodeToPNG();
|
||||
UnityEngine.Object.DestroyImmediate(screenshot);
|
||||
|
||||
// Generate filename with camera prefix
|
||||
string filename;
|
||||
if (!string.IsNullOrEmpty(customFilename))
|
||||
{
|
||||
filename = customFilename.EndsWith(".png") ? customFilename : customFilename + ".png";
|
||||
}
|
||||
else
|
||||
{
|
||||
string prefix = cameraPrefix ?? (specificCamera != null ? specificCamera.name : "MainCamera");
|
||||
filename = $"{prefix}-{System.DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.png";
|
||||
}
|
||||
|
||||
// Determine save path
|
||||
string savePath;
|
||||
if (!string.IsNullOrEmpty(customPath))
|
||||
{
|
||||
// Ensure directory exists
|
||||
Directory.CreateDirectory(customPath);
|
||||
savePath = Path.Combine(customPath, filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use project path with Screenshots folder
|
||||
string projectPath = Path.GetDirectoryName(Application.dataPath); // Get project root (parent of Assets)
|
||||
string screenshotsFolder = Path.Combine(projectPath, "Screenshots");
|
||||
|
||||
// Create Screenshots folder if it doesn't exist
|
||||
if (!Directory.Exists(screenshotsFolder))
|
||||
{
|
||||
Directory.CreateDirectory(screenshotsFolder);
|
||||
Debug.Log($"Created Screenshots folder at: {screenshotsFolder}");
|
||||
}
|
||||
|
||||
savePath = Path.Combine(screenshotsFolder, filename);
|
||||
}
|
||||
|
||||
// Save to file
|
||||
File.WriteAllBytes(savePath, bytes);
|
||||
|
||||
Debug.Log("Screenshot saved to: " + savePath);
|
||||
return savePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user