- 모든 컨트롤러 에디터를 IMGUI → UI Toolkit(UXML/USS)으로 전환 (Camera, Item, Event, Avatar, System, StreamDeck, OptiTrack, Facial) - StreamingleCommon.uss 공통 테마 + 개별 에디터 USS 스타일시트 - SystemController 서브매니저 분리 (OptiTrack, Facial, Recording, Screenshot 등) - 런타임 컨트롤 패널 (ESC 토글, 좌측 오버레이, 150% 스케일) - 웹 대시보드 서버 (StreamingleDashboardServer) + 리타게팅 통합 - 설정 도구(StreamingleControllerSetupTool) UXML 재작성 + 원클릭 설정 - SimplePoseTransfer UXML 에디터 추가 - 전체 UXML 한글화 + NanumGothic 폰트 적용 - Streamingle.Debug → Streamingle.Debugging 네임스페이스 변경 (Debug.Log 충돌 해결) - 불필요 코드 제거 (rawkey.cs, RetargetingHTTPServer, OptitrackSkeletonAnimator 등) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
212 lines
6.7 KiB
C#
212 lines
6.7 KiB
C#
using UnityEngine;
|
|
using System;
|
|
using System.IO;
|
|
|
|
/// <summary>
|
|
/// 스크린샷 캡처 관리 (RGB + 알파채널)
|
|
/// </summary>
|
|
[Serializable]
|
|
public class ScreenshotManager
|
|
{
|
|
[Tooltip("스크린샷 해상도 (기본: 4K)")]
|
|
public int screenshotWidth = 3840;
|
|
|
|
[Tooltip("스크린샷 해상도 (기본: 4K)")]
|
|
public int screenshotHeight = 2160;
|
|
|
|
[Tooltip("스크린샷 저장 경로 (비어있으면 바탕화면)")]
|
|
public string screenshotSavePath = "";
|
|
|
|
[Tooltip("파일명 앞에 붙을 접두사")]
|
|
public string screenshotFilePrefix = "Screenshot";
|
|
|
|
[Tooltip("알파 채널 추출용 셰이더")]
|
|
public Shader alphaShader;
|
|
|
|
[Tooltip("NiloToon Prepass 버퍼 텍스처 이름")]
|
|
public string niloToonPrepassBufferName = "_NiloToonPrepassBufferTex";
|
|
|
|
[Tooltip("촬영할 카메라 (비어있으면 메인 카메라 사용)")]
|
|
public Camera screenshotCamera;
|
|
|
|
[Tooltip("알파 채널 블러 반경 (0 = 블러 없음, 1.0 = 약한 블러)")]
|
|
[Range(0f, 3f)]
|
|
public float alphaBlurRadius = 1.0f;
|
|
|
|
[NonSerialized]
|
|
private Material alphaMaterial;
|
|
|
|
private Action<string> log;
|
|
private Action<string> logError;
|
|
|
|
public void Initialize(Action<string> log, Action<string> logError)
|
|
{
|
|
this.log = log;
|
|
this.logError = logError;
|
|
|
|
if (screenshotCamera == null)
|
|
{
|
|
screenshotCamera = Camera.main;
|
|
}
|
|
|
|
if (alphaShader == null)
|
|
{
|
|
alphaShader = Shader.Find("Hidden/AlphaFromNiloToon");
|
|
if (alphaShader == null)
|
|
{
|
|
logError?.Invoke("알파 셰이더를 찾을 수 없습니다: Hidden/AlphaFromNiloToon");
|
|
}
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(screenshotSavePath))
|
|
{
|
|
screenshotSavePath = Path.Combine(Application.dataPath, "..", "Screenshots");
|
|
}
|
|
|
|
if (!Directory.Exists(screenshotSavePath))
|
|
{
|
|
Directory.CreateDirectory(screenshotSavePath);
|
|
log?.Invoke($"Screenshots 폴더 생성됨: {screenshotSavePath}");
|
|
}
|
|
}
|
|
|
|
public void CaptureScreenshot()
|
|
{
|
|
if (screenshotCamera == null)
|
|
{
|
|
logError?.Invoke("촬영할 카메라가 설정되지 않았습니다!");
|
|
return;
|
|
}
|
|
|
|
string fileName = GenerateFileName("png");
|
|
string fullPath = Path.Combine(screenshotSavePath, fileName);
|
|
|
|
try
|
|
{
|
|
RenderTexture rt = new RenderTexture(screenshotWidth, screenshotHeight, 24);
|
|
RenderTexture currentRT = screenshotCamera.targetTexture;
|
|
|
|
screenshotCamera.targetTexture = rt;
|
|
screenshotCamera.Render();
|
|
|
|
RenderTexture.active = rt;
|
|
Texture2D screenshot = new Texture2D(screenshotWidth, screenshotHeight, TextureFormat.RGB24, false);
|
|
screenshot.ReadPixels(new Rect(0, 0, screenshotWidth, screenshotHeight), 0, 0);
|
|
screenshot.Apply();
|
|
|
|
byte[] bytes = screenshot.EncodeToPNG();
|
|
File.WriteAllBytes(fullPath, bytes);
|
|
|
|
screenshotCamera.targetTexture = currentRT;
|
|
RenderTexture.active = null;
|
|
rt.Release();
|
|
UnityEngine.Object.Destroy(rt);
|
|
UnityEngine.Object.Destroy(screenshot);
|
|
|
|
log?.Invoke($"스크린샷 저장 완료: {fullPath}");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
logError?.Invoke($"스크린샷 촬영 실패: {e.Message}");
|
|
}
|
|
}
|
|
|
|
public void CaptureAlphaScreenshot()
|
|
{
|
|
if (screenshotCamera == null)
|
|
{
|
|
logError?.Invoke("촬영할 카메라가 설정되지 않았습니다!");
|
|
return;
|
|
}
|
|
|
|
if (alphaShader == null)
|
|
{
|
|
logError?.Invoke("알파 셰이더가 설정되지 않았습니다!");
|
|
return;
|
|
}
|
|
|
|
string fileName = GenerateFileName("png", "_Alpha");
|
|
string fullPath = Path.Combine(screenshotSavePath, fileName);
|
|
|
|
try
|
|
{
|
|
RenderTexture rt = new RenderTexture(screenshotWidth, screenshotHeight, 24);
|
|
RenderTexture currentRT = screenshotCamera.targetTexture;
|
|
|
|
screenshotCamera.targetTexture = rt;
|
|
screenshotCamera.Render();
|
|
|
|
Texture niloToonPrepassBuffer = Shader.GetGlobalTexture(niloToonPrepassBufferName);
|
|
|
|
if (niloToonPrepassBuffer == null)
|
|
{
|
|
logError?.Invoke($"NiloToon Prepass 버퍼를 찾을 수 없습니다: {niloToonPrepassBufferName}");
|
|
screenshotCamera.targetTexture = currentRT;
|
|
UnityEngine.Object.Destroy(rt);
|
|
return;
|
|
}
|
|
|
|
if (alphaMaterial == null)
|
|
{
|
|
alphaMaterial = new Material(alphaShader);
|
|
}
|
|
|
|
RenderTexture alphaRT = new RenderTexture(screenshotWidth, screenshotHeight, 0, RenderTextureFormat.ARGB32);
|
|
alphaMaterial.SetTexture("_MainTex", rt);
|
|
alphaMaterial.SetTexture("_AlphaTex", niloToonPrepassBuffer);
|
|
alphaMaterial.SetFloat("_BlurRadius", alphaBlurRadius);
|
|
|
|
Graphics.Blit(rt, alphaRT, alphaMaterial);
|
|
|
|
RenderTexture.active = alphaRT;
|
|
Texture2D screenshot = new Texture2D(screenshotWidth, screenshotHeight, TextureFormat.RGBA32, false);
|
|
screenshot.ReadPixels(new Rect(0, 0, screenshotWidth, screenshotHeight), 0, 0);
|
|
screenshot.Apply();
|
|
|
|
byte[] bytes = screenshot.EncodeToPNG();
|
|
File.WriteAllBytes(fullPath, bytes);
|
|
|
|
screenshotCamera.targetTexture = currentRT;
|
|
RenderTexture.active = null;
|
|
rt.Release();
|
|
UnityEngine.Object.Destroy(rt);
|
|
alphaRT.Release();
|
|
UnityEngine.Object.Destroy(alphaRT);
|
|
UnityEngine.Object.Destroy(screenshot);
|
|
|
|
log?.Invoke($"알파 스크린샷 저장 완료: {fullPath}");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
logError?.Invoke($"알파 스크린샷 촬영 실패: {e.Message}");
|
|
}
|
|
}
|
|
|
|
public void OpenScreenshotFolder()
|
|
{
|
|
if (Directory.Exists(screenshotSavePath))
|
|
{
|
|
System.Diagnostics.Process.Start(screenshotSavePath);
|
|
log?.Invoke($"저장 폴더 열기: {screenshotSavePath}");
|
|
}
|
|
else
|
|
{
|
|
logError?.Invoke($"저장 폴더가 존재하지 않습니다: {screenshotSavePath}");
|
|
}
|
|
}
|
|
|
|
private string GenerateFileName(string extension, string suffix = "")
|
|
{
|
|
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
|
return $"{screenshotFilePrefix}{suffix}_{timestamp}.{extension}";
|
|
}
|
|
|
|
public void Cleanup()
|
|
{
|
|
if (alphaMaterial != null)
|
|
{
|
|
UnityEngine.Object.Destroy(alphaMaterial);
|
|
}
|
|
}
|
|
}
|