2016年6月24日金曜日

Android Wearな端末一覧

発売日は適当。国によって発売日が異なっていたりして。(それなりに世代順に並べられればなという程度。)

機種名 LG G Watch Samsung Gear Live Moto 360
(1st Gen)
LG G Watch R ZenWatch
(WI500Q)
SmartWatch 3 LG Watch Urbane Huawei Watch Moto 360
(2nd Gen)
ZenWatch2
(WI501Q/WI502Q)
LG Watch Urbane
2nd Edition
TAG Heuer
Connected
Moto 360 Sport Smart Outdoor Watch
WSD-F10
発売日 2014年6月25日 2014年6月25日 2014年9月5日 2014年11月12日 2014年11月21日 2014年11月28日 2015年4月27日 2015年9月2日 2015年9月14日 2015年11月13日 2015年11月12日 2015年11月12日 2015年12月18日 2016年3月25日
ディスプレイ 1.65-inch
IPS
1.63-inch
Super AMOLED
1.56-inch
IPS
1.3-inch
P-OLED
1.63-inch
Super AMOLED
1.6-inch
TFT
1.3-inch
P-OLED
1.4-inch
AMOLED
1.56-inch/1.37-inch
IPS
1.63-inch/1.45-inch
AMOLED
1.38-inch
P-OLED
1.5-inch
LTPS
1.37-inch
AnyLight Hybrid Display
1.32-inch
カラーTFT+モノクロ
形状 Square Square Round Chin Round Square Square Round Round Round Chin Square Round Round Round Chin Round Chin
解像度 280x280 320x320 320x290 320x320 320x320 320x320 320x320 400x400 360x330/360x325 320x320/280x280 480x480 360x360 360x325 320x300
CPU Snapdragon 400
1.2GHz
Snapdragon 400
1.2GHz
OMAP 3
1.0GHz
Snapdragon 400
1.2GHz
Snapdragon 400
1.2GHz
Snapdragon 400
1.2GHz
Snapdragon 400
1.2GHz
Snapdragon 400
1.2GHz
Snapdragon 400
1.2GHz
Snapdragon 400
1.2GHz
Snapdragon 400
1.2GHz
Atom Z34XX
1.6GHz
Snapdragon 400
1.2GHz
メモリ 512MB 512MB 512MB 512MB 512MB 512MB 512MB 512MB 512MB 512MB 768MB 1GB 512MB 512MB
ストレージ 4GB 4GB 4GB 4GB 4GB 4GB 4GB 4GB 4GB 4GB 4GB 4GB 4GB 4GB
Bluetooth 4.0 4.0 4.0 4.0 4.0 4.0 4.1 4.1 4.0 4.1 4.1 4.1 4.0 4.1
Wi-Fi - -
スピーカー - - - - - - - - - -
GPS - - - - - - - - - -
心拍数センサー - - - -
加速度センサー
ジャイロセンサー
磁気センサー - - - - -
光センサー - - - - - - - - -
気圧センサー - - - - - - -
防水/防塵 IP67 IP67 IP67 IP67 IP55 IP68 IP67 IP67 IP67 IP67 IP67 IP67 IP67 5気圧
その他 - - - - - - - - - - LTE/3G - - MIL-STD-810G

2016年6月22日水曜日

UnityでAmbisonicな録音を試みる

YouTubeさんのSpatial Audio(空間音声)対応を見かけて興味が湧いたところに

360 度動画や VR 動画で空間音声を使用する - YouTube ヘルプ
https://support.google.com/youtube/answer/6395969?hl=ja

こちらのブログ記事と出会ったのでUnityで試してみたメモ。

niu log: 4chサラウンドをAmbisonicsに変換する
http://niulog.blogspot.jp/2016/05/4chambisonics.html

環境

Unity 5.3.5
OS X Yosemite(10.10.5)
Soundflower 2.0b2

準備

4chサラウンドをAmbisonicに変換するということなので
Unityのオーディオ設定でサラウンドを使用するのですが(DefaultはStereo)
こちらの設定はPCのオーディオデバイスがStereo(2ch)出力だと
サラウンド設定が有効にならないようなので(Stereo(2ch)として出力される)
Soundflower(仮想オーディオデバイス)を使用しました。
※Soundflowerの導入方法はここでは割愛しますので、Web検索等で調べてください

