おもちゃラボ

Unityで遊びを作ってます

【Unity】Unity5.6で綺麗な画面を作るための5つの手順

Unityでキレイな画作りをしたいときの、基本的な設定手順を5つに分けて紹介します。Cinematic Filterやカラースペースの変更は処理が重いので、スマートフォン向けではないかもしれません。

f:id:nn_hokuson:20170410191838j:plain

完成までのステップは次のようになります。

手順1 オブジェクトを配置する

シーンビューにオブジェクトを配置してから、マテリアルを作成&設定します。マテリアルの設定は、基本的にMetalicとSmoothnessで調整します。
このままでは、「ただ配置した感」が拭えませんね・・・

f:id:nn_hokuson:20170410192000j:plain

上の金色とピンクゴールドの玉の設定は次のようにしてみました。

f:id:nn_hokuson:20170410192037p:plain:w280 f:id:nn_hokuson:20170410192045p:plain:w270

金属っぽい見た目にしたい場合は次のページが参考になります。
blogs.unity3d.com

手順4でライトをベイクするため、動かないオブジェクトはインスペクタから「static」を設定しておきましょう。

f:id:nn_hokuson:20170410192211p:plain:w350

手順2 カラースペースをリニアにする

カラースペースをGanmmaからLinearに変更します。カラースペースについては次のページが参考になります。
docs.unity3d.com

f:id:nn_hokuson:20170410200726j:plain

カラースペースを変更するには、メニューバーから「Edit」→「Project Settings...」→「Player」を選択し、インスペクタから「Other Settings」→「Color Space」を「Linear」に変更します。

f:id:nn_hokuson:20170410200545p:plain:w350

カラースペースを変更した結果は次のようになります。

f:id:nn_hokuson:20170410193453j:plain

手順3 スカイボックスを設定する

金属などの反射をキレイに見せるためには反射する映像が必要です。反射映像としてスカイボックスを設定します。スカイボックスはAsset Storeやサイトで配布されているので、それを利用しましょう。

www.hdrlabs.com

ダウンロードしたスカイボックスをプロジェクトビューに追加し、インスペクタから「Texture Shape」を「Cube」に変更します。

f:id:nn_hokuson:20170410193551p:plain:w300

続いてプロジェクトビューで新規にマテリアルを作成し、それをSkybox用のマテリアルとして設定します。インスペクタの「Shader」の欄から「Skyboxy/CubeMap」を選択して、CubeMap(HDR)の欄に先程の天球画像を設定します。

f:id:nn_hokuson:20170410193827j:plain:w300

作成したマテリアルをシーンビューにドラッグ&ドロップすると、作成したスカイボックスが表示されます。

f:id:nn_hokuson:20170410193917j:plain

球への映り込みも反映されて、だいぶん絵として落ち着いてきました。でも、まだ影が浮いている感じがしますね〜

手順4 アンビエントオクルージョンを表現する

アンビエントオクルージョン(影になる暗いところをしっかりと暗くする)を表現するため、ライトをベイクします。(ベイクの主目的はライティング負荷の軽減ですけど・・・^^;)

ライトを焼く対象はStep1で「static」に設定したオブジェクトです。ちゃんとstaticに設定されているか確認しておきましょう。

続いて、ライトの設定をベイク用の設定に変更します。Directional Lightのインスペクタから「Mode」を「Mixed」に設定します。

f:id:nn_hokuson:20170410194042p:plain:w350

ライトをMixedに設定することで、staticオブジェクトの影を焼き、動くオブジェクトの影はリアルタイムで計算する、という折衷案を実現できます。ちなみに・・・ライトのタイプをBakedに設定すると、リアルタイムで動くオブジェクトの影は表示されません。

メニューバーから「Window」→「Lighting」→「Settings」を選択し、Lightingウインドウを表示してください。
設定するのは次の3点です

  • Ambient Occlusionのチェックを入れる
  • IndirectContributionを設定する
  • DirectContributionを設定する

f:id:nn_hokuson:20170410194101p:plain:w450

こちらの記事でもAmbient Occlusionの設定について紹介しています。
nn-hokuson.hatenablog.com

アンビエントオクルージョンの設定をした後の画像がこちらになります。オブジェクトと床が接する部分や、球の間の空間が他の部分と比べるとさらに暗くなっています。

f:id:nn_hokuson:20170410194431j:plain

手順5 Cinematic Image Effectを使う

Unity5.6からは標準のEffectパッケージが廃止されたため、Asset Storeからダウンロードする必要があります。Unityが標準で提供しているエフェクトのアセットには

