Blog
홀로렌즈 UI 변경
홀로렌즈 AR Controller의 UI를 변경하는 작업진행
2019.10.04
홀로렌즈 UI 변경
기존 홀로렌즈 AR Controller의 직관성 및 조작의 편리성 향상위해 UI를 변경하는 작업을 진행하였다.
이를 통해 메인매니저의 OnGazeEnter, OnGazeLeave, Update 함수등을 변경하였다.
결과
일정 시간 물체를 바라보면 Controller의 조종 대상이 변경된다.
조종 대상 중 Vuforia Image Target을 통해 그 자리에 “고정”된 물체는 인식시 이동버튼이 비활성화 되도록 변경하였다.
리모콘으로 조종하는 물체만 영향을 받는다. 위 시진에서, 왼쪽에 위치한 물체만 분해가 되는 모습이다.
위 영상은 두 물체를 조종하는 모습이다. 조종 할 물체를 바라보고 있으면, 컨트롤러의 대상이 바뀌고 그 대상을 조작 할 수 있다.
같은 방법으로 하나의 리모콘으로 두 물체를 모두 제거하는 모습이다.
구현
아래는 아예 기존의 방식을 참조하여 새로 만든 AR Controller UI 코드이다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
//================================================================================
// ENUM 선언 | AR Remote Contoller Btn 클래스에서 버튼 구분을 위해 이용
//================================================================================
public enum EnumARReomoteContolUIBtnType {
EnumARContolUIBtnType_MOVE = 1,
EnumARContolUIBtnType_SHOW = 1 << 1,
EnumARContolUIBtnType_ASSEMBLE = 1 << 2,
EnumARContolUIBtnType_ZOOM = 1 << 3,
EnumARContolUIBtnType_ROTATE = 1 << 4,
EnumARContolUIBtnType_RESET = 1 << 5,
EnumARContolUIBtnType_ANIMATION = 1 << 6,
EnumARContolUIBtnType_REMOVE = 1 << 7,
EnumARContolUIBtnType_HIDDEN = 1 << 8,
}
//================================================================================
// AR Remote Controller | AR Control UI Handler 참고해서 구현
//================================================================================
public class ARRemoteController : MonoBehaviour {
//============================================================================
// Public, Private 필드 선언
//============================================================================
public GameObject targetObject; // 바라본 물체
public Text objectNameTitle; // 바라본 물체의 이름을
// 적을 텍스트 필드
public GameObject[] buttonArr = new GameObject[7]; // 버튼 GameObject
// 저장하는 배열
public Sprite[] activeSprite = new Sprite[7]; // 활성화된 버튼 Sprite
public Sprite[] inactiveSprite = new Sprite[7]; // 비활성화된 버튼 Sprite
private bool isPartModel = false; // 파트모델인지 여부
private bool isHyundaiModel = false; // 현대 모델인지 여부
private bool isShowing = true; // 물체를 보여줄지 여부
private ARRemoteControllerBtn[] buttonScriptArr
= new ARRemoteControllerBtn[7];
// 버튼들의 Dictionary
private GestureAction gestureAction; // 바라본 물체의
// 제스처 액션
private class TransformValue { // 원복시 사용할
// transform 클래스
public Vector3 localPosition;
public Vector3 localScale;
public Quaternion rotation;
}
private TransformValue originalTransformValue = new TransformValue();
// 초기 transform 상태
// 저장용 변수
//============================================================================
// Start 메소드
//============================================================================
public void Start() {
// GameObject인 buttonArr에서 AR Remote Controller Btn
// 클래스만 꺼내서 따로 저장
for (int i = 0; i < 7; i++)
buttonScriptArr[i] =
buttonArr[i].GetComponent<ARRemoteControllerBtn>();
// 타겟의 분류에 따라, 버튼 활성도 다르게 처리
foreach (ARRemoteControllerBtn button in buttonScriptArr) {
switch (button.buttonType) {
case EnumARReomoteContolUIBtnType.EnumARContolUIBtnType_MOVE:
button.SetOnClickARControlButton(OnClick_Move);
break;
case EnumARReomoteContolUIBtnType.EnumARContolUIBtnType_SHOW:
button.SetOnClickARControlButton(OnClick_Show);
break;
case EnumARReomoteContolUIBtnType.EnumARContolUIBtnType_ASSEMBLE:
button.SetOnClickARControlButton(OnClick_Assemble);
break;
case EnumARReomoteContolUIBtnType.EnumARContolUIBtnType_RESET:
button.SetOnClickARControlButton(OnClick_Reset);
break;
case EnumARReomoteContolUIBtnType.EnumARContolUIBtnType_ANIMATION:
button.SetOnClickARControlButton(OnClick_Animation);
break;
case EnumARReomoteContolUIBtnType.EnumARContolUIBtnType_ROTATE:
button.SetOnClickARControlButton(OnClick_Rotate);
break;
case EnumARReomoteContolUIBtnType.EnumARContolUIBtnType_REMOVE:
button.SetOnClickARControlButton(OnClick_Remove);
break;
}
}
}
//============================================================================
// 물체를 바라봤을 경우, 리모컨이 제어할 대상 변경해주는 메소드
//============================================================================
public void ChangeObject (GameObject target) {
//========================================================================
// 새로 바라볼 경우, 관련된 필드들 초기화
//========================================================================
this.targetObject = target;
this.isShowing = true;
this.objectNameTitle.text = "3D MODEL CONTROLLER : " + target.name;
this.originalTransformValue.localScale =
targetObject.transform.localScale;
this.originalTransformValue.localPosition =
targetObject.transform.localPosition;
this.originalTransformValue.rotation = targetObject.transform.rotation;
// 제스처 액션 컴포넌트 초기화 (없으면 만듦)
if (!target.GetComponent<GestureAction>())
targetObject.AddComponent<GestureAction>();
this.gestureAction = targetObject.GetComponent<GestureAction>();
/*
*
* @kimYC1223
* TO-DO : Tag에 따른 변수 설정 (isPartModel,isHyundaiModel)
*
*/
// 타겟의 분류에 따라, 버튼 활성도 다르게 처리
if (target.tag == "PartModel_ImageTarget") {
buttonScriptArr[0].SetOnClickARControlButton(null);
buttonArr[0].GetComponent<SpriteRenderer>().sprite =
inactiveSprite[0];
buttonArr[0].GetComponent<BoxCollider>().enabled = false;
} else {
buttonScriptArr[0].SetOnClickARControlButton(OnClick_Move);
buttonArr[0].GetComponent<SpriteRenderer>().sprite =
activeSprite[0];
buttonArr[0].GetComponent<BoxCollider>().enabled = true;
}
}
//============================================================================
// 물체를 이동시키는 버튼
//============================================================================
public void OnClick_Move() {
if (targetObject == null) return;
Debug.Log("MOVE BUTTON CLICK");
// MOVE 버튼의 경우, Placeable 스크립트의 On Placement Start 실행
if (targetObject.GetComponent<Placeable>())
targetObject.GetComponent<Placeable>().OnPlacementStart();
}
//============================================================================
// 렌더러를 토글시키는 버튼
//============================================================================
public void OnClick_Show() {
if (targetObject == null) return;
Debug.Log("SHOW BUTTON CLICK");
isShowing = !isShowing;
// Show 버튼의 경우, 바라보고 있는 오브젝트의 Mesh Renderer를 토글
foreach (MeshRenderer childMeshRenderer in
targetObject.GetComponentsInChildren<MeshRenderer>()) {
childMeshRenderer.enabled = isShowing;
}
}
//============================================================================
// 물체를 파츠로 분해 / 파츠를 물체로 재조립 하는 버튼
//============================================================================
public void OnClick_Assemble() {
if (targetObject == null) return;
Debug.Log("ASSEMBLE BUTTON CLICK");
// AR Twin Model Assemble Handler를 이용
if (targetObject.GetComponent<ARTwinModelAssembleHandler>()) {
int transformSendAssignType =
(int)EnumTransformAssignType.EnumTransformAssignType_Assemble;
ARTwinModelAssembleHandler handler =
targetObject.GetComponent<ARTwinModelAssembleHandler>();
int assembleState = handler.ProcAssmebleState();
CustomMessages.Instance.
SendObjectTransform(targetObject,transformSendAssignType,
targetObject.transform,assembleState,0);
}
}
//============================================================================
// 물체의 여러가지 상태를 초기 상태로 되돌리는 버튼
//============================================================================
public void OnClick_Reset() {
if (targetObject == null) return;
Debug.Log("RESET BUTTON CLICK");
// 일단 Position / Rotation / Scale을 원복함
targetObject.transform.rotation = originalTransformValue.rotation;
targetObject.transform.localScale = originalTransformValue.localScale;
targetObject.transform.localPosition =
originalTransformValue.localPosition;
// AR Twin Model Assemble Handler 리셋
foreach (ARTwinModelAssembleHandler handler in
targetObject.GetComponentsInChildren<ARTwinModelAssembleHandler>())
handler.ResetAssmebleState();
// Button 의 상태도 초기화 시켜줌
foreach (ARRemoteControllerBtn button in buttonScriptArr)
button.ResetButtonColor();
}
//============================================================================
// 물체가 가지고있는 애니메이션을 재생하는 버튼
//============================================================================
public void OnClick_Animation() {
if (targetObject == null) return;
Debug.Log("ANIMATION BUTTON CLICK");
// TO-DO
// @KimYC1223 애니메이션 재생되도록 설정
}
//============================================================================
// 물체를 제스처 액션을 통해 회전 / 확대 / 축소 하는 버튼
//============================================================================
public void OnClick_Rotate() {
if (targetObject == null) return;
Debug.Log("ROTATE BUTTON CLICK");
// Gesture Action 컴포넌트가 있다면, 해당 기능을 토글함
if (gestureAction != null)
gestureAction.StartStopGestureAction();
}
//============================================================================
// 물체를 Active 상태를 비활성화 시키는 버튼 (Show Btn과 유사)
//============================================================================
public void OnClick_Remove() {
if (targetObject == null) return;
Debug.Log("REMOVE BUTTON CLICK");
// 만약 Vuforia 기반 오브젝트라면, 리셋 해줌
if (GetComponentsInChildren<PartImageTargetTrackableEventHandler>()
.Length > 0) {
PartImageTargetTrackableEventHandler[] handlers =
GetComponentsInChildren<PartImageTargetTrackableEventHandler>();
foreach (PartImageTargetTrackableEventHandler handler in handlers)
handler.ResetFound();
}
// 오브젝트 제거
targetObject.SetActive(false);
targetObject = null;
objectNameTitle.text = "3D MODEL CONTROLLER";
// 버튼 원복
for(int i = 0; i < buttonArr.Length; i++)
buttonArr[i].GetComponent<SpriteRenderer>().sprite = activeSprite[i];
}
}
이슈
- 현재 물체의 애니메이션이 없다. #116 이후에 수정 할 것.
- 현재 설정 리셋과 분해/조립에 약간의 버그가 있다. 수정할 것.
- 현재 버튼의 하이라이트 (트리거 버튼의 ON/OFF 표시)에 버그가 조금 있다. 수정 할 것.