仮想空間VR:AIThirdPersonControllerをあれこれいじってみた

こんにちは (‘ω’)ノかずまなぶ です。

わたしのVR空間にだんだんと人が集まってきました。紹介します。

アイドルのおっかけ

  1. 先日紹介しました、アイドルのおっかけです。ユニティちゃんはロコモーションなのでPCのキーボードで自由に動けるのですが、それをずっと追っかけていきます。
  2. おっかけはAIThirdPersonControllerプレハブでAICharacterControlスクリプトのTargetをWalkTargetに設定しています。
  3. walkTargetはEmptyの名前を変えただけのオブジェクトです。追跡対象であるユニティちゃんの子オブジェクトにいれています。
  4. 言い換えれば、おっかけはユニティちゃんではなく、ユニティちゃんの保有するWalkTargetオブジェクトに反応しているのです。
  5. 星白しずかのエナがいつもカビザシを見つめているような感じです。ランカ・リーのVウィルスだったり、バサラのアニマスピリチアだったりもします。解らなかったらスルーしてください。

石盤のおっかけ

  1. アイドルのおっかけを改良して、追跡対象をユニティーちゃんから、地面を這う石盤に変更した「石盤のおっかけ」です。
  2. ユニティちゃんのときは追跡対象のユニティちゃんの中にTargetを入れていましたので、今回は石盤(cylinderオブジェクト)にTargetを入れていると普通は思いますが、違います。
  3. AIThirdPersonControllerプレハブのAICharacterContorolスクリプトのTargetをWalkTarget_lookMoveToオブジェクトにし、LookMoveToスクリプトを適用しています。
  4. LookMoveToスクリプトでは、カメラ目線の始点座標とベクトルを調べ、そのベクトルの延長上に何かしらのオブジェクトがあり、それが地面(変数ground)だったら、その座標にWalkTarget_lookMoveToオブジェクトを移動させるのです。変数GroundにはInspectorパネルからGroundPlaneを適用します
  5. そして、目線によって任意に動かすことができるようになったWalkTarget_lookMoveToオブジェクトに対してはcylinderオブジェクトという実体を与えて(子にして)、目で見ることができるようにしました。
  6. ゲームを実行してみると、目線の先に常に石盤がいるかと思います。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LookMoveTo : MonoBehaviour
{
public GameObject ground;//ゲームオブジェクト型の変数groundを定義
// Use this for initialization
void Start() { }
// Update is called once per frame
void Update()
{
Transform camera = Camera.main.transform;//アクティブなカメラの座標を得る。
//MainCameraというタグを探しに行くのでInstectorでタグの設定をすること
Ray ray;//レイとして表現(始点とベクトル)。変数名ray と定義する
RaycastHit[] hits;//追加
GameObject hitObject;
Debug.DrawRay(camera.position, camera.rotation * Vector3.forward * 100.0f);//レイが描かれるはずだが、見えない?
ray = new Ray(camera.position, camera.rotation * Vector3.forward);//カメラの座標, 3軸回転角度*単位ベクトル。見ている方向Rayを定義
hits=Physics.RaycastAll(ray);//追加
for (int i = 0; i < hits.Length; i++)//追加
{
RaycastHit hit = hits[i];//追加
hitObject = hit.collider.gameObject; //hit.colider.gameObjectにそのオブジェクトが入る
if (hitObject == ground)//もし、顔をさげてRayが衝突したオブジェクトhitObjectがgroundだったら実行する。
//途中にground以外のオブジェクトがあったら条件を満たさない。
{
Debug.Log("Hit(x,y,z): " + hit.point.ToString("F2"));//デバックログ。衝突した座標hit.pointをコンソールに表示
//ToString:ベクトルを文字列として出力
transform.position = hit.point;//衝突した座標を 移動目標の座標とする
}
}
}
}