・Legacy Image Effect
・Cinematic Image Effect

があるようです。

ここでは後者のシネマティックイメージエフェクトのアセットを使ってみます。

f:id:nn_hokuson:20170410194719j:plain

ダウンロードしたCinematic Image Effectの中からBloomとTonemappingスクリプトをMain Cameraにアタッチしてください。

それぞれのエフェクトのパラメータはインスペクタから調整します。ここは、どのような絵にしたいかによって設定が変わってきます。色々と試してみてくださいね!

f:id:nn_hokuson:20170410194822p:plain:w250  f:id:nn_hokuson:20170410194827p:plain:w250

また、Bloomについてはこちらの記事で紹介しています。合わせてどうぞ。
nn-hokuson.hatenablog.com

最終的な画像はこちらになります!
f:id:nn_hokuson:20170410191838j:plain

【Arduino】ESP-WROOM-02( ESP8266 )を使ってWifiで無線通信する

マイコンを使って無線通信をする、となると一昔前までは非常に大変だったのですが、最近は便利なモジュールが安価で販売されているようです。この記事ではESP-WROOM-02と呼ばれる無線モジュールを使った無線通信の実験をしてみましょう。

f:id:nn_hokuson:20170409091121j:plain

この記事の目次は次のようになります。

無線通信のシステム構成

今回作るArduinoを使った無線通信システムの全体的な構成は次のようになります。

f:id:nn_hokuson:20170409075115p:plain:w300

ArduinoからサーバにGETでデータを送信し、サーバ側ではPHPを使ってデータを受け取ってから保存します。受け取ったデータはブラウザから確認できるようにします。

ESP-WROOM-02を使った通信に必要なものを揃える

ESP-WROOM-02

Arduino Unoでwifiを使った無線通信をするためには、無線通信用のモジュールが必要になります。

スイッチサイエンスなどから非常に安価なモジュールが販売されているため、それを利用します。今回使用したモジュールは次のESP-WROOM-02です。

ESP-WROOM-02はESP8266という無線チップを実装したモジュールになります。スイッチサイエンスからはシンプル版やフル版が販売されていますが、ここでは簡単に使えるシンプル版を使います

3端子レギュレータ

また、ESP-WROOM-02には3.3Vの電源供給が必要になります。Arduinoにも3.3Vのポートが用意されていますが、供給できる電流値が少ないため使えません。

5Vから3.3Vの電源を作るために3端子レギュレータが追加で必要になります。秋月のセットであれば、必要になるキャパシタとセットで販売されています。

f:id:nn_hokuson:20170408153422p:plain:w240
http://akizukidenshi.com/catalog/g/gI-00538/

レベルシフタ

ArduinoとESP-WROOM-02はシリアルで通信します。上にも書いたとおりESP-WROOM-02は3.3Vで動作するため、Arduinoとシリアル通信に入力するには3.3V↔5Vを変換する双方向レベルシフタが必要になります。

実はレベルシフタがなくても動作しますが、データの受信時に不安定になる傾向があります。今回はESP-WROOM-02からはデータの送信しかしないため、レベルシフタは使用していません。

wifi通信のための回路図

ArduinoとESP-WROOM-02を接続する回路図は次のようになります。
f:id:nn_hokuson:20170614231708j:plain

初期設定

ArduinoとESP-WROOM-02間の通信はソフトウエアシリアル通信を使います。ESP-WROOM-02が初期状態では115200bpsで通信するのに対して、Arduinoのソフトウエアシリアルの最高速度は9600bpsです。

このままでは安定した通信ができないため、ESP-WROOM-02の通信速度を9600bpsまで下げる必要があります。まずは次のスケッチを作成してArduinoに転送して下さい。

#include <SoftwareSerial.h>

SoftwareSerial mySerial(2, 3); // RX, TX

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  Serial.println("Goodnight moon!");

  // set the data rate for the SoftwareSerial port
  mySerial.begin(115200);
  mySerial.println("Hello, world?");
}

void loop() { // run over and over
  if (mySerial.available()) {
    Serial.write(mySerial.read());
  }
  if (Serial.available()) {
    mySerial.write(Serial.read());
  }
}

転送できたら、右上のシリアルモニタボタンをクリックして、シリアルモニタを開いて下さい。

f:id:nn_hokuson:20170408155735p:plain
シリアルモニタウインドウの右下の改行コードを「CRおよびLF」、転送レートを「112500」に変更します。

f:id:nn_hokuson:20170408160013p:plain:w300