Soundflowerがインストールされた状態でMacの[Audio MIDI 設定]を開き
サウンド出力装置をSoundflower(64ch)に変更します。
[出力]の[スピーカーを構成...]を開き



[マルチチャンネル]の[4チャンネル]に設定します。



Unityを起動し、AudioManager([Edit] -> [Project Settings] -> [Audio])の
[Default Speaker Mode]を[Quad]に設定します。



Quadは前左右、後左右の4chです。

Unity - スクリプトリファレンス: AudioSpeakerMode.Quad http://docs.unity3d.com/ja/current/ScriptReference/AudioSpeakerMode.Quad.html

※Unityは起動時にオーディオデバイスをチェックしているようなので
 Soundflowerの設定前に既にUnityを起動していた場合は再起動してください。

コード

wxyzチャネルの並び順は上記YouTubeさんのヘルプに
wyzx云々と書いてあったので(よく意味は分かっていない...)
その並びでWAVEファイルを作っています。

Unityのシーン内のオーディオをWAVEファイルに録音する方法は下記を
Writing AudioListener.GetOutputData to wav - problem | Unity Community
http://forum.unity3d.com/threads/writing-audiolistener-getoutputdata-to-wav-problem.119295/

また、WAVEファイルのヘッダ構造はこちらのサイトを参考にさせていただきました。
WAVEファイルの構造
http://www.graffiti.jp/pc/p030506a.htm

using UnityEngine;
using System;
using System.Collections;
using System.IO;

public class AmbisonicRecorder : MonoBehaviour
{
 private int outputRate = 44100;
 private string fileName = "output.wav";
 private int headerSize = 44;
 //default for uncompressed wav
 private int ambisonicChannels = 4;
 private bool recOutput;
 private FileStream fileStream;

 // Use this for initialization
 void Start ()
 {
  Debug.Log (AudioSettings.driverCapabilities);

  StartWriting (fileName);
  recOutput = true;
 }
 
 // Update is called once per frame
 void Update ()
 {
 }

 void OnDestroy ()
 {
  recOutput = false;
  WriteHeader ();
 }

 void OnAudioFilterRead (float[] data, int channels)
 {
  // Debug.Log("data.Length:" + data.Length + "/channels:" + channels);
  if (recOutput) {
   short[] shortData = new short[data.Length];
   //converting in 2 steps : float[] to short[], //then short[] to Byte[]

   byte[] bytesData = new Byte[data.Length * 2];
   //bytesData array is twice the size of
   //dataSource array because a float converted in short is 2 bytes.

   int rescaleFactor = 32767; //to convert float to short

   //Ambisonic
   int index = 0;
   for (int i = 0; i < data.Length; i += channels) {
    float frontL = data [i];
    float frontR = data [i + 1];
    float backL = data [i + 2];
    float backR = data [i + 3];

    float front = (frontL + frontR) / 2.0f;
    float back = (backL + backR) / 2.0f;
    float left = (frontL + backL) / 2.0f;
    float right = (frontR + backR) / 2.0f;

    float w = (frontL + frontR + backL + backR) / 4.0f;
    float x = front - back;
    float y = left - right;
    float z = 0.0f;

    // Debug.Log ("w:" + w + "/x:" + x + "/y:" + y + "/z:" + z);
    for (int j = 0; j < ambisonicChannels; j++) {
     float writeData = 0.0f;
     switch (j) {
     case 0:
      writeData = w;
      break;
     case 1:
      writeData = y;
      break;
     case 2:
      writeData = z;
      break;
     case 3:
      writeData = x;
      break;
     }
     byte[] bytes = new Byte[2];
     shortData [index] = (short)(writeData * rescaleFactor);
     bytes = BitConverter.GetBytes (shortData [index]);
     bytes.CopyTo (bytesData, index * 2);
     index++;
    }
   }

   if (!recOutput) {
    return;
   }
   fileStream.Write (bytesData, 0, bytesData.Length);
  }
 }

