デジタル・デザイン・ラボラトリーな日々

アラフィフプログラマーが数学と物理と英語を基礎からやり直す。https://qiita.com/yaju

静岡Developers勉強会の「UnityとBlenderハンズオン第5章」の資料公開

2015/06/27(土) 13:00~17:00に、静岡Developers勉強会 UnityとBlenderハンズオンが行われる島田市地域交流センター歩歩路(ぽぽろ) 第4会議室には7名が集まりました。

今回はUnity公式のチュートリアルのシューティングゲームで前回の続きの10章からです。
また、前回できなかったBlenderも再開しました。

シューティングゲームが最後まで出来たわけですが、内容を理解できているのかというと微妙なところです。
来月はミニゲーム発表会です。
今までチュートリアルをハンズオン形式で作成してきましたが、いざ一からゲームを作ろうとすると理解できてなかったところが出てくるはずなので、 自分で考えて答えを出さないと本当に作れるようにはならない。まー分からなかったところは、次以降のセッションで解決策を考えて出来るようになってもらうのがいい。
また、モバイル機に転送するようなこともやってないので、これからやっていきます。

Blenderは2ヶ月ぶりなので結構忘れてしまってますね。 今回は人型モデルにアーマーチェアを入れて、各ボーンを動かしてポーズを作るという簡易的な部分を体験してもらった感じです。オートIKの機能もあったので、 IKとFKの違いなども見てもらいました。
あと、Blenderって数字キーのみだとレイヤー変更なんですね、誤って押してしまうとモデルが消えたってことになる。その場合は冷静になって「1」キーを押せばいい。
自分の場合は最初の段階のユーザー設定で「テンキーを模倣」にチェックが付けていたので気が付かなかった。

UnityとBlenderハンズオンの勉強会をやろうと思ったのは、下記の動画を見たからなんですよね。年末までにはこの段階まで出来るようにしておきたい。
【ユニティちゃん】HGベアッガイさんが踊ってみた【3Dキャプチャ】

 

<

静岡Developers勉強会の「UnityとBlenderハンズオン第4章」の資料公開

2015/05/23(土) 13:00~17:00に、静岡Developers勉強会 UnityとBlenderハンズオンが行われる島田市地域交流センター歩歩路(ぽぽろ) 第4会議室には7名が集まりました。

今回のUnityはシューティングゲームで、Unity公式のチュートリアルです。
Unity公式のチュートリアルなんですが、古いバージョンのままなのでプロジェクトをダウンロードしてもエラーとなってしまいます。今回の資料作成はチュートリアルチュートリアルで差分だけ作れば楽出来ると思ってたんですが、結局12章までマメに作成してしまい、膨大な為かなり心が折れつつもなんとか完成させました。
今回はUnityだけで12章まであるので、4時間だと1章平均20分でやればこなせるだろうと、その為、今回はBlenderは間に合わないとして次回に持ち越すことにしました。

いざセッションをやってみると、思い通りに動かないなどでつまずいてしまうところがあるわけです。その場合、まわりでフォローしながら解決したりしていきます。
それでも自分としては最後まで終わらせようとペース配分を考えながら進めていきました。しかし、終了30分前で11章の前半まではやれたものの、残り30分で全て終わらせるのは無理だと判断しました。 次回の6月はミニゲーム発表会として、これまで学んだことを実践して作成してもらう予定でいたのですが、皆と相談して次回はシューティングゲームの10章、11章、12章とBlenderの続きをやることにして、ミニゲーム発表会は7月に延期しました。

今回のセッションの反省点として、時間内で終わらせようとペースを早めた結果、理解する前にマウスの操作しているのに忙しいとのことだったので、毎月継続してやるわけだし次からは無理に時間内で終わらせようとしないで、余裕をもたせるようにしようと思いました。

静岡Developers勉強会の「UnityとBlenderハンズオン第3章」の資料公開

2015/04/04(土) 13:00~17:00に、静岡Developers勉強会 UnityとBlenderハンズオンが行われる島田市地域交流センター歩歩路(ぽぽろ) 第4会議室には7名が集まりました。

