More servicesWindows Live
HomeHotmailSpacesOneCare
 
MSN
Sign in
 
 
Spaces home  宇宙仮面の C# 研究室.Live SpacePhotosProfileFriendsMore Tools Explore the Spaces community

宇宙仮面の C# 研究室.Live Space

C#, Windows Mobile, X-Box360などに関連したブログです。
May 20

第28回codeseek勉強会

勉強会のお知らせです。
http://www.codeseek.net/event/index.html
 
----------------------------
第28回codeseek勉強会
「Windows Server 2008、Visual Studio 2008、SQL Server 2008コミュニティラウンチ」
(共催:tk-engineeringこみゅぷらすeパウダ~.Net/C# Group)
2008年5月27日(火) 19:00~21:00

場所:渋谷駅からすぐの貸し会議室 (ご登録後お知らせいたします)

募集締め切り:2008年5月25(日)23時59分59秒
24名まで
無料

第28回codeseek勉強会は、
Windows Server 2008、Visual Studio 2008、SQL Server 2008の発売に合わせた、
コミュニティラウンチとして開催します。
スピーカーは、宇宙仮面様、めさいあ様、ひろりん様、こた様の予定です。
内容については調整中です。

参加をご希望の方は以下の事項を記入しメールにてご登録ください。

送付先:codeseektatsugoro(アットマーク)yahoo.co.jp

メールタイトル:codeseek勉強会参加希望
名前(必須):
メールアドレス(必須):
住所(必須):
ハンドル:
連絡用電話番号:
懇親会に参加する:はい/いいえ/未定

いただいた情報はcodeseekの活動自身のためにしか使いません。
いただいた情報を会場にお知らせすることがあります。
登録なしでの参加はできません。

May 06

WPF Morphing してみる

眼を開いた状態と目を閉じた状態の MeshGeometry3Dを、スライダーで線形合成してみた

左から右へ、眼を開いた状態、目を閉じた状態、合成したもの

 

眼をあいている状態では、目の周りにアイシャドウを引いていたりして、合成した時に汚くなることがある。結構細かいところに気をつける必要あり。

それから、六角大王で dxf ファイルにエクスポートした際に、頂点数が変わってしまう。このため、単純にマッピングできず、TriangleIndices でマッピングを取っている。このため、処理的にはかなり重い。動かない場所は処理しないなどの高速化が必要かもしれない。

それから、六角大王から通常状態と目を閉じた状態でエクスポートした場合、わずかに座標がずれている。このため、単純に動かない場所は処理しないという処理ができない。結構厄介だ・・・・・

namespace Morphing_V1
{
    public partial class Window1 : System.Windows.Window
    {

・・・
        GeometryModel3D gm1 = null;
        MeshGeometry3D mg10 = null;
        Point3DCollection p3dcol10 = null;

・・・

        private void slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            double v = this.slider1.Value / 10d;
            for (int c = 0; c < this.NormalOR32.Children.Count; c++)
            {
                gm1 = (GeometryModel3D)(this.NormalOR32.Children[c]);
                mg10 = (MeshGeometry3D)(gm1.Geometry);
                p3dcol10 = mg10.Positions;

                gm2 = (GeometryModel3D)(this.CloseEyesOR40.Children[c]);
                mg20 = (MeshGeometry3D)(gm2.Geometry);
                p3dcol20 = mg20.Positions;

                gmRes = (GeometryModel3D)(this.ResOR50.Children[c]);
                mRes = (MeshGeometry3D)(gmRes.Geometry);
                poRes = mRes.Positions;

                Point3DCollection resPoCol = poRes;

                for (int j = 0; j < mg10.TriangleIndices.Count; j++)
                {
                    int inorm = mg10.TriangleIndices[j];
                    int ia = mg20.TriangleIndices[j];
                    resPoCol[ia] = new Point3D(
                        p3dcol10[inorm].X * v + p3dcol20[ia].X * (1.0 - v),
                        p3dcol10[inorm].Y * v + p3dcol20[ia].Y * (1.0 - v),
                        p3dcol10[inorm].Z * v + p3dcol20[ia].Z * (1.0 - v));
                }
                mRes.Positions = resPoCol;

            }
        }
    }
}

頂点座標を直接変更する