 private void StartWriting (string name)
 {
  fileStream = new FileStream (name, FileMode.Create);
  byte emptyByte = new byte ();

  for (int i = 0; i < headerSize; i++) { //preparing the header
   fileStream.WriteByte (emptyByte);
  }
 }

 private void WriteHeader ()
 {

  fileStream.Seek (0, SeekOrigin.Begin);

  byte[] riff = System.Text.Encoding.UTF8.GetBytes ("RIFF");
  fileStream.Write (riff, 0, 4);

  byte[] chunkSize = BitConverter.GetBytes (fileStream.Length - 8);
  fileStream.Write (chunkSize, 0, 4);

  byte[] wave = System.Text.Encoding.UTF8.GetBytes ("WAVE");
  fileStream.Write (wave, 0, 4);

  byte[] fmt = System.Text.Encoding.UTF8.GetBytes ("fmt ");
  fileStream.Write (fmt, 0, 4);

  byte[] subChunk1 = BitConverter.GetBytes (16);
  fileStream.Write (subChunk1, 0, 4);

  byte[] audioFormat = BitConverter.GetBytes (1); //Uncompressed PCM
  fileStream.Write (audioFormat, 0, 2);

  byte[] numChannels = BitConverter.GetBytes (ambisonicChannels);
  fileStream.Write (numChannels, 0, 2);

  byte[] sampleRate = BitConverter.GetBytes (outputRate);
  fileStream.Write (sampleRate, 0, 4);

  byte[] byteRate = BitConverter.GetBytes (outputRate * 2 * ambisonicChannels);
  // sampleRate * bytesPerSample*number of channels, here 44100 * 2 * 4
  fileStream.Write (byteRate, 0, 4);

  byte[] blockAlign = BitConverter.GetBytes (8);
  // 16bit * number of channels, here 16bit * 4 = 64bit = 8byte
  fileStream.Write (blockAlign, 0, 2);

  byte[] bitsPerSample = BitConverter.GetBytes (16);
  fileStream.Write (bitsPerSample, 0, 2);

  byte[] dataString = System.Text.Encoding.UTF8.GetBytes ("data");
  fileStream.Write (dataString, 0, 4);

  byte[] subChunk2 = BitConverter.GetBytes (fileStream.Length - headerSize);
  fileStream.Write (subChunk2, 0, 4);

  fileStream.Close ();
 }
}

使い方

AmbisonicRecorder.csをAudioListenerコンポーネントがアタッチされているGameObjectにアタッチします。

Unity EditorのPlay Mode開始〜終了まで録音します。

4ch前提で作っていますのでStart()内のDebug.Log()で
”Quad”とConsoleに表示されることを確認します。

作成されたWAVEファイルはプロジェクトディレクトリ直下に
output.wavというファイル名で出力されます。

プレビュー

プレビューにはJump Inspectorを使用しました。



Jump InspectorはGoogleさんがPlay Storeのベータプログラムで公開している
360度動画ビューアーアプリでSpatial Audioにも対応しています。
因みにSpatial Audioなオーディオファイルのみでもプレビュー可能。
対応端末が
・Samsung Galaxy S6
・Nexus 6P
なのが。。(その他の端末で動かないのかは試してません)

Jump Inspector Overview - Jump Help https://support.google.com/jump/answer/6400241?hl=en
※Play Storeのベータプログラムとして公開されているのでベータ登録が必要です。

デモ

作成したVR動画をYouTubeにアップしました。
音源が付いた車が自分の周りをぐるぐる回ります。
※デモが微妙でゴメンナサイ。。
因みに、この記事を書いている時点でYouTubeの空間音声が体験できるのは
バージョン 4.2 以降の Android 端末で YouTube Android アプリを利用している
場合のみとなっています。
ヘッドフォン・イヤフォンを付けて視聴してみてください。
どうですかね、音の聞こえ方。

2015年5月15日金曜日

Oculus Mobile SDK Unity IntegrationのProjectSettingsを差分ツールで眺めてみた


