ボリュームレンダリング実験

色空間の調整により頭骨から髪まで観察することができる。

ただし血管を外部から透視するには頭骨が邪魔になるので色空間(WL)外の色を透過するように変更※左画像
if (src > 1) src = 0;

それでもうまく表示できないので
一定の濃さが蓄積されるまでは透視できるようしてみた。※右画像
シェーダー

float src = (_VolumeData[id] + ws) / _WindowWidth;
if (src > 1) src = 0;

float a = saturate(src);//透明度
if (rayopa > 0) {
    rayopa -= a;
    a = 0;
}

静止画で見るとわかりづらいがなかなか面白い結果が得られた。

ComputeBufferによるボリュームレンダリング

CPU部分

        _volumeData = new ComputeBuffer(volumeSizeX * volumeSizeY * volumeSizeZ, 4);
        _volumeData.SetData(volumeColors);
        _rayMarchMaterial.SetInt("_VolumeSizeX", volumeSizeX);
        _rayMarchMaterial.SetInt("_VolumeSizeY", volumeSizeY);
        _rayMarchMaterial.SetInt("_VolumeSizeZ", volumeSizeZ);
        _rayMarchMaterial.SetBuffer("_VolumeData", _volumeData);

GPU部分

	#define STEP_CNT 512
	#define STEP_SIZE 1 / STEP_CNT
	half4 raymarch(v2f i, float offset) 
	{
		float3 frontPos = tex2D(_FrontTex, i.uv[1]).xyz;		
		float3 backPos = tex2D(_BackTex, i.uv[1]).xyz;				
		float3 dir = backPos - frontPos;
		float3 pos = frontPos;
		float4 dst = 0;
		float3 stepDist = dir * STEP_SIZE;
		float ws = _WindowCenter - _WindowWidth/2;

//外側ならすべてが1になるみたい。
		if (pos.x >= 1.0f && pos.y >= 1.0f && pos.z >= 1.0f)
		{
			return dst;
		}
		for(int k = 0; k < STEP_CNT; k++)
		{
			int3 size = { _VolumeSizeX ,_VolumeSizeY ,_VolumeSizeZ};
			int3 index = (int3)(pos.xyz*size);
			int id = index.x + (index.y * size.x) + (index.z * (size.x * size.y));
			float src = (_VolumeData[id] + ws) / _WindowWidth;
			float a = saturate(src);

			// clipping
			float border = step(1 - _ClipDims.x, pos.x);
			border *= step(pos.y, _ClipDims.y);
			border *= step(pos.z, _ClipDims.z);
			border *= step(0, dot(_ClipPlane, float4(pos - 0.5, 1)) + _ClipPlane.w);

			// Standard blending	        
			a *= saturate(_Opacity * border);

			src *= a;
			dst.r = (1.0f - dst.a) * src + dst.r;
			dst.a = (1.0f - dst.a) * a + dst.a;
			pos += stepDist;
//一定の不透明度を超えたら演算中断
			if (dst.a >= 0.8) {
				break;
			}
		}
		dst.g = dst.b = dst.r / 2;
//黒い部分にも色を付けたい
		dst.b += 0.1;
		dst.g += 0.1;
		return dst;
	}

前回失敗していたのは
_volumeData = new ComputeBuffer(volumeSizeX * volumeSizeY * volumeSizeZ, 4);
での引数の4部分が小さかったためだった。
実機でTexture3Dの倍の512*512*120ほどのボクセルデータが読み込めるようになった。
もっといけるはずだが今のとこ描画が追いつかない・・。

ボリュームレンダリングの実験

Twitterだと書ききれないのでこちらに。
試行錯誤の独り言です。

Unityの3dテクスチャによるボリュームレンダリングは参考になるサイトもそれなりにあって表示もうまく行ったのだけどAPIが初期化時に実際の8倍以上のメモリを要求する。
部分初期化はサポートしてないようだ。