スライダーで、MeshGeometry3Dの BOX の頂点座標 Positions を直接変更してみる。このぐらいの頂点数なら問題なくスムーズに変形できるが・・・・・

image

image

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace Morphing_V2
{
    public partial class Window1 : System.Windows.Window
    {
        private void slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            double v = slider1.Value / 10f;

            GeometryModel3D gm3d = (GeometryModel3D)this.BoxOR9.Children[0];
            MeshGeometry3D mesh3d = (MeshGeometry3D)gm3d.Geometry;

            for (int i = 0; i < mesh3d.Positions.Count; i++)
            {
                mesh3d.Positions[i] = new Point3D(
                   originalMeshGeometry3DPosition[i].X * v,
                   originalMeshGeometry3DPosition[i].Y * v,
                   originalMeshGeometry3DPosition[i].Z * v);
            }
        }

        Point3DCollection originalMeshGeometry3DPosition = null;

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            GeometryModel3D gm3d = (GeometryModel3D)this.BoxOR9.Children[0];
            MeshGeometry3D mesh3d = (MeshGeometry3D)gm3d.Geometry;

            originalMeshGeometry3DPosition = new Point3DCollection();
            for (int i = 0; i < mesh3d.Positions.Count; i++)
                originalMeshGeometry3DPosition.Add(mesh3d.Positions[i]);
        }
    }
}

<Window x:Class="Morphing_V2.Window1" Title="Morphing_V2" Width="497" Height="450" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/interactivedesigner/2006" xmlns:c="http://schemas.openxmlformats.org/markup-compatibility/2006" c:Ignorable="d" Loaded="Window_Loaded">
    <Grid>
        <Viewport3D x:Name="ZAM3DViewport3D" ClipToBounds="true" Width="400" Height="300">
            <Viewport3D.Resources>
                <ResourceDictionary>
                    <MaterialGroup x:Key="ER___Default_MaterialMR1" >
                        <DiffuseMaterial>
                            <DiffuseMaterial.Brush>
                                <SolidColorBrush Color="#D3C8AD" Opacity="1.000000"/>
                            </DiffuseMaterial.Brush>
                        </DiffuseMaterial>
                        <SpecularMaterial SpecularPower="93.8667">
                            <SpecularMaterial.Brush>
                                <SolidColorBrush Color="#333333" Opacity="1.000000"/>
                            </SpecularMaterial.Brush>
                        </SpecularMaterial>
                    </MaterialGroup>
                    <Transform3DGroup x:Key="SceneTR7" >
                        <TranslateTransform3D OffsetX="0" OffsetY="0" OffsetZ="0"/>
                        <ScaleTransform3D ScaleX="1" ScaleY="1" ScaleZ="1"/>
                        <RotateTransform3D>
                            <RotateTransform3D.Rotation>
                                <AxisAngleRotation3D Angle="0" Axis="0 1 0"/>
                            </RotateTransform3D.Rotation>
                        </RotateTransform3D>
                        <TranslateTransform3D OffsetX="0" OffsetY="0" OffsetZ="0"/>
                    </Transform3DGroup>
                    <Transform3DGroup x:Key="BoxOR9TR8" >
                        <TranslateTransform3D OffsetX="0" OffsetY="0" OffsetZ="0"/>
                        <ScaleTransform3D ScaleX="1" ScaleY="1" ScaleZ="1"/>
                        <RotateTransform3D>
                            <RotateTransform3D.Rotation>
                                <AxisAngleRotation3D Angle="47.33348273" Axis="0.5325566653 -0.8245461129 -0.1910683281"/>
                            </RotateTransform3D.Rotation>
                        </RotateTransform3D>
                        <TranslateTransform3D OffsetX="0" OffsetY="0" OffsetZ="0"/>
                    </Transform3DGroup>
                    <MeshGeometry3D x:Key="BoxOR9GR10"
                        TriangleIndices="0,1,2 2,3,0 4,5,6 6,7,4 8,9,10 10,11,8 12,13,14 14,15,12 16,17,18 18,19,16 20,21,22 22,23,20 "
                        Normals="0,0,-1 0,0,-1 0,0,-1 0,0,-1 0,0,1 0,0,1 0,0,1 0,0,1 0,-1,0 0,-1,0 0,-1,0 0,-1,0 1,0,0 1,0,0 1,0,0 1,0,0 0,1,0 0,1,0 0,1,0 0,1,0 -1,0,0 -1,0,0 -1,0,0 -1,0,0 "
                        Positions="-0.5,-0.5,-0.5 -0.5,0.5,-0.5 0.5,0.5,-0.5 0.5,-0.5,-0.5 -0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,-0.5 0.5,-0.5,-0.5 0.5,-0.5,0.5 -0.5,-0.5,0.5 0.5,-0.5,-0.5 0.5,0.5,-0.5 0.5,0.5,0.5 0.5,-0.5,0.5 0.5,0.5,-0.5 -0.5,0.5,-0.5 -0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,-0.5 -0.5,-0.5,-0.5 -0.5,-0.5,0.5 -0.5,0.5,0.5 "
                    />
                </ResourceDictionary>
            </Viewport3D.Resources>

            <Viewport3D.Camera>
                <PerspectiveCamera x:Name="FrontOR6" FarPlaneDistance="10" LookDirection="0,0,-1" UpDirection="0,1,0" NearPlaneDistance="1" Position="0,0,2.38423" FieldOfView="39.5978" />
            </Viewport3D.Camera>

            <ModelVisual3D>
                <ModelVisual3D.Content>
                    <Model3DGroup x:Name="Scene" Transform="{DynamicResource SceneTR7}"> <!-- Scene (XAML Path = ) -->
                        <AmbientLight Color="#333333" />
                        <DirectionalLight Color="#FFFFFF" Direction="-0.612372,-0.5,-0.612372" />
                        <DirectionalLight Color="#FFFFFF" Direction="0.612372,-0.5,-0.612372" />
                        <Model3DGroup x:Name="BoxOR9" Transform="{DynamicResource BoxOR9TR8}"> <!-- Box (XAML Path = (Viewport3D.Children)[0].(ModelVisual3D.Content).(Model3DGroup.Children)[3]) -->
                            <GeometryModel3D x:Name="BoxOR9GR10" Geometry="{DynamicResource BoxOR9GR10}" Material="{DynamicResource ER___Default_MaterialMR1}" BackMaterial="{DynamicResource ER___Default_MaterialMR1}"/>
                        </Model3DGroup>
                    </Model3DGroup>
                </ModelVisual3D.Content>
            </ModelVisual3D>
        </Viewport3D>
        <Slider Height="31" HorizontalAlignment="Left" Margin="37.5,0,0,8" Name="slider1" VerticalAlignment="Bottom" Width="100" ValueChanged="slider1_ValueChanged" />
    </Grid>
