private IEnumerator GenerateBonePoseFile() { yield return(null); var context = (Context)data; var model = ModelReader.LoadMmdModel(context.ModelPath, new ModelReadConfig { GlobalToonPath = "" }); var motion = new VmdReader().Read(context.MotionPath); Debug.Log("motion load finished" + motion.Length + " frames"); var generator = BonePoseFileGenerator.GenerateAsync(model, motion, context.SavePath, 1.0f / 60.0f, 5.0f, 1.0f / 120.0f); _generator = generator; while (true) { var generatorStatus = generator.Status; if (generatorStatus == BonePoseFileGenerator.GenerateStatus.Failed || generatorStatus == BonePoseFileGenerator.GenerateStatus.Finished || generatorStatus == BonePoseFileGenerator.GenerateStatus.Canceled) { break; } if (generatorStatus == BonePoseFileGenerator.GenerateStatus.CalculatingFrames) { _tipText.text = "已计算" + generator.CalculatedFrames + "帧, 共" + generator.TotalFrames + "帧。 已完成" + 100L * generator.CalculatedFrames / generator.TotalFrames + "%"; } yield return(null); } if (generator.Status == BonePoseFileGenerator.GenerateStatus.Finished) { MainSceneController.Instance.ChangeCurrentBonePoseFile(context.SavePath); } ClosePage(); switch (generator.Status) { case BonePoseFileGenerator.GenerateStatus.Finished: ShowPage <OkDialog>(new OkDialog.Context { Title = "提示", Tip = "计算完成。现在可以流畅地播放了。以后如果需要再次播放同模型配同动作,选择模型、动作后可以再载入已保存的动作结果文件。记得在选择结果文件时可能需要先点“扫描”才能看到计算结果文件。", OnOk = () => { OnceTipPage.ShowOnceTip(TipNames.WhereIsBonePoseFile); } }); break; case BonePoseFileGenerator.GenerateStatus.Failed: ShowPage <OkDialog>(new OkDialog.Context { Title = "提示", Tip = "计算发生错误。" }); break; } }
protected void Start() { var model = new PmxReader().Read(ModelPath, new ModelReadConfig { GlobalToonPath = "" }); Debug.Log("model load finished"); var motion = new VmdReader().Read(MotionPath); Debug.Log("motion load finished" + motion.Length + " frames"); var bonePoseFileGenerator = BonePoseFileGenerator.GenerateAsync(model, motion, BonePoseFileOutputPath); StartCoroutine(CheckGenerateStatus(bonePoseFileGenerator)); }
private static void BuildVmd([NotNull] string outputRoot, [NotNull] string subDirName, [NotNull] string vmdFilePath) { var vmd = VmdReader.ReadMotionFrom(vmdFilePath); var set = new HashSet <string>(); foreach (var frame in vmd.BoneFrames) { set.Add(frame.Name); } foreach (var name in set) { UnityEngine.Debug.Log(name); } }
static void Main(string[] args) { #if DEBUG string path = @"C:\tmp\Sample_000000000213_keypoints.vmd"; #else string path = args[0]; #endif var vr = new VmdReader(path); var vmd = vr.Read(); var vw = new VmdWriter(path.Substring(0, path.LastIndexOf('.')) + "_rewrite.vmd"); vw.Write(vmd); foreach (var frame in vmd.Frames) { Console.WriteLine($"Frame #{frame.Index}"); Console.WriteLine($"-----------------------------------------"); foreach (var bone in frame.Bones) { Console.WriteLine($"Bone {bone.Key}:"); var p = bone.Value.Position; Console.WriteLine($" Position (x,y,z) = ({p.X}, {p.Y}, {p.Z})"); var q = bone.Value.Quaternion; Console.WriteLine($" Quartenion (x,y,z,w) = ({q.X}, {q.Y}, {q.Z}, {q.W})"); var e = EulerAngle.FromQuaternion(q); Console.WriteLine($" Euler angles (h,p,b) = ({e.HeadingDeg}, {e.PitchDeg}, {e.BankDeg})"); } Console.WriteLine($""); } #if DEBUG Console.WriteLine("Press any key to continue..."); Console.ReadKey(true); #else #endif }
/// <summary> /// LoadContent will be called once per game and is the place to load /// all of your content. /// </summary> protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. _spriteBatch = new SpriteBatch(GraphicsDevice); // TODO: use this.Content to load your game content here var modelBaseDir = Content.RootDirectory; PmxModel pmxModel; using (var fileStream = File.Open(Path.Combine(modelBaseDir, "mayu.pmx"), FileMode.Open, FileAccess.Read, FileShare.Read)) { pmxModel = PmxReader.ReadModel(fileStream); } Debug.Assert(pmxModel != null, nameof(pmxModel) + " != null"); foreach (var mat in pmxModel.Materials) { if (string.IsNullOrEmpty(mat.TextureFileName)) { continue; } TryLoadTexture(mat.TextureFileName); } if (!_modelTextures.ContainsKey(string.Empty)) { var tex = new Texture2D(GraphicsDevice, 1, 1, false, SurfaceFormat.Color); tex.SetData(new[] { 0xffffffff }); _modelTextures[string.Empty] = tex; } _pmxModel = pmxModel; _modelBaseDir = modelBaseDir; var camera = this.SimpleFindComponentOf <Camera>(); Debug.Assert(camera != null, nameof(camera) + " != null"); _pmxRenderer.InitializeContents(pmxModel, camera, _modelTextures); VmdMotion vmdMotion; using (var fileStream = File.Open(Path.Combine(modelBaseDir, "LD.vmd"), FileMode.Open, FileAccess.Read, FileShare.Read)) { vmdMotion = VmdReader.ReadMotion(fileStream); } const bool rescaleVmd = true; if (rescaleVmd) { var vmdMotionScaleFactor = TryDetectVmdScaleFactor(); vmdMotion.Scale(vmdMotionScaleFactor); } _pmxVmdAnimator.InitializeContents(pmxModel, vmdMotion); _pmxVmdAnimator.Enabled = false; _vmdMotion = vmdMotion; _boneDebugVisualizer.InitializeContents(pmxModel, camera, _spriteBatch); void TryLoadTexture(string relativeFilePath) { if (_modelTextures.ContainsKey(relativeFilePath)) { return; } var texture = ContentHelper.LoadTexture(GraphicsDevice, Path.Combine(modelBaseDir, relativeFilePath)); if (texture != null) { _modelTextures[relativeFilePath] = texture; } } float TryDetectVmdScaleFactor() { const float defaultScaleFactor = 1.0f; PmxBone pmxBone1, pmxBone2; try { pmxBone1 = pmxModel.Bones.SingleOrDefault(b => string.Equals(b.Name, "全ての親", StringComparison.Ordinal)); pmxBone2 = pmxModel.Bones.SingleOrDefault(b => string.Equals(b.Name, "センター", StringComparison.Ordinal)); } catch (InvalidOperationException ex) { // Multiple bones in PMX model having the same name. Debug.Print(ex.ToString()); return(defaultScaleFactor); } var vmdBone1 = vmdMotion.BoneFrames.FirstOrDefault(b => string.Equals(b.Name, "全ての親", StringComparison.Ordinal)); var vmdBone2 = vmdMotion.BoneFrames.FirstOrDefault(b => string.Equals(b.Name, "センター", StringComparison.Ordinal)); if (pmxBone1 == null || pmxBone2 == null || vmdBone1 == null || vmdBone2 == null) { Debug.Print("At least one of the standard bones is not found. Returning default scale."); return(defaultScaleFactor); } if (vmdBone1.FrameIndex != 0 || vmdBone2.FrameIndex != 0) { Debug.Print("The two VMD standard bones should have appeared at the first frame (index=0). Returning default scale."); return(defaultScaleFactor); } if (pmxBone2.ParentBone != pmxBone1) { Debug.Print("The parent of PMX bone #2 (\"センター\") should be PMX bone #1 (\"全ての親\")."); return(defaultScaleFactor); } var pmxRelativePosition = pmxBone2.InitialPosition - pmxBone1.InitialPosition; var vmdRelativePosition = vmdBone2.Position - vmdBone1.Position; var pmxLength = pmxRelativePosition.Length(); var vmdLength = vmdRelativePosition.Length(); if (vmdLength.Equals(0)) { return(defaultScaleFactor); } else { return(pmxLength / vmdLength); } } }