対策としてComputeBufferを使って処理しようとしたらたしか、4の倍数で2048以下でないとダメというエラーがでたので早々に諦めて
テクスチャを数枚z軸に対して積み重ねるようにしてみた。
例えばzが0.5以下なら0番目のテクスチャを
z値2倍で使う
それより上なら1番目のテクスチャをz値0.5差し引いた上で2倍で使う。
この試みは一応の成功、
問題点としてはつなぎ目がおかしくなる
これはボリューム内のz軸一枚分それぞれ余分に持ち計算式を少し変えれば解決できそうだ。
他にもシェーダー変更後Unityをアクティブにした瞬間Unityがなぜかフリーズというレベルで固まる。
10分以上応答がなくおそらく変換処理をしてるのだろうけど重すぎる。
これにより知識が足りない故のトライアンドエラーがうまくいかなくなる。
テクスチャを3枚以上同じ方法でつかうと
実行する前にループ文にフラグつけろとのエラーがでてつけてみたけど変わらない。(もしかしてマテリアルにシェーダー設定されてる時点で内部実行されてる?)
Unityはさらにフリーズするようになる。

とりあえず次回は
https://developer.microsoft.com/en-us/windows/mixed-reality/volume_rendering
を真似てやはりComputeBufferをつかう方法を再度チャレンジ

A-Bikeカスタマイズ ハンドルのバタつき

ハンドルのバタつきは標準でゴム紐により対応しているがこれにより折りたたみ時のハンドルの引き抜きが困難になっている。
あと使っているうちに外れたので
今回は簡易的に対応する事に
引っ張る力が必要で磁石なら接着するほど近くないといけない。
今回は微妙に離れているのと折りたたみ時の移動でも問題ないようにしたい。
リールキーホルダーを使えば近距離で引く力が得られるし、片方の固定で使う時に引っかければよい感じになる。
ゴムバンドでは片方の固定だけだとぶら下がって邪魔になるのでこちらの方が利点が大きい。、


今回はもともと付いてたクリップで対応したけど
時間ある時に裏にネジ止めしたいところ。

A-Bike 用カバー作成

折りたたみ状態で転がせるようになったので
移動時用の簡易カバーが欲しいので
100円ショップのパーツで試作して見た。
ハサミあればできるのでらくちん。
専用バッグは入れるのが困難な上に転がせない
かさばるなどの欠点があるので
そこに特化してみる。
袋の片面が切れた形状で
被せた後、切れた内側中央と端の二箇所をとめると
袋状になるのでそのまま袋外側を縛るかわりに
上下二箇所をマジックテープでとめるだけでよい。
コストもかからず作るのが楽なので
耐久性は気にしない。
IMG_3659

IMG_3661

IMG_3662

HoloLens用のコントローラーブックマークレット

試作版を公開します。

iPhoneのSafariでの動作はできなかったのでiPhoneではとりあえずChrome使ってください。

Solica HoloLensTools
※マルウェア検知されますね・・回避方法はまたあとで考えますが危険なコードは含まれてないです。

インストール方法:
Hololens device portalに接続し
File ExplorerによりDocumentsに
solica.hololens.js
user.hololens.js
をアップします。

スマホやPCのブラウザに
bookmarklet.txtの内容で適当な名前を付けて登録します。
スマホの場合ブックマークの名前はシンプルなものにしてください。

使い方:
接続方法
まずHololens device portalに接続します。
そのページを開いた状態で
PCならブックマークを開きます。
スマホならアドレスバーに先ほど登録したブックマーク名を入力していくと一覧に登録したものが出てくるのでそこで選んで開きます。

起動後
現在の版では下のテキストボックスに文字を入力しソフトウェアキーボードのEnterをすると送信されます。
テキストがない場合そのコードが入力されます。
例えばテキストボックスにカーソルがある状態でバックスペースなどをするとそのまま送信されます。
マウスかタッチにより
上のパネルでドラッグした方向に該当するカーソルキーが入力されます。
キー入力が確定後タッチをやめるなどの解除処理をするまで定期的に処理されます。
3本指で下に動かすとWindowsキーが入力されホーム画面が現れます。
その他詳細は
user.hololens.js
を読み、改造してください。

スクロールやジェスチャーを送信するREST APIも見つけましたが今のところ動作を確認できませんでした。
せめてクリックができればモチベが上がるのですが。

備考:httpsの上クロスサイトドメインの回避の為にブックマークレットによる実装となりました。REST APIをつついてみるのにもよさそうですね。