はじめに

 新規プロジェクトの場合はプロジェクト作成時に忘れないようにProjectSettingsを上書きすれば良いですが、既存プロジェクトをGear VRに移植する場合は既存のProjectSettingsにOculus Mobile SDK Unity IntegrationのProjectSettingsの設定を適用したいケースもあるかと思い調べてみました。

環境

Oculus Mobile SDK 0.5.1
Unity 4.6.5p1

調査方法

 Unity 4.6.5p1で新規作成したプロジェクトのProjectSettingsとOculus Mobile SDK Unity IntegrationのProjectSettingsを差分ツールで比較。
※Oculus Mobile SDK Unity IntegrationのProjectSettingsはUnity 4系のものであると思われるため、Unity 5ではなくUnity 4.6.5p1と比較
※新規作成したプロジェクトのProjectSettingsディレクトリ配下のファイルはバイナリ形式であるため[Edit] - [Project Settings] - [Editor]の[Asset Serialization]のModeを[Force Text]に変更してから差分ツールで比較を実施
※Oculus Mobile SDK Unity IntegrationのProjectSettingsはテキスト形式

差分

・InputManager.asset
 [Edit] - [Project Settings] - [Input]
  ここは上書きでも良いかなと思うので割愛

・TagManager.asset
 [Edit] - [Project Settings] - [Tags and Layers]
  Layers
   User Layer 8:IgnoreBlobShadow

・QualitySettings.asset
 [Edit] - [Project Settings] - [Quality]
  ここは上書きでも良いかなと思うので割愛

・EditorSettings.asset
 [Edit] - [Project Settings] - [Editor]
  Version Control
   Mode:Visible Meta Files(Gear VRと特に関係無さそう)
  Sprite Packer
   Mode:Disabled

・NavMeshAreas.asset
 Oculus Mobile SDK側にのみ存在

・ProjectSettings.asset
 [Edit] - [Project Settings] - [Player]
  ここは上書き後に必要な項目を修正した方が効率良さそうなので割愛
  Company Name/Product Name/Icon/Bundle Identifier等

まとめ

Input/Quality/Player設定の上書きが許容できるのであれば、差分はそんなに多くない。

2015年4月2日木曜日

360度動画の底にロゴを表示する

環境

・Mac
・Blender 2.74
・Premiere Pro CC 2014

手順

1. Cycles Renderに切り替え


2. Lensの設定
 カメラを選択して
 [Panoramic]
 Typeを[Equirectangular]
 に設定


3. Circleを作成
 3D View上で[shift]+[A]
 [Mesh]-[Circle]


 円を滑らかにするために[Vertices]を256
 デフォルトでは面が無いので[Fill Type]を[Triangle Fan]にして面を作成



4. UV展開
 作成したCircleを選択した状態で[tab]キーでEdit Modeへ
 [UV Mapping]で[Cube Projection]を選択


5. マテリアル作成
 [New]からマテリアルを作成


 [Color]の右端のボタンをクリック
 [Image Texture]を選択


 ロゴ画像を指定


 画像はみかんにゃさんの「ずん子マーク2」を使わせて頂きました。
 【ずんきょ】みかんにゃさんのイラストを追加しました! | 東北ずん子ポータル
  http://t-zunko.moe/2015-03-11-mikannya

 3D ViewのViewport Shadingを[Material]に変更


 テクスチャが表示されるとこんな感じ


6. カメラの位置・角度調整
 カメラを選択してスクリーンショットの通りに位置・角度を調整
 ※このメニューは3D Viewで[N]キーを押すと表示される


7. ライトの位置・角度調整
 ライトを選択してスクリーンショットの通り位置・角度を調整


8. レンダリング解像度と透過の設定
 解像度を設定
 ロゴ以外の部分は透過でレンダリングして動画に合成したいので
 [Film]の[Transparent]にチェック



9. レンダリングと画像書き出し
 レンダリング実行


[F3]キーで画像を書き出し


10. Premiereで合成
 Blenderで書き出したロゴをPremiereのタイムラインにドラッグ&ドロップ
 動画の尺にロゴ画像を合わせる


仕上がり

アキバ ホコ天(2015.03.22) | ハコスコストア


最後に

 Blender Lv.1なのでツッコミお待ちしております。
 そもそも、Blender使わなくてももっと簡単に出来るよ!とかあれば教えてください。

