ぷろみん

プログラミング的な内容を扱ってます

毎月開催、自分頑張れよ会議

概要

8月の振り返りと9月の目標について

2017年8月の目標 - ぷろみん

8月の振り返り

とりあえず、無事フリーランスになれた。

Rustの勉強はちょっとずつ進めている。

英語は相変わらず単語アプリで遊ぶ程度。

結局ブログも書こう書こうと思ってたけどこんな時期に。もう9月半分過ぎてるよ。
新しい環境と新しい仕事で忙しかったことにしておこう。

9月にできること

色々列挙してもTODOリストからすべきことに変化しないので、できると思うことだけに厳選

英語の単語アプリを完走する。
既にいくつかのアプリは完走しているので、そこまで苦労することなく完走できるんじゃないかと思う。

やっぱり大好きなC++関連じゃないとモチベーションが続かない気がするのでRustからのC++呼び出しをやってみようかと思う。
何度か調べた限りでは記事もそれなりにあるし多分そのまま実装できるのではないかと思う。

余裕があればUnityからのC++呼び出しについても何か書けたらと思う。
ここは前の仕事でやってた所なのでまとめる感じになるので時間さえ作れればいける。
ただ、直接の関数呼び出しに関しては上手くいかなかったのでそこを何とかしたい。

2017年8月の目標

概要

マイルストーンを置かないと人間はどこまでも怠惰になるので。
月初めに立てて、月終わりに見直そう。

したいこと

大き過ぎで小目標に向かないのもとりあえず書きだす。

C++

大好きC++
私がC++のことをどうやって知っていったかという記事をいつか書きたい。
最近知った面白ネタとしては

d.hatena.ne.jp

がある。プライベート侵害である。合法とはいったい。
アクセスが許されないからってテンプレートから侵入してコンストラクタでポインタを無理矢理奪取してるの面白過ぎるでしょ

後はC++17についてもうちょい詳しくなりたい。
最近@pink_bangbiさんに variant を教わった。便利。

英語

最近話題になったシャーロックホームズが対訳で読めるサイト がカジュアルに英語に触れられるので重宝している。

ブログの更新

有意義な情報の発信を目指すと研究が進まない場合、長期間ブログが更新できない。
目標を立てることで進捗を確認するといういつでも気軽に書ける概念が手に入る。
少しも進まないくらいなら少しでも進んでいる感触を得た方がモチベーションを保てるかもしれない。
強制的なやるべき事があるとモチベーションが下がったりもするので用観察。

独自ドメイン運用上の問題

私はレンタルしているクラウドサーバをカジュアルLinux機として運用しているので
興味もったパッケージやアプリケーションを入れたりするので環境を初期化することを定期的にやってしまう。
こないだもGhostからWordPressに変更して独自ドメインのアドレスパスを無効にしてしまった。

この状態だと独自ドメインを安定運用することもできない。
安定したサーバを一つ用意しておき、そこから不安定なサーバに飛ばすようにするべきか。
今の格安サーバだとVMコンテナで管理するのは難しいのだろうか。
アクセスが集中するようなことは無いと思うので問題ない気はする。

Rust

最近勉強を始めた。まだまだ右も左も分からないよちよちプログラマー
Rustのドキュメントは読み物としても面白い。エラーハンドリングだけでこの分量とか初心者を殺しにきている。

OSS

世の中のOSSはコードが汚いものが多く、リファクタリングをしたいと前々から思っている。
しかし、綺麗なコードは主観的な表現で絶対的な改善ではないため受け入れられないんじゃないかなと二の足を踏んでいる。
個人的には変数名を意味不明な省略表現から脱却するだけでもかなり読みやすくなると思うのだけれども。

今気になっているのはredisで有名な割にコード量が少ない。
Unity等にも持っていけるポータブルメモリインデータベースにならないかなとコードを眺めている。
モバイルまで見るのならrealmだろうが。

ゲーム制作

やってみてスケール感大き過ぎて諦めるが多過ぎるので、もっと適当に小さく作る必要がある。
完璧主義はゲームにおいては最悪な考え方だ。

クォータニオン解説

torini.hateblo.jp

上記でもちょっと書いたが、複数環境でクォータニオンを運用するために詳しい知識を学習して共有したい。

