Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/tsoview/TDCG/TMOFile.cs

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2275 - (show annotations) (download)
Fri Dec 22 00:21:06 2017 UTC (6 years, 3 months ago) by nomeu
File size: 44106 byte(s)
indent; rotation with scale
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Text;
5 using Microsoft.DirectX;
6 using Microsoft.DirectX.Direct3D;
7 using TDCG.Extensions;
8
9 namespace TDCG
10 {
11 /// <summary>
12 /// TMOファイルを扱います。
13 /// </summary>
14 public class TMOFile
15 {
16 /// <summary>
17 /// バイナリ値として読み取ります。
18 /// </summary>
19 protected BinaryReader reader;
20
21 /// <summary>
22 /// ヘッダ
23 /// </summary>
24 public byte[] header;
25 /// <summary>
26 /// オプション値0
27 /// </summary>
28 public int opt0;
29 /// <summary>
30 /// オプション値1
31 /// </summary>
32 public int opt1;
33 /// <summary>
34 /// bone配列
35 /// </summary>
36 public TMONode[] nodes;
37 /// <summary>
38 /// フレーム配列
39 /// </summary>
40 public TMOFrame[] frames;
41 /// <summary>
42 /// フッタ
43 /// </summary>
44 public byte[] footer;
45
46 /// <summary>
47 /// bone名称とboneを関連付ける辞書
48 /// </summary>
49 public Dictionary<string, TMONode> nodemap;
50
51 internal TMONode w_hips_node = null;
52 internal List<TMONode> root_nodes_except_w_hips;
53
54 /// <summary>
55 /// 指定パスに保存します。
56 /// </summary>
57 /// <param name="dest_file">パス</param>
58 public void Save(string dest_file)
59 {
60 using (Stream dest_stream = File.Create(dest_file))
61 Save(dest_stream);
62 }
63
64 /// <summary>
65 /// 指定ストリームに保存します。
66 /// </summary>
67 /// <param name="dest_stream">ストリーム</param>
68 public void Save(Stream dest_stream)
69 {
70 BinaryWriter bw = new BinaryWriter(dest_stream);
71
72 WriteMagic(bw);
73 bw.Write(header);
74 bw.Write(opt0);
75 bw.Write(opt1);
76
77 bw.Write(nodes.Length);
78 foreach (TMONode node in nodes)
79 node.Write(bw);
80
81 bw.Write(frames.Length);
82 foreach (TMOFrame frame in frames)
83 frame.Write(bw);
84
85 bw.Write(footer);
86 }
87
88 /// <summary>
89 /// 'TMO1' を書き出します。
90 /// </summary>
91 public static void WriteMagic(BinaryWriter bw)
92 {
93 bw.Write(0x314F4D54);
94 }
95
96 /// <summary>
97 /// 指定パスから読み込みます。
98 /// </summary>
99 /// <param name="source_file">パス</param>
100 public void Load(string source_file)
101 {
102 using (Stream source_stream = File.OpenRead(source_file))
103 Load(source_stream);
104 }
105
106 /// <summary>
107 /// 指定ストリームから読み込みます。
108 /// </summary>
109 /// <param name="source_stream">ストリーム</param>
110 public void Load(Stream source_stream)
111 {
112 this.reader = new BinaryReader(source_stream, System.Text.Encoding.Default);
113
114 byte[] magic = reader.ReadBytes(4);
115
116 if (magic[0] != (byte)'T' || magic[1] != (byte)'M' || magic[2] != (byte)'O' || magic[3] != (byte)'1')
117 throw new Exception("File is not TMO");
118
119 this.header = reader.ReadBytes(8);
120 this.opt0 = reader.ReadInt32();
121 this.opt1 = reader.ReadInt32();
122
123 int node_count = reader.ReadInt32();
124 nodes = new TMONode[node_count];
125 for (int i = 0; i < node_count; i++)
126 {
127 nodes[i] = new TMONode(i);
128 nodes[i].Read(reader);
129 }
130
131 GenerateNodemapAndTree();
132
133 int frame_count = reader.ReadInt32();
134 frames = new TMOFrame[frame_count];
135
136 for (int i = 0; i < frame_count; i++)
137 {
138 frames[i] = new TMOFrame(i);
139 frames[i].Read(reader);
140 }
141
142 foreach (TMONode node in nodes)
143 node.LinkMatrices(frames);
144
145 this.footer = reader.ReadBytes(4);
146 }
147
148 internal void GenerateNodemapAndTree()
149 {
150 nodemap = new Dictionary<string, TMONode>();
151
152 for (int i = 0; i < nodes.Length; i++)
153 {
154 nodemap.Add(nodes[i].Path, nodes[i]);
155 }
156
157 List<TMONode> root_nodes = new List<TMONode>();
158
159 for (int i = 0; i < nodes.Length; i++)
160 {
161 int index = nodes[i].Path.LastIndexOf('|');
162 if (index == 0)
163 root_nodes.Add(nodes[i]);
164 if (index <= 0)
165 continue;
166 string path = nodes[i].Path.Substring(0, index);
167 nodes[i].parent = nodemap[path];
168 nodes[i].parent.children.Add(nodes[i]);
169 }
170
171 root_nodes_except_w_hips = new List<TMONode>();
172
173 foreach (TMONode node in root_nodes)
174 {
175 if (node.Path == "|W_Hips")
176 w_hips_node = node;
177 else
178 root_nodes_except_w_hips.Add(node);
179 }
180 }
181
182 /// <summary>
183 /// 行列を得ます。
184 /// </summary>
185 /// <param name="name">bone名称</param>
186 /// <param name="frame_index">フレーム番号</param>
187 /// <returns></returns>
188 public TMOMat GetTMOMat(string name, int frame_index)
189 {
190 return frames[frame_index].matrices[nodemap[name].Id];
191 }
192
193 /// <summary>
194 /// node idのペアを作成します。
195 /// ペアのキーはnode id
196 /// ペアの値はもうひとつのtmoにおいて名称(短い形式)が一致するnode idになります。
197 /// </summary>
198 /// <param name="motion">もうひとつのtmo</param>
199 /// <returns>tmo frame indexのペア</returns>
200 public int[] CreateNodeIdPair(TMOFile motion)
201 {
202 Dictionary<string, TMONode> source_nodes = new Dictionary<string, TMONode>();
203
204 Dictionary<string, TMONode> motion_nodes = new Dictionary<string, TMONode>();
205
206 foreach (TMONode node in motion.nodes)
207 try
208 {
209 motion_nodes.Add(node.Name, node);
210 }
211 catch (ArgumentException)
212 {
213 Console.WriteLine("node {0} already exists.", node.Name);
214 }
215 foreach (TMONode node in nodes)
216 {
217 if (!motion_nodes.ContainsKey(node.Name))
218 {
219 throw new ArgumentException("error: node not found in motion: " + node.Name);
220 }
221 try
222 {
223 source_nodes.Add(node.Name, node);
224 }
225 catch (ArgumentException)
226 {
227 Console.WriteLine("node {0} already exists.", node.Name);
228 }
229 }
230
231 int[] id_pair = new int[nodes.Length];
232
233 foreach (TMONode node in nodes)
234 id_pair[node.Id] = motion_nodes[node.Name].Id;
235
236 return id_pair;
237 }
238
239 /// <summary>
240 /// 指定tmoからフレームを追加します。
241 /// </summary>
242 /// <param name="motion">tmo</param>
243 public void AppendFrameFrom(TMOFile motion)
244 {
245 int[] id_pair = CreateNodeIdPair(motion);
246
247 TMOFrame source_frame = frames[0];
248 int append_length = motion.frames.Length;
249 TMOFrame[] append_frames = new TMOFrame[append_length];
250 for (int i = 0; i < motion.frames.Length; i++)
251 append_frames[i] = TMOFrame.Select(source_frame, motion.frames[i], id_pair);
252
253 int old_length = frames.Length;
254 Array.Resize(ref frames, frames.Length + append_length);
255 Array.Copy(append_frames, 0, frames, old_length, append_length);
256 this.opt0 = frames.Length - 1;
257 }
258
259 /// <summary>
260 /// 指定tmoへフレームを補間します。
261 /// </summary>
262 /// <param name="motion">tmo</param>
263 /// <param name="append_length">補間するフレーム長さ</param>
264 /// <param name="p1">補間速度係数</param>
265 public void SlerpFrameEndTo(TMOFile motion, int append_length, float p1)
266 {
267 int[] id_pair = CreateNodeIdPair(motion);
268
269 int i0 = (frames.Length > 1) ? frames.Length - 1 - 1 : 0;
270 int i1 = frames.Length - 1;
271 int i2 = 0;
272 int i3 = (motion.frames.Length > 1) ? 1 : 0;
273
274 TMOFrame frame0 = frames[i0];
275 TMOFrame frame1 = frames[i1];
276 TMOFrame frame2 = motion.frames[i2];
277 TMOFrame frame3 = motion.frames[i3];
278
279 TMOFrame[] interp_frames = TMOFrame.Slerp(frame0, frame1, frame2, frame3, append_length, p1, id_pair);
280 int old_length = frames.Length;
281 Array.Resize(ref frames, frames.Length + append_length);
282 Array.Copy(interp_frames, 0, frames, old_length, append_length);
283 this.opt0 = frames.Length - 1;
284 }
285
286 /// <summary>
287 /// 指定tmoへフレームを補間します。
288 /// </summary>
289 /// <param name="motion">tmo</param>
290 /// <param name="append_length">補間するフレーム長さ</param>
291 public void SlerpFrameEndTo(TMOFile motion, int append_length)
292 {
293 SlerpFrameEndTo(motion, append_length, 0.5f);
294 }
295
296 /// <summary>
297 /// 指定tmoへフレームを補間します。
298 /// </summary>
299 /// <param name="motion">tmo</param>
300 public void SlerpFrameEndTo(TMOFile motion)
301 {
302 SlerpFrameEndTo(motion, 200, 0.5f);
303 }
304
305 /// <summary>
306 /// フレームを指定indexのみに切り詰めます。
307 /// </summary>
308 /// <param name="frame_index">index</param>
309 public void TruncateFrame(int frame_index)
310 {
311 if (frames == null)
312 return;
313 if (frame_index < 0)
314 return;
315 if (frame_index > frames.Length - 1)
316 return;
317 if (frame_index > 0)
318 Array.Copy(frames, frame_index, frames, 0, 1);
319 Array.Resize(ref frames, 1);
320 this.opt0 = 1;
321 }
322
323 /// <summary>
324 /// 現在の行列を指定フレームに保存します。
325 /// </summary>
326 /// <param name="frame_index">index</param>
327 public void SaveTransformationMatrixToFrame(int frame_index)
328 {
329 if (frames == null)
330 return;
331
332 foreach (TMONode node in nodes)
333 node.matrices[frame_index].m = node.TransformationMatrix;
334 }
335
336 /// <summary>
337 /// 指定フレームの行列を保持します。
338 /// </summary>
339 /// <param name="frame_index">index</param>
340 public void LoadTransformationMatrixFromFrame(int frame_index)
341 {
342 if (frames == null)
343 return;
344
345 foreach (TMONode node in nodes)
346 node.TransformationMatrix = node.matrices[frame_index].m;
347 }
348
349 /// <summary>
350 /// 指定名称(短い形式)を持つnodeを検索します。
351 /// </summary>
352 /// <param name="name">node名称(短い形式)</param>
353 /// <returns></returns>
354 public TMONode FindNodeByName(string name)
355 {
356 foreach (TMONode node in nodes)
357 if (node.Name == name)
358 return node;
359 return null;
360 }
361
362 /// <summary>
363 /// 指定tmoのモーション(開始フレームからの変位)を複写します。
364 /// </summary>
365 /// <param name="motion">tmo</param>
366 public void CopyMotionFrom(TMOFile motion)
367 {
368 int[] id_pair = CreateNodeIdPair(motion);
369
370 TMOFrame source_frame = frames[0];
371 TMOFrame motion_frame = motion.frames[0];
372 int append_length = motion.frames.Length;
373 TMOFrame[] interp_frames = new TMOFrame[append_length];
374 for (int i = 0; i < motion.frames.Length; i++)
375 interp_frames[i] = TMOFrame.AddSub(source_frame, motion.frames[i], motion_frame, id_pair);
376
377 int old_length = frames.Length;
378 Array.Resize(ref frames, frames.Length + append_length);
379 Array.Copy(interp_frames, 0, frames, old_length, append_length);
380 this.opt0 = frames.Length - 1;
381 }
382
383 /// <summary>
384 /// 指定tmoにある指定名称(短い形式)のnodeを同じ名称のnodeに複写します。
385 /// ただし複写の対象は子node以降です。指定nodeは複写しません。
386 /// また、除外node以降のnodeは複写しません。
387 /// </summary>
388 /// <param name="motion">tmo</param>
389 /// <param name="name">node名称(短い形式)</param>
390 /// <param name="except_names">除外node名称(短い形式)リスト</param>
391 public void CopyChildrenNodeFrom(TMOFile motion, string name, List<string> except_names)
392 {
393 TMONode node = this.FindNodeByName(name);
394 if (node == null)
395 return;
396 TMONode motion_node = motion.FindNodeByName(name);
397 if (motion_node == null)
398 return;
399 node.CopyChildrenMatFrom(motion_node, except_names);
400 }
401
402 /// <summary>
403 /// 指定tmoにある指定名称(短い形式)のnodeを同じ名称のnodeに複写します。
404 /// </summary>
405 /// <param name="motion">tmo</param>
406 /// <param name="name">node名称(短い形式)</param>
407 public void CopyNodeFrom(TMOFile motion, string name)
408 {
409 TMONode node = this.FindNodeByName(name);
410 if (node == null)
411 return;
412 TMONode motion_node = motion.FindNodeByName(name);
413 if (motion_node == null)
414 return;
415 node.CopyMatFrom(motion_node);
416 }
417
418 /// <summary>
419 /// 指定tmoと同じnode treeを持つか。
420 /// </summary>
421 /// <param name="motion">tmo</param>
422 /// <returns></returns>
423 public bool IsSameNodeTree(TMOFile motion)
424 {
425 if (nodes.Length != motion.nodes.Length)
426 {
427 //Console.WriteLine("nodes length mismatch {0} {1}", nodes.Length, motion.nodes.Length);
428 return false;
429 }
430 int i = 0;
431 foreach (TMONode node in nodes)
432 {
433 TMONode motion_node = motion.nodes[i];
434 //Console.WriteLine("node Name {0} {1}", node.Name, motion_node.Name);
435 if (motion_node.Name != node.Name)
436 return false;
437 i++;
438 }
439 return true;
440 }
441
442 /// <summary>
443 /// tmoからtmoを生成します。
444 /// </summary>
445 public TMOFile Dup()
446 {
447 TMOFile tmo = new TMOFile();
448 tmo.header = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
449 tmo.opt0 = 1;
450 tmo.opt1 = 0;
451
452 int node_count = nodes.Length;
453 tmo.nodes = new TMONode[node_count];
454
455 for (int i = 0; i < node_count; i++)
456 {
457 tmo.nodes[i] = new TMONode(i);
458 tmo.nodes[i].Path = nodes[i].Path;
459 }
460
461 tmo.GenerateNodemapAndTree();
462
463 int frame_count = 1;
464 tmo.frames = new TMOFrame[frame_count];
465
466 for (int i = 0; i < frame_count; i++)
467 {
468 tmo.frames[i] = new TMOFrame(i);
469
470 int matrix_count = node_count;
471 tmo.frames[i].matrices = new TMOMat[matrix_count];
472 for (int j = 0; j < matrix_count; j++)
473 {
474 tmo.frames[i].matrices[j] = new TMOMat(ref frames[i].matrices[j].m);
475 }
476 }
477 foreach (TMONode node in tmo.nodes)
478 node.LinkMatrices(tmo.frames);
479
480 tmo.footer = new byte[4] { 0, 0, 0, 0 };
481
482 return tmo;
483 }
484
485 /// <summary>
486 /// tmoからtmoを生成します。
487 /// </summary>
488 public TMOFile GenerateTMOFromTransformationMatrix()
489 {
490 TMOFile tmo = new TMOFile();
491 tmo.header = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
492 tmo.opt0 = 1;
493 tmo.opt1 = 0;
494
495 int node_count = nodes.Length;
496 tmo.nodes = new TMONode[node_count];
497
498 for (int i = 0; i < node_count; i++)
499 {
500 tmo.nodes[i] = new TMONode(i);
501 tmo.nodes[i].Path = nodes[i].Path;
502 }
503
504 tmo.GenerateNodemapAndTree();
505
506 int frame_count = 1;
507 tmo.frames = new TMOFrame[frame_count];
508
509 for (int i = 0; i < frame_count; i++)
510 {
511 tmo.frames[i] = new TMOFrame(i);
512
513 int matrix_count = node_count;
514 tmo.frames[i].matrices = new TMOMat[matrix_count];
515 for (int j = 0; j < matrix_count; j++)
516 {
517 Matrix m = nodes[j].TransformationMatrix;
518 tmo.frames[i].matrices[j] = new TMOMat(ref m);
519 }
520 }
521
522 foreach (TMONode node in tmo.nodes)
523 node.LinkMatrices(tmo.frames);
524
525 tmo.footer = new byte[4] { 0, 0, 0, 0 };
526
527 return tmo;
528 }
529 }
530
531 /// <summary>
532 /// 変形行列を扱います。
533 /// </summary>
534 public class TMOMat
535 {
536 /// Direct3D Matrix
537 public Matrix m;
538
539 /// <summary>
540 /// TMOMatを作成します。
541 /// </summary>
542 public TMOMat()
543 {
544 }
545
546 /// <summary>
547 /// 行列を読み込みます。
548 /// </summary>
549 public void Read(BinaryReader reader)
550 {
551 reader.ReadMatrix(ref this.m);
552 }
553
554 /// <summary>
555 /// 行列を書き出します。
556 /// </summary>
557 public void Write(BinaryWriter bw)
558 {
559 bw.Write(ref this.m);
560 }
561
562 /// <summary>
563 /// TMOMatを作成します。
564 /// </summary>
565 /// <param name="m">matrix</param>
566 public TMOMat(ref Matrix m)
567 {
568 this.m = m;
569 }
570
571 /// <summary>
572 /// 指定比率で拡大します。
573 /// </summary>
574 /// <param name="x">X軸拡大比率</param>
575 /// <param name="y">Y軸拡大比率</param>
576 /// <param name="z">Z軸拡大比率</param>
577 public void Scale(float x, float y, float z)
578 {
579 /*
580 m.M11 *= x;
581 m.M22 *= y;
582 m.M33 *= z;
583 */
584 m.Multiply(Matrix.Scaling(x, y, z));
585 m.M41 /= x;
586 m.M42 /= y;
587 m.M43 /= z;
588 }
589
590 /// <summary>
591 /// 指定行列で拡大します。
592 /// </summary>
593 /// <param name="scaling">scaling matrix</param>
594 public void Scale(Matrix scaling)
595 {
596 /*
597 m.M11 *= x;
598 m.M22 *= y;
599 m.M33 *= z;
600 */
601 m.Multiply(scaling);
602 m.M41 /= scaling.M11;
603 m.M42 /= scaling.M22;
604 m.M43 /= scaling.M33;
605 }
606
607 /// <summary>
608 /// 指定行列で縮小します。位置は変更しません。
609 /// </summary>
610 /// <param name="scaling">scaling matrix</param>
611 public void Scale0(Matrix scaling)
612 {
613 m.M11 /= scaling.M11;
614 m.M21 /= scaling.M11;
615 m.M31 /= scaling.M11;
616 m.M12 /= scaling.M22;
617 m.M22 /= scaling.M22;
618 m.M32 /= scaling.M22;
619 m.M13 /= scaling.M33;
620 m.M23 /= scaling.M33;
621 m.M33 /= scaling.M33;
622 }
623
624 /// <summary>
625 /// 指定行列で拡大します。位置は変更しません。
626 /// </summary>
627 /// <param name="scaling">scaling matrix</param>
628 public void Scale1(Matrix scaling)
629 {
630 m.M11 *= scaling.M11;
631 m.M12 *= scaling.M11;
632 m.M13 *= scaling.M11;
633 m.M21 *= scaling.M22;
634 m.M22 *= scaling.M22;
635 m.M23 *= scaling.M22;
636 m.M31 *= scaling.M33;
637 m.M32 *= scaling.M33;
638 m.M33 *= scaling.M33;
639 }
640
641 /// <summary>
642 /// 指定角度でX軸回転します。
643 /// </summary>
644 /// <param name="angle">角度(ラジアン)</param>
645 public void RotateX(float angle)
646 {
647 if (angle == 0.0f)
648 return;
649
650 Vector3 v = new Vector3(m.M11, m.M12, m.M13);
651 m *= Matrix.RotationAxis(v, angle);
652 }
653
654 /// <summary>
655 /// 指定角度でY軸回転します。
656 /// </summary>
657 /// <param name="angle">角度(ラジアン)</param>
658 public void RotateY(float angle)
659 {
660 if (angle == 0.0f)
661 return;
662
663 Vector3 v = new Vector3(m.M21, m.M22, m.M23);
664 m *= Matrix.RotationAxis(v, angle);
665 }
666
667 /// <summary>
668 /// 指定角度でZ軸回転します。
669 /// </summary>
670 /// <param name="angle">角度(ラジアン)</param>
671 public void RotateZ(float angle)
672 {
673 if (angle == 0.0f)
674 return;
675
676 Vector3 v = new Vector3(m.M31, m.M32, m.M33);
677 m *= Matrix.RotationAxis(v, angle);
678 }
679
680 /// <summary>
681 /// 指定変位だけ移動します。
682 /// </summary>
683 /// <param name="translation">変位</param>
684 public void Move(Vector3 translation)
685 {
686 m.M41 += translation.X;
687 m.M42 += translation.Y;
688 m.M43 += translation.Z;
689 }
690
691 /// <summary>
692 /// 補間を行います。
693 /// </summary>
694 /// <param name="mat0">行列0</param>
695 /// <param name="mat1">行列1</param>
696 /// <param name="mat2">行列2</param>
697 /// <param name="mat3">行列3</param>
698 /// <param name="length">分割数</param>
699 /// <returns>分割数だけTMOMatを持つ配列</returns>
700 public static TMOMat[] Slerp(TMOMat mat0, TMOMat mat1, TMOMat mat2, TMOMat mat3, int length)
701 {
702 return Slerp(mat0, mat1, mat2, mat3, length, 0.5f);
703 }
704
705 /// <summary>
706 /// 補間を行います。
707 /// </summary>
708 /// <param name="mat0">行列0</param>
709 /// <param name="mat1">行列1</param>
710 /// <param name="mat2">行列2</param>
711 /// <param name="mat3">行列3</param>
712 /// <param name="length">分割数</param>
713 /// <param name="p1">補間速度係数</param>
714 /// <returns>分割数だけTMOMatを持つ配列</returns>
715 public static TMOMat[] Slerp(TMOMat mat0, TMOMat mat1, TMOMat mat2, TMOMat mat3, int length, float p1)
716 {
717 TMOMat[] ret = new TMOMat[length];
718
719 Matrix m1 = mat1.m;
720 Matrix m2 = mat2.m;
721
722 Vector3 scaling1;
723 Vector3 scaling2;
724 Vector3 v1 = Helper.DecomposeMatrix(ref m1, out scaling1);
725 Vector3 v2 = Helper.DecomposeMatrix(ref m2, out scaling2);
726
727 Quaternion q1 = Quaternion.RotationMatrix(m1);
728 Quaternion q2 = Quaternion.RotationMatrix(m2);
729
730 Vector3 v0 = new Vector3(mat0.m.M41, mat0.m.M42, mat0.m.M43);
731 //Vector3 v1 = new Vector3(mat1.m.M41, mat1.m.M42, mat1.m.M43);
732 //Vector3 v2 = new Vector3(mat2.m.M41, mat2.m.M42, mat2.m.M43);
733 Vector3 v3 = new Vector3(mat3.m.M41, mat3.m.M42, mat3.m.M43);
734
735 float p0 = 0.0f;
736 float p2 = 1.0f;
737 float dt = 1.0f / length;
738 for (int i = 0; i < length; i++)
739 {
740 float t = dt * i;
741 float p = t * t * (p2 - 2 * p1 + p0) + t * (2 * p1 - 2 * p0) + p0;
742 Matrix m = Matrix.Scaling(Vector3.Lerp(scaling1, scaling2, p)) * Matrix.RotationQuaternion(Quaternion.Slerp(q1, q2, p)) * Matrix.Translation(Vector3.CatmullRom(v0, v1, v2, v3, p));
743 ret[i] = new TMOMat(ref m);
744 }
745 return ret;
746 }
747
748 /// <summary>
749 /// 加減算を行います。
750 /// </summary>
751 /// <param name="mat0">行列0</param>
752 /// <param name="mat1">行列1</param>
753 /// <param name="mat2">行列2</param>
754 /// <returns>行列1 - 行列2 + 行列0</returns>
755 public static TMOMat AddSub(TMOMat mat0, TMOMat mat1, TMOMat mat2)
756 {
757 Matrix m0 = mat0.m;
758 Matrix m1 = mat1.m;
759 Matrix m2 = mat2.m;
760 Vector3 t0 = Helper.DecomposeMatrix(ref m0);
761 Vector3 t1 = Helper.DecomposeMatrix(ref m1);
762 Vector3 t2 = Helper.DecomposeMatrix(ref m2);
763 Matrix m = m1 * Matrix.Invert(m2) * m0 * Matrix.Translation(t1 - t2 + t0);
764 return new TMOMat(ref m);
765 }
766
767 /// 左右反転します。
768 public void Flip()
769 {
770 Helper.FlipMatrix(ref m);
771 }
772
773 /// 180度Y軸回転します。
774 public void Turn()
775 {
776 Helper.TurnMatrix(ref m);
777 }
778 }
779
780 /// <summary>
781 /// フレームを扱います。
782 /// </summary>
783 public class TMOFrame
784 {
785 int id;
786
787 /// <summary>
788 /// 行列の配列
789 /// </summary>
790 public TMOMat[] matrices;
791
792 /// <summary>
793 /// Id
794 /// </summary>
795 public int Id { get { return id; } }
796
797 /// <summary>
798 /// フレームを生成します。
799 /// </summary>
800 public TMOFrame(int id)
801 {
802 this.id = id;
803 }
804
805 /// <summary>
806 /// フレームを読み込みます。
807 /// </summary>
808 public void Read(BinaryReader reader)
809 {
810 int matrix_count = reader.ReadInt32();
811 this.matrices = new TMOMat[matrix_count];
812 for (int i = 0; i < matrix_count; i++)
813 {
814 this.matrices[i] = new TMOMat();
815 this.matrices[i].Read(reader);
816 }
817 }
818
819 /// <summary>
820 /// フレームを書き出します。
821 /// </summary>
822 public void Write(BinaryWriter bw)
823 {
824 bw.Write(matrices.Length);
825 foreach (TMOMat mat in matrices)
826 mat.Write(bw);
827 }
828
829 /// <summary>
830 /// フレームを補間します。
831 /// </summary>
832 /// <param name="frame0">フレーム0</param>
833 /// <param name="frame1">フレーム1</param>
834 /// <param name="frame2">フレーム2</param>
835 /// <param name="frame3">フレーム3</param>
836 /// <param name="length">分割数</param>
837 /// <param name="p1">補間速度係数</param>
838 /// <param name="id_pair">node idのペア</param>
839 /// <returns></returns>
840 public static TMOFrame[] Slerp(TMOFrame frame0, TMOFrame frame1, TMOFrame frame2, TMOFrame frame3, int length, float p1, int[] id_pair)
841 {
842 TMOFrame[] frames = new TMOFrame[length];
843
844 for (int frame_index = 0; frame_index < length; frame_index++)
845 {
846 frames[frame_index] = new TMOFrame(frame_index);
847 frames[frame_index].matrices = new TMOMat[frame1.matrices.Length];
848 }
849
850 for (int i = 0; i < frame1.matrices.Length; i++)
851 {
852 TMOMat[] interpolated_matrices = TMOMat.Slerp(
853 frame0.matrices[i],
854 frame1.matrices[i],
855 frame2.matrices[id_pair[i]],
856 frame3.matrices[id_pair[i]],
857 length,
858 p1);
859
860 for (int frame_index = 0; frame_index < length; frame_index++)
861 frames[frame_index].matrices[i] = interpolated_matrices[frame_index];
862 }
863 return frames;
864 }
865
866 /// <summary>
867 /// frame1の行列で構成された新たなframeを得ます。
868 /// 新たなframeはframe0と同じnode並びとなります。
869 /// </summary>
870 /// <param name="frame0"></param>
871 /// <param name="frame1"></param>
872 /// <param name="id_pair">node idのペア</param>
873 /// <returns>新たなframe</returns>
874 public static TMOFrame Select(TMOFrame frame0, TMOFrame frame1, int[] id_pair)
875 {
876 TMOFrame ret = new TMOFrame(0);
877 ret.matrices = new TMOMat[frame0.matrices.Length];
878 for (int i = 0; i < frame0.matrices.Length; i++)
879 {
880 ret.matrices[i] = frame1.matrices[id_pair[i]];
881 }
882 return ret;
883 }
884
885 /// <summary>
886 /// 加減算の結果として新たなframeを得ます。
887 /// 新たなframeはframe0と同じnode並びとなります。
888 /// </summary>
889 /// <param name="frame0">frame0</param>
890 /// <param name="frame1">frame1</param>
891 /// <param name="frame2">frame2</param>
892 /// <param name="id_pair">node idのペア</param>
893 /// <returns>新たなframe</returns>
894 public static TMOFrame AddSub(TMOFrame frame0, TMOFrame frame1, TMOFrame frame2, int[] id_pair)
895 {
896 TMOFrame ret = new TMOFrame(0);
897 ret.matrices = new TMOMat[frame0.matrices.Length];
898 for (int i = 0; i < frame0.matrices.Length; i++)
899 {
900 ret.matrices[i] = TMOMat.AddSub(frame0.matrices[i], frame1.matrices[id_pair[i]], frame2.matrices[id_pair[i]]);
901 }
902 return ret;
903 }
904 }
905
906 /// <summary>
907 /// boneを扱います。
908 /// </summary>
909 public class TMONode
910 {
911 private int id;
912 private string path;
913 private string name;
914
915 private Vector3 scaling;
916 private Quaternion rotation;
917 private Vector3 translation;
918
919 private Matrix transformation_matrix;
920 private bool need_update_transformation;
921
922 /// <summary>
923 /// TMONodeを生成します。
924 /// </summary>
925 public TMONode(int id)
926 {
927 this.id = id;
928 }
929
930 /// <summary>
931 /// TMONodeを読み込みます。
932 /// </summary>
933 public void Read(BinaryReader reader)
934 {
935 this.Path = reader.ReadCString();
936 }
937
938 /// <summary>
939 /// TMONodeを書き出します。
940 /// </summary>
941 public void Write(BinaryWriter bw)
942 {
943 bw.WriteCString(this.Path);
944 }
945
946 /// <summary>
947 /// 行列をリンクします。
948 /// </summary>
949 public void LinkMatrices(TMOFrame[] frames)
950 {
951 this.matrices.Clear();
952 foreach (TMOFrame frame in frames)
953 this.matrices.Add(frame.matrices[id]);
954 }
955
956 /// <summary>
957 /// 拡大変位
958 /// </summary>
959 public Vector3 Scaling
960 {
961 get { return scaling; }
962 set
963 {
964 scaling = value;
965 need_update_transformation = true;
966 }
967 }
968
969 /// <summary>
970 /// 回転変位
971 /// </summary>
972 public Quaternion Rotation
973 {
974 get { return rotation; }
975 set
976 {
977 rotation = value;
978 need_update_transformation = true;
979 }
980 }
981
982 /// <summary>
983 /// 位置変位
984 /// </summary>
985 public Vector3 Translation
986 {
987 get { return translation; }
988 set
989 {
990 translation = value;
991 need_update_transformation = true;
992 }
993 }
994
995 /// <summary>
996 /// 子nodeリスト
997 /// </summary>
998 public List<TMONode> children = new List<TMONode>();
999
1000 /// <summary>
1001 /// 親node
1002 /// </summary>
1003 public TMONode parent;
1004
1005 /// <summary>
1006 /// 行列リスト
1007 /// </summary>
1008 public List<TMOMat> matrices = new List<TMOMat>();
1009
1010 /// <summary>
1011 /// ワールド座標系での位置と向きを表します。これはviewerから更新されます。
1012 /// </summary>
1013 public Matrix combined_matrix;
1014
1015 /// <summary>
1016 /// Id
1017 /// </summary>
1018 public int Id { get { return id; } }
1019 /// <summary>
1020 /// 名称
1021 /// </summary>
1022 public string Path
1023 {
1024 get { return path; }
1025 set
1026 {
1027 path = value;
1028 name = path.Substring(path.LastIndexOf('|') + 1);
1029 }
1030 }
1031 /// <summary>
1032 /// 名称の短い形式。これはTMOFile中で重複する可能性があります。
1033 /// </summary>
1034 public string Name { get { return name; } }
1035
1036 /// <summary>
1037 /// 指定名称(短い形式)を持つ子nodeを検索します。
1038 /// </summary>
1039 /// <param name="name">名称(短い形式)</param>
1040 /// <returns></returns>
1041 public TMONode FindChildByName(string name)
1042 {
1043 foreach (TMONode child_node in children)
1044 if (child_node.name == name)
1045 return child_node;
1046 return null;
1047 }
1048
1049 /// <summary>
1050 /// 指定nodeから行列を複写します。
1051 /// </summary>
1052 /// <param name="motion">node</param>
1053 public void CopyThisMatFrom(TMONode motion)
1054 {
1055 //Console.WriteLine("copy mat {0} {1}", name, motion.Name);
1056 int i = 0;
1057 foreach (TMOMat mat in matrices)
1058 {
1059 mat.m = motion.matrices[i % motion.matrices.Count].m;
1060 i++;
1061 }
1062 }
1063
1064 void CopyChildrenMatFrom_0(TMONode motion, List<string> except_names)
1065 {
1066 List<TMONode> select_children = new List<TMONode>();
1067 foreach (TMONode child_node in children)
1068 {
1069 bool found = false;
1070 foreach (string except_name in except_names)
1071 {
1072 if (child_node.name == except_name)
1073 {
1074 found = true;
1075 break;
1076 }
1077 }
1078 if (found)
1079 except_names.Remove(child_node.name);
1080 else
1081 select_children.Add(child_node);
1082 }
1083 foreach (TMONode child_node in select_children)
1084 {
1085 TMONode motion_child = motion.FindChildByName(child_node.name);
1086 child_node.CopyThisMatFrom(motion_child);
1087 child_node.CopyChildrenMatFrom_0(motion_child, except_names);
1088 }
1089 }
1090
1091 /// <summary>
1092 /// 指定nodeから行列を複写します。
1093 /// ただし複写の対象は子node以降です。指定nodeは複写しません。
1094 /// また、除外node以降のnodeは複写しません。
1095 /// </summary>
1096 /// <param name="motion">node</param>
1097 /// <param name="except_names">除外node名称(短い形式)リスト</param>
1098 public void CopyChildrenMatFrom(TMONode motion, List<string> except_names)
1099 {
1100 List<string> dup_except_names = new List<string>();
1101 foreach (string except_name in except_names)
1102 {
1103 dup_except_names.Add(except_name);
1104 }
1105 CopyChildrenMatFrom_0(motion, dup_except_names);
1106 }
1107
1108 /// <summary>
1109 /// 指定nodeから行列を複写します。
1110 /// </summary>
1111 /// <param name="motion">node</param>
1112 public void CopyMatFrom(TMONode motion)
1113 {
1114 CopyThisMatFrom(motion);
1115 foreach (TMONode child_node in children)
1116 {
1117 child_node.CopyMatFrom(motion.FindChildByName(child_node.name));
1118 }
1119 }
1120
1121 /// <summary>
1122 /// 指定変位だけ拡大します。
1123 /// </summary>
1124 /// <param name="x">X軸変位</param>
1125 /// <param name="y">Y軸変位</param>
1126 /// <param name="z">Z軸変位</param>
1127 public void Scale(float x, float y, float z)
1128 {
1129 Matrix scaling = Matrix.Scaling(x, y, z);
1130
1131 foreach (TMOMat i in matrices)
1132 i.Scale(scaling);
1133 }
1134
1135 /// <summary>
1136 /// 指定変位だけ縮小します。
1137 /// </summary>
1138 /// <param name="x">X軸変位</param>
1139 /// <param name="y">Y軸変位</param>
1140 /// <param name="z">Z軸変位</param>
1141 public void Scale0(float x, float y, float z)
1142 {
1143 Matrix scaling = Matrix.Scaling(x, y, z);
1144
1145 foreach (TMOMat i in matrices)
1146 i.Scale0(scaling);
1147 }
1148
1149 /// <summary>
1150 /// 指定変位だけ拡大します。さらに各子nodeを縮小します。
1151 /// </summary>
1152 /// <param name="x">X軸変位</param>
1153 /// <param name="y">Y軸変位</param>
1154 /// <param name="z">Z軸変位</param>
1155 public void Scale1(float x, float y, float z)
1156 {
1157 Matrix scaling = Matrix.Scaling(x, y, z);
1158
1159 foreach (TMOMat i in matrices)
1160 i.Scale1(scaling);
1161
1162 foreach (TMONode child_node in children)
1163 child_node.Scale0(x, y, z);
1164 }
1165
1166 /// <summary>
1167 /// 指定角度でX軸回転します。
1168 /// </summary>
1169 /// <param name="angle">角度(ラジアン)</param>
1170 public void RotateX(float angle)
1171 {
1172 foreach (TMOMat i in matrices)
1173 i.RotateX(angle);
1174 }
1175
1176 /// <summary>
1177 /// 指定角度でY軸回転します。
1178 /// </summary>
1179 /// <param name="angle">角度(ラジアン)</param>
1180 public void RotateY(float angle)
1181 {
1182 foreach (TMOMat i in matrices)
1183 i.RotateY(angle);
1184 }
1185
1186 /// <summary>
1187 /// 指定角度でZ軸回転します。
1188 /// </summary>
1189 /// <param name="angle">角度(ラジアン)</param>
1190 public void RotateZ(float angle)
1191 {
1192 foreach (TMOMat i in matrices)
1193 i.RotateZ(angle);
1194 }
1195
1196 /// <summary>
1197 /// 指定変位だけ移動します。
1198 /// </summary>
1199 /// <param name="x">X軸変位</param>
1200 /// <param name="y">Y軸変位</param>
1201 /// <param name="z">Z軸変位</param>
1202 public void Move(float x, float y, float z)
1203 {
1204 Vector3 translation = new Vector3(x, y, z);
1205
1206 foreach (TMOMat i in matrices)
1207 i.Move(translation);
1208 }
1209
1210 /// <summary>
1211 /// ワールド座標系での位置を得ます。
1212 /// </summary>
1213 /// <returns></returns>
1214 public Vector3 GetWorldPosition()
1215 {
1216 TMONode node = this;
1217 Vector3 v = Vector3.Empty;
1218 while (node != null)
1219 {
1220 v = Vector3.TransformCoordinate(v, node.TransformationMatrix);
1221 node = node.parent;
1222 }
1223 return v;
1224 }
1225
1226 /// <summary>
1227 /// ワールド座標系での位置と向きを得ます。
1228 /// </summary>
1229 /// <returns></returns>
1230 public Matrix GetWorldCoordinate()
1231 {
1232 TMONode node = this;
1233 Matrix m = Matrix.Identity;
1234 while (node != null)
1235 {
1236 m.Multiply(node.TransformationMatrix);
1237 node = node.parent;
1238 }
1239 return m;
1240 }
1241
1242 /// <summary>
1243 /// 拡大行列
1244 /// </summary>
1245 public Matrix ScalingMatrix
1246 {
1247 get
1248 {
1249 return Matrix.Scaling(scaling);
1250 }
1251 }
1252
1253 /// <summary>
1254 /// 回転行列
1255 /// </summary>
1256 public Matrix RotationMatrix
1257 {
1258 get
1259 {
1260 return Matrix.RotationQuaternion(rotation);
1261 }
1262 }
1263
1264 /// <summary>
1265 /// 位置行列
1266 /// </summary>
1267 public Matrix TranslationMatrix
1268 {
1269 get
1270 {
1271 return Matrix.Translation(translation);
1272 }
1273 }
1274
1275 static Vector3 Reciprocal(Vector3 v)
1276 {
1277 return new Vector3(1 / v.X, 1 / v.Y, 1 / v.Z);
1278 }
1279
1280 static void ScalingLocal(ref Matrix m, Vector3 scaling)
1281 {
1282 m.M11 *= scaling.X;
1283 m.M21 *= scaling.X;
1284 m.M31 *= scaling.X;
1285 m.M41 *= scaling.X;
1286
1287 m.M12 *= scaling.Y;
1288 m.M22 *= scaling.Y;
1289 m.M32 *= scaling.Y;
1290 m.M42 *= scaling.Y;
1291
1292 m.M13 *= scaling.Z;
1293 m.M23 *= scaling.Z;
1294 m.M33 *= scaling.Z;
1295 m.M43 *= scaling.Z;
1296 }
1297
1298 /// <summary>
1299 /// 変形行列。これは 拡大行列 x 回転行列 x 位置行列 です。
1300 /// </summary>
1301 public Matrix TransformationMatrix
1302 {
1303 get
1304 {
1305 if (need_update_transformation)
1306 {
1307 Matrix m = ScalingMatrix * RotationMatrix;
1308 m.M41 = translation.X;
1309 m.M42 = translation.Y;
1310 m.M43 = translation.Z;
1311 if (parent != null)
1312 ScalingLocal(ref m, Reciprocal(parent.Scaling));
1313 transformation_matrix = m;
1314 need_update_transformation = false;
1315 }
1316 return transformation_matrix;
1317 }
1318 set
1319 {
1320 transformation_matrix = value;
1321 Matrix m = value;
1322 if (parent != null)
1323 ScalingLocal(ref m, parent.Scaling);
1324 translation = Helper.DecomposeMatrix(ref m, out scaling);
1325 rotation = Quaternion.RotationMatrix(m);
1326 }
1327 }
1328 }
1329 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26