2015年3月26日木曜日

AndroidなUnityのGamepad for Nexus Player キーアサイン

環境

Unity 5.0.0p2
Nexus 5(Android 5.1)

キーアサイン

joystick button 0(Fire1)
A
joystick button 1(Fire2)
B
joystick button 2(Fire3)
X
joystick button 3(Jump)
Y
joystick button 4
L1
joystick button 5
L2
X axis
Analog Stick Left ←→
Y axis
Analog Stick Left ↑↓
3rd axis
Analog Stick Right ←→
4th axis
Analog Stick Right ↑↓
5th axis
←→
6th axis
↑↓
7th axis
L2
8th axis
R2

因にペアリングをクリアして他の端末とペアリングしたい時は
電源ONの状態で「戻る」ボタンと「ホーム」ボタンを押しながら
「電源」ボタンを長押しのようです。
そうするとLEDx4が点滅に変わってペアリング待ちの状態になりました。

Unity Remote 4経由でゲームパッドの入力取れたらデバッグ楽かな
と思って試してみたけど出来ないようです。

2014年7月25日金曜日

Android StudioでUnityのNative Plugin(jar)をつくる

Gradleについてあまり詳しくないですが、とりあえずHello World的なものが動いたのでメモ。

環境

OS X Mavericks 10.9.4
Android Studio (Beta) 0.8.2
Unity 4.5.2f1

空のプロジェクトを作成

Android Studioで[Add No Activity]を選択して空のプロジェクトを作成。

jarファイルの追加


classes.jarファイルをプロジェクトのlibsフォルダにコピー。
Macの場合のパス
<Unityインストールディレクトリ>/Unity.app/Contents/PlaybackEngines/AndroidPlayer/release/bin/classes.jar

android.jarファイルをプロジェクトのlibsフォルダにコピー。
パス
<Android SDK Root>/platforms/android-19/android.jar
※今回はAndroid 4.4のjarを使用

Sync Project with Gradle Files


Native Plugin側のコード

<Project Root>/app/src/main/java/<Package Name>/配下にJava Classを新規作成。
適当にToastを表示するだけのプラグインを作成。

package com.example.unityplugin;

import android.app.Activity;
import android.widget.Toast;

import com.unity3d.player.UnityPlayer;

public class AndroidNative {
    public static void showToast() {
        final Activity activity = UnityPlayer.currentActivity;
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(activity, "Hello Native Plugin!", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

build.gradleの編集

// apply plugin: 'com.android.application'
apply plugin: 'java'

jar.baseName = 'android-native-plugin'
version = '1.0.0'

//android {
//    compileSdkVersion 20
//    buildToolsVersion "20.0.0"
//
//    defaultConfig {
//        applicationId "com.example.unityplugin"
//        minSdkVersion 15
//        targetSdkVersion 20
//        versionCode 1
//        versionName "1.0"
//    }
//    buildTypes {
//        release {
//            runProguard false
//            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//        }
//    }
//}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
}

jarファイルの作成

Android StudioのTerminalを開き下記のコマンドを実行。
./../gradlew jar


jarファイルは下記のディレクトリ配下に作成される。
<Project Root>/app/build/libs/

作成したjarファイルをUnityプロジェクトのAssets/Plugins/Android/ディレクトリ配下に配置。

呼び出し側コード

using UnityEngine;
using System.Collections;

public class Toast : MonoBehaviour {

 // Use this for initialization
 void Start () {
  AndroidJavaClass androidNativePlugin = new AndroidJavaClass("com.example.unityplugin.AndroidNative");
  androidNativePlugin.CallStatic("showToast");
 }
 
 // Update is called once per frame
 void Update () {
 
 }
}

動作確認


2014年3月28日金曜日

Unreal Engine 4でFPSを表示する方法


[`]キーで画面下部にプロンプトが表示されるので
表示されたプロンプトに「Stat FPS」と入力する。
※プロンプトでのコマンド入力時はTABキーで補完が使える


Editor上でPlay中は右上のEnter console commandと表示されているところに「stat fps」と入力する。