</Window>

May 02

第27回 Codeseek勉強会 プレゼン・デモ資料

2008年4月30日(水) 第27回 Codeseek勉強会で、「宇宙仮面のZAM3D で簡単3D XAML プログラミング」というタイトルで、僭越ながら講師をやらせていただきました。
ここでは、その資料、デモサンプルなどをアップします。

AGENDA
  1. 自己紹介
  2. WPF と XAML の概要
  3. Expression Blend
  4. ZAM3D とは
  5. ZAM3D と Visual Studio の連携
  6. XAML の基礎 Viewport3D
  7. アニメーションと Storyboard
  8. WPF の 3D 能力
  9. 3Dデータのインポート
  10. 回してみよう
  11. ベクトルの外積とクオータニオン
  12. 触ってみよう Hit Test
  13. おまけ 初音ミクは電気羊の夢を見るか
説明に使用した PowerPoint はこちらからどおぞ。

デモパッケージ
デモに使用したパッケージはこちらからどおぞ。
巨大(78MB)なので、ご注意ください。
また、グラフィックスアクセラレータがないと、厳しいです。
使用したなソフトウェア
  • ZAM 3D 1.0
  • Visual Studio 2008
  • 六角大王 Super 5.5
注意
このデモで使用している 3D データは下記のものを使用しています。使用条件は下記 URL より確認してください。
HONDA CRX の 3D モデリングデータ
http://www.honda.co.jp/WebPlamo/
初音ミクの 3D モデリングデータ
http://kiomodel3.sblo.jp/
 
April 24

第27回codeseek勉強会:ZAM3D で簡単3D XAML プログラミング のお知らせ