うろちょろゾンビ

  1. ランダムに出現する見えないターゲットに向かってひたすら歩き続けます。ターゲットは5秒間隔で移動します。
  2. AIThirdPersonControllerプレハブのAICharacter ControlのTargetにWalkTarget_Randomオブジェクトを適用する。
  3. WalkTarget_RandomオブジェクトはRandomPositionスクリプトを持ちます。
  4. RandomPositionスクリプトがWalkTarget_Randomオブジェクトの座標を移動させます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RandomPosition : MonoBehaviour {
// Use this for initialization
void Start () {
StartCoroutine(RePositionWithDelay());
}
IEnumerator RePositionWithDelay()
{
while (true)
{
SetRandomPosition();
yield return new WaitForSeconds(5);
}
}
void SetRandomPosition()
{
float x = Random.Range(-5.0f, 5.0f);
float z = Random.Range(-5.0f, 5.0f);
Debug.Log("X,Z: " + x.ToString("F2") + "," + x.ToString("F2"));
transform.position = new Vector3(x, 0.0f, z);
}
// Update is called once per frame
void Update () {
}
}

バイツァーダストの被害者

  1. 目線を合わせると、赤いパーティクルが体を包み3秒後に爆死!します。
  2. 何回でもリスポーンしますので、タイミングよくバイツァーダスト!と叫びましょう。要練習です。
  3. AIThirdPersonControllerプレハブのThirdPersonCharacterスクリプトには何もいれません。こいつは特になにかの目標に向かって移動する知能は与えていません。爆死能力だけです。AudioSourceに爆発音だけ入れましたが、機能していません。(課題です)
  4. EmptyからGameControllerを作ります。killTargetスクリプトとAudioSource爆発音をコンポーネントとして追加しました。AIThirdPersonControllerプレハブの中にGameControllerを入れておきましょう。
  5. killTargetスクリプトにはTarget , Hit Effect , Kill Effect , Time To Select , Score、といったいろいろなものをセッティングできるようにしました。
  6. killTargetスクリプトでは、カメラ目線をレイとし、レイが変数targetに当たっていたら、当たっている座標にEffiectを出し、設定時間経過後にkillEffectを出し、そのあとに新しい座標にリスポーンします。
