おもちゃラボ

Unityで遊びを作っていきます

【Unityシェーダ入門】綺麗に半透明のモデルが表示できるシェーダを作る

UnityのStandard Surface Shaderを使うと3Dモデルを半透明で表示することが出来ます。ただ、モデルの形状が複雑な場合には、裏面のポリゴンが見えて汚い表示になってしまうことがあります。

そこで、隠面は表示せず、手前側の面のみ半透明で表示するシェーダを作ってみました。左が綺麗な半透明シェーダを使ったドラゴン、右がStandard Surface Shaderを使って半透明にしたドラゴンです。

f:id:nn_hokuson:20180123193622j:plain

Standard Surface Shaderではドラゴン裏側の羽まで見えてしまっていますね。

f:id:nn_hokuson:20180123194352j:plain:w300

これを解決する方法を紹介していきます。目次は次のとおりです。

半透明でモデルをきれいに表示する方法

綺麗に表示する方法を考える前に、なぜモデルを半透明で表示すると汚く表示されるのかを考えてみましょう。

Unityのサイトによると・・・

Usually semitransparent shaders do not write into the depth buffer. However, this can create draw order problems, especially with complex non-convex meshes. If you want to fade in & out meshes like that, then using a shader that fills in the depth buffer before rendering transparency might be useful.

Unity - Manual: ShaderLab: Culling & Depth Testing

どうやらコレが原因のようです。半透明モデルを描画する際にデプスバッファ(Zバッファ)への書き込みを行わないため、後から裏面を描画すると上書きされてしまうのですね。

これを解決するため、先にデプスバッファにモデルのZ値(デプス値)のみを書き込みます。この時モデルは描画しません。

f:id:nn_hokuson:20180123202047j:plain:w600

これでモデルを表示する場所のZ値だけ正しく更新されます。続けて、そのZ値を参照しながらモデルを描画します。デプス値は正しく設定されているので、Zテストにより裏面は描画されないことになります。

f:id:nn_hokuson:20180123201728j:plain:w600

分かってしまえば、超簡単ですね!では早速シェーダを作ってみましょう。

半透明シェーダプログラム作る

プロジェクトウインドウで右クリックし、Create→Shader→Standard Surface Shaderを選択してください。名前はSemiTransparent.shaderにしました。

f:id:nn_hokuson:20180123194944p:plain:w100

いま作ったシェーダファイルを右クリックし、Create→Materialを選択してください。これでSemiTransparent用のマテリアルが作成できました。

f:id:nn_hokuson:20180123195132p:plain:w220

今回はSurface Shaderを使ってモデルを綺麗に半透明表示するシェーダを作ってみます。SemiTransparent.shaderを開いて次のプログラムを入力してください。

Shader "SemiTransparent" {
	Properties {
		_Color ("Color", Color) = (1,1,1,1)
		_MainTex ("Albedo (RGB)", 2D) = "white" {}
	}

	SubShader {
		Tags { "RenderType"="Transparent" "Queue"="Transparent"}
		LOD 200

		Pass{
  		  ZWrite ON
  		  ColorMask 0
		}

		CGPROGRAM
		#pragma surface surf Standard fullforwardshadows alpha:fade
		#pragma target 3.0

		sampler2D _MainTex;

		struct Input {
			float2 uv_MainTex;
		};

		fixed4 _Color;

		void surf (Input IN, inout SurfaceOutputStandard o) 
		{
			fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
			o.Albedo = c.rgb;
			o.Metallic = 0;
			o.Smoothness = 0;
			o.Alpha = c.a;
		}
		ENDCG
	}
	FallBack "Diffuse"
}

このシェーダでは2パスでモデルを描画しています。1パス目では「ColorMask 0」を指定することでモデルは描画せずZバッファ(デプスバッファ)にのみ書き込んでいます。

2パス目で通常通りモデルを描画しています。先にZバッファに値を書き込んでいるため、裏面のモデルはZテストに失敗し描画されません。

実行結果

シェーダが作成できたら、マテリアルをモデルにアタッチしてみましょう。プロジェクトウィンドウからマテリアルをドラッグ&ドロップします。

モデルのインスペクタからマテリアルのColorのアルファ値を操作することで、モデルの透明度を変化させることができます。

f:id:nn_hokuson:20180123195539p:plain:w350  f:id:nn_hokuson:20180123200120p:plain:w200

きれいに半透明のモデルが表示されたら成功です!

f:id:nn_hokuson:20180123195938g:plain:w450