第27回codeseek勉強会:ZAM3D で簡単3D XAML プログラミング のお知らせです。
--------- ここから -----------
第27回codeseek勉強会
「宇宙仮面のZAM3D で簡単3D XAML プログラミング」
(共催:tk-engineering、こみゅぷらす、eパウダ~)
2008年4月30日(水) 19:00~21:00

場所:渋谷駅東口からすぐの貸し会議室 (ご登録後お知らせいたします)

募集締め切り:2008年4月27(日)23時59分59秒
24名まで
無料


宇宙仮面のC#プログラミング(http://uchukamen.com/)を主催されている
宇宙仮面様にご登壇いただき、XAMLでの3Dプログラミングについて解説して
いただけることになりました。
この貴重な機会に、ぜひご参加ください。


ZAM3D で簡単3D XAML プログラミング
- ZAM3D の機能と使い方を紹介 20分
- ZAM3D, Expression Blend, Visual Studio の連携 20分
- 3Dデータのインポート 20分
- 3Dの回転について20分
- ZAM3D の問題点、その他注意点など 20分
- Q&Aなど 20分
 
--------- ここまで -----------
March 30

初音ミク XAML化計画~キーボード入力で口と目を動かす

口を動かすには、モーフィングをプログラムでやればできないことはないと思うけど、そこまでやる元気はない。とりあえず六角のデータで複数の顔の表情をインポートして、そのWPFの切り替える方法でどこまでいくか試してみた。

テスト実行用クリックワンス

http://uchukamen.com/WPF/MikuClickOnce/publish.htm

操作方法

  • 右クリックでドラッグ→回転
  • 左シフトを押しながら右クリックでドラッグ→移動
  • ホィール→拡大縮小
  • 左コントロールを押して右クリック→回転、位置のリセット
  • キー
    A...あ、I...い、U....う、E...え、O...お
    1...スマイル その1(にこっ)
    2...スマイル その2(笑)
    3...スマイル その3 (ウィンク)
  • 方向矢印で目の上下左右

image

実装的には、こんな感じで、いくつかの表情を遠くの空間に置いておく。表情のTransform を切り替えてあげるだけで、一瞬で顔を切り替えてしまう方法。ここで、 off は、遠くの空間、trans は顔の場所の Transform。
private void Grid_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
    if (e.Key == System.Windows.Input.Key.A)
    {
        faceNow.Transform = off;
        faceNow = faceA;
        faceA.Transform = trans;
    }
  ・・・以下、同様
}

やっていることは単純だけれど、とりあえず何らかの事象を受けて、表情などを変えることができる。モーフィングに比べればかなり硬いけれど、使えないことはない。

ということで、WPF をつかった新時代にふさわしいインターフェースの名前は・・・

  • Miku Interface
  • Moe Interface
  • Vocaloid Interface
  • Humanoid Interface

そうそう、これをつくりながら、Nexus 6 を作りたかったんだよな…と・・・

March 29

初音ミク XAML化計画~初音ミクは重い

もともとの V6 の XAML データだけでも、 8MB もあるので、Visual Studio 2008 が

image

と 悲鳴を上げている。

やっぱりここまでくると、しゃべらせないとね・・・ということで、顔をモーフィングしたデータをいくつかあわせてエクスポートしてみた。XAML データはさらに重くなって、19MB。Visual Studio 2008 が開くには開くが、Grid を追加したら、Visual Studio 2008 がハンドルされていない例外を発生しましたということで、種類 'System.OutOfMemoryException' の例外が発生して、アウト!

image

少しミクをダイエットさせなければ・・・・

呼び出しのターゲットが例外をスローしました。
   場所 System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   場所 System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   場所 System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   場所 System.Delegate.DynamicInvokeImpl(Object[] args)
   場所 System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
   場所 System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)