文章書き

どんな駄文でも良いので20万文字かけたら、それには価値があると思っているのでそれを目指している。
1000字くらいなら簡単に書けても、それを200回繰り返すことができない。
とりあえず、頭を空っぽにして貪欲に文章を紡ぐ。内容や構成は最低限のステージに上がってからしようかと思う。

お絵かき

最低限アイコンくらい描けたら重宝しそうなので頑張っていきたい。
英語と同じで時間かけている割に上達しない。

VRお絵かき

tips.hecomi.com

esprog.hatenablog.com

凹さんとEsさんのアセットを使えば3D空間に落書きできるのは分かっているのでペンタブのトラッキングさえできれば簡単に実装できる。

VIVE™ | Vive Tracker

TrackerもVive関連商品として存在しているが、ペンのような小さなものをトラッキングする方法はあるのだろうか。
最初は普通に3Dペインターをサクッと作っちゃった方が良いかもしれない。
上記2つのアセットが優秀なので多分1日もかからずに作れる。

就職

仕事しないと生きられないから仕方ないね。
前の仕事でVRをメインでやっていたので、VR関連が良い。
更に前の仕事でゲームを作っていたので、ゲームだとなお良い。
ただ、ソシャゲ以外のゲーム業界は給料安過ぎる上に古代の音が聞こえるので避けたいな。

オイラー角と空間座標系

概要

複数の環境間での回転のインポート、エクスポートについて調べていたのですが、全然進まないので最小限のアウトプットを目指したメモです。

オイラー

説明はWikipediaに投げます。

重要なのは単にオイラー角といっても12通りの表現方法があることです。

今回の対象環境の1つであるUnityはz-x-y系を採用しています。

Z 座標を軸に z 度、X 座標を軸に x 度、Y 座標を軸に y 度 (順番はこのとおり) 回転する回転

オイラー角については上記座標系とCW(clockwise, 時計回り)とCCW(counterclockwise, 反時計回り)を合わせる事で他空間に同じ回転を適用することができます。
90度回転させると時計回りに回転するので、UnityではCWを使っているようです。

Tait–Bryan angles

航空力学で採用されている形式、 正面にX軸、右側にY軸、下方向にZ軸にそれぞれの正の値が割り当てられます。回転方向はCW。

オイラー角と違って軸の定義まで含まれています。
そして、ここまで厳密ではないと現実世界を定義できないのでジャイロセンサ等の出力はこの形式であることが多いです。

Quaternion

Quaternion Conventions: Hamilton and JPL

QuaternionにはHamiltonとJPL形式があるけど混同したり意識せずに混ぜて使ってしまっていることが多いよって話です。

Convert from JPL to Hamilton

Quaternionからオイラー角への変換

Sensor Fusion

訳語が何になるかは分かりませんが、Sensor Fusionで検索すると参考になるものが色々出てきます。
Sensor Fusion · jherico/OculusRiftHacking Wiki · GitHub

参考

Conversion between quaternions and Euler angles - Wikipedia

中途半端なbit幅の符号付整数を扱い易くするSign extending trick

charじゃ大きすぎる

charは何気に256もの数字を記録できます。
しかし、組み込みのような制限の厳しい環境では1bitでも送受信のデータは節約したいものです。
そんな時はbit演算を駆使してデータをやりとりすることになるのですが、困った状況というものがあります。

例えば、あるセンサーが-10~+10の値を返す場合どうやって値を管理すれば良いのでしょうか?
負の値を表現するには通常2の補数表現が使われますが、それを自分でやるしかないのでしょうか?
実はbit fieldを使えばそんな問題も簡単に解決できるようになります。

bit field

知らない人も多そうですが、データのやり取りの際にUnion等と一緒に使われることが多い機能です。 bit fieldでは指定した変数に割り当てるbit数が指定できます。
極々ローレベルな問題を扱うことが多いCならではの機能といえるでしょう。
書き方としては単純で、クラスや構造体のメンバ変数の最後にコロンと割り当てるbit数を書くだけです。

struct BitField
{
    int a: 3;
};