今回のUnityはパックマンだったんですが、資料作成の作業量が結構あって何回か心が折れてました。セッション前日までの段階でBlenderの資料は1割しか出来ておらず、金曜日の夜に必至こいて何とか作成しました。本当はつま先と顔まで作成する予定でしたが間に合わないので次回に持ち越し。
また、セッション当日の午前中には必死にスクリプトを組んでいました。パックマンの迷路の衝突設定が52個、ドットの設定が330個、巡回ルート用のポイントが120個あって、これをセッション内で皆さんに入力させるのはさすがに時間が足りないんで、スクリプトで設定を追加できるようにしたかったわけです。ですが、さすがに巡回ルート用のポイントまでは手がまわらず、セッション時はチュートリアル通りに5つの巡回ルートを入力して動作させるところで終わらせました。
セッション翌日の日曜日に資料の誤字等の修正と巡回ルート用のポイントとスコアのスクリプトを作成して、再度SlideShareとGit Hubに資料をアップロードしておきました。セッションを受けた方は、巡回ルートとスコアの部分を追加でやってみてください。

4月ということもあって、何か新しいことをやるとして「Unity」や「Blender」を選ぶ方には丁度いい資料になっていると思います。
今回のパックマンは作業量が少し多めですが、前回の第2章アルカノイドやサイコロは気軽にやるにはいいでしょう。

資料の作成元になっているnoobtutsさんのUnityのチュートリアル(英語)も参考になりますよ。
http://noobtuts.com/unity


静岡Developers勉強会の「UnityとBlenderハンズオン第2章」の資料公開

2015/03/07(土)に、静岡Developers勉強会 UnityとBlenderハンズオンが行われる島田市地域交流センター歩歩路(ぽぽろ) 第4会議室には7名が集まりました。同じ日に島田市静岡市浜松市三島市と4つ勉強会が重なってしまい2人欠けましたが、今回は県外の名古屋から1人参加してくださいました。参照:静岡でUNITYとBLENDERをやった話
前回:静岡Developers勉強会 UnityとBlenderハンズオン第1章

当日は参加者全員が、Unityのアルカノイドもどき(ブロック崩し)とBlenderのサイコロ(モデリング)を完成させることが出来たのが良かったです。

今回のUnityはブロック崩しということで物理演算を使っているのですが、やはり物理演算って面白いですね。数値を間違って入力してしまったことで、ボールがブロックに跳ね返らないで止まってしまったり、ボールがラケットにぶつかるとラケットがボールの重みで徐々に沈んでしまったりと、ミスもまた別のゲーム性を産みます。参加者ともどもミスで起こる現象に笑いながら楽しんでハンズオン出来ました。

Blenderはたかがサイコロされどサイコロですね、Macを使用している方はマウスではなくトラックパッドを使っての操作方法に苦労してました。おまけとして木目調のテーブル作成もやってもらったのですが時間切れでした。参加者の方が仰っていたけど、Blenderは一人でやっていたら絶対挫折していたが皆で協力して何とか解決出来ている。そういうところが勉強会のいいところだと思います。

家に帰宅していてツイッターを眺めていたら「UnityやUnrealを覚えないといけない脅迫観念にかられている若者へ」が流れてきました。
一部引用:「unityを勉強しないとだめかも…どうしよう…どうしよう…。」「ゲームを自分で完成させたいけど、なんかいいツールないかな、unityならできそうだ!全部ひとりゲームを完成できた!」後者ならunityを勉強する価値があります。前者が多くてしかもみんな不安になってるから心配。

まー静岡Developers勉強会としては、後者でありスマホアプリを開発する上で汎用的なツールとしてUnityとBlenderを学び、6月にはUnityの2Dでミニゲームを作成してもらって発表会をする予定です。


静岡Developers勉強会の「UnityとBlenderハンズオン第1章」の資料公開

静岡Developers勉強会では、過去に下記の勉強会を行いました。
2010年:「Programming in Haskell
2011年:「JavaScript: The Good Parts」
2012年:「HTML5&CSS3実践入門」、「GitHubハンズオン」、「node.jsハンズオン」
2013年:「入門 機械学習
2014年:「実践 コンピュータビジョン」

今年の2015年は上記の勉強会で学んだことを実践し、Shizudev名義のスマホアプリを開発します。
その為、スマホアプリを開発する上で汎用的なツールとしてUnityとBlenderを学ぶことにしました。