種類 'System.OutOfMemoryException' の例外がスローされました。
   場所 MS.Internal.Host.Isolation.Protocols.ITextReadCursor.Read(Int32 length)
   場所 MS.Internal.Host.Isolation.Adapters.ToTextReadCursor.Read(Int32 length)
   場所 MS.Internal.Host.MarkupSourceProvider.SourceReader.Read(Int64 location, Int32 length)
   場所 Microsoft.Windows.Design.SourceUpdate.TextRangeManager.TextRangeSourceReader.Read(Int64 location, Int32 length)
   場所 MS.Internal.Xaml.Parser.ScannerProviderAdapter.Read(Int32 location, Int32 length)
   場所 MS.Internal.Xaml.Scanner.ReadSource(Int32 current)
   場所 MS.Internal.Xaml.Scanner.GetNextToken(Boolean stopAtEndOfLine)
   場所 MS.Internal.Xaml.Parser.ParseXmlDocument(Int32 elements)
   場所 MS.Internal.DocumentTrees.Markup.XamlSourceDocument.ParseElementFromSkeleton(XamlParseContext context, SkeletonNode node, XamlElement parent, Boolean fullElement)
   場所 MS.Internal.DocumentTrees.Markup.XamlSourceDocument.UpdateSkeleton(IDamageListener listener, Boolean force)
   場所 Microsoft.Windows.Design.Documents.Trees.MarkupDocumentTreeManager.Update()
   場所 Microsoft.Windows.Design.Documents.MarkupDocumentManager.Update()
   場所 Microsoft.Windows.Design.Documents.MarkupDocumentManager.AutoUpdater.DoUpdate()

March 24

初音ミク XAML化計画~ Trackball.cs を組み込んで、初音ミクをグリングリン回す

さて、クオータニオンの原理がわかったところで、Trackball.cs を組み込みます。

MSDN の Cube Animation Demo の trackball.cs は、

http://msdn2.microsoft.com/en-us/library/ms771572.aspx

にありますので、ダウンロードしておきます。必要なファイルは、trackball.cs です。このファイルは、これまで書いたように、回転に関して示唆に富むソースコードです。3D が初めての人は、ぜひ一読して、理解することをお勧めします。わずか200行程度なのですが、ベクトルの外積、クオータニオンを凝縮したコードです。また、簡単に組み込むことも意識して作られており、参考になります。

  1. ZAM 3D から Export する。
  2. trackball.cs をプロジェクトに追加する。
  3. Form をロードした際のイベント Window_Loaded を追加する。
  4. Windows1.xaml.cs に以下の trackball をコールするコードを追加する。
    -------- ここから --------
    Trackball _trackball;
    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        // setup trackball for moving the model around
        _trackball = new Trackball();
        _trackball.Attach(this);
        _trackball.Slaves.Add(this.ZAM3DViewport3D);
        _trackball.Enabled = true;
    }
  5. trackball.cs の private void UpdateSlaves(Quaternion q, double s, Vector3D t)  を修正
    オリジナルコードだと、ZAM3Dが生成するコードとTransform3Dの相性が悪く、クラッシュします。
    また、オリジナルの trackball.cs では、カメラではなく ModelVisual3D を動かすコードになっています。オブジェクトを動かすのでも問題ありませんが、カメラを動かしたほうがスマートです。そこで、このメソッドを次のようにカメラを動かすように修正します。

    private void UpdateSlaves(Quaternion q, double s, Vector3D t)
    {   
        ////// カメラバージョン
        if (_slaves != null)
        {
            foreach (Viewport3D i in _slaves)
            {
                Transform3D t3dg = i.Camera.Transform;

                ScaleTransform3D scaleTransform = new ScaleTransform3D();
                scaleTransform.ScaleX = s;
                scaleTransform.ScaleY = s;
                scaleTransform.ScaleZ = s;

                Rotation3D rotation = new AxisAngleRotation3D(q.Axis, q.Angle);
                TranslateTransform3D trtf = new TranslateTransform3D(-t.X * 10, -t.Y * 10, -t.Z * 10);
                Transform3DGroup tg = new Transform3DGroup();
                tg.Children.Add(scaleTransform);
                tg.Children.Add(new RotateTransform3D(rotation));
                tg.Children.Add(trtf);

                i.Camera.Transform = tg;
            }
        }
    }

  6. あと、trackball.cs のもともとのコードが、F1 や、Spaceキーを使っていますが、使いにくいので適当にキーを修正します。
  7. コンパイル&実行

これで、次のように ミクをグリングリン回すことができるようになります。

テスト用 ClickOnce

操作方法

  • 右クリックでドラッグ→回転
  • 左シフトを押しながら右クリックでドラッグ→移動
  • ホィール→拡大縮小
  • 左コントロールを押して右クリック→回転、位置のリセット

image 