爆死!(; ・`д・´)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class killTarget : MonoBehaviour {
public GameObject target;
public ParticleSystem hitEffect;
public GameObject killEffect;
public float timeToSelect = 3.0f;
public int score;
private ParticleSystem.EmissionModule hitEffectEmission;
private float countDown;
// Use this for initialization
void Start () {
score = 0;
countDown = timeToSelect;
hitEffectEmission = hitEffect.emission;
hitEffectEmission.enabled = false;
}
// Update is called once per frame
void Update() {
Transform camera = Camera.main.transform;
Ray ray = new Ray(camera.position, camera.rotation * Vector3.forward);
RaycastHit hit;
if(Physics.Raycast(ray,out hit) && (hit.collider.gameObject == target))
{
if (countDown > 0.0){
//レイがターゲットに当たった時の処理
countDown -= Time.deltaTime;
hitEffect.transform.position = hit.point;
hitEffectEmission.enabled = true;
}else{
//殺された時の処理
GetComponent<AudioSource>().Play();//Playメソド
Instantiate(killEffect, target.transform.position, target.transform.rotation);
score += 1;
countDown = timeToSelect;
SetRandomPosition();//新規関数を作成(後述)
}
}
else {
//リセットする
countDown = timeToSelect;
hitEffectEmission.enabled = false;
}
}
void SetRandomPosition()
{
float x = Random.Range(-5.0f, 5.0f);
float z = Random.Range(-5.0f, 5.0f);
target.transform.position = new Vector3(x, 0.0f, z);
}
}

仮想空間VR:ユニティちゃんをジャンプさせる

こんにちは、(; ・д・´)圧倒的かずまなぶ です。

ユニティちゃんがジャンプできないので、小一時間かけて解決した記録をUPしておきます。

走っているときにスペースキーを押すと、ジャンプするはずですが、ジャンプして、浮いた瞬間にスクリプトが止まってしまいます。Projectパネル横のConsoleパネルで確認できます。

UnityChanControlScriptWithRgidBody.csを開いて(エラーログをダブルクリックでもいけます。)

126行目

cameraObject.SendMessage("setCameraPositionJumpView"); // ジャンプ中のカメラに変更

で引っかかっているので、//でコメントアウトします。

ジャンプ中にカメラが切り替わるようですが、そんなカメラ作った覚えはないですし。

それだけ。以上 圧倒的かずまなぶ でした。(; ・д・´)

仮想空間VR:AIThirdPersonControllerとWalkTargetとNavigationのBakeをやってみる。

こんにちは (‘ω’)ノ 圧倒的かずまなぶ です。

きょうの作品は

”アイドルの追っかけ” です。

アイドルをasdwキーで操作すると、追っかけが付いてきます。どこまでもついてきます。崖から落っこちても、死を恐れずに追いかけてきます。たぶん。

追記:崖から追いかけては来ませんでした!おっかけには歩ける領域が定義されているからです。そこまでの根性はないようです( ゚Д゚)

ユニティちゃんだけが落っこちて おっかけは見えない壁にひっかかって足踏みしていますす。

やったこと

  1. カメラを適当に配置します。私はいつも、MainCameraをGvrEditorEmulatorと一緒にMeMyselfEye(EmptyなGameObject)の子に入れています。
  2. >アイドル役としてUnityちゃんを設置します。UnityChan>Prefabs>for Locotion>unitychanプレハブ です。ロコモーションの方です。
  3. おっかけ役として、Standard Assets>Characters>ThrdPersonCharacter>Prefabs>AIThirdPersonController.プレハブを設置します。
  4. おっかける対象として、WalkTarget(EmptyなGameObject)を設置します。
  5. このWalkTargetをInspectorからAIThirdPersonControllerのAI Character Control(Script)のTargetにドラッグアンドドロップします。
  6. そしてこの、WalkTargetをunitychanの子に入れます。
  7. 歩ける場所を定義します。メニューWindow>AI>Navigation>Bake>BakeでNavMeshを作成します。この青い領域が歩ける場所です。
はまりどころ : Navigationってどこにあるの?

以上です。スタートボタンを押して、走ってみましょう。

written by 圧倒的かずまなぶ

おまけ

VR:動かない・・・

かずまなぶです。

さっきまで、ethanが浮いていました。

地面(plate)のMesh Collider(衝突)のconvexのチェックを外すと、浮かなくなりました。見えない厚みの定義でしょうかね?1時間悩みました。

しかし、まだethanが動いてくれません。 Cキーでしゃがむことはできますが、asdwxキーが機能しません。

わかりません・・

タスケテ

圧倒的python:numpy についてまとめる

こんにちは かずまなぶ(=゚ω゚)ノ です。

きょうは、python numpy についてまとめました。超基本的なことだけです。

応用例や他の便利メソドなどはdocsで確認してください。

基本形を作る

# 行列演算
a=np.array([1,2,3,4,5,6])
a=a.reshape(2,3)
# array([[1, 2, 3],
# [4, 5, 6]])
a*2
# array([[ 2, 4, 6],
# [ 8, 10, 12]])
a-2
# array([[ 2, 4, 6],
# [ 8, 10, 12]])
a/2.0
# array([[0.5, 1. , 1.5],
# [2. , 2.5, 3. ]])
#ブール演算
a=np.array([3,5,42,65,8])
a<40 # array([ True, True, False, False, True])
# pandasでブールマスクとして使用する
#便利メソド
a=np.arange(8).reshape(2,4)
# array([[0, 1, 2, 3],
# [4, 5, 6, 7]])
a.min(axis=1) # array([0, 4]) 第二軸(=列)に沿った最小
a.sum(axis=0) # array([ 4, 6, 8, 10]) 第一軸(=行)に沿った合計
a.mean(axis=1)# array([1.5, 5.5]) 第二軸(=列)に沿った平均
a.std(axis=1) # array([1.11803399, 1.11803399]) 第二軸(=列)に沿った標準偏差

# 応用例:移動平均の計算
def moving_average(a,n=3): #デフォルトを3点とする
ret=np.cumsum(a,dtype=float)
ret[n:]=ret[n:]-ret[:-n]
return ret[n-1:]/n
a=np.arange(10)
moving_average(a,4) # array([1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5])

調べる

変形する

#配列の形を変更 .reshape( , )
a=np.arange(6)
b=a.reshape(2,3)
#配列の要素をシャフル permutation()
np.random.permutation(range(6)) # array([1, 0, 5, 2, 4, 3])
#省略型 range()は省略できる
np.random.permutation(6) # array([2, 0, 5, 4, 3, 1])

演算する

import numpy as np
ar=np.array([1,2,3]) # array([1, 2, 3]) array定義
ar+ar # array([2, 4, 6]) 足し算
# np.arrayの詳細情報
def print_array_detail(a):
print("Dimensions:%d,shape:%s,dtype:%s" %(a.ndim,a.shape,a.dtype))
a=np.array([1,2,3,4,5,6,7,8])
print_array_detail(a) # Dimensions:1,shape:(8,),dtype:int32
#=========================================================
a.reshape(2,4) # 2行4列の 2次元配列へ変換
# array([[1, 2, 3, 4],
# [5, 6, 7, 8]])
a.reshape(2,2,2) # 2行2列2枚の3次元配列へ変換
# array([[[1, 2],
# [3, 4]],
# [[5, 6],
# [7, 8]]])
#配列shape変更
a.shape # (8,)
a.shape=(2,4)
#array([[1, 2, 3, 4],
# [5, 6, 7, 8]])
#配列dtype変更
a.dtype # dtype('int32')
a=a.astype("int64")
#a.dtype=("int64") これでもできた
a.dtype # dtype('int64')
#配列を作成する
a=np.zeros([2,3]) # 2x3のゼロ行列
a.dtype # dtype('float64')
# array([[0., 0., 0.],
# [0., 0., 0.]])
b=np.ones([3,3]) # 2x3の1だけ行列
# array([[1., 1., 1.],
# [1., 1., 1.]])
c=np.random.random([2,3])#2x3のランダム行列 0~1
# array([[0.27446726, 0.43087194, 0.04761962],
# [0.2873613 , 0.56118093, 0.03471013]])
d=np.linspace(2,10,5) #array([ 2., 4., 6., 8., 10.]) 2~10を5等分
d.dtype #dtype('float64')
e=np.arange(2,10,5) #array([2, 7])2~10 を5ステップで
e.dtype # dtype('int32')
#和 積 差
a=np.arange(8).reshape(2,4)
# array([[0, 1, 2, 3],
# [4, 5, 6, 7]])
np.cumsum(a,axis=1) # 第2軸(=列)に沿った累積の和
# array([[ 0, 1, 3, 6],
# [ 4, 9, 15, 22]], dtype=int32)
np.cumsum(a) # 引数なし = 配列を1次元(フラット)にする
# array([ 0, 1, 3, 6, 10, 15, 21, 28], dtype=int32)

ベクトル演算する

#ベクトルの演算
a=np.array([0,1,2,3])
b=np.array([4,5,6,7])
a.dot(b) # ベクトルの内積
# 38
np.cross(a,b) # ベクトルの外積1
np.outer(a,b) # ベクトルの外積2

行列演算する

#行列の演算
a=np.array([[0,1,2],[3,4,5]])
b=np.array([[0,1],[2,3],[4,5]])
a.dot(b) # 行列の内積
# [[10 13]
# [28 40]]
numpy.multiply.outer # 行列の外積1
numpy.einsum # 行列の外積2
# 転置 逆行列 行列式
a=np.array([0,6,3,-2,7,2,0,0,3]) 
a=a.reshape(3,3) #3x3行列を作成
# [[ 0 6 3]
# [-2 7 2]
# [ 0 0 3]]
a.T # 転置行列
# [[ 0 -2 0]
# [ 6 7 0]
# [ 3 2 3]]
np.linalg.inv(a) # 逆行列
# [[ 0.58333333 -0.5 -0.25 ]
# [ 0.16666667 0. -0.16666667]
# [ 0. 0. 0.33333333]]
np.linalg.det(a) # 行列式
# 36.0

連結する

#配列の連結
a=np.array([0,1,2,3,4,5])
a=a.reshape(2,3)
b=np.array([6,7,8,9,10,11])
b=b.reshape(2,3)
print("a=",a)
print("b=",b)
#配列を右(水平)に連結 hstack([ , ])
#配列を下(垂直)に連結 vstack([ , ])
c=np.hstack([a,b])
d=np.vstack([a,b])
print("hstack:",c)
print("vstack:",d)

削除する

#特定の行を消す
#numpy.delete(arr, obj, axis=None)
#arr: 入力配列
#obj: 消去する行番号や列番号をslice, int, リスト(配列)で指定
#axis: 消去対象となる軸(次元)
a=np.array([0,6,3,-2,7,2,0,0,3])
a=a.reshape(3,3)
print(a) #3x3行列を作成
new = np.delete(a, obj=0, axis=0)
print(new)

pandas.DataFrameにする

数学関数

#数学関数
pi=np.pi#3.141592653589793
type(pi) #float
a=np.array([pi,pi/2,pi/4,pi/6])
np.degrees(a) # array([180., 90., 45., 30.])
sin_a=np.sin(a) # array([1.22464680e-16, 1.00000000e+00, 7.07106781e-01, 5.00000000e-01])
#浮動小数点の誤差が発生することに注意
np.round(sin_a,7)# array([0. , 1. , 0.7071068, 0.5 ])
#小数点第7位に四捨五入

インデックス指定をする

#インデックス指定
f=np.array([1,2,3,4,5,6])
f[2] # 3
f[2:5] # array([3, 4, 5]) 2~5
f[:5:2]# array([1, 3, 5]) 0~5 を2ステップ
f[::-1]# array([6, 5, 4, 3, 2, 1]) 逆順
#多次元インデックス指定
g=np.arange(16,dtype="int32")
g=g.reshape([2,2,4]) #2行4列を2枚
# array([[[ 0, 1, 2, 3],
# [ 4, 5, 6, 7]],
# [[ 8, 9, 10, 11],
# [12, 13, 14, 15]]])
g[0]
# array([[0, 1, 2, 3],
# [4, 5, 6, 7]])
g[0,0] #array([0, 1, 2, 3])
g[0,1,0] # 4
#配列の加工
a=np.array([0,1,2,3,4,5,6,7,8,9,10,11])
a=a.reshape(3,4)
print(a)
#2行目を取り除く=必要な行だけを取り出す
b=a[[0,2],:] # [[取り出したい行],他は捨てる] という意味
print(b)
#3列目を取り除く=必要な列だけを取り出す
c=a[:,[0,1,3]]
print(c)
#条件にあった要素を置き換える
a[a%2==0]=-1 #2で割れる配列番号の要素だけに-1を代入する
print(a)

仮想空間VR:BlenderでUV作成#2 Unityで使ってみる

こんにちは かずまなぶ(‘ω’) です

前回Blenderで作ったオブジェクトをUnityに取り込んでみましょう。

ボディを .blendファイルとして保存します。

テクスチャーを.pngファイルとして保存します。

Unity側ではAssetsフォルダの下のModelsフォルダ と Textureフォルダにそれぞれ入れましょう。フォルダがなければ作りましょう。

そして、Modelsフォルダに入れた.Blendファイルをシーンビューの中にドラッグ&ドロップしてオブジェクトを配置します。そのオブジェクトにTextureフォルダにいれた.pngファイルをドラッグ&ドロップします。

以上です。だんだんUnityに慣れてきましたね。ボキャブラリーが増えてきたおかげで、覚えが速くなってきました。

Mirage Solo:自分で作ったVR空間を自由に歩く!

こんにちは かずまなぶです。(‘ω’)ノ

遂に

自分で作ったVR空間を自由に歩く

という 一つの大きな目標を達成できましたので記録しておきます。

前回はスマホで3DOFだったので、この位置から動くことはできませんでした。

初めてのVR ファーウェイP9と安物ヘッドセット。 それでも感動モノ (*´ω`*)