すると、シリアルモニタに次のように表示されると思います。表示されない場合はArduinoのリセットボタンを押してみて下さい。

Goodnight moon!
Hello, world?

これに続けて次のコマンドを入力して、送信ボタンを押します。

AT+UART_DEF=9600,8,1,0,0

シリアルモニタの画面上にOKが表示されれば、設定は完了です。

ESP8266のライブラリをインストール

まずはESP8266を動かすためのライブラリをインストールしましょう。
ライブラリを↓からダウンロードしてください。

www.dropbox.com

ダウンロードしたライブラリをインストールします。

Arduinoのメニューから「スケッチ」→「ライブラリをインクルード」→「.ZIP形式のライブラリをインストール」を選択し、ダウンロードしたITEADLIB_Arduino_WeeESP8266-masterをインストールします。

上記ライブラリは、本家で提供されているライブラリを修正し、ソフトウエアシリアルを使えるようにしたものです。
github.com

無線通信プログラムの作成

ではいよいよ、データを送信するためのプログラムの作成を作りましょう。次のプログラムを入力して下さい。

#include "ESP8266.h"
#include <SoftwareSerial.h>

#define SSID "Buffalo-G-XXXX"
#define PASSWORD "xxxxxxxxxxxxx"
#define HOST_NAME "192.168.xx.xx"
#define FILE_NAME "test.php"

int n = 0;

SoftwareSerial mySerial(2, 3);  //RX, TX
ESP8266 wifi(mySerial);

/**
 * 初期設定
 */
void setup(void)
{
  Serial.begin(9600);

  if (wifi.setOprToStationSoftAP()) {
    Serial.println("to station ok");
  } else {
    Serial.println("to station error");
  }

  if (wifi.joinAP(SSID, PASSWORD)) {
    Serial.println("connect success");
  } else {
    Serial.println("connect error");
  }

  if (wifi.disableMUX()) {
    Serial.println("disable mux success");
  } else {
    Serial.println("disable mux error");
  } 
}

void loop(void)
{
  n++;

  // TCPで接続
 wifi.createTCP(HOST_NAME, 80);
  
  // サーバーへ渡す情報
 char sendStr[128];
 sprintf(sendStr, "GET /%s?data=%d HTTP/1.0\r\nHost: %s\r\nUser-Agent: arduino\r\n\r\n", FILE_NAME, n, HOST_NAME);
 wifi.send((const uint8_t*)sendStr, strlen(sendStr));

  Serial.println(n);

  delay(100);
 }

SSIDとPASSWORDの欄にはお使いのルータのSSIDとパスワードを入力して下さい。HOST_NAMEの欄には、次のステップで作成するPHPファイルを置くサーバのホスト名を入力します(お使いのMacをサーバーにする場合は、自分のMacのIPアドレスを入力して下さい)

作成したプログラムをArduinoに転送して実行してみて下さい。シリアルモニタを起動して次のように表示されたらルータとの接続は成功です。転送速度を9600bpsに設定するのを忘れないようにしてくださいね〜

f:id:nn_hokuson:20170409084813j:plain:w400

サーバー側のプログラムを作っていないため、データを送信する部分は失敗します。

サーバー側のプログラムを作る

最後にArduinoから送信されたデータをサーバで受け取るプログラムを作りましょう。

f:id:nn_hokuson:20170409091847p:plain:w300

サーバー側のプログラムはPHPで作成しています。次のプログラムを入力して「test.php」という名前で保存して下さい。

<?php
$data = $_GET['data'];
if($data=='a'){
    $fp = fopen("data.txt", "r");
    $contents = fread($fp, filesize($filename));
    print($contents);
    fclose($fp);
}
else
{
    $fp = fopen("data.txt", 'w');
    fwrite($fp,  $data);
    fclose($fp);
}
?>

このプログラムはGETで送られてきたデータが

  • 「a」だったら保存しているデータをブラウザ上に表示し
  • 「a」以外だったらそのデータをファイルに書き込む

という、超適当なものです(^^;;)

今回は自宅のMacをサーバーとして使うので、上記ファイルを/Library/WebServer/Documents/フォルダ(Macの場合)に保存します。Macをお持ちではない場合は、お使いのサーバにアップロードしておいて下さい。

Macをサーバーとして動かすためには次の手順が必要になります。

  1. httpd.confの修正
  2. Apacheの起動
  3. ファイルの配置

この手順は次のサイトに詳しくまとめられていましたので、参考にして下さい。
qiita.com

動かしてみる