追記:
書き忘れていたのでですがiPhone Chromeのポップアップブロックを解除する必要もあり。
追記2:
ドラッグ(スワイプ)とフリックが排他制御入ってるせいで操作性が悪くてスクリプト作りづらいですね。
次のバージョンでは修正します。

HoloLens用にカスタマイズしたブラウザ

いろいろあって※
ファイルを直接公開してみるよ。
HoloLensを開発者モードにした後HoloLensのIPにブラウザから接続して(たぶん警告がでるけどそのまま進む)
ユーザーとパスワードを設定すると
Appsというところがあるからそこから直接パッケージインストールしてね。
ブックマークとかタブ機能ないけどクリップボードにURLあったら開けるようにしといたよ。

Scroll WebBrowser

捕捉:現在のURL補完処理概要
.がなければ.comを後ろに(手抜き過ぎる・・)
プロトコル指定がなければhttp://を
なのでtwitterだけでtwitterは開けるよ。
うまくスクロールしないときは普通にブラウザが重くて固まってるので待っててください。

※MSDN入っていると無料でWindowsストアの開発者アカウントが取得できるのに気づかず
そのアカウントで有料でWindowsストアの開発者アカウントを取得してしまう。
すると内部的におかしくなってしまったのか
認証メールがどうやっても送られてこなくソフトの公開ができない状態に
初のインシデントの有効化処理を行い。
その処理が終わったら調査してもらう予定

A-Bike electricの問題点とその解決

以下の方法は推奨するものではなくまねる方は自己責任でお願いします。

もともとA-Bikeは全シリーズ購入しており
A-Bike City
折りたたみ状態での移動は体を傾ける必要があり腰が痛くなるので取っ手MINOURA(ミノウラ) アクセサリーホルダー [SGL-300M] φ28-35mm対応 バー幅130mm シルバー
をつける事で解決し快適に使っていたのですが。

新しく購入したA-Bike electricは同様に転がすと右に曲がっていく問題がありました。
力をいれてもここまでしか曲がらずこの状態でも右に曲がります。
img_3707
これはバッテリーホルダーにペダル軸が当たるためだと判明しました。
img_3499

そこでダイソーで以下のパーツを購入し取り付けてみました。
ダイソーで購入
取り付け
これにより折りたたみ状態でまっすぐどころか左にも曲がるようになり転がすのが楽に。
最大角度

ついでにこの時期は持つ部分が冷たいのでダイソーでシールフェルトを購入
ダイソー シールフェルト

サイズはピッタリだけど下が1cmほど届かない。
ピッタリサイズ

下からもう一枚回して完成
下足りないので二重

折りたたみ時に動かすと開いてしまう問題もダイソーで
カチッとはめるとロックされるような仕組みにしたくて検討した結果
子供用ドアロックでできそう。そのなかでそれなりにまともなデザインなのはこれだけだった。
写真のはセンサーケーブルの上ですが下を通すと展開時も邪魔にならない。
折りたたみ時
展開時
接着力に問題があるのでグルーガンで貼り付けたほうがよさそう

追記:
しばらくすると斜めに落ちてしまう問題が発覚、このままでも左にずれてるので折りたたんでも直進できるのだけど
斜めになる

ダイソーで3つ穴タイプを購入しはめなおした。
3つ穴
3つ穴止める

これで落ちようがない・・はず

TypeScriptでの拡張ではまる

interface String {
format(...arr: any[]): string;
}
String.prototype.format = (...arr: any[]):string=>{
 var str=this;

この直後でブレイクしウォッチを見るとthisは文字列であるがstrはWindowオブジェクトである。

String.prototype.format = function (...arr: any[]): string{

これで解決するがデバッガの挙動が怪しくなるパターンなので気を付けないと・・

TypeScript実験

TypeScriptでジェネリッククラス内でジェネリック型の生成をうまくnew T()する事が出来なかったので。

class ObjectManage<T> {
private CreateObject: () => T;
constructor(createObject: () => T) {
this.CreateObject = createObject;
}

//以下実装省略

}

var mng= new ObjectManage(() => { return new Hoge() });

な感じでやってみたらうまくいったぽい。
ジェネリックの型を省略しても理解してくれてるのは賢いな。

※classの<T>がタグとみなされたのか消え去っていたので修正