2015/02/07(土)に、静岡Developers勉強会 UnityとBlenderハンズオンが行われる島田市地域交流センター歩歩路(ぽぽろ) 第4会議室には8名(新規参加者が4名)が集まりました。
セッションの準備をしていると自分のノートPCのACアダプタを家に忘れたことが気が付きました。
その為、セッション中の1時間過ぎ後にはバッテリーが切れ、たまたま参加者にMBAVAIOの2台持ちの方がいたため、MBAをスライド専用にお借りしてセッションを進めることが出来ました。
Unity1セッションとBlender2セッションを行う予定でしたが、みな操作が不慣れだったため2セッションで終了時間20分前となってしまい、次回に持ち越しとなりました。もっとも、最後のセッション資料の作成が間に合ってなかったんですけどね。
当日は参加者全員が、UnityのテトリスもどきとBlenderのサイコロを完成させることが出来たのが良かったです。

「サザエさんのじゃんけん データ分析」の2014年の結果

2013年の静岡Developers勉強会では「機械学習」をテーマにしてR言語を覚えました。
そこでネタとして、サザエさんのじゃんけんのデータを分析して次の手を予測、10年分(2004~2013)勝負したプログラム作成し内容をまとめて、2014年1月にSlideShareに公開しました。


2014年の静岡Developers勉強会では「コンピュータビジョン」をテーマにしてPythonを覚えましたので、Pythonとデータ分析用ライブラリであるPandasで作り直すのも悪くないですけどね。
当時は理解不足だったので、今ならもっと機械学習っぽく決定木とかN-gramモデルとかで説明したかったな。

さてさて、お風呂に入っていたら、ふと2014年のサザエさんのじゃんけん結果はどうだったんだろうと思って、久しぶりにR Studioを起動して、ちゃちゃっとやってみたんです。
結果は、30勝10敗11分(勝率0.75)でした。

次の手の予測アルゴリズム
・チョキが多いので、グー > チョキ > パーの優先順位とする
・前回と違う手を出すので、上記の優先順位で勝手を選ぶ
・二手前と一手前が違う手なら、残りの手を出すので勝手を選ぶ
・三手の中に同手がある場合、 残りの手を出すので勝手を選ぶ
・二手前と一手前が同じ手なら、勝手を出すので負手を選ぶ

年月 サザエさんの手 予想の手 勝敗結果
1月5日 チョキ グー 勝ち
1月12日 グー グー 引き分け
1月19日 パー チョキ 勝ち
1月26日 グー グー 引き分け
2月2日 チョキ グー 勝ち
2月9日 パー チョキ 勝ち
2月16日 チョキ パー 負け
2月23日 グー パー 勝ち
3月2日 グー チョキ 負け
3月9日 パー チョキ 勝ち
3月16日 チョキ グー 勝ち
3月23日 パー パー 引き分け
3月30日 グー パー 勝ち
4月6日 チョキ グー 勝ち
4月13日 グー チョキ 負け
4月20日 グー チョキ 負け
4月27日 パー チョキ 勝ち
5月4日 チョキ グー 勝ち
5月11日 パー パー 引き分け
5月18日 グー パー 勝ち
5月25日 パー グー 負け
6月1日 チョキ グー 勝ち
6月8日 パー パー 引き分け
6月15日 グー パー 勝ち
6月22日 チョキ グー 勝ち
6月29日 パー チョキ 勝ち
7月6日 チョキ パー 負け
7月13日 グー パー 勝ち
7月20日 チョキ チョキ 引き分け
7月27日 チョキ チョキ 引き分け
8月3日 パー チョキ 勝ち
8月10日 グー パー 勝ち
8月17日 パー グー 負け
8月24日 チョキ グー 勝ち
8月31日 パー パー 引き分け
9月7日 グー パー 勝ち
9月14日 チョキ グー 勝ち
9月21日 パー チョキ 勝ち
9月28日 パー パー 引き分け
10月5日 チョキ パー 負け
10月12日 グー パー 勝ち
10月19日 グー チョキ 負け
10月26日 チョキ チョキ 引き分け
11月2日 パー チョキ 勝ち
11月9日 グー パー 勝ち
11月16日 パー グー 負け
11月23日 チョキ グー 勝ち
11月30日 グー パー 勝ち
12月7日 チョキ チョキ 引き分け
12月21日 パー チョキ 勝ち
12月28日 グー パー 勝ち


