/// <summary> /// 通过skin把所有的texture打包到一个图集 /// </summary> /// <returns>The repacked from skin.</returns> /// <param name="skin">Skin.</param> /// <param name="newName">New name.</param> /// <param name="shader">Shader.</param> /// <param name="outputMaterial">Output material.</param> /// <param name="outputTexture">Output texture.</param> /// <param name="maxAtlasSize">Max atlas size.</param> /// <param name="padding">Padding.</param> /// <param name="textureFormat">Texture format.</param> /// <param name="mipmaps">If set to <c>true</c> mipmaps.</param> /// <param name="materialPropertySource">Material property source.</param> /// <param name="clearCache">If set to <c>true</c> clear cache.</param> private void GetRepackedFromSkin(CombineTextureData combineTextureData, Skin skin, string newName, Shader shader, int maxAtlasSize = SpineConstValue.smallAtlasSize, int padding = SpineConstValue.atlasPadding, TextureFormat textureFormat = SpineConstValue.textureFormat, bool mipmaps = SpineConstValue.atlasMipMaps, Material materialPropertySource = null, bool clearCache = SpineConstValue.atlasClearCache) { //用CPU合并图集 //return AtlasUtilities.GetRepackedSkin(skin, newName, shader, out outputMaterial, out outputTexture); //用GPU合并图集 SpineChangeCommonTools.GetSpineRepackedSkin(combineTextureData, skin, newName, shader, maxAtlasSize, textureFormat, mipmaps, materialPropertySource, clearCache); }
/// <summary> /// 替换完attachment数据之后进行刷新 /// </summary> private void UpdateRoleEquipment(SkeletonAnimation skeletonAnim, CombineTextureData combineTextureData) { //合并图集 if (null != combineTextureData.combineCoroutine) { GameManager.Instance.StopCoroutine(combineTextureData.combineCoroutine); } combineTextureData.combineCoroutine = GameManager.Instance.StartCoroutine(TexturePackaged(skeletonAnim, combineTextureData)); }
/// <summary> /// 重置 /// </summary> private void ResetValue(CombineTextureData combineTextureData) { endIndex = 0; beginIndex = 0; currentAllWidth = 0; currentAllHeight = 0; lineHeightList = new List <float> (); combineTextureData.smallAtlasNumber = 0; }
private void DestroyResources(CombineTextureData combineTextureData) { if (null != combineTextureData.resultData) { if (null != combineTextureData.resultData.lastRenderTex) { RenderTexture.ReleaseTemporary(combineTextureData.resultData.lastRenderTex); combineTextureData.resultData.lastRenderTex.Release(); combineTextureData.resultData.lastRenderTex = null; } } UnityEngine.Resources.UnloadUnusedAssets(); }
//合并小的图集为一张大图 private IEnumerator FinallyPackage(CombineTextureData combineTextureData, Dictionary <RenderTexture, TextureClass[]> dic, Action <PackagedTextureResult> finishCallBack) { PackagedTextureResult result = new PackagedTextureResult(); TextureSize size = GetAtlasSize(combineTextureData.smallAtlasNumber); MaxRectsBinPack maxRectsBinPack = new MaxRectsBinPack(size.x, size.y, false); Material material = InitMaterial(); RenderTexture render = RenderTexture.GetTemporary(size.x, size.y, 0, RenderTextureFormat.ARGB4444); List <TextureClass> tc = new List <TextureClass> (); Graphics.Blit(null, null, material, 0); foreach (KeyValuePair <RenderTexture, TextureClass[]> keys in dic) { RenderTexture tempTexture = keys.Key; Rect rect = maxRectsBinPack.Insert(tempTexture.width, tempTexture.height, MaxRectsBinPack.FreeRectChoiceHeuristic.RectBestAreaFit); //重新计算位置 for (int i = 0; i < keys.Value.Length; i++) { keys.Value[i].rect = new Rect(rect.x + keys.Value[i].rect.x, rect.y + keys.Value[i].rect.y, keys.Value[i].rect.width, keys.Value[i].rect.height); tc.Add(keys.Value[i]); } Rect scaleRect = GetScaleRect(rect, size.x, size.y); material.SetTexture("_MainTex", tempTexture); material.SetFloat("_ScaleX", scaleRect.width); material.SetFloat("_ScaleY", scaleRect.height); material.SetFloat("_OffsetX", scaleRect.x); material.SetFloat("_OffsetY", scaleRect.y); Graphics.Blit(null, render, material, 1); //归还小图集RenderTexture RenderTexture.ReleaseTemporary(tempTexture); tempTexture.Release(); tempTexture = null; yield return(null); } Graphics.Blit(null, null, material, 0); for (int i = 0; i < tc.Count; i++) { tc[i].rect = GetUVRect(GetScaleRect(tc[i].rect, size.x, size.y), tc[i].textureSize, size.x, size.y); } result.renderTexture = render; result.textureInfo = tc.ToArray(); if (null != finishCallBack) { finishCallBack.Invoke(result); } }
/// <summary> /// 初始化角色的插槽和附件信息 /// </summary> /// <param name="successfulCallBack">Successful call back.</param> /// <param name="failCallBack">Fail call back.</param> public void SpineInitRoleSlotAttachment(RoleAnaimationData animationData, SkeletonAnimation skeletonAnim, RoleEquipmentData tempData, CombineTextureData combineTextureData, Dictionary <int, List <string> > TempSlotAttachmentDic, List <Texture2D> destoryTextureList, Action <bool> setRoleStatus, bool isTP, bool isHide, Action <string> failCallBack = null) { if (null != setRoleStatus && isHide) { setRoleStatus.Invoke(false); } if (null != combineTextureData.initRoleCoroutine) { GameManager.Instance.StopCoroutine(combineTextureData.initRoleCoroutine); } combineTextureData.initRoleCoroutine = GameManager.Instance.StartCoroutine(spineChangeCoreLogic.InitRoleEquipment(animationData, skeletonAnim, tempData, combineTextureData, TempSlotAttachmentDic, destoryTextureList, setRoleStatus, failCallBack, isTP)); }
/// <summary> /// 角色换装 /// </summary> /// <param name="slotStr">Slot string.</param> /// <param name="texture2D">Texture2 d.</param> /// <param name="successfulCallBack">Successful call back.</param> /// <param name="failCallBack">Fail call back.</param> public void SpineRoleChange(RoleAnaimationData animationData, SkeletonAnimation skeletonAnim, CombineTextureData combineTextureData, Dictionary <int, List <string> > slotAttachmentDic, RoleEquipmentData equipmentData, RoleEquipmentItem equipmentItem, bool isTexturePackaged, List <Texture2D> destoryTextureList, Action <bool> setRoleStatus, Action <string> failCallBack = null) { if (null != setRoleStatus) { setRoleStatus.Invoke(false); } System.DateTime time1 = System.DateTime.Now; SpineChangeDataLogic.Instance.GetRoleEquipmentObject(equipmentItem, (UnityEngine.Object o) => { //SpineChangeDataLogic.Instance.SaveRoleEquipmentToServerAndLocal (equipmentData, equipmentItem); if (null != combineTextureData.changeRoleCoroutine) { GameManager.Instance.StopCoroutine(combineTextureData.changeRoleCoroutine); } combineTextureData.changeRoleCoroutine = GameManager.Instance.StartCoroutine(spineChangeCoreLogic.Change(animationData, skeletonAnim, combineTextureData, slotAttachmentDic, o as EquipmentObject, isTexturePackaged, destoryTextureList, setRoleStatus, failCallBack)); System.DateTime time2 = System.DateTime.Now; if (null != GameObject.FindObjectOfType <ChangeTest> ()) { GameObject.FindObjectOfType <ChangeTest> ().text.text += "加载AB用时:" + (time2 - time1).TotalMilliseconds + "\n"; } }); }
private System.Collections.IEnumerator TexturePackaged(SkeletonAnimation skeleAnim, CombineTextureData combineTextureData) { combineTextureData.isFinished = false; Skin skin = new Skin(SpineConstValue.NewSkinname); skin.Append(skeleAnim.skeleton.data.DefaultSkin); System.DateTime time1 = System.DateTime.Now; GetRepackedFromSkin(combineTextureData, skin, SpineConstValue.NewSkinname, Shader.Find(SpineConstValue.shaderPath)); while (!combineTextureData.isFinished) { yield return(null); } System.DateTime time2 = System.DateTime.Now; if (null != GameObject.FindObjectOfType <ChangeTest> ()) { GameObject.FindObjectOfType <ChangeTest> ().text.text += "合并图集用时:" + (time2 - time1).TotalMilliseconds + "\n"; } if (combineTextureData.isFinished) { skeleAnim.skeleton.SetSkin(combineTextureData.resultData.skin); skeleAnim.skeleton.data.defaultSkin = combineTextureData.resultData.skin; combineTextureData.resultData.self.DestroyEquipment(); DestroyResources(combineTextureData); } }
/// <summary> /// 换装 /// </summary> /// <returns>The change.</returns> /// <param name="item">装备数据</param> public System.Collections.IEnumerator Change(RoleAnaimationData animationData, SkeletonAnimation skeletonAnim, CombineTextureData combineTextureData, Dictionary <int, List <string> > slotAttachmentDic, EquipmentObject eo, bool isTexturePackage, List <Texture2D> destoryTextureList, Action <bool> setRoleStatus, Action <string> failCallBack, bool isCreateInit = false) { #if UNITY_ANDROID destoryTextureList.Add(eo.equipmentTexture_Alpha); destoryTextureList.Add(eo.equipmentTexture_RGB); #elif UNITY_IPHONE || UNITY_EDITOR destoryTextureList.Add(eo.equipmentTexture); #endif SpineReadJsonDataLogic.Instance.GetSpineJsonObjectDic(eo.equipmentJsonAsset); List <AtlasRegion> regions = SpineChangeDataLogic.Instance.GetEquipmentAtlasRegions(eo, SpineChangeDataLogic.Instance.GetEquipmentMaterial()); List <string> slotAttachmentNameList = new List <string> (); List <AtlasRegionData> sortData = SpineCreateAttachment.Instance.GetSortRegionList(skeletonAnim, regions, slotAttachmentDic); //更换皮肤数据里面的Attachment字典KeyValuePair<Skin.AttachmentKeyTuple, Attachment >(换成我们自己创建的) for (int i = 0; i < sortData.Count; i++) { // List<int> slotIndexList = GetSlotListForSlotAttachmentDic (slotAttachmentDic, regions[i].name); // for (int j = 0; j < slotIndexList.Count; j++) { // Attachment tempattachment = GetAttachmentByType (skeletonAnim, SpineChangeDataLogic.Instance.GetAttachmentType (skeletonAnim, slotIndexList[j] + "|" + regions[i].name), slotIndexList[j] + "|" + regions[i].name, regions[i]); // if (null == tempattachment) { // yield return null; // } // skeletonAnim.Skeleton.Data.DefaultSkin.AddAttachment (slotIndexList[j], regions[i].name, tempattachment); // slotAttachmentNameList.Add (SpineChangeCoreLogic.Instance.GetSlotNameBySlotIndex (skeletonAnim, slotIndexList[j]) + "$" + tempattachment.Name); // } Attachment tempattachment = GetAttachmentByType(skeletonAnim, sortData[i].type, sortData[i].allName, sortData[i].region); if (null == tempattachment) { yield return(null); } skeletonAnim.Skeleton.Data.DefaultSkin.AddAttachment(SpineChangeDataLogic.Instance.GetSlotIndexFromAllAttachmentName(sortData[i].allName), SpineChangeDataLogic.Instance.GetAttachmentFromAllAttachmnetName(sortData[i].allName), tempattachment); slotAttachmentNameList.Add(SpineChangeCoreLogic.Instance.GetSlotNameBySlotIndex(skeletonAnim, SpineChangeDataLogic.Instance.GetSlotIndexFromAllAttachmentName(sortData[i].allName)) + "$" + tempattachment.Name); } //替换完附件之后刷新(有的附件可以不用刷新) if (null == skeletonAnim) { yield break; } skeletonAnim.Skeleton.SetToSetupPose(); System.DateTime time1 = System.DateTime.Now; //重组Json yield return(GameManager.Instance.StartCoroutine(SpineReadJsonDataLogic.Instance.CreateNewRoleJsonDic(animationData, eo.equipmentJsonAsset, slotAttachmentNameList, skeletonAnim, setRoleStatus))); yield return(null); System.DateTime time2 = System.DateTime.Now; if (null != GameObject.FindObjectOfType <ChangeTest> ()) { GameObject.FindObjectOfType <ChangeTest> ().text.text += "重组Json的时间:" + (time2 - time1).TotalMilliseconds + "\n"; } //当不是创建时change的话就判断是否合图集 if (!isCreateInit) { if (null != roleObject) { setRoleStatus.Invoke(true); } if (isTexturePackage) { UpdateRoleEquipment(skeletonAnim, combineTextureData); } else { DestroyResources(combineTextureData); } } }
/// <summary> /// 初始化角色的插槽附件 /// </summary> /// <returns><c>true</c>, if role slot attachment info was inited, <c>false</c> otherwise.</returns> public System.Collections.IEnumerator InitRoleEquipment(RoleAnaimationData animationData, SkeletonAnimation skeletonAnim, RoleEquipmentData tempData, CombineTextureData combineTextureData, Dictionary <int, List <string> > TempSlotAttachmentDic, List <Texture2D> destoryTextureList, Action <bool> setRoleStatus, Action <string> failCallBack, bool isTP) { if (skeletonAnim == null) { if (null != failCallBack) { failCallBack.Invoke("<-初始化角色的插槽和附件信息失败->"); } yield break; } System.DateTime time1 = System.DateTime.Now; for (int i = 0; i < tempData.RoleEquipmentItems.Count; i++) { // if(tempData.RoleEquipmentItems[i].EquipmentType == RoleEquipmentType.RoleHat || tempData.RoleEquipmentItems[i].EquipmentType == RoleEquipmentType.RoleGlasses) // continue; EquipmentRes res = SpineChangeDataLogic.Instance.GetRoleEquipmentObject(tempData.RoleEquipmentItems[i], null); while (!res.isDone) { yield return(null); } combineTextureData.changeRoleCoroutine = GameManager.Instance.StartCoroutine(Change(animationData, skeletonAnim, combineTextureData, TempSlotAttachmentDic, res.GetRes(), isTP, destoryTextureList, setRoleStatus, failCallBack, true)); yield return(combineTextureData.changeRoleCoroutine); } System.DateTime time2 = System.DateTime.Now; if (null != GameObject.FindObjectOfType <ChangeTest> ()) { GameObject.FindObjectOfType <ChangeTest> ().text.text += "创建角色并初始化用时:" + (time2 - time1).TotalMilliseconds + "\n"; } if (null != roleObject) { setRoleStatus.Invoke(true); } if (isTP) { //需要合图集 UpdateRoleEquipment(skeletonAnim, combineTextureData); } else { DestroyResources(combineTextureData); } }
/// <summary> /// 通过skeletonDataAsset创建角色 /// </summary> /// <returns><c>true</c>, if spine role was created, <c>false</c> otherwise.</returns> /// <param name="skeletonDataAsset">Skeleton data asset.</param> /// <param name="animationName">Animation name.</param> /// <param name="skinName">Skin name.</param> /// <param name="pos">Position.</param> private System.Collections.IEnumerator Create(SpineAvatarType avatarType, EquipmentObject eo, SkeletonDataAsset skeletonDataAsset, string roleGameObjectName, string animationName, string skinName, bool loop, RoleEquipmentData data, Action <Avatar> createSucCallBack, Action <string> failCallBack, Action <bool> createQueueCallBack, bool isTP) { if (skeletonDataAsset == null) { if (failCallBack != null) { failCallBack.Invoke("<-创建角色失败->"); } yield break; } GameObject roleSpine = new GameObject { name = roleGameObjectName }; roleObject = roleSpine; skeletonAnimation = SkeletonAnimation.AddToGameObject(roleSpine, skeletonDataAsset); skeletonAnimation.Initialize(false); skeletonAnimation.Skeleton.SetSkin(skinName); skeletonAnimation.state.SetAnimation(SpineConstValue.TrackIndex, animationName, loop); CreateSlotAttachmentDic(skeletonAnimation.Skeleton.Data.DefaultSkin.Attachments); if (null == data) { equipmentData = new RoleEquipmentData(); equipmentData.RoleEquipmentItems = new List <RoleEquipmentItem> (); } else { equipmentData = data; } CombineTextureData combineTextureData = new CombineTextureData(); combineTextureData.resultData = new CombineFinishedData(); RoleAnaimationData rad = new RoleAnaimationData { roleJsonStr = eo.equipmentJsonAsset.text }; Avatar avatar = new SpineAvatar(equipmentData, skeletonAnimation, slotAttachmentDic, rad, combineTextureData, avatarType, roleObject, eo.equipmentJsonAsset.text); combineTextureData.resultData.self = avatar; if (createSucCallBack != null) { if (null != roleSpine) { roleSpine.SetActive(false); createSucCallBack.Invoke(avatar); } } //初始化角色的所有服装信息 if (equipmentData.RoleEquipmentItems.Count > 0) { if (null != combineTextureData.initRoleCoroutine) { GameManager.Instance.StopCoroutine(combineTextureData.initRoleCoroutine); } combineTextureData.initRoleCoroutine = GameManager.Instance.StartCoroutine(InitRoleEquipment(rad, skeletonAnimation, equipmentData, combineTextureData, slotAttachmentDic, avatar.GetDestoryTextureList, roleSpine.SetActive, null, isTP)); yield return(combineTextureData.initRoleCoroutine); } else { roleSpine.SetActive(true); } if (null != createQueueCallBack) { createQueueCallBack.Invoke(true); } }
public IEnumerator GetRenderTextureByTexturesOptimize(CombineTextureData combineTextureData, List <Spine.AtlasRegion> regions, int renderTextureSize, Action <PackagedTextureResult> finishCallBack) { ResetValue(combineTextureData); currentAtlasSize = renderTextureSize; List <TextureClass> textureList = new List <TextureClass>(); //GetTextureClassList (textures); List <TextureClass> currentTextureList = new List <TextureClass> (); Material material = InitMaterial(); MaxRectsBinPack maxRectsBinPack = new MaxRectsBinPack(currentAtlasSize, currentAtlasSize, false); RenderTexture render = RenderTexture.GetTemporary(currentAtlasSize, currentAtlasSize, 0, RenderTextureFormat.ARGB4444); Dictionary <RenderTexture, TextureClass[]> dic = new Dictionary <RenderTexture, TextureClass[]> (); Graphics.Blit(null, null, material, 0); for (int i = 0; i < regions.Count; i++) { UnityEngine.Profiling.Profiler.BeginSample("SpineChange_ToTexture"); RenderTexture regionTex = Spine.Unity.Modules.AttachmentTools.AtlasUtilities.ToTexture(regions[i]); UnityEngine.Profiling.Profiler.EndSample(); textureList.Add(new TextureClass { index = i, texture = regionTex, textureSize = new TextureSize { x = regionTex.width, y = regionTex.height } }); if (!IsSuitableTexture(textureList[i].texture)) { throw new System.NotSupportedException("[--散图 " + textureList[i].texture.name + " 的大小超出单位图集的大小,请修改散图或单位图集的大小(SpineConstValue.smallAtlasSize)--]"); } Rect posRect = maxRectsBinPack.Insert(textureList[i].texture.width, textureList[i].texture.height, MaxRectsBinPack.FreeRectChoiceHeuristic.RectBestAreaFit); if (posRect.height <= 0) { //保存本次的图集和散图的位置信息 TextureClass[] array1 = new TextureClass[currentTextureList.Count]; currentTextureList.CopyTo(array1); dic.Add(render, array1); currentTextureList.Clear(); Graphics.Blit(null, null, material, 0); //初始化参数进行下一次的合图 material = InitMaterial(); maxRectsBinPack = new MaxRectsBinPack(currentAtlasSize, currentAtlasSize, false); render = RenderTexture.GetTemporary(currentAtlasSize, currentAtlasSize, 0, RenderTextureFormat.ARGB4444); Graphics.Blit(null, null, material, 0); textureList.RemoveAt(i); --i; combineTextureData.smallAtlasNumber++; continue; } Rect scaleRect = GetScaleRect(posRect, renderTextureSize, renderTextureSize); material.SetTexture("_MainTex", textureList[i].texture); material.SetFloat("_ScaleX", scaleRect.width); material.SetFloat("_ScaleY", scaleRect.height); material.SetFloat("_OffsetX", scaleRect.x); material.SetFloat("_OffsetY", scaleRect.y); Graphics.Blit(null, render, material, 1); textureList[i].rect = posRect; currentTextureList.Add(textureList[i]); //卸载散图资源 // textureList[i].texture = null; // UnityEngine.Resources.UnloadUnusedAssets(); RenderTexture.ReleaseTemporary(textureList[i].texture); textureList[i].texture.Release(); textureList[i].texture = null; yield return(null); } Graphics.Blit(null, null, material, 0); TextureClass[] array2 = new TextureClass[currentTextureList.Count]; currentTextureList.CopyTo(array2); dic.Add(render, array2); if (null != combineTextureData.combineCoroutineBig) { GameManager.Instance.StopCoroutine(combineTextureData.combineCoroutineBig); } combineTextureData.combineCoroutineBig = GameManager.Instance.StartCoroutine(FinallyPackage(combineTextureData, dic, finishCallBack)); }
public static void GetSpineRepackedSkin(CombineTextureData combineTextureData, Skin skin, string newName, Shader shader, int maxAtlasSize, TextureFormat textureFormat, bool mipMaps, Material materialPropertySource, bool clearCache) { if (skin == null) { throw new System.NullReferenceException("Skin was null"); } var skinAttachments = skin.Attachments; var newSkin = new Skin(newName); var existingRegions = new Dictionary <AtlasRegion, int> (); var regionIndexes = new List <int> (); var repackedAttachments = new List <Attachment> (); var texturesToPack = new List <Texture2D> (); var originalRegions = new List <AtlasRegion> (); int newRegionIndex = 0; foreach (var kvp in skinAttachments) { var newAttachment = kvp.Value.GetClone(true); if (IsRenderable(newAttachment)) { var region = newAttachment.GetAtlasRegion(); int existingIndex; if (existingRegions.TryGetValue(region, out existingIndex)) { regionIndexes.Add(existingIndex); // Store the region index for the eventual new attachment. } else { originalRegions.Add(region); //texturesToPack.Add (region.ToTexture ()); // Add the texture to the PackTextures argument existingRegions.Add(region, newRegionIndex); // Add the region to the dictionary of known regions regionIndexes.Add(newRegionIndex); // Store the region index for the eventual new attachment. newRegionIndex++; } repackedAttachments.Add(newAttachment); } var key = kvp.Key; newSkin.AddAttachment(key.slotIndex, key.name, newAttachment); } //合并图集 if (null != combineTextureData.combineCoroutineSmall) { //region.ToTexture ()??? GameManager.Instance.StopCoroutine(combineTextureData.combineCoroutineSmall); } combineTextureData.combineCoroutineSmall = GameManager.Instance.StartCoroutine(CombineTexturesTool.Instance.GetRenderTextureByTexturesOptimize(combineTextureData, originalRegions, maxAtlasSize, (PackagedTextureResult result) => { RenderTexture renderTexture = result.renderTexture; TextureClass[] outTextureClassList = result.textureInfo; var newMaterial = new Material(shader); if (materialPropertySource != null) { newMaterial.CopyPropertiesFromMaterial(materialPropertySource); newMaterial.shaderKeywords = materialPropertySource.shaderKeywords; } newMaterial.name = newName; newMaterial.mainTexture = renderTexture; var page = newMaterial.ToSpineAtlasPage(); page.name = newName; var repackedRegions = new List <AtlasRegion> (); for (int i = 0, n = originalRegions.Count; i < n; i++) { var oldRegion = originalRegions[i]; var newRegion = UVRectToAtlasRegion(GetTargetRectByIndex(outTextureClassList, i), oldRegion.name, page, oldRegion.offsetX, oldRegion.offsetY, oldRegion.rotate); repackedRegions.Add(newRegion); } for (int i = 0, n = repackedAttachments.Count; i < n; i++) { var a = repackedAttachments[i]; a.SetRegion(repackedRegions[regionIndexes[i]]); } if (clearCache) { AtlasUtilities.ClearCache(); } if (null != combineTextureData.resultData) { combineTextureData.resultData.skin = null; combineTextureData.resultData.material = null; if (null != combineTextureData.resultData.currentRenderTex) { combineTextureData.resultData.lastRenderTex = combineTextureData.resultData.currentRenderTex; } } combineTextureData.resultData.skin = newSkin; combineTextureData.resultData.material = newMaterial; combineTextureData.resultData.currentRenderTex = renderTexture; combineTextureData.isFinished = true; })); }