int main()
{
    BitField bitField = {};
    bitField.a = 0b0000; // 0
    bitField.a = 0b0001; // 1
    bitField.a = 0b0010; // 2
    bitField.a = 0b0011; // 3
    bitField.a = 0b0100; // -4
    bitField.a = 0b0101; // -3
    bitField.a = 0b0110; // -2
    bitField.a = 0b0111; // -1
    bitField.a = 0b1000; // 0
    bitField.a = 0b1001; // 1
    bitField.a = 0b1010; // 2
    bitField.a = 0b1011; // 3
    bitField.a = 0b1100; // -4
    bitField.a = 0b1101; // -3
    bitField.a = 0b1110; // -2
    bitField.a = 0b1111; // -1

これでaには3bit以上の値が入らないようになります。
4bit目以降の数値は無視されていることが分かると思います。
そして、3bit目が補数表現のための負値の役割を果たしていることも分かります。

Sign extending trick

template <typename T, unsigned B>
inline T signextend(const T x)
{
  struct {T x:B;} s;
  return s.x = x;
}

int r = signextend<signed int,5>(x);  // 5bitの符号付整数をintに変換する

まとめ

これで1byteに符号付整数を2つ入れてくるようなセンサーを相手にしても頭を抱えなくて済みますね。
template引数をbit fieldにも使う事ができるって面白かったので紹介してみました。
頭の片隅に置いておくといつか役に立つ日がくるかもしれません。

参考

http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend

C++では典型的なif文は使わない方が良い

よくある間違い

あなたはコンテナから指定のデータを探す時に以下のようなコードを書いていませんか?

for(int i = 0; i < 10; i++)
{
    if(list[i] == 5)
    {
        // do something
        break;
    }
}

正しい書き方

// #include <algorithm>が必要
auto result = std::find(list.cbegin(), list.cend(), 5);
if(result != list.cend())
{
    // do something
}

理由

一見するとC++の知識の必要のない最初のコードの方が読みやすく感じるかもしれません。
しかし、熟練のプログラマでも最初のコードを見ると一瞬これは何のコードだろうか?となります。
これは基本的な構文のみで書かれたコードにありがちな分かり辛さです。
一方、正しい書き方の方はすぐに何をしているか分かります。std::findって書いてあるのですから。

間違った書き方の方では更に悪い事にイテレータ破壊の危険性が高いです。
イテレータ破壊についての詳細は以前書いた記事を参照してください。

std::vectorの正しい使い方 - ぷろみん

しかし、algorithmを使おうとするとまずfindでは機能が足らなくなります。
find_ifになると大体の用途では問題なくなるのですが、今度はラムダを理解する必要が出てきます。
最近のコンパイラならラムダにautoを使えるので、

[](const auto& item){ return false; }

みたいに書いたら大体そのままいけるので大分楽にはなっているんで頑張ってください。スコープだけは意識して欲しいところですが。

キャプチャ内での変数宣言はもう入ったんでしたっけ。アレも出来たら便利ですね。

Unityの新入力システム

Unityの入力システムは汎用性が低い

Unityはマルチプラットホームという利点がありますが、入力システムの汎用性は低いです。
当然同一で処理したいタッチ処理とマウスクリック処理を別々に書かなければいけなかったり、マルチプレイヤーゲームで1プレイヤーはキーボード操作、1プレイヤーはコントローラーといったことをするのに複雑な機構が必要になってしまいます。
また、プレイヤーの状態に合わせて操作を変更したいというのは自然な要望ですが、それにも対応していませんでした。 そこでUnityでは新しい入力システムとしてPlayerInputという機能をβ版で発表しています。

新しい入力システム

新しいインプットシステム、一緒に開発しませんか? – Unity Blog

また、こちらのコードがgithubにも上がっています。

https://github.com/Unity-Technologies/input-prototype

どういった機能なのかは動画を見てもらうのが一番早いかと思います。

youtu.be

今までとは何が違うのか

今まではProjectSettings/InputManager.asset等に保存していたため、プロジェクト全体でグローバルに入力システムを運用する必要がありスコープが広い上に指定も文字列でやらなければいけない等、とても積極的に使いたいシステムではありませんでした。

この新しいシステムではプレイヤーのある状態でのキーマップをActionMapとして作成し、そのアクションマップを状態に合わせて切り替えることでキーコンフィグを動的に切り替えることができるようになります。

これによってコード上では

if(firstPersonControls.fire.isHeld){ ... }

という風に入力システムを意識しない統一的なアクションでコーディングできるようになります。

未来と生きるために

Unityでは難しいことを簡単にするという明確なミッションがあります。なので、VR等の最先端の技術や新しいデバイスの対応をどんどんしていくことになるでしょう。
例えば、このゲームをViveコントローラとOculus Touchに対応して欲しいと言われた際にそれぞれがインハウスで開発するのはいかにも時間の無駄です。
この機能が入れば、そのDeviceProfile機能で入力とアクションをマッピングできるようになるかもしれません。
汎用的な機能が入ればAssetStoreに各デバイスのプロファイラーやマッパーがリリース会社から提供されることが期待できるので信頼性もあがります。

良きデベロッパーのために

Unityはスコープがゆるかったりパブリックにするように設計されていたりで悪いデベロッパーを育てる側面が強いです。
しかし、Unityは新しい機能で確かに問題を切り分けて良い設計ができるようにしています。
この思想にのって、ステートマシンという概念、ステート毎の入力(アクションマップ)、どのスクリプトで入力を取得すべきか。を学習することは良いデベロッパーへの近道に思えてなりません。

Unityのフォルダ構成ベストプラクティス

モチベーション

Unityでは多岐にわたるプロジェクトを考慮してフォルダ関係のサポートは薄く、プロジェクト毎に自由に設定しなければならない。
自由は素晴らしいことだが統一規格がないことは他の人のコードを読む時にもんにゃりする。
そこで、私が良いと思っているフォルダ構成を紹介しようかと思う。

オススメする方法

とりあえず結論から紹介する。

  • Assets直下をAsset Storeのインポート先とする。
  • Assets以下に自身のグループや会社名のフォルダを作り、ここを作業フォルダとする。
  • Assets/MyGroup以下にScenesやScripts、Prefabs等のフォルダを作る。ここは複数のシーンで利用するアセットを格納する。
  • Assets/MyGroup/Scenes以下にシーン名フォルダを作る
  • Assets/MyGroup/Scenes/SceneName以下にScripts、Prefabs等のフォルダを作る。ここはこのシーン専用のアセットを格納する。
  • Assets/MyGroup/Scenes/SceneName/SceneName.unityにシーンファイルを作る。

タグを有効活用すれば、もっと良い方法もありそう。
けど、いちいちアセットを作る度にタグ打つのが私には無理だった。

ダメだった方法

Assets/Pluginsフォルダに全てのAsset Store等の外部アセットを入れる。

上記をすると誤作動するアセットが度々存在したためダメだった。
スクリプトに自身のパスを指定しており、デフォルトインポートパス以外では動作しないアセットが存在する以上デフォルトインポート以外は信用し辛い。
そして多くのデフォルトインポート先はAssets/GroupNameである。これはもう諦めてそれに従った方が良い。
たまにAssets直下に展開しているアセットもあるが、その場合は適当なフォルダを作って詰める。
それで動かなかった場合はスクリプト修正か利用しないかを選択した方が良いと思う。プラグインを簡単に外せる環境構築は大事。
というか、有料アセットが間違ってgithubに上がってたりするのでプラグインマネージャ欲しい。いろんな人が困っているはず。

ダメだった方法2

Assets/Scenesに全てのシーンファイルを詰める。
Assets/Scriptsに全てのスクリプトファイルを詰める。
Assets/Prefabsに全てのPrefabファイルを詰める。

シーンが増えてくるとアセットのスコープが見えなくなってくる。
スコープが見えないということは変更に対する影響範囲が見えなくなるということだ。
つまり、ちょっとシェーダを書き換えたり、ちょっとPrefabを更新したりするだけで他のシーンでは動作しなくなっている可能性がある。
スクリプトのnamespaceもシーン毎に変える。

ちょっと横にそれるが、Unityではスコープの概念がゆるゆるなので色んな所で自ら制限をかけた方が良いかと思う。
例えば私はtransform.parentは使わないようにしている。こうすることで、末端のgameObjectはアクセスできる範囲が狭まり必要以上に多機能になることはないはず。