ちなみに、サザエさんじゃんけん研究所 公式ウェブサイト
サザエさんの手の予想と勝負結果(2014年)が30勝9敗12分(勝率0.769)でした。

3Dを基礎から勉強する アニメーションの表示

今年、最初のブログです。
前回の「3Dを基礎から勉強する 複数モデルの表示」から2ヶ月経ってしまいましたが、また再開したいと思います。
jsdo.itにて、han.kuroさんが馬の3Dモデルにてアニメーション表示していたのを見かけました。
プログラムも3Dライブラリーを使わないで自前で表示していたので、参考にするには丁度いいと思いました。
馬の3Dモデルデータだけ拝借して、アニメーション表示させるだけなら大分前に出来てたわけです。
この馬の3Dモデルデータは、Three.jsサンプルにあるデータであることが分かりまして、早速ダウンロードして見てみました。
horse.js」でJSONデータになっていまして、参考にしたjsdo.itの馬の3Dモデルデータは必要部分のみ切り取ったデータになっていたわけです。

この段階でブログを書けばよかったんですが、欲を書いてJSONデータを読み込んで表示させようと思ってやり始めたところで急にやる気が停滞してしまい正月休みでやっと復活したところです。


プログラムの大まかなところは「複数モデルの表示」の応用です。違いはThree.jsサンプルにあるデータを使用したところにあります。
今回は、その部分について書いていきます。

ラジオボタンでモデルの種類を選びます。選択したモデルのJSONデータをロードします。
わざわざ連想配列にしているのは、jsdo.itではファイルをアップロードするとそれぞれにURLを割り当てられるため、
jsdo.itに投稿する際、例えば"horse.js"は"http://jsrun.it/assets/7/7/Y/3/77Y3s"に書き換えます。

// モデルデータロード完了
changeModelData() {
    var dict: { key?: string; } = {};
    dict["horse"] = "horse.js";         // 馬
    dict["flamingo"] = "flamingo.js";   // フラミンゴ
    dict["stork"] = "stork.js";         // コウノトリ
    dict["parrot"] = "parrot.js";       // オウム

    for (var i = 0; i < this.elmModels.length; i++) {
        var elm: HTMLInputElement = <HTMLInputElement>this.elmModels[i];
        if (elm.checked) {
            // モデルデータ読込
            this.index = 0;
            this.frameCount = 0;
            this.JSONLoader(dict[elm.value], (() => this.onJSONLoaded()));
            break;
        }
    }
}

// モデルJSONデータ読み込み
JSONLoader(file, callback: Function) {
    var x = new XMLHttpRequest();

    x.open('GET', file);
    x.onreadystatechange = () => {
        if (x.readyState == 4) {
            this.json = JSON.parse(x.responseText);
            // 読込完了コールバック
            callback();
        }
    }
    x.send();
}


「horse.js」を例にするとアニメーションに必要なのは、"morphTargets"内の"horse_A_001"~"horse_A_015"にある各頂点データとなります。
頂点データは複数ですが面データは1つです。今回は色も付けるようにしたので"morphColors"から色データを取得しています。
色データはRGBの順に入っていますが値は0.0~1.0までの浮動小数点となっていますので、255倍して16進で格納するようにしています。

