2024-12-23 19:25:03 +08:00
|
|
|
|
using System.Collections.Generic;
|
2025-01-02 19:52:57 +08:00
|
|
|
|
using System.IO;
|
2025-01-22 15:13:44 +08:00
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using Art.temp.Editor.PrefabTool;
|
2026-01-17 12:16:50 +08:00
|
|
|
|
using artcfg.ArtDesign;
|
|
|
|
|
|
using Framework;
|
2025-01-02 19:52:57 +08:00
|
|
|
|
using Sirenix.Utilities;
|
2025-01-22 15:13:44 +08:00
|
|
|
|
using UnityEditor;
|
|
|
|
|
|
using UnityEngine;
|
2024-12-23 10:19:53 +08:00
|
|
|
|
|
2026-01-16 19:41:39 +08:00
|
|
|
|
namespace Art.temp.Editor.AnimationTools
|
2024-12-23 10:19:53 +08:00
|
|
|
|
{
|
2024-12-25 15:00:20 +08:00
|
|
|
|
public static class AnimHelper
|
|
|
|
|
|
{
|
|
|
|
|
|
public static GameObject FindDisplayPrefab(string nameId)
|
|
|
|
|
|
{
|
2025-01-22 15:13:44 +08:00
|
|
|
|
switch (nameId[0])
|
2024-12-25 15:00:20 +08:00
|
|
|
|
{
|
2025-01-22 15:13:44 +08:00
|
|
|
|
case 'A':
|
|
|
|
|
|
{
|
2025-03-31 16:52:54 +08:00
|
|
|
|
var player = CharacterFactory.CreatePlayer(nameId);
|
2025-01-22 15:13:44 +08:00
|
|
|
|
return player.DisplayPrefab;
|
|
|
|
|
|
}
|
|
|
|
|
|
case 'E':
|
|
|
|
|
|
{
|
2025-03-31 16:52:54 +08:00
|
|
|
|
var enemy = CharacterFactory.CreateEmeny(nameId);
|
2025-01-22 15:13:44 +08:00
|
|
|
|
return enemy.DisplayPrefab;
|
|
|
|
|
|
}
|
|
|
|
|
|
case 'N':
|
|
|
|
|
|
{
|
2025-03-31 16:52:54 +08:00
|
|
|
|
var npc = CharacterFactory.CreateNpc(nameId);
|
2025-01-22 15:13:44 +08:00
|
|
|
|
return npc.DisplayPrefab;
|
|
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
return null;
|
2024-12-25 15:00:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-12-23 19:25:03 +08:00
|
|
|
|
|
2024-12-25 15:00:20 +08:00
|
|
|
|
|
|
|
|
|
|
// filter = "name t:xx l:xx" Name Labels Types
|
2026-01-13 13:35:32 +08:00
|
|
|
|
public static IEnumerable<T> FindAssetsByFolders<T>(string filter, string[] folders) where T : Object
|
2024-12-25 15:00:20 +08:00
|
|
|
|
{
|
2025-03-11 20:39:16 +08:00
|
|
|
|
// FindAssets 能找子文件夹
|
2024-12-25 15:00:20 +08:00
|
|
|
|
string[] guids = AssetDatabase.FindAssets(filter, folders);
|
2025-03-12 14:05:02 +08:00
|
|
|
|
IEnumerable<string> paths = guids.Select(AssetDatabase.GUIDToAssetPath);
|
2026-01-13 13:35:32 +08:00
|
|
|
|
return paths.Select(AssetDatabase.LoadAssetAtPath<T>);
|
2024-12-25 15:00:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-02 19:52:57 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 合并 prefab 中的 mesh, 要求只有一个材质,并且合并后只有一个 material
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="go">cloned prefab</param>
|
|
|
|
|
|
/// <param name="texNames">shader 贴图字段 [_MainTex, _MaskTex]</param>
|
2025-01-22 15:13:44 +08:00
|
|
|
|
private static void CombineSkinnedMesh(GameObject go, string[] texNames)
|
2025-01-02 19:52:57 +08:00
|
|
|
|
{
|
2025-01-22 15:13:44 +08:00
|
|
|
|
var parts = go.GetComponentsInChildren<SkinnedMeshRenderer>(true);
|
2025-01-02 19:52:57 +08:00
|
|
|
|
if (parts.Length < 2) return;
|
|
|
|
|
|
|
2025-01-02 20:08:23 +08:00
|
|
|
|
// 获取蒙皮骨骼
|
2025-01-02 19:52:57 +08:00
|
|
|
|
var bones = parts.SelectMany(p => p.bones).ToArray();
|
|
|
|
|
|
|
|
|
|
|
|
// 合并贴图
|
2025-01-22 15:13:44 +08:00
|
|
|
|
var texGroups = texNames.Select(t => parts.Select(p => p.sharedMaterial.GetTexture(t) as Texture2D))
|
|
|
|
|
|
.ToArray();
|
|
|
|
|
|
var combineTextures = texGroups.Select(g =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var tex = new Texture2D(4, 4, TextureFormat.ARGB4444, true);
|
|
|
|
|
|
tex.PackTextures(g.ToArray(), 0, 2048);
|
|
|
|
|
|
return tex;
|
|
|
|
|
|
});
|
2025-01-02 19:52:57 +08:00
|
|
|
|
|
|
|
|
|
|
// 合并 mesh uv
|
|
|
|
|
|
var uvGroups = parts.Select(p => p.sharedMesh.uv).ToArray();
|
2025-01-22 15:13:44 +08:00
|
|
|
|
var rects =
|
|
|
|
|
|
new Texture2D(4, 4, TextureFormat.ARGB4444, true).PackTextures(texGroups.ElementAt(0).ToArray(), 0,
|
|
|
|
|
|
2048);
|
2025-01-02 19:52:57 +08:00
|
|
|
|
var newUvs = uvGroups.Zip(rects, (uv, rect) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < uv.Length; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
uv[i].x = Mathf.Lerp(rect.xMin, rect.xMax, uv[i].x);
|
|
|
|
|
|
uv[i].y = Mathf.Lerp(rect.yMin, rect.yMax, uv[i].y);
|
|
|
|
|
|
}
|
2025-01-22 15:13:44 +08:00
|
|
|
|
|
2025-01-02 19:52:57 +08:00
|
|
|
|
return uv;
|
|
|
|
|
|
}).SelectMany(uv => uv).ToArray();
|
|
|
|
|
|
|
2025-01-02 20:08:23 +08:00
|
|
|
|
// copy and combine mesh
|
2025-01-02 19:52:57 +08:00
|
|
|
|
var combineInstances = parts.Select(p => new CombineInstance() { mesh = DeepCopyMesh(p.sharedMesh) });
|
|
|
|
|
|
Mesh newMesh = new();
|
|
|
|
|
|
newMesh.CombineMeshes(combineInstances.ToArray(), true, false);
|
|
|
|
|
|
|
2025-01-02 20:08:23 +08:00
|
|
|
|
// set texture
|
2025-01-02 19:52:57 +08:00
|
|
|
|
var mat = Object.Instantiate(parts[0].sharedMaterial);
|
2025-01-22 15:13:44 +08:00
|
|
|
|
var list = texNames.Zip(combineTextures, (name, tex) =>
|
2025-01-02 19:52:57 +08:00
|
|
|
|
{
|
|
|
|
|
|
mat.SetTexture(name, tex);
|
|
|
|
|
|
return 0;
|
2025-01-22 15:13:44 +08:00
|
|
|
|
}).ToArray();
|
2025-01-02 19:52:57 +08:00
|
|
|
|
|
|
|
|
|
|
// create combine
|
|
|
|
|
|
GameObject combinedMesh = new GameObject("combined_mesh");
|
|
|
|
|
|
combinedMesh.transform.SetParent(go.transform.GetChild(0));
|
|
|
|
|
|
var smr = combinedMesh.AddComponent<SkinnedMeshRenderer>();
|
|
|
|
|
|
smr.sharedMesh = newMesh;
|
|
|
|
|
|
smr.sharedMesh.uv = newUvs.ToArray();
|
|
|
|
|
|
smr.bones = bones;
|
2025-01-02 20:08:23 +08:00
|
|
|
|
smr.rootBone = go.transform.GetChild(0).Find("Root");
|
2025-01-02 19:52:57 +08:00
|
|
|
|
smr.sharedMaterial = mat;
|
|
|
|
|
|
|
|
|
|
|
|
parts.ForEach(p => Object.DestroyImmediate(p.gameObject));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-02 20:08:23 +08:00
|
|
|
|
public static void CombineSkinSaveAssets(GameObject go, string[] texNames, string parentPath)
|
2025-01-02 19:52:57 +08:00
|
|
|
|
{
|
|
|
|
|
|
string nameId = go.transform.GetChild(0).name;
|
|
|
|
|
|
AnimHelper.CombineSkinnedMesh(go, texNames);
|
|
|
|
|
|
var smr = go.transform.GetChild(0).GetComponentInChildren<SkinnedMeshRenderer>();
|
|
|
|
|
|
var mat = smr.sharedMaterial;
|
|
|
|
|
|
// texture
|
|
|
|
|
|
foreach (var name in texNames)
|
|
|
|
|
|
{
|
|
|
|
|
|
var tex = mat.GetTexture(name);
|
|
|
|
|
|
var texPath = $"{parentPath}/{name}.png";
|
|
|
|
|
|
var newTex = SaveAndReloadTexture2D(tex as Texture2D, texPath);
|
|
|
|
|
|
mat.SetTexture(name, newTex);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// material
|
|
|
|
|
|
var matSavePath = $"{parentPath}/mat_{nameId}.mat";
|
|
|
|
|
|
AssetDatabase.CreateAsset(mat, matSavePath);
|
|
|
|
|
|
// mesh
|
|
|
|
|
|
var mesh = smr.sharedMesh;
|
|
|
|
|
|
var meshSavePath = $"{parentPath}/mesh_{nameId}.asset";
|
|
|
|
|
|
AssetDatabase.CreateAsset(mesh, meshSavePath);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static Texture2D SaveAndReloadTexture2D(Texture2D t2d, string savePath)
|
|
|
|
|
|
{
|
|
|
|
|
|
var bytes = t2d.EncodeToPNG();
|
|
|
|
|
|
File.WriteAllBytes(savePath, bytes);
|
|
|
|
|
|
AssetDatabase.Refresh();
|
|
|
|
|
|
var newT2d = AssetDatabase.LoadAssetAtPath<Texture2D>(savePath);
|
|
|
|
|
|
return newT2d;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static string[] PreSetAll(GameObject prefab)
|
|
|
|
|
|
{
|
|
|
|
|
|
var allSkin = prefab.GetComponentsInChildren<SkinnedMeshRenderer>();
|
|
|
|
|
|
string[] allTexNames = new string[] { "_MainTex", "_MaskTex" };
|
|
|
|
|
|
foreach (SkinnedMeshRenderer skin in allSkin)
|
|
|
|
|
|
{
|
|
|
|
|
|
var material = skin.sharedMaterial;
|
|
|
|
|
|
if (material.shader.name != "NLD_URP/NLD_Charactor")
|
|
|
|
|
|
{
|
|
|
|
|
|
// 修改为NLD_URP/NLD_Charactor
|
|
|
|
|
|
material.shader = Shader.Find("NLD_URP/NLD_Charactor");
|
|
|
|
|
|
}
|
2025-01-22 15:13:44 +08:00
|
|
|
|
|
2025-01-02 19:52:57 +08:00
|
|
|
|
// 判断所有的贴图是否已开启read/write
|
|
|
|
|
|
foreach (var texName in allTexNames)
|
|
|
|
|
|
{
|
|
|
|
|
|
var tex = material.GetTexture(texName);
|
2025-01-22 15:13:44 +08:00
|
|
|
|
if (!tex) continue;
|
|
|
|
|
|
var texPath = AssetDatabase.GetAssetPath(tex);
|
|
|
|
|
|
var importer = AssetImporter.GetAtPath(texPath) as TextureImporter;
|
|
|
|
|
|
if (!importer) continue;
|
|
|
|
|
|
importer.isReadable = true;
|
|
|
|
|
|
importer.SaveAndReimport();
|
2025-01-02 19:52:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-01-22 15:13:44 +08:00
|
|
|
|
|
2025-01-02 19:52:57 +08:00
|
|
|
|
return allTexNames;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-22 15:13:44 +08:00
|
|
|
|
private static Mesh DeepCopyMesh(Mesh originalMesh)
|
2025-01-02 19:52:57 +08:00
|
|
|
|
{
|
2025-01-22 15:13:44 +08:00
|
|
|
|
Mesh copiedMesh = new Mesh
|
|
|
|
|
|
{
|
|
|
|
|
|
vertices = (Vector3[])originalMesh.vertices.Clone(),
|
|
|
|
|
|
triangles = (int[])originalMesh.triangles.Clone(),
|
|
|
|
|
|
uv = (Vector2[])originalMesh.uv.Clone(),
|
|
|
|
|
|
normals = (Vector3[])originalMesh.normals.Clone(),
|
|
|
|
|
|
tangents = (Vector4[])originalMesh.tangents.Clone(),
|
|
|
|
|
|
colors = (Color[])originalMesh.colors.Clone(),
|
|
|
|
|
|
boneWeights = (BoneWeight[])originalMesh.boneWeights.Clone(),
|
|
|
|
|
|
bindposes = (Matrix4x4[])originalMesh.bindposes.Clone()
|
|
|
|
|
|
};
|
2025-01-02 19:52:57 +08:00
|
|
|
|
|
|
|
|
|
|
return copiedMesh;
|
2024-12-25 15:00:20 +08:00
|
|
|
|
}
|
2025-01-03 17:01:45 +08:00
|
|
|
|
|
|
|
|
|
|
public static void PreSetModel(GameObject model)
|
|
|
|
|
|
{
|
|
|
|
|
|
var objPath = AssetDatabase.GetAssetPath(model);
|
2025-01-15 19:01:09 +08:00
|
|
|
|
var modelImporter = AssetImporter.GetAtPath(objPath) as ModelImporter;
|
2025-01-22 15:13:44 +08:00
|
|
|
|
if (!modelImporter) return;
|
2025-01-15 19:01:09 +08:00
|
|
|
|
modelImporter.avatarSetup = ModelImporterAvatarSetup.CreateFromThisModel;
|
2025-01-03 17:01:45 +08:00
|
|
|
|
AssetDatabase.Refresh();
|
2025-01-15 19:01:09 +08:00
|
|
|
|
modelImporter.SaveAndReimport();
|
2025-01-03 17:01:45 +08:00
|
|
|
|
}
|
2025-09-23 15:53:11 +08:00
|
|
|
|
|
|
|
|
|
|
public static void SetFaceMaterial(GameObject model)
|
|
|
|
|
|
{
|
|
|
|
|
|
const string browTexPath = "Assets/Art_Out/Manual/Emoji/Tex/T_emoji_eyebows_{0}_01.png";
|
|
|
|
|
|
const string browMaskPath = "Assets/Art_Out/Manual/Emoji/Tex/T_emoji_eyebows_{0}_01_mask.png";
|
|
|
|
|
|
const string eyeTexPath = "Assets/Art_Out/Manual/Emoji/Tex/T_emoji_eyes_0{0}.png";
|
|
|
|
|
|
const string eyeMaskPath = "Assets/Art_Out/Manual/Emoji/Tex/T_emoji_eyes_0{0}_mask.png";
|
|
|
|
|
|
const string mouthPath = "Assets/Art_Out/Manual/Emoji/Tex/T_emoji_mouth_0{0}.png";
|
|
|
|
|
|
|
|
|
|
|
|
string nameId = model.name;
|
2026-01-23 14:43:17 +08:00
|
|
|
|
DataPerson dataPerson = ArtTableManager.instance.tables.PersonConfig.DataList.FirstOrDefault(p => p.NameId == nameId);
|
2026-01-17 12:16:50 +08:00
|
|
|
|
if (dataPerson == null)
|
2025-09-23 15:53:11 +08:00
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning($"{nameId} not found face config");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GameObject emoji = model.transform
|
|
|
|
|
|
.Find("Root/Bip001/Bip001 Spine/Bip001 Spine1/Bip001 Neck/Bip001 Head/G_emoji").gameObject;
|
|
|
|
|
|
Material[] mats = emoji.GetComponent<MeshRenderer>().sharedMaterials;
|
|
|
|
|
|
|
2026-01-17 12:16:50 +08:00
|
|
|
|
if (!string.IsNullOrEmpty(dataPerson.BowsColor))
|
2025-09-23 15:53:11 +08:00
|
|
|
|
{
|
2026-01-17 12:16:50 +08:00
|
|
|
|
ColorUtility.TryParseHtmlString(dataPerson.BowsColor, out Color browColor);
|
2025-09-23 15:53:11 +08:00
|
|
|
|
mats[0].SetColor("_MainColor", browColor);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-17 12:16:50 +08:00
|
|
|
|
if (!string.IsNullOrEmpty(dataPerson.EyesColor))
|
2025-09-23 15:53:11 +08:00
|
|
|
|
{
|
2026-01-17 12:16:50 +08:00
|
|
|
|
ColorUtility.TryParseHtmlString(dataPerson.EyesColor, out Color eyeColor);
|
2025-09-23 15:53:11 +08:00
|
|
|
|
mats[1].SetColor("_MainColor", eyeColor);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-17 12:16:50 +08:00
|
|
|
|
Texture2D browTex = AssetDatabase.LoadAssetAtPath<Texture2D>(string.Format(browTexPath, dataPerson.BowsType));
|
|
|
|
|
|
Texture2D browMask = AssetDatabase.LoadAssetAtPath<Texture2D>(string.Format(browMaskPath, dataPerson.BowsType));
|
2025-09-23 15:53:11 +08:00
|
|
|
|
mats[0].SetTexture("_MainTex", browTex);
|
|
|
|
|
|
mats[0].SetTexture("_MaskTex", browMask);
|
|
|
|
|
|
|
2026-01-17 12:16:50 +08:00
|
|
|
|
Texture2D eyeTex = AssetDatabase.LoadAssetAtPath<Texture2D>(string.Format(eyeTexPath, dataPerson.EyesType));
|
|
|
|
|
|
Texture2D eyeMask = AssetDatabase.LoadAssetAtPath<Texture2D>(string.Format(eyeMaskPath, dataPerson.EyesType));
|
2025-09-23 15:53:11 +08:00
|
|
|
|
mats[1].SetTexture("_MainTex", eyeTex);
|
|
|
|
|
|
mats[1].SetTexture("_MaskTex", eyeMask);
|
|
|
|
|
|
|
2026-01-17 12:16:50 +08:00
|
|
|
|
Texture2D mouthTex = AssetDatabase.LoadAssetAtPath<Texture2D>(string.Format(mouthPath, dataPerson.MouseType));
|
2025-09-23 15:53:11 +08:00
|
|
|
|
mats[2].SetTexture("_MainTex", mouthTex);
|
|
|
|
|
|
}
|
2025-10-16 14:41:51 +08:00
|
|
|
|
|
|
|
|
|
|
public static void RenameAnim(GameObject go)
|
|
|
|
|
|
{
|
|
|
|
|
|
string goPath = AssetDatabase.GetAssetPath(go);
|
|
|
|
|
|
ModelImporter importer = AssetImporter.GetAtPath(goPath) as ModelImporter;
|
|
|
|
|
|
importer.avatarSetup = ModelImporterAvatarSetup.CreateFromThisModel;
|
|
|
|
|
|
|
|
|
|
|
|
ModelImporterClipAnimation clip = importer.defaultClipAnimations[0];
|
|
|
|
|
|
clip.name = go.name;
|
|
|
|
|
|
if (clip.name.EndsWith("idle") || clip.name.EndsWith("move")) clip.loopTime = true;
|
|
|
|
|
|
importer.clipAnimations = new[] { clip };
|
|
|
|
|
|
importer.SaveAndReimport();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void CopyAnimToCompressed(GameObject obj)
|
|
|
|
|
|
{
|
|
|
|
|
|
const string tempFolder = "Assets/Art/temp/Animation";
|
|
|
|
|
|
const string destFilePath = "Assets/Art/Animations/compressed/{0}";
|
|
|
|
|
|
|
|
|
|
|
|
string[] fileNames = CopyAnim(obj, tempFolder, true);
|
|
|
|
|
|
foreach (string f in fileNames)
|
|
|
|
|
|
{
|
|
|
|
|
|
string animFile = string.Format(destFilePath, Path.GetFileName(f));
|
|
|
|
|
|
File.Copy(f, animFile, true);
|
|
|
|
|
|
Debug.Log(animFile);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AssetDatabase.Refresh();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-01-22 17:18:30 +08:00
|
|
|
|
private static string[] CopyAnim(GameObject fbx, string destFolder, bool toCompressed = false)
|
2025-10-16 14:41:51 +08:00
|
|
|
|
{
|
|
|
|
|
|
string fbxPath = AssetDatabase.GetAssetPath(fbx);
|
|
|
|
|
|
var assets = AssetDatabase.LoadAllAssetRepresentationsAtPath(fbxPath);
|
|
|
|
|
|
var animPaths = new List<string>();
|
|
|
|
|
|
foreach (Object asset in assets)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (asset is not AnimationClip clip) continue;
|
|
|
|
|
|
AnimOptimize(clip);
|
|
|
|
|
|
AnimationClip newClip = new();
|
|
|
|
|
|
EditorUtility.CopySerialized(clip, newClip);
|
|
|
|
|
|
string str = clip.name + ".anim";
|
|
|
|
|
|
string compressed = toCompressed ? "compressed_" + str : str;
|
|
|
|
|
|
string newPath = Path.Combine(destFolder, compressed);
|
|
|
|
|
|
AssetDatabase.CreateAsset(newClip, newPath);
|
|
|
|
|
|
animPaths.Add(newPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return animPaths.ToArray();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void AnimOptimize(AnimationClip clip)
|
|
|
|
|
|
{
|
|
|
|
|
|
var curveBindings = AnimationUtility.GetCurveBindings(clip);
|
|
|
|
|
|
for (int ii = 0; ii < curveBindings.Length; ++ii)
|
|
|
|
|
|
{
|
|
|
|
|
|
AnimationCurve curve = AnimationUtility.GetEditorCurve(clip, curveBindings[ii]);
|
|
|
|
|
|
|
|
|
|
|
|
// 删除移动帧(除了Bip001)和缩放帧
|
|
|
|
|
|
string propName = curveBindings[ii].propertyName.ToLower();
|
|
|
|
|
|
string nodeName = Path.GetFileName(curveBindings[ii].path);
|
|
|
|
|
|
/*if (propName.Contains("position") && nodeName.StartsWith("Bip001 "))
|
|
|
|
|
|
{
|
|
|
|
|
|
curve = null; //有空格,排除了“Bip001”
|
|
|
|
|
|
}*/
|
|
|
|
|
|
if (propName.Contains("scale") && !nodeName.Contains("Grip_point01"))
|
|
|
|
|
|
{
|
|
|
|
|
|
curve = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (nodeName.StartsWith("Fire"))
|
|
|
|
|
|
{
|
|
|
|
|
|
curve = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 压缩浮点数
|
|
|
|
|
|
if (curve is { keys: not null })
|
|
|
|
|
|
{
|
|
|
|
|
|
var keyFrames = curve.keys;
|
|
|
|
|
|
for (int i = 0; i < keyFrames.Length; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
Keyframe key = keyFrames[i];
|
|
|
|
|
|
key.value = float.Parse(key.value.ToString("f4"));
|
|
|
|
|
|
key.inTangent = float.Parse(key.inTangent.ToString("f4"));
|
|
|
|
|
|
key.outTangent = float.Parse(key.outTangent.ToString("f4"));
|
|
|
|
|
|
keyFrames[i] = key;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
curve.keys = keyFrames;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// curve 为 null, 则删除曲线
|
|
|
|
|
|
AnimationUtility.SetEditorCurve(clip, curveBindings[ii], curve);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-12-25 15:00:20 +08:00
|
|
|
|
}
|
2025-01-22 15:13:44 +08:00
|
|
|
|
}
|