public static bool ExportTexture2D(AssetItem item, string exportPath, string format) { var converter = new Texture2DConverter((Texture2D)item.Asset); ImageFormat dstFormat = ImageFormat.Png; if (format == "recommanded" || format == "png") { format = "png"; dstFormat = ImageFormat.Png; } var oriPath = item.Asset.assetsFile.originalPath; var exportFullName = exportPath + Path.GetFileNameWithoutExtension(oriPath) + "." + format; if (format != "original") { var bitmap = converter.ConvertToBitmap(true); if (bitmap == null) { return(false); } bitmap.Save(exportFullName, dstFormat); bitmap.Dispose(); return(true); } else { File.WriteAllBytes(exportFullName, converter.ConvertToContainer()); return(true); } }
public static bool ExportTexture2D(AssetItem item, string exportPathName) { var m_Texture2D = new Texture2D(item.reader, true); if (m_Texture2D.image_data == null || m_Texture2D.image_data.Length == 0) { return(false); } var converter = new Texture2DConverter(m_Texture2D); var convertTexture = (bool)Properties.Settings.Default["convertTexture"]; if (convertTexture) { var bitmap = converter.ConvertToBitmap(true); if (bitmap == null) { return(false); } ImageFormat format = null; var ext = (string)Properties.Settings.Default["convertType"]; switch (ext) { case "BMP": format = ImageFormat.Bmp; break; case "PNG": format = ImageFormat.Png; break; case "JPEG": format = ImageFormat.Jpeg; break; } var exportFullName = exportPathName + item.Text + "." + ext.ToLower(); if (ExportFileExists(exportFullName)) { return(false); } bitmap.Save(exportFullName, format); bitmap.Dispose(); return(true); } else { var exportFullName = exportPathName + item.Text + converter.GetExtensionName(); if (ExportFileExists(exportFullName)) { return(false); } File.WriteAllBytes(exportFullName, converter.ConvertToContainer()); return(true); } }
public virtual IHVImageFormatImporter GenerateIHVImporter(IExportContainer container) { return(Texture2DConverter.GenerateIHVImporter(container, this)); }
public virtual TextureImporter GenerateTextureImporter(IExportContainer container) { return(Texture2DConverter.GenerateTextureImporter(container, this)); }
private void RunDownload() { if (!Directory.Exists(txt_Save.Text + "Unity3D")) { Directory.CreateDirectory(txt_Save.Text + "Unity3D"); } List <DownloadInfo> list = new List <DownloadInfo>(); string Extension = (chb_Unity3d.Checked ? ".unity3d" : ""); string[] FileList = lib_File.Items.Cast <string>().ToArray(); string Url; if (rdb_ST.Checked) { Url = "http://img.wcproject.so-net.tw/assets/469/"; } else if (rdb_SJ.Checked) { Url = "http://i.wcat.colopl.jp/assets/2018/"; } else if (rdb_SK.Checked) { Url = "http://i-wcat-colopl-kr.akamaized.net/assets/465/"; } else if (rdb_tennis.Checked) { Url = "http://i-tennis-colopl-jp.akamaized.net/asset_bundle/"; } else { Url = txt_URL.Text; } if (rdb_tennis.Checked && RB_A.Checked) { Url += "android/0.0.1/"; } else if (rdb_tennis.Checked && RB_I.Checked) { Url += "ios/0.0.1/"; } else if (!rdb_Custom.Checked && RB_A.Checked) { Url += "a/"; } else if (!rdb_Custom.Checked && RB_I.Checked) { Url += "i/"; } SetProgressBarValue(0, PB_TotalFile); tbManager.SetProgressValue(0, FileList.Length); tbManager.SetProgressState(TaskbarProgressBarState.Normal); foreach (string fileName in FileList) { if (fileName == "" || fileName.Substring(0, 1) == "'" || !fileName.ComparisonFileName()) { DelListBox(fileName.ToString(), lib_File); } else { string urlAddress = Url + fileName + Extension + "?r=" + DateTime.Now.ToFileTime().ToString(); DownloadInfo info = new DownloadInfo(urlAddress, txt_Save.Text, this, fileName + ".unity3d"); list.Add(info); info.StartDownload(); } } list.ForEach(delegate(DownloadInfo item) { SetToolStripLabelText("下載中 (" + (PB_TotalFile.Value * 100.0 / list.Count).ToString("0.0") + "%)", lab_Status); while (!item.IsDone) { if (!isWorking) { if (item.WC != null) { item.WC.CancelAsync(); } break; } SetLabelText("下載檔案: " + item.FileName, lab_Download); SetLabelText(string.Format("{0} KB / {1} KB", item.KBytesReceived.ToString("0.0"), item.TotalKBytesToReceive.ToString("0.0")), lab_Speed); SetProgressBarValue(item.KBytesReceived, PB_SingleFile); SetProgressBarMaxValue(item.TotalKBytesToReceive, PB_SingleFile); Thread.Sleep(500); } if (item.IsCancelled) { AddListBoxItem(Path.GetFileNameWithoutExtension(item.FileName), lib_Error); } else if (item.Error != "") { AddListBoxItem(Path.GetFileNameWithoutExtension(item.FileName), lib_Error); } SetProgressBarValue(PB_TotalFile.Value + 1, PB_TotalFile); SetToolStripLabelText("錯誤檔案數: " + lib_Error.Items.Count.ToString(), lab_ErrorItem); SetToolStripLabelText("已下載數: " + PB_TotalFile.Value, lab_DownItem); DelListBox(Path.GetFileNameWithoutExtension(item.FileName), lib_File); tbManager.SetProgressValue(PB_TotalFile.Value, FileList.Length); }); list.Clear(); SetProgressBarValue(0, PB_SingleFile); SetProgressBarMaxValue(0, PB_SingleFile); SetLabelText("0 KB / 0 KB", lab_Speed); if (extFile.Count != 0) { SetToolStripLabelText("檔案數: " + extFile.Count, lab_Item); SetProgressBarValue(0, PB_TotalFile); SetProgressBarMaxValue(extFile.Count, PB_TotalFile); SetToolStripLabelText("載入資料中", lab_Status); assetsManager.LoadFolder(txt_Save.Text + "Unity3D"); SetToolStripLabelText("解包中", lab_Status); Parallel.ForEach(assetsManager.assetsFileList, (item) => { string fileName = Path.GetFileNameWithoutExtension(item.originalPath); if (!extFile.Contains(fileName + ".unity3d")) { return; } bool Export = true; if (TSM_UnPrefab.Checked && TSM_Exclude.Text != "") { foreach (string item2 in TSM_Exclude.Text.Split(new char[] { ',' })) { if (fileName.ToLower().Contains(item2.ToLower())) { Export = false; break; } } } if (Export) { SetToolStripLabelText("解包: " + fileName, lab_Execute); foreach (var item2 in item.m_Objects) { string SavePath = ""; ObjectReader OR = new ObjectReader(item.reader, item, item2); switch (OR.type) { case ClassIDType.Texture2D: SavePath = txt_Save.Text + "Texture\\"; if (File.Exists(SavePath + fileName + ".png")) { return; } if (!Directory.Exists(SavePath)) { Directory.CreateDirectory(SavePath); } var m_Texture2D = new Texture2D(OR); var converter = new Texture2DConverter(m_Texture2D); var bitmap = converter.ConvertToBitmap(true); if (bitmap != null) { if (fileName.StartsWith("Card")) { if (!fileName.Contains("std") && !fileName.EndsWith("w_png") && (bitmap.Width == 1024 && bitmap.Height == 1024)) { bitmap = bitmap.ResizeImage(1024, 1331); } } else if (fileName.StartsWith("Location")) { if (bitmap.Width == 512 && bitmap.Height == 512) { bitmap = bitmap.ResizeImage(768, 512); } else if (bitmap.Width == 1024 && bitmap.Height == 1024) { bitmap = bitmap.ResizeImage(1536, 1024); } } else if (fileName.Contains("loginBonus_bg") && (bitmap.Width == 1024 && bitmap.Height == 1024)) { bitmap = bitmap.ResizeImage(1024, 1536); } bitmap.Save(SavePath + fileName + ".png", ImageFormat.Png); bitmap.Dispose(); } m_Texture2D = null; break; case ClassIDType.AudioClip: SavePath = txt_Save.Text + "Audio\\"; if (fileName.StartsWith("Sound_Voice")) { string[] path = fileName.Split(new char[] { '_' }); string finalPath = ""; for (int i = 0; i < path.Length - 2; i++) { finalPath += path[i] + "_"; } SavePath += finalPath.Remove(finalPath.Length - 1) + "\\"; } if (!Directory.Exists(SavePath)) { Directory.CreateDirectory(SavePath); } AudioClip m_AudioClip = new AudioClip(OR); var audioClipConverter = new AudioClipConverter(m_AudioClip); if (audioClipConverter.IsFMODSupport) { byte[] m_AudioData = audioClipConverter.ConvertToWav(); File.WriteAllBytes(SavePath + fileName + ".wav", m_AudioData); } else { byte[] m_AudioData = m_AudioClip.m_AudioData.Value; File.WriteAllBytes(SavePath + fileName + audioClipConverter.GetExtensionName(), m_AudioData); } m_AudioClip = null; break; case ClassIDType.TextAsset: SavePath = txt_Save.Text + "Text\\"; if (!Directory.Exists(SavePath)) { Directory.CreateDirectory(SavePath); } TextAsset TA = new TextAsset(OR); File.WriteAllBytes(SavePath + fileName + ".txt", TA.m_Script); TA = null; break; } } } else { string SavePath = txt_Save.Text + "Unity3D\\"; if (!Directory.Exists(SavePath)) { Directory.CreateDirectory(SavePath); } SetToolStripLabelText("略過: " + fileName, lab_Execute); File.Move(item.originalPath, SavePath + fileName + ".unity3d"); } SetProgressBarValue(PB_TotalFile.Value + 1, PB_TotalFile); tbManager.SetProgressValue(PB_TotalFile.Value, extFile.Count); SetToolStripLabelText("已解包數: " + PB_TotalFile.Value, lab_DownItem); }); assetsManager.Clear(); extFile.Clear(); GC.Collect(); } SW.Stop(); timer1.Stop(); SetLabelText("下載檔案:無", lab_Download); SetToolStripLabelText("等待中", lab_Status); Work_Event(false); tbManager.SetProgressState(TaskbarProgressBarState.NoProgress); Invoke(new Action(delegate { Text = "清單檔案下載器 "; })); if (Program.autoClose) { Environment.Exit(1); } if (lib_Error.Items.Count <= 0) { SetButtonEnable(false, btn_Save_Error); } Environment.ExitCode = 1; MessageBox.Show("下載完成"); }
static void Main(string[] args) { if (args.Length != 1) { return; } if (!Directory.Exists(args[0])) { return; } Console.WriteLine($"Loading..."); var assetsManager = new AssetsManager(); assetsManager.LoadFolder(args[0]); if (assetsManager.assetsFileList.Count == 0) { return; } var containers = new Dictionary <AssetStudio.Object, string>(); var cubismMocs = new List <MonoBehaviour>(); foreach (var assetsFile in assetsManager.assetsFileList) { foreach (var asset in assetsFile.Objects) { switch (asset) { case MonoBehaviour m_MonoBehaviour: if (m_MonoBehaviour.m_Script.TryGet(out var m_Script)) { if (m_Script.m_ClassName == "CubismMoc") { cubismMocs.Add(m_MonoBehaviour); } } break; case AssetBundle m_AssetBundle: foreach (var m_Container in m_AssetBundle.m_Container) { var preloadIndex = m_Container.Value.preloadIndex; var preloadSize = m_Container.Value.preloadSize; var preloadEnd = preloadIndex + preloadSize; for (int k = preloadIndex; k < preloadEnd; k++) { var pptr = m_AssetBundle.m_PreloadTable[k]; if (pptr.TryGet(out var obj)) { containers[obj] = m_Container.Key; } } } break; } } } var basePathList = new List <string>(); foreach (var cubismMoc in cubismMocs) { var container = containers[cubismMoc]; var basePath = container.Substring(0, container.LastIndexOf("/")); basePathList.Add(basePath); } var lookup = containers.ToLookup(x => basePathList.Find(b => x.Value.Contains(b)), x => x.Key); var baseDestPath = Path.Combine(Path.GetDirectoryName(args[0]), "Live2DOutput"); foreach (var assets in lookup) { var key = assets.Key; if (key == null) { continue; } var name = key.Substring(key.LastIndexOf("/") + 1); Console.WriteLine($"Extract {name}"); var destPath = Path.Combine(baseDestPath, name) + Path.DirectorySeparatorChar; var destTexturePath = Path.Combine(destPath, "textures") + Path.DirectorySeparatorChar; var destAnimationPath = Path.Combine(destPath, "motions") + Path.DirectorySeparatorChar; Directory.CreateDirectory(destPath); Directory.CreateDirectory(destTexturePath); Directory.CreateDirectory(destAnimationPath); var monoBehaviours = new List <MonoBehaviour>(); var texture2Ds = new List <Texture2D>(); var gameObjects = new List <GameObject>(); var animationClips = new List <AnimationClip>(); foreach (var asset in assets) { if (asset is MonoBehaviour m_MonoBehaviour) { monoBehaviours.Add(m_MonoBehaviour); } else if (asset is Texture2D m_Texture2D) { texture2Ds.Add(m_Texture2D); } else if (asset is GameObject m_GameObject) { gameObjects.Add(m_GameObject); } else if (asset is AnimationClip m_AnimationClip) { animationClips.Add(m_AnimationClip); } } //physics var physics = monoBehaviours.FirstOrDefault(x => { if (x.m_Script.TryGet(out var m_Script)) { return(m_Script.m_ClassName == "CubismPhysicsController"); } return(false); }); if (physics != null) { File.WriteAllText($"{destPath}{name}.physics3.json", ParsePhysics(physics)); } //moc var moc = monoBehaviours.First(x => { if (x.m_Script.TryGet(out var m_Script)) { return(m_Script.m_ClassName == "CubismMoc"); } return(false); }); File.WriteAllBytes($"{destPath}{name}.moc3", ParseMoc(moc)); //texture var textures = new SortedSet <string>(); foreach (var texture2D in texture2Ds) { using (var bitmap = new Texture2DConverter(texture2D).ConvertToBitmap(true)) { textures.Add($"textures/{texture2D.m_Name}.png"); bitmap.Save($"{destTexturePath}{texture2D.m_Name}.png", ImageFormat.Png); } } //motion var motions = new List <string>(); var rootTransform = gameObjects[0].m_Transform; while (rootTransform.m_Father.TryGet(out var m_Father)) { rootTransform = m_Father; } rootTransform.m_GameObject.TryGet(out var rootGameObject); var converter = new CubismMotion3Converter(rootGameObject, animationClips.ToArray()); foreach (ImportedKeyframedAnimation animation in converter.AnimationList) { var json = new CubismMotion3Json { Version = 3, Meta = new CubismMotion3Json.SerializableMeta { Duration = animation.Duration, Fps = animation.SampleRate, Loop = true, AreBeziersRestricted = true, CurveCount = animation.TrackList.Count, UserDataCount = animation.Events.Count }, Curves = new CubismMotion3Json.SerializableCurve[animation.TrackList.Count] }; int totalSegmentCount = 1; int totalPointCount = 1; for (int i = 0; i < animation.TrackList.Count; i++) { var track = animation.TrackList[i]; json.Curves[i] = new CubismMotion3Json.SerializableCurve { Target = track.Target, Id = track.Name, Segments = new List <float> { 0f, track.Curve[0].value } }; for (var j = 1; j < track.Curve.Count; j++) { var curve = track.Curve[j]; var preCurve = track.Curve[j - 1]; if (Math.Abs(curve.time - preCurve.time - 0.01f) < 0.0001f) //InverseSteppedSegment { var nextCurve = track.Curve[j + 1]; if (nextCurve.value == curve.value) { json.Curves[i].Segments.Add(3f); json.Curves[i].Segments.Add(nextCurve.time); json.Curves[i].Segments.Add(nextCurve.value); j += 1; totalPointCount += 1; totalSegmentCount++; continue; } } if (float.IsPositiveInfinity(curve.inSlope)) //SteppedSegment { json.Curves[i].Segments.Add(2f); json.Curves[i].Segments.Add(curve.time); json.Curves[i].Segments.Add(curve.value); totalPointCount += 1; } else if (preCurve.outSlope == 0f && Math.Abs(curve.inSlope) < 0.0001f) //LinearSegment { json.Curves[i].Segments.Add(0f); json.Curves[i].Segments.Add(curve.time); json.Curves[i].Segments.Add(curve.value); totalPointCount += 1; } else //BezierSegment { var tangentLength = (curve.time - preCurve.time) / 3f; json.Curves[i].Segments.Add(1f); json.Curves[i].Segments.Add(preCurve.time + tangentLength); json.Curves[i].Segments.Add(preCurve.outSlope * tangentLength + preCurve.value); json.Curves[i].Segments.Add(curve.time - tangentLength); json.Curves[i].Segments.Add(curve.value - curve.inSlope * tangentLength); json.Curves[i].Segments.Add(curve.time); json.Curves[i].Segments.Add(curve.value); totalPointCount += 3; } totalSegmentCount++; } } json.Meta.TotalSegmentCount = totalSegmentCount; json.Meta.TotalPointCount = totalPointCount; json.UserData = new CubismMotion3Json.SerializableUserData[animation.Events.Count]; var totalUserDataSize = 0; for (var i = 0; i < animation.Events.Count; i++) { var @event = animation.Events[i]; json.UserData[i] = new CubismMotion3Json.SerializableUserData { Time = @event.time, Value = @event.value }; totalUserDataSize += @event.value.Length; } json.Meta.TotalUserDataSize = totalUserDataSize; motions.Add($"motions/{animation.Name}.motion3.json"); File.WriteAllText($"{destAnimationPath}{animation.Name}.motion3.json", JsonConvert.SerializeObject(json, Formatting.Indented, new MyJsonConverter())); } //model var job = new JObject(); var jarray = new JArray(); foreach (var motion in motions) { var tempjob = new JObject(); tempjob["File"] = motion; jarray.Add(tempjob); } job[""] = jarray; var groups = new List <CubismModel3Json.SerializableGroup>(); var eyeBlinkParameters = monoBehaviours.Where(x => { x.m_Script.TryGet(out var m_Script); return(m_Script.m_ClassName == "CubismEyeBlinkParameter"); }).Select(x => { x.m_GameObject.TryGet(out var m_GameObject); return(m_GameObject.m_Name); }).ToArray(); if (eyeBlinkParameters.Length > 0) { groups.Add(new CubismModel3Json.SerializableGroup { Target = "Parameter", Name = "EyeBlink", Ids = eyeBlinkParameters }); } var lipSyncParameters = monoBehaviours.Where(x => { x.m_Script.TryGet(out var m_Script); return(m_Script.m_ClassName == "CubismMouthParameter"); }).Select(x => { x.m_GameObject.TryGet(out var m_GameObject); return(m_GameObject.m_Name); }).ToArray(); if (lipSyncParameters.Length > 0) { groups.Add(new CubismModel3Json.SerializableGroup { Target = "Parameter", Name = "LipSync", Ids = lipSyncParameters }); } var model3 = new CubismModel3Json { Version = 3, FileReferences = new CubismModel3Json.SerializableFileReferences { Moc = $"{name}.moc3", Textures = textures.ToArray(), //Physics = $"{name}.physics3.json", Motions = job }, Groups = groups.ToArray() }; if (physics != null) { model3.FileReferences.Physics = $"{name}.physics3.json"; } File.WriteAllText($"{destPath}{name}.model3.json", JsonConvert.SerializeObject(model3, Formatting.Indented)); } Console.WriteLine("Done!"); Console.Read(); }
public static Bitmap GetCardArt(Card card) { var texture2DConverter = new Texture2DConverter(_loadedAssets[$"{card.CardArt}_AIF"]); return(texture2DConverter.ConvertToBitmap(true)); }
public static bool ExportTexture2D(AssetItem item, string exportPathName) { var converter = new Texture2DConverter((Texture2D)item.Asset); var convertTexture = (bool)Properties.Settings.Default["convertTexture"]; if (convertTexture) { var bitmap = converter.ConvertToBitmap(true); if (bitmap == null) { return(false); } ImageFormat format = null; var ext = (string)Properties.Settings.Default["convertType"]; bool tga = false; switch (ext) { case "BMP": format = ImageFormat.Bmp; break; case "PNG": format = ImageFormat.Png; break; case "JPEG": format = ImageFormat.Jpeg; break; case "TGA": tga = true; break; } var exportFullName = exportPathName + item.Text + "." + ext.ToLower(); if (ExportFileExists(exportFullName)) { return(false); } if (tga) { var file = new TGA(bitmap); file.Save(exportFullName); } else { bitmap.Save(exportFullName, format); } bitmap.Dispose(); return(true); } else { var exportFullName = exportPathName + item.Text + converter.GetExtensionName(); if (ExportFileExists(exportFullName)) { return(false); } File.WriteAllBytes(exportFullName, converter.ConvertToContainer()); return(true); } }
static void Main(string[] args) { if (args.Length == 0) { return; } foreach (var arg in args) { if (!File.Exists(arg)) { continue; } var path = Path.GetFullPath(arg); var bundleFile = new BundleFile(path, new EndianBinaryReader(File.OpenRead(path))); if (bundleFile.fileList.Count == 0) { return; } var assetsFile = new AssetsFile(path, new EndianBinaryReader(bundleFile.fileList[0].stream)); var assets = assetsFile.preloadTable.Select(x => x.Value).ToArray(); var name = Path.GetFileName(path); var destPath = @"live2d\" + name + @"\"; var destTexturePath = @"live2d\" + name + @"\textures\"; var destAnimationPath = @"live2d\" + name + @"\motions\"; Directory.CreateDirectory(destPath); Directory.CreateDirectory(destTexturePath); Directory.CreateDirectory(destAnimationPath); Console.WriteLine($"Extract {name}"); //physics var physics = new TextAsset(assets.First(x => x.Type == ClassIDReference.TextAsset)); File.WriteAllBytes($"{destPath}{physics.m_Name}.json", physics.m_Script); //moc var moc = assets.First(x => x.Type == ClassIDReference.MonoBehaviour); foreach (var assetPreloadData in assets.Where(x => x.Type == ClassIDReference.MonoBehaviour)) { if (assetPreloadData.Size > moc.Size) { moc = assetPreloadData; } } var mocReader = moc.InitReader(); mocReader.Position += 28; mocReader.ReadAlignedString(); var mocBuff = mocReader.ReadBytes(mocReader.ReadInt32()); File.WriteAllBytes($"{destPath}{name}.moc3", mocBuff); //texture var textures = new SortedSet <string>(); foreach (var texture in assets.Where(x => x.Type == ClassIDReference.Texture2D)) { var texture2D = new Texture2D(texture); using (var bitmap = new Texture2DConverter(texture2D).ConvertToBitmap(true)) { textures.Add($"textures/{texture2D.m_Name}.png"); bitmap.Save($"{destTexturePath}{texture2D.m_Name}.png", ImageFormat.Png); } } //motions var motions = new List <string>(); var animatorAsset = assets.First(x => x.Type == ClassIDReference.Animator); var animator = new Animator(animatorAsset); var rootGameObject = new GameObject(animator.m_GameObject.Get()); var animations = assets.Where(x => x.Type == ClassIDReference.AnimationClip).Select(x => new AnimationClip(x)).ToArray(); var converter = new CubismMotion3Converter(rootGameObject, animations); foreach (ImportedKeyframedAnimation animation in converter.AnimationList) { var json = new CubismMotion3Json { Version = 3, Meta = new SerializableMeta { Duration = animation.Duration, Fps = animation.SampleRate, Loop = true, CurveCount = animation.TrackList.Count, UserDataCount = 0, TotalUserDataSize = 0 }, Curves = new SerializableCurve[animation.TrackList.Count] }; int totalSegmentCount = 1; int totalPointCount = 1; for (int i = 0; i < animation.TrackList.Count; i++) { var track = animation.TrackList[i]; json.Curves[i] = new SerializableCurve { Target = track.Target, Id = track.Name, Segments = new List <float> { 0f, track.Curve[0].value } }; for (var j = 1; j < track.Curve.Count; j++) { var curve = track.Curve[j]; if (track.Curve.Count == 2) //LinearSegment { json.Curves[i].Segments.Add(0f); json.Curves[i].Segments.Add(curve.time); json.Curves[i].Segments.Add(curve.value); totalPointCount += 1; } else { var preCurve = track.Curve[j - 1]; if (Math.Abs(curve.time - preCurve.time - 0.01f) < 0.0001f) //InverseSteppedSegment { var nextCurve = track.Curve[j + 1]; if (nextCurve.value == curve.value) { json.Curves[i].Segments.Add(3f); json.Curves[i].Segments.Add(nextCurve.time); json.Curves[i].Segments.Add(nextCurve.value); j += 1; totalPointCount += 1; continue; } } if (curve.inSlope == float.PositiveInfinity) //SteppedSegment { json.Curves[i].Segments.Add(2f); json.Curves[i].Segments.Add(curve.time); json.Curves[i].Segments.Add(curve.value); totalPointCount += 1; } /*else if (preCurve.outSlope == 0f && Math.Abs(curve.inSlope) < 0.0001f) //LinearSegment * { * json.Curves[i].Segments.Add(0f); * json.Curves[i].Segments.Add(curve.time); * json.Curves[i].Segments.Add(curve.value); * totalPointCount += 1; * }*/ else //BezierSegment { var tangentLength = (curve.time - preCurve.time) / 3f; json.Curves[i].Segments.Add(1f); json.Curves[i].Segments.Add(preCurve.time + tangentLength); json.Curves[i].Segments.Add(preCurve.outSlope * tangentLength + preCurve.value); json.Curves[i].Segments.Add(curve.time - tangentLength); json.Curves[i].Segments.Add(curve.value - curve.inSlope * tangentLength); json.Curves[i].Segments.Add(curve.time); json.Curves[i].Segments.Add(curve.value); totalPointCount += 3; } } totalSegmentCount++; } } json.Meta.TotalSegmentCount = totalSegmentCount; json.Meta.TotalPointCount = totalPointCount; motions.Add($"motions/{animation.Name}.motion3.json"); File.WriteAllText($"{destAnimationPath}{animation.Name}.motion3.json", JsonConvert.SerializeObject(json, Formatting.Indented, new MyJsonConverter())); } //model var job = new JObject(); var jarray = new JArray(); var tempjob = new JObject(); foreach (var motion in motions) { tempjob["File"] = motion; jarray.Add(tempjob); } job[""] = jarray; var model3 = new CubismModel3Json { Version = 3, FileReferences = new SerializableFileReferences { Moc = $"{name}.moc3", Textures = textures.ToArray(), Physics = $"{physics.m_Name}.json", Motions = job }, Groups = new[] { new SerializableGroup { Target = "Parameter", Name = "LipSync", Ids = new[] { "ParamMouthOpenY" } }, new SerializableGroup { Target = "Parameter", Name = "EyeBlink", Ids = new[] { "ParamEyeLOpen", "ParamEyeROpen" } } } }; File.WriteAllText($"{destPath}{name}.model3.json", JsonConvert.SerializeObject(model3, Formatting.Indented)); } Console.WriteLine("Done!"); Console.Read(); }
static void Main(string[] args) { if (args.Length == 0) { return; } foreach (var arg in args) { if (!File.Exists(arg)) { continue; } var path = Path.GetFullPath(arg); var assetsManager = new AssetsManager(); assetsManager.LoadFiles(path); if (assetsManager.assetsFileList.Count == 0) { continue; } var assets = assetsManager.assetsFileList[0].Objects.Values.ToList(); var name = Path.GetFileName(path); var destPath = @"live2d\" + name + @"\"; var destTexturePath = @"live2d\" + name + @"\textures\"; var destAnimationPath = @"live2d\" + name + @"\motions\"; Directory.CreateDirectory(destPath); Directory.CreateDirectory(destTexturePath); Directory.CreateDirectory(destAnimationPath); Console.WriteLine($"Extract {name}"); //MonoBehaviour var monoBehaviours = assets.OfType <MonoBehaviour>().ToArray(); //physics var physics = monoBehaviours.First(x => { if (x.m_Script.TryGet(out var m_Script)) { return(m_Script.m_ClassName == "CubismPhysicsController"); } return(false); }); File.WriteAllText($"{destPath}{name}.physics3.json", ParsePhysics(physics)); //moc var moc = monoBehaviours.First(x => { if (x.m_Script.TryGet(out var m_Script)) { return(m_Script.m_ClassName == "CubismMoc"); } return(false); }); File.WriteAllBytes($"{destPath}{name}.moc3", ParseMoc(moc)); //texture var textures = new SortedSet <string>(); foreach (var texture2D in assets.OfType <Texture2D>()) { using (var bitmap = new Texture2DConverter(texture2D).ConvertToBitmap(true)) { textures.Add($"textures/{texture2D.m_Name}.png"); bitmap.Save($"{destTexturePath}{texture2D.m_Name}.png", ImageFormat.Png); } } //motions var motions = new List <string>(); var animator = (Animator)assets.First(x => x is Animator); var animations = assets.OfType <AnimationClip>().ToArray(); animator.m_GameObject.TryGet(out GameObject rootGameObject); var converter = new CubismMotion3Converter(rootGameObject, animations); foreach (ImportedKeyframedAnimation animation in converter.AnimationList) { var json = new CubismMotion3Json { Version = 3, Meta = new CubismMotion3Json.SerializableMeta { Duration = animation.Duration, Fps = animation.SampleRate, Loop = true, AreBeziersRestricted = true, CurveCount = animation.TrackList.Count, UserDataCount = animation.Events.Count }, Curves = new CubismMotion3Json.SerializableCurve[animation.TrackList.Count] }; int totalSegmentCount = 1; int totalPointCount = 1; for (int i = 0; i < animation.TrackList.Count; i++) { var track = animation.TrackList[i]; json.Curves[i] = new CubismMotion3Json.SerializableCurve { Target = track.Target, Id = track.Name, Segments = new List <float> { 0f, track.Curve[0].value } }; for (var j = 1; j < track.Curve.Count; j++) { var curve = track.Curve[j]; var preCurve = track.Curve[j - 1]; if (Math.Abs(curve.time - preCurve.time - 0.01f) < 0.0001f) //InverseSteppedSegment { var nextCurve = track.Curve[j + 1]; if (nextCurve.value == curve.value) { json.Curves[i].Segments.Add(3f); json.Curves[i].Segments.Add(nextCurve.time); json.Curves[i].Segments.Add(nextCurve.value); j += 1; totalPointCount += 1; totalSegmentCount++; continue; } } if (float.IsPositiveInfinity(curve.inSlope)) //SteppedSegment { json.Curves[i].Segments.Add(2f); json.Curves[i].Segments.Add(curve.time); json.Curves[i].Segments.Add(curve.value); totalPointCount += 1; } else if (preCurve.outSlope == 0f && Math.Abs(curve.inSlope) < 0.0001f) //LinearSegment { json.Curves[i].Segments.Add(0f); json.Curves[i].Segments.Add(curve.time); json.Curves[i].Segments.Add(curve.value); totalPointCount += 1; } else //BezierSegment { var tangentLength = (curve.time - preCurve.time) / 3f; json.Curves[i].Segments.Add(1f); json.Curves[i].Segments.Add(preCurve.time + tangentLength); json.Curves[i].Segments.Add(preCurve.outSlope * tangentLength + preCurve.value); json.Curves[i].Segments.Add(curve.time - tangentLength); json.Curves[i].Segments.Add(curve.value - curve.inSlope * tangentLength); json.Curves[i].Segments.Add(curve.time); json.Curves[i].Segments.Add(curve.value); totalPointCount += 3; } totalSegmentCount++; } } json.Meta.TotalSegmentCount = totalSegmentCount; json.Meta.TotalPointCount = totalPointCount; json.UserData = new CubismMotion3Json.SerializableUserData[animation.Events.Count]; var totalUserDataSize = 0; for (var i = 0; i < animation.Events.Count; i++) { var @event = animation.Events[i]; json.UserData[i] = new CubismMotion3Json.SerializableUserData { Time = @event.time, Value = @event.value }; totalUserDataSize += @event.value.Length; } json.Meta.TotalUserDataSize = totalUserDataSize; motions.Add($"motions/{animation.Name}.motion3.json"); File.WriteAllText($"{destAnimationPath}{animation.Name}.motion3.json", JsonConvert.SerializeObject(json, Formatting.Indented, new MyJsonConverter())); } //model var job = new JObject(); var jarray = new JArray(); foreach (var motion in motions) { var tempjob = new JObject(); tempjob["File"] = motion; jarray.Add(tempjob); } job[""] = jarray; var groups = new List <CubismModel3Json.SerializableGroup>(); var eyeBlinkParameters = monoBehaviours.Where(x => { x.m_Script.TryGet(out var m_Script); return(m_Script.m_ClassName == "CubismEyeBlinkParameter"); }).Select(x => { x.m_GameObject.TryGet(out var m_GameObject); return(m_GameObject.m_Name); }).ToArray(); if (eyeBlinkParameters.Length > 0) { groups.Add(new CubismModel3Json.SerializableGroup { Target = "Parameter", Name = "EyeBlink", Ids = eyeBlinkParameters }); } var lipSyncParameters = monoBehaviours.Where(x => { x.m_Script.TryGet(out var m_Script); return(m_Script.m_ClassName == "CubismMouthParameter"); }).Select(x => { x.m_GameObject.TryGet(out var m_GameObject); return(m_GameObject.m_Name); }).ToArray(); if (lipSyncParameters.Length > 0) { groups.Add(new CubismModel3Json.SerializableGroup { Target = "Parameter", Name = "LipSync", Ids = lipSyncParameters }); } var model3 = new CubismModel3Json { Version = 3, FileReferences = new CubismModel3Json.SerializableFileReferences { Moc = $"{name}.moc3", Textures = textures.ToArray(), Physics = $"{name}.physics3.json", Motions = job }, Groups = groups.ToArray() }; File.WriteAllText($"{destPath}{name}.model3.json", JsonConvert.SerializeObject(model3, Formatting.Indented)); } Console.WriteLine("Done!"); Console.Read(); }
static void Main(string[] args) { foreach (var arg in args) { if (!File.Exists(arg)) { continue; } var path = Path.GetFullPath(arg); var bundleFile = new BundleFile(path, new EndianBinaryReader(File.OpenRead(path))); if (bundleFile.fileList.Count == 0) { return; } var assetsFile = new AssetsFile(path, new EndianBinaryReader(bundleFile.fileList[0].stream)); var assets = assetsFile.preloadTable.Select(x => x.Value).ToArray(); var name = Path.GetFileName(path); var destPath = @"live2d\" + name + @"\"; var destTexturePath = @"live2d\" + name + @"\textures\"; var destAnimationPath = @"live2d\" + name + @"\motions\"; Directory.CreateDirectory(destPath); Directory.CreateDirectory(destTexturePath); Directory.CreateDirectory(destAnimationPath); Console.WriteLine($"Extract {name}"); //physics var physics = new TextAsset(assets.First(x => x.Type == ClassIDReference.TextAsset)); File.WriteAllBytes($"{destPath}{physics.m_Name}.json", physics.m_Script); //moc var moc = assets.First(x => x.Type == ClassIDReference.MonoBehaviour); foreach (var assetPreloadData in assets.Where(x => x.Type == ClassIDReference.MonoBehaviour)) { if (assetPreloadData.Size > moc.Size) { moc = assetPreloadData; } } var mocReader = moc.InitReader(); mocReader.Position += 28; mocReader.ReadAlignedString(); var mocBuff = mocReader.ReadBytes(mocReader.ReadInt32()); File.WriteAllBytes($"{destPath}{name}.moc3", mocBuff); //texture var textures = new SortedSet <string>(); foreach (var texture in assets.Where(x => x.Type == ClassIDReference.Texture2D)) { var texture2D = new Texture2D(texture); using (var bitmap = new Texture2DConverter(texture2D).ConvertToBitmap(true)) { textures.Add($"textures/{texture2D.m_Name}.png"); bitmap.Save($"{destTexturePath}{texture2D.m_Name}.png", ImageFormat.Png); } } //motions var motions = new List <string>(); var animatorAsset = assets.First(x => x.Type == ClassIDReference.Animator); var animator = new Animator(animatorAsset); var rootGameObject = new GameObject(animator.m_GameObject.Get()); var animations = assets.Where(x => x.Type == ClassIDReference.AnimationClip).Select(x => new AnimationClip(x)).ToArray(); var converter = new CubismMotion3Converter(rootGameObject, animations); foreach (ImportedKeyframedAnimation animation in converter.AnimationList) { var json = new CubismMotion3Json { Version = 3, Meta = new SerializableMeta { Duration = animation.Duration, Fps = animation.SampleRate, Loop = true, AreBeziersRestricted = true, CurveCount = animation.TrackList.Count, TotalSegmentCount = 63, //TODO How to calculate this? TotalPointCount = 165, //TODO How to calculate this? UserDataCount = 0, TotalUserDataSize = 0 }, Curves = new SerializableCurve[animation.TrackList.Count] }; for (int i = 0; i < animation.TrackList.Count; i++) { var track = animation.TrackList[i]; json.Curves[i] = new SerializableCurve { Target = track.Target, Id = track.Name, Segments = new List <float> { 0f, track.Curve[0].value } }; for (var j = 1; j < track.Curve.Count; j++) { var curve = track.Curve[j]; if (curve != null) { json.Curves[i].Segments.Add(0f); json.Curves[i].Segments.Add(curve.time); json.Curves[i].Segments.Add(curve.value); } } } motions.Add($"motions/{animation.Name}.motion3.json"); File.WriteAllText($"{destAnimationPath}{animation.Name}.motion3.json", JsonConvert.SerializeObject(json, Formatting.Indented, new MyJsonConverter())); } //model var model3 = new CubismModel3Json { Version = 3, FileReferences = new SerializableFileReferences { Moc = $"{name}.moc3", Textures = textures.ToArray(), Motions = motions.ToArray(), Physics = $"{physics.m_Name}.json" }, Groups = new[] { new SerializableGroup { Target = "Parameter", Name = "LipSync", Ids = new[] { "ParamMouthOpenY" } }, new SerializableGroup { Target = "Parameter", Name = "EyeBlink", Ids = new[] { "ParamEyeLOpen", "ParamEyeROpen" } } } }; File.WriteAllText($"{destPath}{name}.model3.json", JsonConvert.SerializeObject(model3, Formatting.Indented)); } Console.WriteLine("Done!"); Console.Read(); }