これですべての要素が整いました。Arduinoのリセットボタンを押してプログラムを再起動してシリアルモニタを確認してみましょう。次のように表示されていれば、ESP-WROOM-02からのデータ送信は成功です。

f:id:nn_hokuson:20170409085329j:plain:w500

次にブラウザからサーバのプログラムにアクセスし、ちゃんとデータが送られてきているかを見てみましょう。

f:id:nn_hokuson:20170409092152p:plain:w300

ブラウザのアドレスバーには次のように入力してアクセスして下さい。

192.168.xx.xx/test.php?data=a

次のように表示されていれば受信も成功です!ESP-WROOM-02から正常にデータが送信されていれば、ページをリロードするとどんどん数字が増加していくはずです。

f:id:nn_hokuson:20170409082927p:plain:w300

まとめと参考

ESP-WROOM-02とArduinoを使った無線通信の実験をしました。無線通信と聞くと難しく感じられるかもしれませんが、安価に始められるので是非挑戦してみて下さいね!

以下は参考にさせていただいた記事です。
https://ics.media/entry/10457/2ics.media
www.mgo-tec.com
www.qoosky.io

[asin:4798046604:detail]
[asin:4873117895:detail]

【Unity】Animatorでステートが遷移するタイミングを検知する

Animatorを使っていると、あるステートから別のステートへ遷移したタイミングを検知して、アクションを起こしたいことがあります。

例えばジャンプアニメーションが終了して着地したタイミングで効果音を鳴らしたいとか、カメラを振動させたい、といった場合です。

このような場合はStateMachineBehaviourというコールバック用のスクリプトを使うと便利です。

f:id:nn_hokuson:20170407193927p:plain

StateMachineBehaviourの使い方

StateMachineBehaviourはAnimatorにアタッチして使う専用のスクリプトです。ここでは2Dユニティちゃんのサンプルを使って、ジャンプ終了のタイミングを検知してみます。まずはAnimatorを開くと次のような構成になっています。

f:id:nn_hokuson:20170407194657p:plain

Animatorにスクリプトをアタッチするため、ウインドウ右側のインスペクタに表示されている「Add Behaviour」をクリックして、スクリプトをアタッチしてください。

f:id:nn_hokuson:20170407194625p:plain

作成したスクリプトをプロジェクトビューから開くと、次のコールバック関数がコメントアウトされています。

  • OnStateEnter
  • OnStateExit
  • OnStateMachineEnter
  • OnStateMachineExit
  • OnStateMove
  • OnStateUpdate
  • OnStateIK

よく使うのは、OnStateEnterとOnStateExitです。これらはそれぞれ、ステートに入ったときとステートから出たときに呼び出されるコールバック関数です。

OnStateMachineEnter/Exitはそれぞれスクリプトをアタッチしたアニメーションレイヤに入ったときと出たときに呼び出されます。

StateMachineBehaviourから別のメソッドを呼び出す

ジャンプが終了したタイミングでカメラを振動させたいので、ステートが終了したときに呼び出されるOnStateExitメソッドを使います。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StateController : StateMachineBehaviour {
    // OnStateExit is called before OnStateExit is called on any state inside this state machine
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
        if (stateInfo.IsName ("JumpDown"))
        {
            Camera.main.GetComponent<CameraShaker> ().Shake ();
        }
    }
}

ここでは、ジャンプが終了したタイミング(JumpDownステートを抜けるタイミング)を検知するため、AnimatorStateInfoのIsNameメソッドを使って、現在のステートがJumpDownステートかどうかを調べています。

JumpDownであれば、カメラオブジェクトにアタッチしたCameraShakerスクリプトのShakeメソッドを呼び出しています。

カメラを振動させるスクリプトをアタッチする

ユニティちゃんがジャンプし終わったときに呼び出すスクリプトを作ります。
カメラを振動させるスクリプトは次のようになります。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraShaker : MonoBehaviour {
    IEnumerator _Shake() {
        for (int i = 0; i <= 360 * 1; i += 60) {
            float y = 0.2f*Mathf.Sin (i * Mathf.Deg2Rad);
            transform.position = new Vector3 (0, y, -10);
            yield return null;
        }
    }
    public void Shake() {
        StartCoroutine (_Shake ());
    }
}

これをヒエラルキービューのMainCameraにアタッチしておきましょう。

f:id:nn_hokuson:20170407194844j:plain

実行結果

実行結果は次のようになります。ジャンプの終了のタイミングでちゃんと画面が振動していますね。

f:id:nn_hokuson:20170407194853g:plain
© Unity Technologies Japan/UCL