はじめてのレイトレーシング
レイトレーシングを一度はやってみたいと思っていましたので挑戦してます。
参考になるサイトや書籍を探す
ネットでいろいろ調べては見たけれど、具体的なやり方やソースコードまで載せている分かりやすいところは見つかりませんでしたが、おすすめのレイトレーシングの本を挙げていらっしゃる方がいました。
この中から初心者向けかつ Kindle で今すぐ手に入る本として以下を選んでみました。
内容は基礎から説明されており、かつ、C++ で書かれた具体的な実装のソースコードも記載されていて良い感じです。
ソースコードは配布されてもいるのですが、Windows 向けではないので、ビルドを通そうとするとソースコードに修正が必要です。私は面倒くさいので、こちらのビルドを通すのは諦めました。
また、本に記載されるソースコードと微妙に違うようです。
SharpDX + BulletSharp
物理演算をやりたい。
物理エンジンを選ぶ
いろいろ調べたけれど、今回は .NET 用ラッパーがある Bullet を選びました。
bulletsharp - BulletSharp is a .NET wrapper for the Bullet physics library. - Google Project Hosting
こちら、参考にしました。
3D物理エンジンの比較 ( ソフトウェア ) - Star☆Dust〜ゲームとか萌えるAIとか作りたい〜 - Yahoo!ブログ
3D物理エンジンの比較2 ( ソフトウェア ) - Star☆Dust〜ゲームとか萌えるAIとか作りたい〜 - Yahoo!ブログ
Bullet を使う
Bullet の使い方は、以下の書籍から習いました。
Amazon.co.jp: Learning Game Physics with Bullet Physics and OpenGL 電子書籍: Chris Dickinson: Kindleストア
サンプルソースコード付きでページ数の少ない本で、とりあえず初めて見る目的で読む分には都合が良いと思いました。
公式のサンプルはどうもミニマムじゃないので分かりにくい。
3 章まで読んだ内容で、コリジョンを処理するプログラムを作成しました。
BulletSharp for SharpDX を使うとビルドエラーが起きる
Bullet を使うよりも、BulletSharp を正しく使える環境を用意することに時間がかかりました。
nuget から SharpDX を導入している環境で BulletSharp for SharpDX のアセンブリを参照して実装を行うと、ビルド時にエラーが出ました。
Error 1 The type 'SharpDX.Vector3' is defined in an assembly that is not referenced. You must add a reference to assembly 'SharpDX, Version=2.6.3.0, Culture=neutral, PublicKeyToken=null'.
SharpDX がアカンといわれる。参照しているはずなのに。
nuget から SharpDX を導入した場合、以下の SharpDX.dll が参照されていました。
packages\SharpDX.2.6.3\build\..\Bin\DirectX11-Signed-net40\SharpDX.dll
これは、"SharpDX, Version=2.6.3.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1" な DLL です。
PublicKeyToken が null ではない。
どうも、BulletSharp は、PublicKeyToken=null な SharpDX しか受け付けないようなビルドが行われているっぽい?
そこで、nuget から SharpDX を導入した時に一緒に落ちてきている以下の Unsigned な DLL を参照するように変更します。
packages\SharpDX.2.6.3\build\..\Bin\DirectX11-net40\SharpDX.dll
これで正しくビルドが通りました。
MMD PMD + VMD
タイトル修正。PMX やめて PMD でやったのだった。
まず、C++ なんてものでコーディングしてられないなって思ったので C# で DirectX を扱える SharpDX に乗り換えました。
C# で実装できる素晴らしさ。
そして、3D Game Programming with DirectX11 という本で勉強しました。
英語ですが、ソースコード付きでわかりやすい。
ここまでで、VMD ファイルを使って MMD モデルを躍らせることができるようになりました。
さらに、VMD は IK を使わないと足が棒のようにぶらぶらするだけなので、IK を実装しました。
以下の動画など参考にしました。動いてるものがソースコード付きであると助かります。
【ゆっくり解説】 第8回 MMDモデルを踊らす 【3Dプログラミング】 ‐ ニコニコ動画:GINZA
最初に作った踊らせる仕組みが悪くて苦労させられました。
出来上がったのがこちら。膝がガクガクなのは、正しくは角度制限しなきゃいけないところをやってないから。
WPF で MVVM
Livet などの MVVM ライブラリを真面目に使いたいので、まずは WPF での MVVM について勉強しました。
メインはここの内容を参考にしました。
WPF/MVVM Quick Start Tutorial - CodeProject
関連してその他いろいろ参考にしました。
連載 WPF/Silverlight UIフレームワーク入門:第2回 データの表示と入力に必要な知識 (1/5) - @IT
CommandManager クラス (System.Windows.Input)
連載:WPF入門:第6回 「コマンド」と「MVVMパターン」を理解する (1/3) - @IT
CommandManager.RequerySuggested を使う意味がよくわからずに困りました。
RoutedCommand.CanExecuteChanged イベント (System.Windows.Input)
RoutedCommand は、CommandManager が発生させる RequerySuggested イベントを待機します。 RequerySuggested イベントは、キーボード フォーカスの変更など、コマンドを実行するかどうかを変更する可能性のある条件が満たされたときに発生します。 コマンドが RequerySuggested イベントを受け取ると、CanExecuteChanged イベントを発生させます。 通常、コマンド ソースはこのイベントを待機し、CanExecute メソッドを使用して RoutedCommand に照会します。 コマンドを実行できない場合、多くのコマンド ソースでは、コマンド バインディングの一部として、自動的に自身を無効にします。 コマンドを実行できない場合に淡色表示になる MenuItem は、その一例です。
CommandManager.InvalidateRequerySuggested メソッド (System.Windows.Input)
CommandManager は、キーボード フォーカスの変更など、一定の条件だけを基に、コマンド ターゲットが変更されたものと判断します。 コマンドを実行不可能にする条件が変更されたことを CommandManager が適切に判断しない場合は、InvalidateRequerySuggested を呼び出すことによって、CommandManager に RequerySuggested イベントを強制的に発生させることができます。
キーボードから入力があったとか、マウスがクリックされたとか、ウィンドウにフォーカスが移ったとか、そのたぐいの動きがあったら RequerySuggested に登録されたイベントハンドラをコールしてくれるのでしょう。
今回の CanExecute の実装は、これにおんぶに抱っこでお世話になることで、いろいろ楽をしているようです。
RequerySuggested が呼び出される正確な条件ってどこかにまとめられてないでしょうか。このへんの挙動を理解した上でないと使いにくいと思います。
ソフトウェアの更新機能の実装
.exe ファイルを置き換える
こちらの記事を参考に実装。update ディレクトリに Update.exe を置くと、それを更新データとして現在の Update.exe と置き換える。
public partial class MainWindow : Window { public MainWindow() { Clean(); InitializeComponent(); } private void Clean() { if (Environment.CommandLine.IndexOf("/up", StringComparison.CurrentCultureIgnoreCase) != -1) { try { string[] args = Environment.GetCommandLineArgs(); int pid = Convert.ToInt32(args[2]); Process.GetProcessById(pid).WaitForExit(); // 終了待ち } catch (Exception) { } File.Delete("Update.old"); } } private void Button_Click(object sender, RoutedEventArgs e) { if(File.Exists("update/Update.exe")) { File.Delete("Update.old"); File.Move("Update.exe", "Update.old"); File.Move("update/Update.exe", "Update.exe"); Process.Start("Update.exe", "/up " + Process.GetCurrentProcess().Id); this.Close(); } else { textBlock.Text = "update not found."; } } }
C# でトースト通知
C# でトースト通知する方法を調べた。
AppUserModelID 周りは意味わからんかったのでまったく理解してない。
公式の解説
http://msdn.microsoft.com/en-us/library/windows/desktop/hh802768
http://msdn.microsoft.com/en-us/library/windows/desktop/hh802762