注意: 原点を中心に回転するようになっていますので、ミクを原点に配置しないとうまく回転してくれません。

六角、ZAM3D、VS2008の パッケージ一式はこちら

注意: キオ式 初音ミクの XAML 化データに関しては、本家 キオ式アニキャラ3D の "当方の3Dデータ、動画の使用条件について" を参照してください。

注意: 今回使用したミクのデータは、V1.1-1.5 ぐらいで、少々古いです。また、ごみが混じっていたり、消し忘れの球が見えていたりしますが、ご愛嬌ということで w

March 23

初音ミク XAML化計画~初音ミクをグリングリンするには、ベクトルの外積とクオータニオン

http://www-sens.sys.es.osaka-u.ac.jp/users/kanaya/Documents/VCQ/kanaya-handai-quaternion.pdf

を勉強してみたところ、クオータニオンの積は、2つの回転を含むベクトルの合成であると書いてある。クオータニオン L, R, Res を適当に取り、Res = L * R を図解すると、下の図のように、クオータニオン L の軸に対して、クオータニオン Rののベクトルを、クオータニオン Lの回転角度だけ回転したものが クオータニオン Res となる。

image 

右項のクオータニオンの回転が0の場合は上の絵のように回転面に対して、右項Rを回転させるだけでわかりやすいが、右項のクオータニオンの回転が0ではない場合に、Rにさらに回転が加わったものに対して、左項のクオータニオンの回転が合成されるため、先の資料を読んでいても、よくわからない。

そこで、XAML でプログラムを作って、実際に動作を確かめてみた。Form 左のスライダーが、左項クオータニオンの X, Y, Z, W、右側のスライダーが 右項のクオータニオンの X, Y, Z, W。ピンクのベクトルが 左項のクオータニオン、黄色のベクトルが右項のクオータニオン、黒のベクトルが積のクオータニオン。スライダーで、左項、右項のクオータニオンを動かすと、結果としての積のクオータニオンを表示するWPFアプリケーション。

image

スライダーの値を読み取って、クオータニオンの積を計算し、表示する処理の一部抜粋。

private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    try
    {
        // 左項
        Vector3D leftAxis = new Vector3D(lx.Value, ly.Value, lz.Value);
        Quaternion leftQuaternion = new Quaternion(leftAxis, lrot.Value);
        QuaternionRotation3D qrot3d = new QuaternionRotation3D(leftQuaternion);
        RotateTransform3D leftRot3D = new RotateTransform3D(qrot3d);

        Transform3DGroup leftT3DG = (Transform3DGroup)(this.LeftOR23.Transform);
        leftT3DG.Children[2] = leftRot3D;
        this.LeftOR23.Transform = leftT3DG;

        this.textBlock1.Text = "Left:"
            + lx.Value.ToString("f2") + ":"
            + ly.Value.ToString("f2") + ":"
            + lz.Value.ToString("f2") + ":"
            + lrot.Value.ToString("f2");

        // 右項
        Vector3D rightAxis = new Vector3D(rx.Value, ry.Value, rz.Value);
        Quaternion rightQuaternion = new Quaternion(rightAxis, rrot.Value);
        QuaternionRotation3D rightQRot3D = new QuaternionRotation3D(rightQuaternion);
        RotateTransform3D rightRot3D = new RotateTransform3D(rightQRot3D);

        Transform3DGroup rightT3DG = (Transform3DGroup)(this.RightOR26.Transform);
        rightT3DG.Children[2] = rightRot3D;
        this.RightOR26.Transform = rightT3DG;

        this.textBlock1.Text += "\nRight:"
            + rx.Value.ToString("f2") + ":"
            + ry.Value.ToString("f2") + ":"
            + rz.Value.ToString("f2") + ":"
            + rrot.Value.ToString("f2");

        // クオータニオンの積
        Quaternion resultQuaternion = leftQuaternion * rightQuaternion;
        QuaternionRotation3D resultQR3D = new QuaternionRotation3D(resultQuaternion);
        RotateTransform3D resultRot3D = new RotateTransform3D(resultQR3D);

        Transform3DGroup resultTr = (Transform3DGroup)(this.ResultOR29.Transform);
        resultTr.Children[2] = resultRot3D;
        this.ResultOR29.Transform = resultTr;

        this.textBlock1.Text += "\nResult:"
            + resultQuaternion.X.ToString("f2") + ":"
            + resultQuaternion.Y.ToString("f2") + ":"
            + resultQuaternion.Z.ToString("f2") + ":"
            + resultQuaternion.W.ToString("f2");
    }
    catch
    {
    }
}

