ThumbnailUtils.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. /*
  2. Copyright (c) 2021 Omar Duarte
  3. Unauthorized copying of this file, via any medium is strictly prohibited.
  4. Writen by Omar Duarte, 2021.
  5. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  6. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  7. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  8. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  9. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  10. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  11. THE SOFTWARE.
  12. */
  13. using System.Linq;
  14. using UnityEngine;
  15. namespace PluginMaster
  16. {
  17. [UnityEditor.InitializeOnLoad]
  18. public class RenderPipelineDefine
  19. {
  20. static RenderPipelineDefine()
  21. {
  22. void SetDefineSymbol(string define)
  23. {
  24. var target = UnityEditor.EditorUserBuildSettings.activeBuildTarget;
  25. var buildTargetGroup = UnityEditor.BuildPipeline.GetBuildTargetGroup(target);
  26. #if UNITY_2022_2_OR_NEWER
  27. var namedBuildTarget = UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(buildTargetGroup);
  28. var definesSCSV = UnityEditor.PlayerSettings.GetScriptingDefineSymbols(namedBuildTarget);
  29. #else
  30. var definesSCSV = UnityEditor.PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup);
  31. #endif
  32. if (definesSCSV.Contains(define)) return;
  33. definesSCSV += ";" + define;
  34. #if UNITY_2022_2_OR_NEWER
  35. UnityEditor.PlayerSettings.SetScriptingDefineSymbols(namedBuildTarget, definesSCSV);
  36. #else
  37. UnityEditor.PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, definesSCSV);
  38. #endif
  39. }
  40. var currentRenderPipeline = UnityEngine.Rendering.GraphicsSettings.currentRenderPipeline;
  41. if (currentRenderPipeline == null) SetDefineSymbol("PWB_BIRP");
  42. else if (currentRenderPipeline.GetType().ToString().Contains("HighDefinition")) SetDefineSymbol("PWB_HDRP");
  43. else if (currentRenderPipeline.GetType().ToString().Contains("Universal")) SetDefineSymbol("PWB_URP");
  44. }
  45. }
  46. public class ThumbnailUtils
  47. {
  48. private static LayerMask layerMask => 1 << PWBCore.staticData.thumbnailLayer;
  49. public const int SIZE = 256;
  50. private const int MIN_SIZE = 24;
  51. private static Texture2D _emptyTexture = null;
  52. private static bool _savingImage = false;
  53. public static bool savingImage => _savingImage;
  54. private class ThumbnailEditor
  55. {
  56. public ThumbnailSettings settings = null;
  57. public GameObject root = null;
  58. public Camera camera = null;
  59. public RenderTexture renderTexture = null;
  60. public Light light = null;
  61. public Transform pivot = null;
  62. public GameObject target = null;
  63. }
  64. public static void RenderTextureToTexture2D(RenderTexture renderTexture, Texture2D texture)
  65. {
  66. var prevActive = RenderTexture.active;
  67. RenderTexture.active = renderTexture;
  68. texture.ReadPixels(new Rect(0, 0, SIZE, SIZE), 0, 0);
  69. texture.Apply();
  70. RenderTexture.active = prevActive;
  71. }
  72. private static Texture2D emptyTexture
  73. {
  74. get
  75. {
  76. if (_emptyTexture == null) _emptyTexture = Resources.Load<Texture2D>("Sprites/Empty");
  77. return _emptyTexture;
  78. }
  79. }
  80. public static void SavePngResource(Texture2D texture, string thumbnailPath)
  81. {
  82. if (texture == null || string.IsNullOrEmpty(thumbnailPath)) return;
  83. _savingImage = true;
  84. byte[] buffer = texture.EncodeToPNG();
  85. System.IO.File.WriteAllBytes(thumbnailPath, buffer);
  86. UnityEditor.AssetDatabase.Refresh();
  87. _savingImage = false;
  88. }
  89. public static Texture2D ScaleImage(string imagePath)
  90. {
  91. if (!System.IO.File.Exists(imagePath)) return null;
  92. var rawData = System.IO.File.ReadAllBytes(imagePath);
  93. Texture2D source = new Texture2D(2, 2);
  94. ImageConversion.LoadImage(source, rawData);
  95. RenderTexture renderTexture = RenderTexture.GetTemporary(SIZE, SIZE);
  96. Graphics.Blit(source, renderTexture);
  97. Texture2D scaledTexture = new Texture2D(SIZE, SIZE);
  98. RenderTextureToTexture2D(renderTexture, scaledTexture);
  99. return scaledTexture;
  100. }
  101. public static void CopyTexture(Texture2D from, out Texture2D to)
  102. {
  103. if (from == null)
  104. {
  105. to = null;
  106. return;
  107. }
  108. to = new Texture2D(from.width, from.height);
  109. to.SetPixels(from.GetPixels());
  110. to.Apply();
  111. }
  112. private static Material _bgMaterial = null;
  113. private static Cubemap _defaultCubemap = null;
  114. public static void UpdateThumbnail(ThumbnailSettings settings,
  115. Texture2D thumbnailTexture, GameObject prefab, string thumbnailPath, bool savePng)
  116. {
  117. var magnitude = BoundsUtils.GetMagnitude(prefab.transform);
  118. var thumbnailEditor = new ThumbnailEditor();
  119. thumbnailEditor.settings = new ThumbnailSettings(settings);
  120. if (magnitude == 0)
  121. {
  122. if (_emptyTexture == null) _emptyTexture = Resources.Load<Texture2D>("Sprites/Empty");
  123. var pixels = _emptyTexture.GetPixels32();
  124. for (int i = 0; i < pixels.Length; ++i)
  125. {
  126. if (pixels[i].a == 0) pixels[i] = thumbnailEditor.settings.backgroudColor;
  127. }
  128. thumbnailTexture.SetPixels32(pixels);
  129. thumbnailTexture.Apply();
  130. return;
  131. }
  132. #if UNITY_2022_2_OR_NEWER
  133. var sceneLights = Object.FindObjectsByType<Light>(FindObjectsSortMode.None)
  134. .ToDictionary(comp => comp, light => light.cullingMask);
  135. #else
  136. var sceneLights = Object.FindObjectsOfType<Light>().ToDictionary(comp => comp, light => light.cullingMask);
  137. #endif
  138. const string rootName = "PWBThumbnailEditor";
  139. do
  140. {
  141. var obj = GameObject.Find(rootName);
  142. if (obj == null) break;
  143. else GameObject.DestroyImmediate(obj);
  144. } while (true);
  145. thumbnailEditor.root = new GameObject(rootName);
  146. var camObj = new GameObject("PWBThumbnailEditorCam");
  147. thumbnailEditor.camera = camObj.AddComponent<Camera>();
  148. thumbnailEditor.camera.transform.SetParent(thumbnailEditor.root.transform);
  149. thumbnailEditor.camera.transform.localPosition = new Vector3(0f, 1.2f, -4f);
  150. thumbnailEditor.camera.transform.localRotation = Quaternion.Euler(17.5f, 0f, 0f);
  151. thumbnailEditor.camera.fieldOfView = 20f;
  152. thumbnailEditor.camera.clearFlags = CameraClearFlags.SolidColor;
  153. thumbnailEditor.camera.backgroundColor = thumbnailEditor.settings.backgroudColor;
  154. thumbnailEditor.camera.cullingMask = layerMask;
  155. thumbnailEditor.renderTexture = new RenderTexture(SIZE, SIZE, 24);
  156. thumbnailEditor.camera.targetTexture = thumbnailEditor.renderTexture;
  157. var originalAmbientMode = RenderSettings.ambientMode;
  158. var originalAmbientLight = RenderSettings.ambientLight;
  159. var originalAmbientEquatorColor = RenderSettings.ambientEquatorColor;
  160. var originalAmbientGroundColor = RenderSettings.ambientGroundColor;
  161. var originalAmbientSkyColor = RenderSettings.ambientSkyColor;
  162. var originalAmbientIntensity = RenderSettings.ambientIntensity;
  163. var originalAmbientProbe = RenderSettings.ambientProbe;
  164. var originalReflectionMode = RenderSettings.defaultReflectionMode;
  165. var originalSkybox = RenderSettings.skybox;
  166. var originalFog = RenderSettings.fog;
  167. var originalFogColor = RenderSettings.fogColor;
  168. var originalFogStartDistance = RenderSettings.fogStartDistance;
  169. var originalFogEndDistance = RenderSettings.fogEndDistance;
  170. var originalFogDensity = RenderSettings.fogDensity;
  171. var originalFogMode = RenderSettings.fogMode;
  172. var originalHaloStrength = RenderSettings.haloStrength;
  173. var originalFlareFadeSpeed = RenderSettings.flareFadeSpeed;
  174. var originalFlareStrength = RenderSettings.flareStrength;
  175. var originalReflectionIntensity = RenderSettings.reflectionIntensity;
  176. var originalReflectionBounces = RenderSettings.reflectionBounces;
  177. var originalDefaultReflectionResolution = RenderSettings.defaultReflectionResolution;
  178. var originalSubtractiveShadowColor = RenderSettings.subtractiveShadowColor;
  179. var originalSun = RenderSettings.sun;
  180. #if UNITY_2022_2_OR_NEWER
  181. var originalReflectionTexture = RenderSettings.customReflectionTexture;
  182. #else
  183. var originalReflectionTexture = RenderSettings.customReflection;
  184. #endif
  185. float intensityMultiplier = 0.7f;
  186. RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Flat;
  187. RenderSettings.ambientLight = thumbnailEditor.settings.lightColor;
  188. RenderSettings.ambientEquatorColor = thumbnailEditor.settings.backgroudColor;
  189. RenderSettings.ambientGroundColor = thumbnailEditor.settings.backgroudColor;
  190. RenderSettings.ambientSkyColor = thumbnailEditor.settings.backgroudColor;
  191. RenderSettings.ambientIntensity = thumbnailEditor.settings.lightIntensity * intensityMultiplier;
  192. RenderSettings.ambientProbe = new UnityEngine.Rendering.SphericalHarmonicsL2();
  193. RenderSettings.defaultReflectionMode = UnityEngine.Rendering.DefaultReflectionMode.Custom;
  194. RenderSettings.skybox = null;
  195. RenderSettings.fog = false;
  196. RenderSettings.fogColor = Color.clear;
  197. RenderSettings.fogStartDistance = 0f;
  198. RenderSettings.fogEndDistance = 1f;
  199. RenderSettings.fogDensity = 0f;
  200. RenderSettings.fogMode = FogMode.Linear;
  201. RenderSettings.haloStrength = 0f;
  202. RenderSettings.flareFadeSpeed = 1f;
  203. RenderSettings.flareStrength = 0f;
  204. RenderSettings.reflectionIntensity = thumbnailEditor.settings.lightIntensity * intensityMultiplier;
  205. RenderSettings.reflectionBounces = 1;
  206. RenderSettings.defaultReflectionResolution = 128;
  207. RenderSettings.subtractiveShadowColor = Color.black;
  208. RenderSettings.sun = null;
  209. if (_defaultCubemap == null)
  210. {
  211. _defaultCubemap = new Cubemap(1, TextureFormat.RGB24, false);
  212. Color[] colors = { Color.white };
  213. for (int face = 0; face < 6; face++)
  214. {
  215. _defaultCubemap.SetPixels(colors, (CubemapFace)face);
  216. }
  217. _defaultCubemap.Apply();
  218. }
  219. #if UNITY_2022_2_OR_NEWER
  220. RenderSettings.customReflectionTexture = _defaultCubemap;
  221. #else
  222. RenderSettings.customReflection = _defaultCubemap;
  223. #endif
  224. var lightObj = new GameObject("PWBThumbnailEditorLight");
  225. thumbnailEditor.light = lightObj.AddComponent<Light>();
  226. thumbnailEditor.light.type = LightType.Directional;
  227. thumbnailEditor.light.transform.SetParent(thumbnailEditor.root.transform);
  228. thumbnailEditor.light.transform.localRotation = Quaternion.Euler(thumbnailEditor.settings.lightEuler);
  229. thumbnailEditor.light.color = thumbnailEditor.settings.lightColor;
  230. thumbnailEditor.light.intensity = thumbnailEditor.settings.lightIntensity;
  231. thumbnailEditor.light.cullingMask = layerMask;
  232. var pivotObj = new GameObject("PWBThumbnailEditorPivot");
  233. pivotObj.layer = PWBCore.staticData.thumbnailLayer;
  234. thumbnailEditor.pivot = pivotObj.transform;
  235. thumbnailEditor.pivot.transform.SetParent(thumbnailEditor.root.transform);
  236. thumbnailEditor.pivot.localPosition = thumbnailEditor.settings.targetOffset;
  237. thumbnailEditor.pivot.transform.localRotation = Quaternion.identity;
  238. thumbnailEditor.pivot.transform.localScale = Vector3.one;
  239. Transform InstantiateBones(Transform source, Transform parent)
  240. {
  241. var obj = new GameObject();
  242. obj.name = source.name;
  243. obj.transform.SetParent(parent);
  244. obj.transform.position = source.position;
  245. obj.transform.rotation = source.rotation;
  246. obj.transform.localScale = source.localScale;
  247. foreach (Transform child in source) InstantiateBones(child, obj.transform);
  248. return obj.transform;
  249. }
  250. bool Requires(System.Type obj, System.Type requirement)
  251. {
  252. return System.Attribute.IsDefined(obj, typeof(RequireComponent))
  253. && System.Attribute.GetCustomAttributes(obj, typeof(RequireComponent)).OfType<RequireComponent>()
  254. .Any(rc => rc.m_Type0.IsAssignableFrom(requirement));
  255. }
  256. bool CanDestroy(GameObject go, System.Type t)
  257. => !go.GetComponents<Component>().Any(c => Requires(c.GetType(), t));
  258. void CopyComponents(GameObject source, GameObject destination)
  259. {
  260. var srcComps = source.GetComponentsInChildren<Component>();
  261. foreach (var srcComp in srcComps)
  262. {
  263. if (srcComp is MonoBehaviour) continue;
  264. var destComp = srcComp is Transform ? destination.transform : destination.AddComponent(srcComp.GetType());
  265. UnityEditor.EditorUtility.CopySerialized(srcComp, destComp);
  266. }
  267. foreach (Transform srcChild in source.transform)
  268. {
  269. var destChild = new GameObject();
  270. destChild.transform.SetParent(destination.transform);
  271. CopyComponents(srcChild.gameObject, destChild);
  272. }
  273. }
  274. GameObject InstantiateAndRemoveMonoBehaviours()
  275. {
  276. var obj = Object.Instantiate(prefab);
  277. var toBeDestroyed = new System.Collections.Generic.List<Component>(obj.GetComponentsInChildren<Component>());
  278. while (toBeDestroyed.Count > 0)
  279. {
  280. var components = toBeDestroyed.ToArray();
  281. int compCount = components.Length;
  282. toBeDestroyed.Clear();
  283. foreach (var comp in components)
  284. {
  285. if (comp is MonoBehaviour)
  286. {
  287. var monoBehaviour = comp as MonoBehaviour;
  288. monoBehaviour.enabled = false;
  289. monoBehaviour.runInEditMode = false;
  290. if (CanDestroy(comp.gameObject, comp.GetType())) Object.DestroyImmediate(comp);
  291. else toBeDestroyed.Add(comp);
  292. }
  293. }
  294. if (compCount == toBeDestroyed.Count) break;
  295. }
  296. if (toBeDestroyed.Count > 0)
  297. {
  298. var noMonoBehaviourObj = new GameObject();
  299. CopyComponents(noMonoBehaviourObj, obj);
  300. Object.DestroyImmediate(obj);
  301. obj = noMonoBehaviourObj;
  302. }
  303. return obj;
  304. }
  305. thumbnailEditor.target = InstantiateAndRemoveMonoBehaviours();
  306. var monoBehaviours = thumbnailEditor.target.GetComponentsInChildren<MonoBehaviour>();
  307. foreach (var monoBehaviour in monoBehaviours)
  308. if (monoBehaviour != null) monoBehaviour.enabled = false;
  309. magnitude = BoundsUtils.GetMagnitude(thumbnailEditor.target.transform);
  310. var targetScale = magnitude > 0 ? 1f / magnitude : 1f;
  311. var targetBounds = BoundsUtils.GetBoundsRecursive(thumbnailEditor.target.transform);
  312. var localPosition = (thumbnailEditor.target.transform.localPosition - targetBounds.center) * targetScale;
  313. thumbnailEditor.target.transform.SetParent(thumbnailEditor.pivot);
  314. thumbnailEditor.target.transform.localPosition = localPosition;
  315. thumbnailEditor.target.transform.localRotation = Quaternion.identity;
  316. thumbnailEditor.target.transform.localScale = prefab.transform.localScale * targetScale;
  317. thumbnailEditor.pivot.localScale = Vector3.one * thumbnailEditor.settings.zoom;
  318. thumbnailEditor.pivot.localRotation = Quaternion.Euler(thumbnailEditor.settings.targetEuler);
  319. var bgObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
  320. bgObject.name = "PWBThumbnailEditorBg";
  321. if (_bgMaterial == null)
  322. {
  323. #if PWB_HDRP
  324. _bgMaterial = new Material(Shader.Find("HDRP/Unlit"));
  325. #else
  326. _bgMaterial = new Material(Shader.Find("Unlit/Color"));
  327. #endif
  328. }
  329. _bgMaterial.color = thumbnailEditor.settings.backgroudColor;
  330. var bgRenderer = bgObject.GetComponent<MeshRenderer>();
  331. bgRenderer.sharedMaterial = _bgMaterial;
  332. bgObject.transform.SetParent(thumbnailEditor.root.transform);
  333. bgObject.transform.localPosition = new Vector3(0, -3, 10);
  334. bgObject.transform.localScale = new Vector3(30, 30, 0.1f);
  335. #if PWB_HDRP || PWB_URP
  336. #if UNITY_2022_2_OR_NEWER
  337. var sceneVolumes = Object.FindObjectsByType<UnityEngine.Rendering.Volume>(FindObjectsSortMode.None)
  338. .ToDictionary(comp => comp, vol => vol.isActiveAndEnabled);
  339. #else
  340. var sceneVolumes = Object.FindObjectsOfType<UnityEngine.Rendering.Volume>()
  341. .ToDictionary(comp => comp, vol => vol.isActiveAndEnabled);
  342. #endif
  343. foreach (var vol in sceneVolumes.Keys) vol.gameObject.SetActive(false);
  344. var meshRenderers = thumbnailEditor.target.GetComponentsInChildren<MeshRenderer>()
  345. .ToDictionary(comp => comp, r => r.lightProbeUsage);
  346. foreach (var meshRenderer in meshRenderers.Keys)
  347. meshRenderer.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off;
  348. var skinnedMeshRenderers = thumbnailEditor.target.GetComponentsInChildren<SkinnedMeshRenderer>()
  349. .ToDictionary(comp => comp, r => r.lightProbeUsage);
  350. foreach (var skinnedMeshRenderer in skinnedMeshRenderers.Keys)
  351. skinnedMeshRenderer.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off;
  352. #endif
  353. #if PWB_HDRP
  354. var HDCamData = camObj.AddComponent<UnityEngine.Rendering.HighDefinition.HDAdditionalCameraData>();
  355. HDCamData.volumeLayerMask = layerMask | 1;
  356. HDCamData.probeLayerMask = 0;
  357. HDCamData.clearColorMode = UnityEngine.Rendering.HighDefinition.HDAdditionalCameraData.ClearColorMode.Color;
  358. HDCamData.backgroundColorHDR = thumbnailEditor.settings.backgroudColor;
  359. HDCamData.antialiasing
  360. = UnityEngine.Rendering.HighDefinition.HDAdditionalCameraData.AntialiasingMode.FastApproximateAntialiasing;
  361. var volumeObj = new GameObject("PWBThumbnailEditorVolume");
  362. var volume = volumeObj.AddComponent<UnityEngine.Rendering.Volume>();
  363. volume.isGlobal = false;
  364. volume.priority = 1;
  365. volume.profile = Resources.Load<UnityEngine.Rendering.VolumeProfile>("ThumbnailVolume");
  366. UnityEngine.Rendering.HighDefinition.Exposure exposure = null;
  367. if (!volume.profile.Has<UnityEngine.Rendering.HighDefinition.Exposure>())
  368. exposure = volume.profile.Add<UnityEngine.Rendering.HighDefinition.Exposure>(true);
  369. else volume.profile.TryGet<UnityEngine.Rendering.HighDefinition.Exposure>(out exposure);
  370. if (exposure != null)
  371. {
  372. exposure.mode.value = UnityEngine.Rendering.HighDefinition.ExposureMode.AutomaticHistogram;
  373. exposure.meteringMode.value = UnityEngine.Rendering.HighDefinition.MeteringMode.CenterWeighted;
  374. exposure.limitMin.Override(13f);
  375. exposure.limitMax.Override(15f);
  376. exposure.compensation.Override(thumbnailEditor.light.intensity);
  377. }
  378. var volumeCollider = volumeObj.AddComponent<BoxCollider>();
  379. volumeCollider.size = new Vector3(50, 50, 50);
  380. volumeObj.transform.SetParent(thumbnailEditor.root.transform);
  381. #endif
  382. thumbnailEditor.root.transform.position = new Vector3(10000, 10000, 10000);
  383. var children = thumbnailEditor.root.GetComponentsInChildren<Transform>();
  384. foreach (var child in children)
  385. {
  386. child.gameObject.layer = PWBCore.staticData.thumbnailLayer;
  387. child.gameObject.hideFlags = HideFlags.HideAndDontSave;
  388. }
  389. foreach (var light in sceneLights.Keys) light.cullingMask = light.cullingMask & ~layerMask;
  390. for (int i = 0; i < 9; ++i) thumbnailEditor.camera.Render();
  391. foreach (var light in sceneLights.Keys) light.cullingMask = sceneLights[light];
  392. #if PWB_HDRP || PWB_URP
  393. foreach (var vol in sceneVolumes) vol.Key.gameObject.SetActive(vol.Value);
  394. foreach (var meshRenderer in meshRenderers) meshRenderer.Key.lightProbeUsage = meshRenderer.Value;
  395. foreach (var skinnedMeshRenderer in skinnedMeshRenderers)
  396. skinnedMeshRenderer.Key.lightProbeUsage = skinnedMeshRenderer.Value;
  397. #endif
  398. RenderTextureToTexture2D(thumbnailEditor.camera.targetTexture, thumbnailTexture);
  399. RenderSettings.ambientMode = originalAmbientMode;
  400. RenderSettings.ambientLight = originalAmbientLight;
  401. RenderSettings.ambientEquatorColor = originalAmbientEquatorColor;
  402. RenderSettings.ambientGroundColor = originalAmbientGroundColor;
  403. RenderSettings.ambientSkyColor = originalAmbientSkyColor;
  404. RenderSettings.ambientIntensity = originalAmbientIntensity;
  405. RenderSettings.ambientProbe = originalAmbientProbe;
  406. RenderSettings.defaultReflectionMode = originalReflectionMode;
  407. RenderSettings.skybox = originalSkybox;
  408. RenderSettings.fog = originalFog;
  409. RenderSettings.fogColor = originalFogColor;
  410. RenderSettings.fogStartDistance = originalFogStartDistance;
  411. RenderSettings.fogEndDistance = originalFogEndDistance;
  412. RenderSettings.fogDensity = originalFogDensity;
  413. RenderSettings.fogMode = originalFogMode;
  414. RenderSettings.haloStrength = originalHaloStrength;
  415. RenderSettings.flareFadeSpeed = originalFlareFadeSpeed;
  416. RenderSettings.flareStrength = originalFlareStrength;
  417. RenderSettings.reflectionIntensity = originalReflectionIntensity;
  418. RenderSettings.reflectionBounces = originalReflectionBounces;
  419. RenderSettings.defaultReflectionResolution = originalDefaultReflectionResolution;
  420. RenderSettings.subtractiveShadowColor = originalSubtractiveShadowColor;
  421. RenderSettings.sun = originalSun;
  422. #if UNITY_2022_2_OR_NEWER
  423. RenderSettings.customReflectionTexture = originalReflectionTexture;
  424. #else
  425. RenderSettings.customReflection = originalReflectionTexture;
  426. #endif
  427. Object.DestroyImmediate(thumbnailEditor.root);
  428. if (savePng) SavePngResource(thumbnailTexture, thumbnailPath);
  429. }
  430. public static void UpdateThumbnail(ThumbnailSettings settings,
  431. Texture2D thumbnailTexture, Texture2D[] subThumbnails, string thumbnailPath, bool savePng)
  432. {
  433. if (subThumbnails.Length == 0)
  434. {
  435. thumbnailTexture.SetPixels(new Color[SIZE * SIZE]);
  436. thumbnailTexture.Apply();
  437. return;
  438. }
  439. var sqrt = Mathf.Sqrt(subThumbnails.Length);
  440. var sideCellsCount = Mathf.FloorToInt(sqrt);
  441. if (Mathf.CeilToInt(sqrt) != sideCellsCount) ++sideCellsCount;
  442. var spacing = (SIZE * sideCellsCount) / MIN_SIZE;
  443. var bigSize = SIZE * sideCellsCount + spacing * (sideCellsCount - 1);
  444. var texture = new Texture2D(bigSize, bigSize);
  445. var pixelCount = bigSize * bigSize;
  446. var pixels = new Color32[pixelCount];
  447. texture.SetPixels32(pixels);
  448. int subIdx = 0;
  449. for (int i = sideCellsCount - 1; i >= 0; --i)
  450. {
  451. for (int j = 0; j < sideCellsCount; ++j)
  452. {
  453. var x = j * (SIZE + spacing);
  454. var y = i * (SIZE + spacing);
  455. if (subThumbnails[subIdx] == null) continue;
  456. var subPixels = subThumbnails[subIdx].GetPixels32();
  457. texture.SetPixels32(x, y, SIZE, SIZE, subPixels);
  458. ++subIdx;
  459. if (subIdx == subThumbnails.Length) goto Resize;
  460. }
  461. }
  462. Resize:
  463. texture.filterMode = FilterMode.Trilinear;
  464. texture.Apply();
  465. var renderTexture = new RenderTexture(SIZE, SIZE, 24);
  466. var prevActive = RenderTexture.active;
  467. RenderTexture.active = renderTexture;
  468. Graphics.Blit(texture, renderTexture);
  469. thumbnailTexture.ReadPixels(new Rect(0, 0, SIZE, SIZE), 0, 0);
  470. thumbnailTexture.Apply();
  471. RenderTexture.active = prevActive;
  472. Object.DestroyImmediate(texture);
  473. if (savePng) SavePngResource(thumbnailTexture, thumbnailPath);
  474. }
  475. public static void UpdateThumbnail(MultibrushItemSettings brushItem, bool savePng, bool updateParent)
  476. {
  477. if (brushItem.thumbnailSettings.useCustomImage)
  478. {
  479. brushItem.LoadThumbnailFromFile();
  480. return;
  481. }
  482. if (brushItem.prefab == null) return;
  483. UpdateThumbnail(brushItem.thumbnailSettings, brushItem.thumbnailTexture,
  484. brushItem.prefab, brushItem.thumbnailPath, savePng);
  485. if (updateParent)
  486. UpdateThumbnail(brushItem.parentSettings, updateItemThumbnails: false, savePng);
  487. }
  488. public static void UpdateThumbnail(MultibrushSettings brushSettings, bool updateItemThumbnails, bool savePng)
  489. {
  490. if (brushSettings.thumbnailSettings.useCustomImage) return;
  491. var brushItems = brushSettings.items;
  492. var subThumbnails = new System.Collections.Generic.List<Texture2D>();
  493. foreach (var item in brushItems)
  494. {
  495. if (updateItemThumbnails) UpdateThumbnail(item, savePng, updateParent: false);
  496. if (item.includeInThumbnail) subThumbnails.Add(item.thumbnail);
  497. }
  498. UpdateThumbnail(brushSettings.thumbnailSettings, brushSettings.thumbnailTexture,
  499. subThumbnails.ToArray(), brushSettings.thumbnailPath, savePng);
  500. }
  501. public static void UpdateThumbnail(BrushSettings brushItem, bool updateItemThumbnails, bool savePng)
  502. {
  503. if (brushItem is MultibrushItemSettings)
  504. UpdateThumbnail(brushItem as MultibrushItemSettings, savePng, updateParent: true);
  505. else if (brushItem is MultibrushSettings)
  506. UpdateThumbnail(brushItem as MultibrushSettings, updateItemThumbnails, savePng);
  507. }
  508. public static void DeleteUnusedThumbnails()
  509. {
  510. var palettes = PaletteManager.paletteData;
  511. bool CheckThumbnailPath(string thumbnailPath)
  512. {
  513. var fileName = System.IO.Path.GetFileNameWithoutExtension(thumbnailPath);
  514. var ids = fileName.Split('_');
  515. if (ids.Length > 2) return false;
  516. long itemId = -1;
  517. long brushId = -1;
  518. var provider = new System.Globalization.CultureInfo("en-US");
  519. if (!long.TryParse(ids[0], System.Globalization.NumberStyles.HexNumber, provider, out brushId)) return false;
  520. var brush = PaletteManager.GetBrushById(brushId);
  521. if (brush == null) return false;
  522. if (ids.Length == 1) return true;
  523. if (!long.TryParse(ids[1], System.Globalization.NumberStyles.HexNumber, provider, out itemId)) return false;
  524. return brush.ItemExist(itemId);
  525. }
  526. var folderPaths = PaletteManager.GetPaletteThumbnailFolderPaths();
  527. foreach (var folderPath in folderPaths)
  528. {
  529. var thumbnailPaths = System.IO.Directory.GetFiles(folderPath, "*.png");
  530. foreach (var thumbnailPath in thumbnailPaths)
  531. {
  532. if (!CheckThumbnailPath(thumbnailPath))
  533. {
  534. System.IO.File.Delete(thumbnailPath);
  535. var metapath = thumbnailPath + ".meta";
  536. if (System.IO.File.Exists(metapath)) System.IO.File.Delete(metapath);
  537. PWBCore.refreshDatabase = true;
  538. }
  539. }
  540. }
  541. }
  542. }
  543. }