Unityの教科書 Unity 2017完全対応版  2D&3Dスマートフォンゲーム入門講座 (Entertainment&IDEA)

Unityの教科書 Unity 2017完全対応版 2D&3Dスマートフォンゲーム入門講座 (Entertainment&IDEA)

GPU Gems 3 日本語版

GPU Gems 3 日本語版

AR Studioを使ったらARアプリが超簡単に作れた

Facebookから提供されている「AR Studio」という開発環境を使ってARアプリを作ってみたので、その使い方をまとめてみました!

f:id:nn_hokuson:20180118202935j:plain

この記事ではAR Studioを使って2Dと3Dのモデル表示までを一通りのことをやってみたいと思います。今回の内容は次のとおりです。

AR Studioとは

AR StudioとはFacebookから提供されている開発環境で、「AR Studio」という名前の通りAR(とくに顔をつかったAR)に特化した開発が簡単に行えるものです。

UnityであればDlibなどのAssetを購入してプログラムを作成する必要がありますが、AR Studioでは標準機能だけで簡単にARアプリを作ることができます。

このAR Studioの使い勝手は、次のように良くも悪くもUnityに非常に似ています。Unityを使ったことがあるのであれば、数分で使い方はマスターできると思います。

では、早速AR Studioのインストールから始めましょう!

AR Studioのインストールとプロジェクト作成

AR StudioはFacebookのDevelopperサイトからダウンロードすることができます。次のページからダウンロードしてインストールしましょう。

developers.facebook.com

AR Studioを起動したら、右下の「Create New Project」をクリックしてください。

f:id:nn_hokuson:20180118194523j:plain:w500

するとUnityっぽい画面が表示されます(笑)

f:id:nn_hokuson:20180118194406j:plain

Face Trackerを使ってみる

まずは顔の向きなどを追跡する「Face Tracker」を追加しましょう。画面左上の「Insertボタン」をクリックし、「Face Tracker」を選択してください。

f:id:nn_hokuson:20180118194701j:plain

すると真ん中のビューに顔に追従して動くマニュピレータが追加されたと思います。

f:id:nn_hokuson:20180118194735g:plain:w400

あとは今追加したFace Trackerの子要素に、2Dの画像なり、3Dオブジェクトなりを追加していくだけで、顔に追従してオブジェクトが動くようになります!超簡単!

2Dの画像を使ってARを表示する

2Dのスプライトを顔に合わせて動かすには、スプライトを張るためのポリゴン(板ポリ)が必要になります。AR Studioには次の2種類のポリゴンが用意されています。

  • Face Mesh
  • Plane

名前の通りFace Meshは顔の形状をした3Dモデル、Plane はただの板ポリです。今回はPlane Meshを使ってみましょう。

左ペイン(Unityでいうことろのヒエラルキービュー)でfacetracker0を右クリックして、「Insert→Plane」をクリックしてください。

f:id:nn_hokuson:20180118194908j:plain

Face Meshの子要素にPlane0が 追加され、顔にも市松模様の板ポリが表示された状態になります。

f:id:nn_hokuson:20180118195121j:plain

次に、市松模様のテクスチャのかわりにヒゲのテクスチャを貼り付けてみましょう。
f:id:nn_hokuson:20180118194958p:plain:w200
ポリゴンにテクスチャを貼るための流れは次の3ステップになります。

  1. マテリアルを作成
  2. マテリアルにテクスチャを設定
  3. モデルにマテリアルを設定

左ペインでAssetsの横の「+ボタン」をクリックして「Create New Material」を選択します。作成したマテリアル名は「bin_mat」に変更しておきましょう。

f:id:nn_hokuson:20180118195412j:plain:w400

次に作成したマテリアルにテクスチャを設定します。右ペイン(Unityで言う所のインスペクタ)から「Diffuse→Texture→Choose Files...」をクリックしてヒゲの画像を選択してください。

f:id:nn_hokuson:20180118195910j:plain

これで、マテリアルにテクスチャが設定できたので、最後にPlane(板ポリ)にマテリアルを設定します。左ペインからfacetracker0の子要素であるplane0を選択し、右ペインのMaterialの横の「+ボタン」をクリック、作成した「bin_mat」を選択します。

f:id:nn_hokuson:20180118195739j:plain

これで、画面上の人にヒゲがAR表示されたと思います!結構簡単じゃなかったですか?

f:id:nn_hokuson:20180118195751g:plain:w400

3Dオブジェクトを使ってARを表示する