これで、スライダーを動かして確かめてみると・・・なるほど・・・こうなるのか・・・。

これを数式から読み取るのは不可能だな・・・・・

こんな3次元のモデルも XAML で簡単にできてしまうあたりに感動してしまった。

ということで、回転させたい対象のクオータニオンをR、回転させる軸と回転角度を表わすクオータニオンLとすると、回転後のクオータニオン RES = L*R でとても簡単に計算ができる。ここで求められた回転後のクオータニオンRESから、RotateTransform3D を回転させたい対象に適用してあげれば、回転してくれるということだ。

クオータニオンがなければ、マトリックス計算の地獄になるところだけれど、クオータニオンの積一発。おまけに、WPF は、このクオータニオンの積も提供してくれているので、とても処理が楽。素晴らしい。

March 19

初音ミク XAML化計画~クオータニオンって何?

カメラの移動方法を調べていたら、そのものずばりの MSDN キューブ アニメーションのデモ を発見。これを組み込めば簡単に視点の変更ができる。

おお、もうひとりのおやじもこれを組み込んだのね。さすがだ。

と思い、デモソフトの Trackball.cs のコードをながめてみたら・・・外積を使っている?と不思議に思い、ソースを読んでみた。

次の図のようにマウスで左から右へドラッグし、ミクを中心にカメラを右方向に動かす場合、Y軸を中心にカメラを右方向に回転させることになります。では、どのようにY軸を中心にと判断しているかというと、カメラの視線ベクトルとカメラの移動ベクトルの外積から回転軸を求めています。外積を使えば、マウスの移動角度に応じて、斜めに回転する回転軸も簡単に求めることができます。

image

なるほど・・・外積ってこういう利用方法があるだぁ・・・と感動。ちなみに下が外積を簡単に説明した図。なつかしい・・・

image

と、さらに ソースを読んでいったところ、回転軸が求まったところで、クオータニオンの計算があり、意味不明 orz。クオータニオン自体初めて耳にするが、3D-CG をする人たちには常識らしい。ところが、にわか ミク3D野郎には難しすぎる・・・

ということで、次の資料があったので、一から勉強中。

http://www-sens.sys.es.osaka-u.ac.jp/users/kanaya/Documents/VCQ/kanaya-handai-quaternion.pdf

まさか、この歳でエルミート行列、オイラー角、テンソル、などなどと、どこかで聞いたことのあることをもう一度ひっくり返すことになるとは・・・・。一通り読んでみたのだが、外積、内積なら、物理的な意味が直感的にわかるのだが、クオータニオン同士の積の物理的な意味が直感的にわからない。ミクをグリングリン回すのにも、修行が足りない orz。

ちなみにクオータニオン(超複素数 or 四元数)は、大学では習わなかった。当時、3Dグラフィックスはなかったので w。

March 17

初音ミク XAML化計画

六角大王スーパーには、モーフィングという機能が付いていて、次のようにいろいろなモーフィングを登録することができる。

image

なんとキオ式ミクには驚くほどのモーフィングが登録されており、たとえばウィンクや、笑うなどがボタン一発でできるようになっている。恐るべし・・・。

image

この WPFデータを作ることはできるので、うまく使えば・・・あんなことや・・・こんなことが・・・

初音ミク XAML化計画

いろいろ試してみたが、マテリアルの色がうまく乗らない。たとえば、髪飾りのピンクと目の色が同じマテリアルにマップされており、髪飾りをピンクにすると、白眼もピンクになってしまう。しょうがないので、六角上でさらに細かく分割しました。

あまり細かくすると、ZAM 3D へのインポートが大変になるので、顔(目、上の歯、下の歯、口の中)、ヘッドセットや、髪飾りは、各1つにグループ化しました。

image

ようやくこれで ZAM 3D上で色が重ならずに、着色ができた。

image

ということで、現在のデータ(六角、ZAM 3D、Visual Studio 2005) をまとめてアップしておきます。

http://uchukamen.com/WPF/MikuData/Miku%20Kio%20V5.zip

