MagicLeap에서 오브젝트 제크트를 실행하는 방법
開発環境
유니티 : 2019.3.7f1
LuminOS : 0.98.11, API레벨 8
MagicLeap : UnitySDK 0.24.1
MagicLeap : ToolKit 특별 버전 表記等はないので現時点(2020/09/22)での最新
MagicLeapToolKitのDLはこちらから
今回開発したアプリの リポジトリはこちら
FloorCheck신에산프루가配置してあります
完成するもの
床を判定するやつ pic.twitter.com/zzhb4lk5g2 — 松本隆介(
)
下準備
ProjectSettings > MagicLeap > ManifestSettings
にて以下の項目にcheckkを入れました
스크립트 등
今回의 스크립팅은 MagicLeap ToolKit의 PlaceOnFloor를 통해 가능합니다.
素のPlaceOnFloorのままだ와 初回の床判定以降は床判定を行わないので何度でも床判定を行えるようにしました.
다음은 FloorChecker.cs 파일입니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if PLATFORM_LUMIN
using UnityEngine.XR.MagicLeap;
#endif
namespace FloorCheck
{
/// <summary>
/// MagicLeapToolsのFloorOnPlaceを改造したクラス.
/// 床検知を何度もにできるようにする.
/// </summary>
public class FloorChecker : MonoBehaviour
{
readonly float HeadLocationIdleThreshold = 0.003f;
readonly float HeadRotationIdleThreshold = .3f;
readonly int HistoryCount = 5;
readonly float HeadIdleRequiredDuration = .2f;
// Public Properties:
public Vector3 Location
{
get;
private set;
}
[Tooltip("Does content's content match it's transform forward?")]
[SerializeField] bool flippedForward;
List<Vector3> headLocationHistory;
List<Quaternion> headRotationHistory;
float headLocationVelocity;
float headRotationVelocity;
Transform mainCamera;
bool headLocationIdle;
bool headRotationIdle;
bool headTemporarilyIdle;
bool headIdle;
bool placementValid;
//Init:
void Awake()
{
//refs:
mainCamera = Camera.main.transform;
//requirements:
if (FindObjectOfType<MLSpatialMapper>() == null)
{
Debug.LogError("PlaceOnFloor requires and instance of the MLSpatialMapper in your scene.");
}
}
//Flow:
void OnEnable()
{
//sets:
headLocationHistory = new List<Vector3>();
headRotationHistory = new List<Quaternion>();
}
//Loops:
void Update()
{
//let headpose warmup a little:
if (Time.frameCount < 3)
{
return;
}
HeadActivityDetermination();
}
//Coroutines:
IEnumerator HeadIdleTimeout()
{
yield return new WaitForSeconds(HeadIdleRequiredDuration);
headIdle = true;
}
void HeadActivityDetermination()
{
//history:
headLocationHistory.Add(mainCamera.position);
if (HistoryCount < headLocationHistory.Count)
headLocationHistory.RemoveAt(0);
headRotationHistory.Add(mainCamera.rotation);
if (HistoryCount < headRotationHistory.Count)
headRotationHistory.RemoveAt(0);
//location velocity:
if (headLocationHistory.Count == HistoryCount)
{
headLocationVelocity = 0;
for (int i = 1; i < headLocationHistory.Count; i++)
{
headLocationVelocity += Vector3.Distance(headLocationHistory[i], headLocationHistory[i - 1]);
}
headLocationVelocity /= headLocationHistory.Count;
//idle detection:
if (headLocationVelocity <= HeadLocationIdleThreshold)
{
if (!headLocationIdle)
{
headLocationIdle = true;
}
}
else
{
if (headLocationIdle)
{
headLocationIdle = false;
}
}
}
//rotation velocity:
if (headRotationHistory.Count == HistoryCount)
{
headRotationVelocity = 0;
for (int i = 1; i < headRotationHistory.Count; i++)
{
headRotationVelocity += Quaternion.Angle(headRotationHistory[i], headRotationHistory[i - 1]);
}
headRotationVelocity /= headRotationHistory.Count;
//idle detection:
if (headRotationVelocity <= HeadRotationIdleThreshold)
{
if (!headRotationIdle)
{
headRotationIdle = true;
}
}
else
{
if (headRotationIdle)
{
headRotationIdle = false;
}
}
}
//absolute idle head determination:
if (headLocationIdle && headRotationIdle)
{
if (!headTemporarilyIdle)
{
headTemporarilyIdle = true;
StartCoroutine(HeadIdleTimeout());
}
}
else
{
if (headTemporarilyIdle)
{
headIdle = false;
headTemporarilyIdle = false;
StopCoroutine(HeadIdleTimeout());
}
}
}
/// <summary>
/// 指定したRayの位置に床があるか否か、ある場合はその座標も返す.
/// </summary>
/// <param name="ray"></param>
/// <returns></returns>
public (bool, Vector3) LookingAtFloorDetermination(
Ray ray)
{
//cast to see if we are looking at the floor:
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
MagicLeapTools.SurfaceType surface = MagicLeapTools.SurfaceDetails.Analyze(hit);
if (surface == MagicLeapTools.SurfaceType.Floor)
{
Location = hit.point;
placementValid = true;
return (true, Location);
}
else
{
placementValid = false;
return (false, Vector3.zero);
}
}
else
{
placementValid = false;
return (false, Vector3.zero);
}
}
}
}
FloorChecker를 사용할 수 있는FloorCheckOnPlaceContent.cs
using System;
using MagicLeapTools;
using UnityEngine;
namespace FloorCheck
{
/// <summary>
/// トリガを入力したときに床を判定し、床の場合はオブジェクトを配置するサンプル.
/// </summary>
[RequireComponent(typeof(FloorChecker),typeof(AudioSource))]
public class FloorCheckOnPlaceContent : MonoBehaviour
{
[SerializeField] AudioClip pressClip;
[SerializeField] AudioClip successClip;
[SerializeField] AudioClip failedClip;
[SerializeField] GameObject content;
[SerializeField] Pointer pointer;
FloorChecker floorChecker;
AudioSource audio;
void Start()
{
floorChecker = GetComponent<FloorChecker>();
audio = GetComponent<AudioSource>();
}
public void OnTriggerDown()
{
audio.PlayOneShot(pressClip);
(bool onFloor, Vector3 pos ) result = floorChecker.LookingAtFloorDetermination(new Ray(pointer.Origin, pointer.Direction));
if (result.onFloor)
{
audio.PlayOneShot(successClip);
content.transform.position = result.pos;
}
else
{
audio.PlayOneShot(failedClip);
}
}
}
}
shin の 構成
シーンの構成は以下の画像の通りになっています
MainCameraは
Assets > MagicLeap > Core > Assets > Prefabs
にある物を使いました
ControlPointerは
Assets > MagicLeap-Tools > Prefabs > Input
(으)로부터
今回はSpatialMapperを表示してどのメッシュの判定が通っているかをわかりやすくするので
Assets > MagicLeap > Core > Assets > Prefabs
のMLSpatialMapper도 사용 가능
MLSpatialMapper는 메쉬 생성을 생성하는 루트가 될 수 있는 개체 생성이 가능합니다. MeshRoot 개체 생성을 생성할 수 있습니다.
FloorChecker(을)를 사용하는 클래스는 다음과 같이 구성할 수 있습니다.
効果音은 魔王魂さんから拝借
Triga入力に対応して床判定を行うためにControlPointer의 이벤트에FloorCheckOnPlaceContent의OnTriggerDown을 실행합니다
完成
実機にBird 또는 ZeroIterationで動作確認をすれば
床を判定するやつ pic.twitter.com/zzhb4lk5g2 — 松本隆介(
)
これで床を判定し、床だけに配置したいOBJECTTOKANO 実装ができるようになります
感想
이 정의를 사용하여 에이전트의 NavMesh를 사용하거나 제거하거나 できるかも?
まだやってない、出来たら記事にするかもしれません
Reference
이 문제에 관하여(MagicLeap에서 오브젝트 제크트를 실행하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/matsumotokaka11/magicleap-2bko텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)