こんどは Mirage Soloに同じデータをインストールして起動したシーンです

初期位置はこの状態です。当然360°見渡せますし。スマホの時よりも視野が広くて、解像度も段違い! 美しいのひとこと!

函館の輝きがさらに向上しています(*´ω`*)

では、回り込んでみましょう。

やりました!完全にもくろみ通り、背中が見えております!

これが

6DOF です (; ・д・´)

これだけで、5万円の価値あります。

VR世界は広いですが、現実世界(家の中)では障害物だらけですので、すり足で恐る恐る行きましょう(; ・д・´)

ではさらに移動してみましょう。

ずいぶん離れたところまで来ました。

完全に自由に動けます!

これが

スタンドアロンの力です!

もうアンビリカルケーブルは必要ありません(; ・`д・´)

函館の夜景にも接近してみましたが、眼前に広がる夜景に圧倒されます(*´ω`*)

この光景を見ながら我思います。

VRは広大だわ・・・・。

草薙素子少佐の気分です。

VRというものを知ってからここまで3週間。Unityをインストールしてからでは2週間でここまで来れました。

みんなもやろう VR!

ではまた逢う日まで。(‘ω’)かずまなぶ

Mirage Solo:はじめの一歩

こんにちは かずまなぶです

遂に、レノボ ミラージュソロを導入いたしました。”スタンドアロンの6DOF” といったら現時点でのベストはコレだと思います。選択肢がありませんので。買わない理由はありませんでした。

早速やっていきましょう。

lenovo mirage solo

スペックを見るとCPU メモリは半年前のハイエンドスマホって感じです。

立ち上げると、googleの儀式 メルアドとパスワードを聞かれます。もはやgoogleなしでは生きていけませんね。

web ブラウザを入れる

これがないと始まりませんよね

google playから chrome と chrome dev というのを入れてみました。今のところ違いは感じられません。(chromeは最初から入ってたのかな?)

で、インストールしたあと、このアプリ どうやって立ち上げるのか?悩みました。

設定>アプリと通知>〇個のアプリをすべて表示>アプリを選択する>アプリの詳細>開く です。 長い!

一度起動すると、以後はトップ画面に出てきます。

移動制限を解除する

次にやったのが、移動制限の解除です。半径1mの制限を解除して、どこまでも行けるようにします。

ディベロッパーモードにするとワールドセンスの制限がなくなります。やり方:設定>システム端末情報>ビルド番号 を 7回クリックする。

そして、設定>daydream>VR設定>ディベロッパー>Enable safety graphics>off して 再起動させる。

但し、これは何かにぶつかったり怪我をしたりする恐れがありますので、メーカーとしても推奨していません。十分理解した上でご判断願います。

USBデバッグをONにする

PCとUSBをつないで、データのやり取りができるようにします。(と、説明には書いています。が・・・)

設定>システム>開発者向けオプション>USBデバッグ>ON

前述のディベロッパーモードにすることで、選択が可能になります。

が!データのやり取りがまだできません!

PCのデータをMirage Soloに入れる

USB経由でやる方法が解りませんでしたので他の方法を考えました。

googleドライブを介してデータを渡します。

PCのgoogle Playからgoogleドライブをリモートで Mirage Soloへインストールします。

渡したいデータをgoogleドライブに入れます。私はUnityで作ったapkファイルを入れてみました。

Mirage Soloから、googleドライブを開きます。(めんどくさいケド、はじめの一回だけは設定からしかアクセスできません。)

apkファイルを見つけて、クリックすると無事インストールが始まりました。

スクリーンショット

スクショの取り方をメモしておきます。

ディベロッパーモードにしておきましょう。

設定>daydream>VRの設定>デベロッパー向けの設定>Enable VR screen recording via chords>ON

これで、〇ボタン+右側面の下ボタン同時押しでスクリーンショットが記録できます。通知エリアに通知されるのでクリックするとみることができます。

ちなみに動画は〇ボタン+右ぎ側面の上ボタン同時押しだそうです。

保存はどこかにされているようですが、PCへ転送する方法が解らないので、リンクボタンを押して、自分宛てのメールで飛ばしてみました。

問題・・・

ディベロッパーモードにしたので、移動制限が解除されているはずですが、されていません・・・

Enable safety graphics>off をしないといけないようです!

PCとUSB接続すれば、データのやり取りができると思ってたのですが、つないでもPC側から認識していません。

開発モードをOFFにするとMTPを有効にできという情報を得ました。MTPをONにしなければならないとは考えていましたが、なぜかオプションボタンにチェックを入れることができない状態だったのです( ゚Д゚)。

いやいやいや! 開発モードをOFFにすると開発者向けオプションの項目が消えてしまうので、このMTPを有効にするためのこのウィンドウ自体が出せなくなります。これは完全に詰んでいます!最高に意味が解らない状態です(; ・д・´)

タスケテー!

MTP選択の画面は 開発者向けオプションの中にある。よって開発者モードをやめるとこの項目自体が消えてしまいます。どうすることもできない(; ・д・´)