ScreenShot.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using UnityEngine;
  5. using UnityEditor;
  6. namespace ChivaXR
  7. {
  8. /// <summary>
  9. /// 屏幕截图管理
  10. /// </summary>
  11. public class ScreenShot : EditorWindow
  12. {
  13. /// <summary>
  14. /// 目标相机,即需要用来截图的层级相机
  15. /// </summary>
  16. public Camera targetCamera;
  17. /// <summary>
  18. /// 最后一个截图的完整路径信息
  19. /// </summary>
  20. public string lastScreenshot = "";
  21. /// <summary>
  22. /// 用于保存所截图片的文件路径
  23. /// </summary>
  24. private string folderPath = "";
  25. /// <summary>
  26. /// 预设宽高,默认为屏幕分辨率
  27. /// </summary>
  28. private int rectWidth = Screen.width;
  29. private int rectHight = Screen.height;
  30. /// <summary>
  31. /// 默认比例
  32. /// </summary>
  33. private int scale = 1;
  34. /// <summary>
  35. /// 图片背景是否透明,默认不透明
  36. /// </summary>
  37. private bool isTransparent = false;
  38. /// <summary>
  39. /// 模型是否居中
  40. /// </summary>
  41. private bool isCenter = false;
  42. /// <summary>
  43. /// 是否隐藏截屏图片
  44. /// </summary>
  45. private bool takeHiResShot = false;
  46. [MenuItem("ChivaXR/Tool/截 图/高分辨率截图")]
  47. public static void SceneScreenShot()
  48. {
  49. EditorWindow editorWindow = EditorWindow.GetWindow(typeof(ScreenShot));
  50. editorWindow.autoRepaintOnSceneChange = true;
  51. editorWindow.Show();
  52. editorWindow.titleContent = new GUIContent("高分辨率截图");
  53. }
  54. private void OnGUI()
  55. {
  56. GUIStyle style = new GUIStyle();
  57. style.fontSize = 16;
  58. style.normal.textColor = Color.white;
  59. EditorGUILayout.LabelField("分辨率", style);
  60. rectWidth = EditorGUILayout.IntField("宽度", rectWidth);
  61. rectHight = EditorGUILayout.IntField("高度", rectHight);
  62. EditorGUILayout.Space();
  63. scale = EditorGUILayout.IntSlider("比例", scale, 1, 15);
  64. //显示帮助信息
  65. EditorGUILayout.HelpBox("截图的默认模式是裁剪,所以需要选择合适的宽高,而比例是在不降低质量的情况下增加或放大渲染的一个因素", MessageType.None);
  66. EditorGUILayout.Space();
  67. GUILayout.Label(" 保存路径", style);
  68. EditorGUILayout.BeginHorizontal();
  69. EditorGUILayout.TextField(folderPath, GUILayout.ExpandWidth(true));
  70. if (GUILayout.Button("预览", GUILayout.ExpandWidth(false)))
  71. {
  72. folderPath = EditorUtility.SaveFolderPanel("保存路径", folderPath, Application.dataPath);
  73. }
  74. EditorGUILayout.EndHorizontal();
  75. EditorGUILayout.HelpBox("选择保存截图的文件夹", MessageType.None);
  76. EditorGUILayout.Space();
  77. GUILayout.Label(" 选择相机", style);
  78. targetCamera = EditorGUILayout.ObjectField(targetCamera, typeof(Camera), true, null) as Camera;
  79. if (targetCamera == null)
  80. {
  81. targetCamera = Camera.main;
  82. }
  83. isTransparent = EditorGUILayout.Toggle("背景是否透明", isTransparent);
  84. EditorGUILayout.HelpBox("选择要捕捉渲染的相机,可以使用透明度选项使背景透明", MessageType.None);
  85. EditorGUILayout.Space();
  86. EditorGUILayout.BeginVertical();
  87. EditorGUILayout.LabelField("默认选项", style);
  88. if (GUILayout.Button("设置为屏幕尺寸"))
  89. {
  90. rectWidth = (int)Handles.GetMainGameViewSize().x;
  91. rectHight = (int)Handles.GetMainGameViewSize().y;
  92. }
  93. if (GUILayout.Button("默认尺寸"))
  94. {
  95. rectWidth = 1920;
  96. rectHight = 1080;
  97. scale = 1;
  98. }
  99. EditorGUILayout.EndVertical();
  100. EditorGUILayout.Space();
  101. EditorGUILayout.LabelField("图片分辨率为:" + rectWidth * scale + " x " + rectHight * scale + " px", EditorStyles.boldLabel);
  102. if (GUILayout.Button("截屏", GUILayout.MinHeight(60)))
  103. {
  104. if (folderPath == "")
  105. {
  106. folderPath = EditorUtility.SaveFolderPanel("保存路径", folderPath, Application.dataPath);
  107. TakeHiResShot();
  108. }
  109. else
  110. {
  111. TakeHiResShot();
  112. }
  113. }
  114. EditorGUILayout.Space();
  115. EditorGUILayout.BeginHorizontal();
  116. if (GUILayout.Button("打开最后一个截图", GUILayout.MaxWidth(160), GUILayout.MinHeight(40)))
  117. {
  118. if (lastScreenshot != "")
  119. {
  120. Application.OpenURL("file://" + lastScreenshot);
  121. }
  122. }
  123. if (GUILayout.Button("打开文件夹", GUILayout.MaxWidth(160), GUILayout.MinHeight(40)))
  124. {
  125. Application.OpenURL("file://" + folderPath);
  126. }
  127. EditorGUILayout.EndHorizontal();
  128. if (takeHiResShot)
  129. {
  130. int width = rectWidth * scale;
  131. int height = rectHight * scale;
  132. RenderTexture rt = new RenderTexture(width, height, 24);
  133. targetCamera.targetTexture = rt;
  134. //纹理格式
  135. TextureFormat textureFormat;
  136. if (isTransparent)
  137. {
  138. textureFormat = TextureFormat.ARGB32;
  139. }
  140. else
  141. {
  142. textureFormat = TextureFormat.RGB24;
  143. }
  144. Texture2D screenShot = new Texture2D(width, height, textureFormat, false);
  145. targetCamera.Render();
  146. RenderTexture.active = rt;
  147. screenShot.ReadPixels(new Rect(0, 0, width, height), 0, 0);
  148. targetCamera.targetTexture = null;
  149. RenderTexture.active = null;
  150. byte[] bytes = screenShot.EncodeToPNG();
  151. string filename = ScreenShotName(width, height);
  152. File.WriteAllBytes(filename, bytes);
  153. Application.OpenURL(filename);
  154. takeHiResShot = false;
  155. }
  156. }
  157. private void TakeHiResShot()
  158. {
  159. takeHiResShot = true;
  160. }
  161. /// <summary>
  162. /// 截图完整路径信息
  163. /// </summary>
  164. /// <param name="width"></param>
  165. /// <param name="height"></param>
  166. /// <returns></returns>
  167. public string ScreenShotName(int width, int height)
  168. {
  169. string strPath = string.Format(
  170. "{0}/screen_{1}x{2}_{3}.png",
  171. folderPath,
  172. width,
  173. height,
  174. System.DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
  175. lastScreenshot = strPath;
  176. return strPath;
  177. }
  178. [MenuItem("GameObject/Chiva/固定视角创建预览图", priority = 0)]
  179. public static void CreatePreview()
  180. {
  181. string folderPath = "";
  182. folderPath = EditorUtility.SaveFolderPanel("保存路径", folderPath, Application.dataPath);
  183. byte[] bytes = GetAssetPreview(Selection.activeGameObject).EncodeToPNG();
  184. string filename = string.Format(
  185. "{0}/screen_{1}.png",
  186. folderPath,
  187. System.DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
  188. File.WriteAllBytes(filename, bytes);
  189. Application.OpenURL(filename);
  190. }
  191. [MenuItem("GameObject/Chiva/Scene视角创建预览图", priority = 0)]
  192. public static void CreatePreviewBySceneView()
  193. {
  194. string folderPath = "";
  195. folderPath = EditorUtility.SaveFolderPanel("保存路径", folderPath, Application.dataPath);
  196. byte[] bytes = GetAssetPreview(Selection.activeGameObject, true).EncodeToPNG();
  197. string filename = string.Format(
  198. "{0}/screen_{1}.png",
  199. folderPath,
  200. System.DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
  201. File.WriteAllBytes(filename, bytes);
  202. Application.OpenURL(filename);
  203. }
  204. private static Vector2 previewSize = new Vector2(512, 512);
  205. /// <summary>
  206. /// 获取预览图象
  207. /// </summary>
  208. /// <param name="obj"></param>
  209. /// <param name="sceneView">是否按照当前Scene视角截图</param>
  210. /// <returns></returns>
  211. private static Texture2D GetAssetPreview(GameObject obj, bool sceneView = false, bool cloneObj = true)
  212. {
  213. GameObject clone;
  214. Transform cloneTransform;
  215. if (cloneObj)
  216. {
  217. clone = GameObject.Instantiate(obj);
  218. cloneTransform = clone.transform;
  219. cloneTransform.position = new Vector3(-1000, -1000, -1000);
  220. cloneTransform.rotation = obj.transform.rotation;
  221. }
  222. else
  223. {
  224. clone = obj;
  225. cloneTransform = clone.transform;
  226. }
  227. Transform[] all = clone.GetComponentsInChildren<Transform>();
  228. foreach (Transform trans in all)
  229. {
  230. trans.gameObject.layer = 21;
  231. }
  232. Bounds bounds = GetBounds(clone);
  233. Vector3 Min = bounds.min;
  234. Vector3 Max = bounds.max;
  235. GameObject cameraObj = new GameObject("render camera");
  236. Camera renderCamera = cameraObj.AddComponent<Camera>();
  237. renderCamera.backgroundColor = new Color(0.2f, 0.2f, 0.2f, 0);
  238. renderCamera.clearFlags = CameraClearFlags.Color;
  239. renderCamera.cullingMask = 1 << 21;
  240. renderCamera.nearClipPlane = 0.01f;
  241. renderCamera.fieldOfView = 30;
  242. Vector3 center = bounds.center;
  243. Vector3 position;
  244. //求相机应当所处的目标位置
  245. if (sceneView)
  246. {
  247. //预览图视角设置为当前Scene视角
  248. position = center - SceneView.lastActiveSceneView.camera.transform.rotation * (bounds.extents.magnitude * 3.8f * Vector3.forward);
  249. }
  250. else
  251. {
  252. //固定视角
  253. position = center - Quaternion.Euler(30, -30, 60) * (bounds.extents.magnitude * 3.8f * Vector3.forward);
  254. }
  255. // 更新位置
  256. cameraObj.transform.position = position;
  257. cameraObj.transform.LookAt(bounds.center);
  258. RenderTexture texture = new RenderTexture((int)previewSize.x, (int)previewSize.y, 24, RenderTextureFormat.Default);
  259. renderCamera.targetTexture = texture;
  260. renderCamera.RenderDontRestore();
  261. //纹理格式
  262. TextureFormat textureFormat = TextureFormat.ARGB32;
  263. Texture2D screenShot = new Texture2D((int)previewSize.x, (int)previewSize.y, textureFormat, false);
  264. renderCamera.Render();
  265. RenderTexture.active = texture;
  266. screenShot.ReadPixels(new Rect(0, 0, (int)previewSize.x, (int)previewSize.y), 0, 0);
  267. renderCamera.targetTexture = null;
  268. RenderTexture.active = null;
  269. if (cloneObj)
  270. {
  271. Object.DestroyImmediate(clone);
  272. }
  273. Object.DestroyImmediate(cameraObj);
  274. return screenShot;
  275. }
  276. /// <summary>
  277. /// 获得某物体的空間bounds
  278. /// </summary>
  279. /// <param name="obj"></param>
  280. private static Bounds GetBounds(GameObject obj)
  281. {
  282. Vector3 Min = new Vector3(99999, 99999, 99999);
  283. Vector3 Max = new Vector3(-99999, -99999, -99999);
  284. MeshRenderer[] renders = obj.GetComponentsInChildren<MeshRenderer>();
  285. for (int i = 0; i < renders.Length; i++)
  286. {
  287. if (renders[i].bounds.min.x < Min.x)
  288. Min.x = renders[i].bounds.min.x;
  289. if (renders[i].bounds.min.y < Min.y)
  290. Min.y = renders[i].bounds.min.y;
  291. if (renders[i].bounds.min.z < Min.z)
  292. Min.z = renders[i].bounds.min.z;
  293. if (renders[i].bounds.max.x > Max.x)
  294. Max.x = renders[i].bounds.max.x;
  295. if (renders[i].bounds.max.y > Max.y)
  296. Max.y = renders[i].bounds.max.y;
  297. if (renders[i].bounds.max.z > Max.z)
  298. Max.z = renders[i].bounds.max.z;
  299. }
  300. Vector3 center = (Min + Max) / 2;
  301. Vector3 size = new Vector3(Max.x - Min.x, Max.y - Min.y, Max.z - Min.z);
  302. return new Bounds(center, size);
  303. }
  304. }
  305. }