次に帽子の3Dモデルを頭の上に表示してみましょう。3Dモデルのフォーマットは今のところ(2018年1月現在)「.dae」の必要があります。daeフォーマットはBlenderで書き出すことができます。

本記事で使用する帽子のモデルテクスチャは↓に置いておきます。自由にご利用下さい。

www.dropbox.com

先ほど、Planeを設定したときと同じようにして、facetracker0の上で右クリックし、「Insert」→「3D Object」を選択し、hat.daeをインポートします。

f:id:nn_hokuson:20180118200014j:plain

帽子のオブジェクトを読み込むとfacetracker0の子要素としてhat.daeが左ペインに表示されます。読み込んだ初期状態では帽子がかなり大きいと思います。

f:id:nn_hokuson:20180118200110j:plain

そこで、うまく頭の上に帽子がのるように、右ペイン(インスペクタ的なところ)でPosition、Scale、Rotationを調節して下さい。これらのパラメータ調整は真ん中のマニュピレータを操作することもできますし、インスペクタで設定することもできます。

f:id:nn_hokuson:20180118200458j:plain

最後に帽子のテクスチャを設定します。こちらもPlaneにヒゲ画像を表示したときと同じように、次の3ステップで進めます。

  1. マテリアルを作成
  2. マテリアルにテクスチャを設定
  3. モデルにマテリアルを設定

右ペインのAssets横の「+ボタン」を押し「Create New Material」を選択して下さい。できたマテリアル名を「hat_mat」に変更します。

f:id:nn_hokuson:20180118200606j:plain:w250

左ペインで「hat_mat」のマテリアルを選択した状態で、右ペインの「Diffuse→Texture→Choose Files...」をクリックし、hattex.pngを選択して下さい。

f:id:nn_hokuson:20180118201218j:plain

最後にhat.daeの子要素のCylinderを選択して、右ペインのMaterial欄に「hat_mat」を設定して下さい。これで帽子のモデルにテクスチャが表示されます。

f:id:nn_hokuson:20180118201223j:plain

これで帽子の3DモデルもAR表示することができました!

f:id:nn_hokuson:20180118201558g:plain:w300

まとめ

Unityで顔を使ったARを作ろうとすると、dlibやOpenCVなどのアセットを使うことになると思います。このAR Studioを使えば非常に簡単に顔を利用したARアプリケーションが作れることが分かりました。

【Arduino】BLE NanoでスマートフォンとBLE通信する

Arduinoとスマートフォンの間でデータのやり取りをしたい場合、Wifi通信を使う方法やBLE通信を使う方法が一般的です。ここではBLE Nanoと呼ばれるモジュールを使ってArduinoとiPhoneの間でデータ通信をしてみたいと思います。

f:id:nn_hokuson:20180110204246j:plain:w550

Wifiを使って通信をする場合はESP-WROOM-02というモジュールを使うのが簡単です。このモジュールの使い方は次の記事にまとめているので参考にして下さい。

nn-hokuson.hatenablog.com

今回の記事の内容は次のようになります。

BLEモジュールを選定する

Arduinoには標準ではBLEがついていないため、次の3つの方法のいずれかでBLEを使うことになります。

  • BLEつきのArduinoを使う
  • BLEモジュールをArduinoに追加する
  • BLEモジュールをArduinoとして使う

BLEつきのArduinoを使う

1つ目のBLE付きのArduinoですが、Genuino 101が有名ですが、既に生産を終了しており在庫限りのようです。(Genuino UnoにはBLEモジュールは搭載されていないので注意して下さい)使い勝手はArduinoと変わらないため便利ですが、4980円と少々お高いのがネックです・・・

akizukidenshi.com

もう少し安価な商品としてはBlunoやBLEduinoなどがあります。こちらは3800円程度でGenuino 101と比べると少しお安くなっています。

BLEモジュールをArduinoに追加する

こちらはArduinoに外付けでBLEモジュールを追加する方法です。スマートフォンと通信する場合は浅草ギ研のBLE Serialモジュールが良さそうです。ホームページでもスマートフォンとの接続方法やプログラムなども公開されており、簡単に始められます。お値段は4000円。

www.robotsfx.com

BLEモジュールをArduinoとして使う

最後の選択肢は、BLEモジュールをArduinoとして使う方法です。これはRedBearLabのBLE Nano キット V2を使用します。このモジュールはArduinoのエディタからプログラムを書き込むことができ、プログラムもArduinoと同じように作ることができます。この記事ではこのBLE Nanoを使ってスマートフォンと通信する方法を紹介します。BLE Nanoは2018年1月現在、SWITCH SCIENCEから3888円で販売されています。