あとは、ZAM 3D でアニメーション機能があるので、下の図のように時間ごとにパーツを動かして、アニメーションを作成する。アニメーションが作成できたところで、Export to XAML で Visual Studio 20005 のプロジェクトに書き出す。このときに、アニメーションは、OnLoaded の ストーリーボードとして作成されます。したがって、このままVS 2005 でコンパイル&実行してあげると、そのまま踊りだします。

image

ZAM 3Dでは、左下にある球体でトラックボールのようにオブジェクトの方向を変更することができ、かなり簡単にアニメーションを作成することができます。ただし、ZAM 3D の制限として、1つのアニメーションしか作成できないので、ちょっと不便です。複数のアニメーションを設定できると楽なんですけど・・・

それから、ちょっとまえのデータですが、MikuMikuDance のスクリーンショットと実行ファイルをさらしておきますw。

image

なお、うしろのビデオは、WMV を WPF でリアルタイムに変形&再生するように、Expression Blend で追加したものです。WPFすげー。

それから、これはカメラのパン、ズーム、それから回転を行うデモ。

http://uchukamen.com/WPF/MikuData/KioVS.exe

image

image

image

コード的には、ズームはとても簡単。FieldOfView の値を変更してあげればよい。

private void sliderZoom_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    this.Target_CameraOR20.FieldOfView = this.slider.Value;
}

マウスホィールを使うのであれば、マイナスとか大きすぎる場合のリミッターを入れて、たとえば次のようにすればよい。

private void ZAM3DViewport3D_MouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
    this.Target_CameraOR63.FieldOfView += e.Delta / 100;
    if (this.Target_CameraOR63.FieldOfView < 10)
        this.Target_CameraOR63.FieldOfView = 10;
    else if (this.Target_CameraOR63.FieldOfView > 100)
        this.Target_CameraOR63.FieldOfView = 100;
}

カメラの方向を変更するのは、こんな感じ。

private void SliderH_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    Transform3DGroup tg = new Transform3DGroup();
    tg.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), this.SliderH.Value)));
    tg.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), this.SliderV.Value)));

    this.Target_CameraOR20.Transform = tg;
}
private void SliderV_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    Transform3DGroup tg = new Transform3DGroup();
    tg.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), this.SliderH.Value)));
    tg.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), this.SliderV.Value)));

    this.Target_CameraOR20.Transform = tg;
}

もう少しスマートにするには、ZAM 3D のトラックボールのようなインターフェースがよいでしょう。これはもう一人のオヤジから展開されると思いますw

March 14

Silverlight for mobile

 

ちょっと前の話だが、MIX08 - Mobile Devices and Microsoft Silverlight のデモビデオがアップされている。

http://visitmix.com/blogs/2008Sessions/T12/

 

3Dはハードウェアアクセラレータが乗らないだろうから、厳しいだろうな・・・

でも、ビデオなど、同じXAMLでかけるのはでかい。

 

今の予定では、次の通り。Windows CE 6 ベースになる。 

Silverlight 1.0 for mobile CTP Q2 CY2008

Silverlight 1.0 for mobile RTW Q4 CY2008

Silverlight 2   for mobile CTP Q4 CY2008

Silverlight 2   for mobile RTW Q2 CY2009

 

かなり気になっている。

March 13

初音ミク XAML化計画

 
六角→ ZAM 3D でテクスチャの喪失があるものの、ある程度のデータ移行が可能。
 
Shade に関してはえムナウさんからのレポートを期待。
データに関しては、勉強会後に Shareベースに切り出した XAML データが
えムナウさんから放流される見込み。
 
ここでめでたく、初音ミク XAML化計画は当初の目的達成。
それにしても、XAML 偉大だ・・・初音ミク がリアルタイムで踊ってくれる。 w
 
ここから先は、福井勉強会 ネタばらになりそうなので、自粛 w。
 

初音ミク XAML化計画

 
テスト用一時置き場 >> きょう萌えムナウさんへ
 
March 12

初音ミク XAML化計画

ようやく、すべてのパーツを ZAM 3Dにインポートするところまできました。ところが、くつかのテクスチャーがドロップしてしまいます。原因未調査です。次に、ZAM 3Dでパーツの関連を付けて、Bone も入れて、回転軸を調整したのが次の状態。