// モデルデータの生成
createModel(modelObject: any) {
    this.modelData = new ModelData();

    this.modelData.vertices = new Array();

    // 頂点データ
    if (modelObject.morphTargets !== undefined) {
        // アニメーション分
        this.animeLength = modelObject.morphTargets.length;
        for (var j = 0; j < this.animeLength; j++) {
            this.modelData.vertices[j] = new Array();
            for (var i = 0; i < modelObject.morphTargets[j].vertices.length; i++) {
                this.modelData.vertices[j].push(modelObject.morphTargets[j].vertices[i]);
            }
        }
    }
    else {
        // アニメーションなし
        this.animeLength = 1;
        this.modelData.vertices[0] = new Array();
        for (var i = 0; i < modelObject.vertices.length; i++) {
            this.modelData.vertices[0].push(modelObject.vertices[i]);
        }
    }

    // 面データ
    this.modelData.faces = new Array();
    for (var i = 0; i < modelObject.faces.length; i++) {
        this.modelData.faces.push(modelObject.faces[i]);
    }

    // 色データ
    this.hasColor = false;
    if (modelObject.morphColors !== undefined) {
        this.hasColor = true;
        this.modelData.colors = new Array();
        for (var i = 0; i < modelObject.morphColors[0].colors.length; i+=3) {
            var r: number = modelObject.morphColors[0].colors[i + 0];
            var g: number = modelObject.morphColors[0].colors[i + 1];
            var b: number = modelObject.morphColors[0].colors[i + 2];

            this.modelData.colors.push(this.getColorHexString(r,g,b));
        }
    }
}


THREE.jsのモデルデータがどうなっているのかのを説明している日本語サイトって検索しても見当たらないんですよね。
JSON Model format 3 と、THREE.JSONLoader.createModelあたりを見るしかないです。
「horse.js」の"faces"では、区切りが10になっており、bitに変換すると「00001010」です。
0: 0 = triangle (3 indices), 1 = quad (4 indices)
1: 0 = no face material, 1 = face material (1 index)
2: 0 = no face uvs, 1 = face uvs (1 index)
3: 0 = no face vertex uvs, 1 = face vertex uvs (3 indices or 4 indices)
4: 0 = no face normal, 1 = face normal (1 index)
5: 0 = no face vertex normals, 1 = face vertex normals (3 indices or 4 indices)
6: 0 = no face color, 1 = face color (1 index)
7: 0 = no face vertex colors, 1 = face vertex colors (3 indices or 4 indices)

0ビットは「0」なので三角形ポリゴンです。1ビット目と3ビットは「1」なんですが今回は使用しません。
区切りの先頭データはType(10=00001010)となり、例 10,v0,v1,v2,0,fv0,fv1,fv2 として8個単位でデータを区切ります。
今回Faceクラスに色データを追加したのは、Faceクラスを面を奥行き座標で並び替えるためにソート(this.faces.sort)させているからです。
最初ソートしていたことに気が付いてなくて、データの順番通りに色をセットしていたため、オウムとか妙なカラフルで表示されてたんですよね。

// THREE.JSONLoader.createModel の超簡易版
var j = 0;
for (var i = 0; i < this.modelData.faces.length; i += 8) {
    // 先頭データはType(10=00001010) 例 10,v0,v1,v2,0,fv0,fv1,fv2  
    if (this.modelData.faces[i] != 10) {
        continue;
    }
    // 頂点インデックスの取得 3頂点のみ対応
    var v0 = this.modelData.faces[i + 1];
    var v1 = this.modelData.faces[i + 2];
    var v2 = this.modelData.faces[i + 3];

    // 面列に新しい面を追加
    this.faces.push(new Face(this.vertices[v0 + addfaces],
                             this.vertices[v1 + addfaces],
                             this.vertices[v2 + addfaces],
                             this.modelData.colors[j++]));
}


3Dモデルはフラットシェーディングで表示しているので、面ごとに色を付けるようにした際も光源の位置によって差をつけています。
ぱっと見では差が出てないようですがですが、よくよく見れば差がついています。
Colorfulチェックボックスを付けて、オンではカラフルにオフの場合には単色の緑色で表示するようにしました。

// 面の塗りつぶし
if (this.isFill) {
    // 描画色の指定
    if (this.isColorful && this.hasColor) {
        // フルカラー
        var col = this.setHex(parseInt(face.color, 16));
        var hsv = this.RGBtoHSV(col.r, col.g, col.b, false);
        var rgb = this.HSVtoRGB(hsv.h, hsv.s, hsv.v - Math.round((1 - face.nz) * 50));
    }
    else {
        // 単色
        var rgb = this.HSVtoRGB(0.4 * 360, 0.5 * 255, face.nz * 255);
    }
    g.fillStyle = 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';     // 面の塗りつぶし
    g.fill();
}



Typescriptで組んだソースリストは、github/Study3Dに公開しました。

スポンサーリンク