www.switch-science.com

ArduinoでBLE Nanoを使う準備

BLE Nanoのキットを使うことで簡単にiPhoneやAndroidと通信するプログラムを作ることができます。BLE Nanoのキットはライター(DAPLink)とBLEモジュールの2つで構成されています。使用するときはライターから取り外してBLEモジュールのみで使うことができます。

f:id:nn_hokuson:20180110204915j:plain:w350

BLE Nano v2をArduinoの開発環境で使うために、まずはパッケージをインストールする必要があります。使用するパッケージはnRF52832用のもので、BLE Nano v1で使用しているnRF51822とは異なるので注意して下さい。

少し古いサイトだとnRF51822のパッケージを使用する方法がかかれていますが、このパッケージではBLE Nanoにプログラムを正しく書き込むことはできないので注意して下さい。

Arduinoを起動し、メニューバーから「Arduino→Preferences」を選択、追加のボードマネージャーのURLの欄に次のURLを入力して下さい。

https://redbear.github.io/arduino/package_redbear_nRF5x_index.json.

f:id:nn_hokuson:20180109210254j:plain:w550

続いてメニューバーから「ツール→ボード→ボードマネージャー」を選択して、ボードマネージャウインドウを開いて下さい。リストから「RedBear nRF52832 Boards」を選択し、インストールして下さい。

最後にメニューバーから「ツール→ボード」から「BLE Nano2」、「ツール→書き込み装置」から「RBL_DAPLINK」を選択します。

f:id:nn_hokuson:20180109214509p:plain:w250

これでBLE Nano v2を使う準備は完了です。いよいよArduinoとスマートフォンを繋ぐBLE通信システムを作っていきましょう!

今回作成するBLE通信システム概要

今回はBLE Nano(Arduino)がペリフェラル、iPhoneがセントラルになるようなシステムを作ります。ペリフェラル側(BLE Nano)のボタンを押したら、1byteのデータがセントラル(iPhone)に送信されます。

f:id:nn_hokuson:20180110205949p:plain:w400

ペリフェラル・セントラルというのはBLE通信でよく使われる言葉で、ペリフェラル=クライアント、セントラル=サーバみたいなものです。BLE通信の概要はクラゲのIoTテクノロジーさんの「開発視点の超簡単BLE入門」で非常にわかりやすく説明されているので、一度読んでおくと、BLE開発の主要な用語と流れがつかめると思います。

jellyware.jp

ペリフェラル側を作る

まずはBLE Nanoにペリフェラルのプログラムを書き込みましょう。Arduinoを開いて次のプログラムを入力してください。

#include <nRF5x_BLE_API.h>
#define DEVICE_NAME            "Simulated RFduino"
#define TXRX_BUF_LEN           20

BLE                            ble;
Timeout                        timeout;
Ticker                         ticker_task1;
int prev = HIGH;

static const uint8_t service1_uuid[]        = { 0x00, 0x00, 0x22, 0x20, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb } ;
static const uint8_t service1_tx_uuid[]     = { 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb } ;
static const uint8_t service1_rx_uuid[]     = { 0x00, 0x00, 0x22, 0x21, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb } ;
static const uint8_t service1_uuid_rev[]    = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x20, 0x22, 0x00, 0x00 } ;

uint8_t tx_value[TXRX_BUF_LEN] = {0,};
uint8_t rx_value[TXRX_BUF_LEN] = {0,};

GattCharacteristic  characteristic1(service1_tx_uuid, tx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE );
GattCharacteristic  characteristic2(service1_rx_uuid, rx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
GattCharacteristic *uartChars[] = {&characteristic1, &characteristic2};
GattService         uartService(service1_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));

void periodicCallback() 
{
  static uint8_t value = 0x30;
  
  int v = digitalRead(D2);
  if( v == LOW && prev == HIGH){
      ble.updateCharacteristicValue(characteristic2.getValueAttribute().getHandle(), (uint8_t *)&value, 1);
      value++;
  }
  prev = v;
}
    
void setup() 
{
  Serial.begin(9600);

  pinMode(D2, INPUT_PULLUP);
  ticker_task1.attach(periodicCallback, 0.1);

  ble.init();
  ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
  ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
                                   (const uint8_t *)"TXRX", sizeof("TXRX") - 1);
  ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
                                   (const uint8_t *)service1_uuid_rev, sizeof(service1_uuid_rev));

  ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
  ble.addService(uartService);
  ble.setDeviceName((const uint8_t *) DEVICE_NAME);
  ble.setTxPower(4);
  ble.setAdvertisingInterval(160);
  ble.setAdvertisingTimeout(0);
  ble.startAdvertising();
  Serial.println("Advertising Start!");
}

void loop() {
    ble.waitForEvent();
}

ここではサービスとキャラクタリスティクスのUUIDを次のように定義しました。

Service UUID 00002220-0000-1000-8000-00805f9b34fb
Characteristics1 00002221-0000-1000-8000-00805f9b34fb
Characteristics2 00002222-0000-1000-8000-00805f9b34fb

プログラムが書き込めたら、BLE Nanoを書き込み装置から取り外して、次のような回路を作成します。ここではボタンが押された場合にBLE NanoのD2端子がLOWになるようにしています。

f:id:nn_hokuson:20180110212157j:plain:w300

回路に電源を入れたらBLE Nanoはペリフェラルとしての動作を自動的に開始し、アドバタイズメントのパケットを送信しはじめます。

セントラル側をつくる

続いてスマートフォンで動くセントラルアプリを作成します。ここではUnityを使ってセントラル側のプログラムを作ります。iOS/Androidのネイティブプログラムでセントラルを作りたい場合は↓を参考にしてみてください。

Unityには、「Bluetooth LE for iOS, tvOS and Android」という超便利なアセットがすでに用意されています。これは、名前の通りiOSやAndroidのBLE通信コードをラップしたPluginです。C#だけでAndroidでもiOSでも簡単にBLE通信のプログラムを作ることができます。

ここでも、「Bluetooth LE for iOS, tvOS and Android」のアセットに付属するサンプルコードを使いましょう。上記アセットをインポートした後、Asset/Example/SimpleTestにある「SimpleTest.unity」をダブルクリックしてシーンを開いてください。

f:id:nn_hokuson:20180110202109j:plain:w600

SimpleTest.csがBLE通信のプログラムです。ヒエラルキービューでMain Cameraを選択し、インスペクタからSimple Testのパラメータを設定します。先ほどペリフェラルに書き込んだDevice Name、Service UUID、Characteristicを指定しましょう。ここでは次のように設定しました。

f:id:nn_hokuson:20180110202712p:plain:w300

UUIDは短縮で記述することができます。短縮する場合はUUIDの4文字目から8文字目までを指定します。サービスのUUIDは00002220-0000-1000-8000-00805f9b34fbですので、短縮で記述すると「2220」になります。UUIDの短縮についてはこちらもクラゲのIoTテクノロジーさんの「UUID詳細」が参考になります。

jellyware.jp

設定が完了したら、スマートフォンにアプリを書き込んでください。指定したService UUIDをアドバタイズしているペリフェラルに自動的に接続し、待機状態になります。待機状態になると次のような画面(左)がスマートフォン上に表示されます。

この状態でペリフェラル側のスイッチを押してみて下さい。スマートフォンに「30」と表示(画面右)されれば成功です!

f:id:nn_hokuson:20180110203342p:plain:w200     f:id:nn_hokuson:20180110203351p:plain:w200

トラブルシューティング

スマートフォン側が正しく動かない場合、まずはペリフェラルが動いているかをチェックしましょう。RedBear(BLE Nanoの開発元)からサンプルアプリが用意されているので、ちゃんとペリフェラルに接続できるか試してみると良いです。

iOS用

BLE Controller

BLE Controller

  • RedBear
  • ユーティリティ
  • 無料

Android用
play.google.com

おまけ:ネイティブプログラムを作りたい場合のオススメ

スマートフォンをセントラルとして動かすプログラムを作るにはiOSの場合はCore Bleutoothのリファレンスが参考になります。このCoreBluetoothのリファレンス、かなーりサンプルコードがしっかりと書かれているので、このとおり作っていけば簡単にセントラルのプログラムが作成できます。

https://developer.apple.com/jp/documentation/CoreBluetoothPG.pdf

iOS用にBLEの通信プログラムを作る場合は次の「iOSxBLE Core Bluetoothプログラミング」が非常に参考になりました。

iOS×BLE Core Bluetoothプログラミング

iOS×BLE Core Bluetoothプログラミング

また、AndroidでBLEの通信プログラムを作る場合はこちらのサイトが参考になります。

qiita.com