4. MRTK에서 제공하는 샘플신을 열고 빌드를 하면 해당폴더에 Visual Studio Project가 생성이되는데 실행하면 비쥬얼 스튜디오가 열린다. (별도 설치 필요)
5. 아까 유니티 빌드세팅에서 맞춰놓은대로 비쥬얼 스튜디오도 그림처럼 맞춘다.
6. 속성을 눌러 들어간다.
7. 디버깅 탭을 누르고 컴퓨터 이름을 맞춰주는데 이때 이름은 홀로렌즈의 이름을 넣어주어야 한다. 홀로렌즈이름은 홀로렌즈홈에서 /세팅/시스템 순서로 들어가면 확인할 수 있다.
8. 상단의 빌드/ 솔루션배포를 누르면 홀로렌즈에 앱을 빌드 할 수 있다. 여기서 만양 홀로렌즈에 배포가 되지 않고 핀번호를 입력하라고 나오면, 홀로렌즈 홈에서 세팅/업데이트/개발자모드 로 들어가서 페어링 버튼을 누르면 기기의 페어링번호가 뜨고 그 번호를 넣어주면 된다.
**2019.1.14f1일 경우 솔루션대상을 변경해주어야 합니다. 마찬가지로 비쥬얼 스튜디오 2019버전을 사용 할 경우 프로젝트/솔루션 대상 변경을 누르고
using UnityEngine;
public class ManagerHandler : MonoBehaviour {
public InfiniteScroll infiniteScroll;
void Start () {
Application.targetFrameRate = 60;
initList ();
}
void initList () {
infiniteScroll.ListStart ();
}
}
ModelHandler.cs
using System.Collections;
using System.Collections.Generic;
using LitJson;
using UnityEngine;
public class ModelHandler : MonoBehaviour {
private JsonData jsonData;
public List<DataVO> List;
string jsonString () {
TextAsset t = (TextAsset) Resources.Load ("data", typeof (TextAsset));
return t.text;
}
void Awake () {
jsonData = JsonMapper.ToObject (jsonString ());
parsing ();
}
void parsing () {
for (int i = 0; i < jsonData["music"].Count; i++) {
ListModel.Instance.dataVO.SongTitle = (string) jsonData["music"][i]["songtitle"];
ListModel.Instance.dataVO.Singer = (string) jsonData["music"][i]["singer"];
ListModel.Instance.dataVO.Color = hexToColor ((string) jsonData["music"][i]["color"]);
ListModel.Instance.dataVO.Genre = (string) jsonData["music"][i]["genre"];
ListModel.Instance.dataVO.PlayTime = float.Parse ((string) jsonData["music"][i]["playtime"]);
ListModel.Instance.MusicList.Add (ListModel.Instance.dataVO);
}
}
static Color hexToColor (string hex) {
hex = hex.Replace ("0x", "");
hex = hex.Replace ("#", "");
byte a = 255;
byte r = byte.Parse (hex.Substring (0, 2), System.Globalization.NumberStyles.HexNumber);
byte g = byte.Parse (hex.Substring (2, 2), System.Globalization.NumberStyles.HexNumber);
byte b = byte.Parse (hex.Substring (4, 2), System.Globalization.NumberStyles.HexNumber);
if (hex.Length == 8) {
a = byte.Parse (hex.Substring (6, 2), System.Globalization.NumberStyles.HexNumber);
}
return new Color32 (r, g, b, a);
}
}
ListModel.cs
using System;
using System.Collections.Generic;
using UnityEngine;
[Serializable]
public struct DataVO {
public string SongTitle;
public string Singer;
public Color32 Color;
public string Genre;
public float PlayTime;
}
public class ListModel : MonoBehaviour {
private static ListModel _instance = null;
public DataVO dataVO;
public List<DataVO> MusicList = new List<DataVO> ();
public static ListModel Instance {
get {
if (_instance == null) {
_instance = (GameObject.Find ("Manager")).AddComponent<ListModel> ();
}
return _instance;
}
}
}
InfiniteScroll.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class InfiniteScroll : MonoBehaviour {
[SerializeField]
private RectTransform m_ItemBase;
[SerializeField]
int m_instantiateItemCount = 9;
[SerializeField]
float m_itemWidth = 1080;
[SerializeField]
float m_itemHeight = 200;
[SerializeField]
float gap = 10;
public Direction direction;
[System.NonSerialized]
public List<RectTransform> m_itemList = new List<RectTransform> ();
protected float m_diffPreFramePosition = 0;
[SerializeField]
private int m_currentItemNo = 0;
public ScrollRect scrollRect;
public List<DataVO> listData;
public enum Direction {
Vertical,
Horizontal,
}
// cache component
public RectTransform m_Content;
private float AnchoredPosition {
get {
return (direction == Direction.Vertical) ?
-m_Content.anchoredPosition.y :
m_Content.anchoredPosition.x;
}
}
private float ItemScale {
get {
return (direction == Direction.Vertical) ?
m_itemHeight :
m_itemWidth;
}
}
void Start () {
m_itemWidth = Screen.width;
m_itemHeight = Screen.height / 12;
}
public void ListStart () {
listData = ListModel.Instance.MusicList;
if (listData.Count < m_instantiateItemCount) {
m_instantiateItemCount = listData.Count;
} else {
m_instantiateItemCount = (direction == Direction.Vertical) ?
Mathf.RoundToInt (Screen.height / ItemScale) + 3 :
Mathf.RoundToInt (Screen.width / ItemScale) + 3;
}
// create items
scrollRect.horizontal = direction == Direction.Horizontal;
scrollRect.vertical = direction == Direction.Vertical;
if (direction == Direction.Vertical) {
m_Content.SetSizeWithCurrentAnchors (RectTransform.Axis.Vertical, (ItemScale + gap) * (listData.Count - 1) + gap);
m_Content.SetSizeWithCurrentAnchors (RectTransform.Axis.Horizontal, m_itemWidth + gap * 2);
} else {
m_Content.SetSizeWithCurrentAnchors (RectTransform.Axis.Horizontal, (ItemScale + gap) * (listData.Count - 1) + gap);
m_Content.SetSizeWithCurrentAnchors (RectTransform.Axis.Vertical, m_itemHeight + gap * 2);
}
scrollRect.onValueChanged.AddListener (valueChange);
Debug.Log (listData.Count);
m_ItemBase.gameObject.SetActive (false);
for (int i = 0; i < m_instantiateItemCount; i++) {
var item = GameObject.Instantiate (m_ItemBase) as RectTransform;
item.SetParent (transform, false);
item.name = i.ToString ();
if (direction == Direction.Vertical) {
item.SetSizeWithCurrentAnchors (RectTransform.Axis.Horizontal, m_itemWidth - gap * 2);
item.SetSizeWithCurrentAnchors (RectTransform.Axis.Vertical, m_itemHeight);
} else {
item.SetSizeWithCurrentAnchors (RectTransform.Axis.Horizontal, m_itemWidth);
item.SetSizeWithCurrentAnchors (RectTransform.Axis.Vertical, m_itemHeight);
}
item.anchoredPosition =
(direction == Direction.Vertical) ?
new Vector2 (gap, -gap - (ItemScale + gap) * i) :
new Vector2 ((ItemScale + gap) * i + gap, -gap);
m_itemList.Add (item);
item.gameObject.SetActive (true);
item.GetComponent<Item> ().UpdateItem (i);
}
}
private void valueChange (Vector2 _pos) {
// scroll up, item attach bottom or right
while (AnchoredPosition - m_diffPreFramePosition < -(ItemScale + gap) * 2) {
m_diffPreFramePosition -= (ItemScale + gap);
var item = m_itemList[0];
m_itemList.RemoveAt (0);
m_itemList.Add (item);
var pos = (ItemScale + gap) * m_instantiateItemCount + (ItemScale + gap) * m_currentItemNo;
item.anchoredPosition = (direction == Direction.Vertical) ? new Vector2 (gap, -pos - gap) : new Vector2 (pos + gap, -gap);
m_currentItemNo++;
if (m_currentItemNo + m_instantiateItemCount < listData.Count) {
item.GetComponent<Item> ().UpdateItem (m_currentItemNo + m_instantiateItemCount);
} else {
item.GetComponent<Item> ().UpdateItem (-100);
}
}
// scroll down, item attach top or left
while (AnchoredPosition - m_diffPreFramePosition > 0) {
m_diffPreFramePosition += (ItemScale + gap);
var itemListLastCount = m_instantiateItemCount - 1;
var item = m_itemList[itemListLastCount];
m_itemList.RemoveAt (itemListLastCount);
m_itemList.Insert (0, item);
m_currentItemNo--;
var pos = (ItemScale + gap) * m_currentItemNo + gap;
item.anchoredPosition = (direction == Direction.Vertical) ? new Vector2 (gap, -pos) : new Vector2 (pos, -gap);
if (m_currentItemNo > -1) {
item.GetComponent<Item> ().UpdateItem (m_currentItemNo);
} else {
item.GetComponent<Item> ().UpdateItem (-100);
}
}
}
}
Item.cs
using UnityEngine;
using UnityEngine.UI;
public class Item : MonoBehaviour {
public Text m_Text;
public Image m_Image;
public void UpdateItem (int count) {
if (count == -100) {
m_Text.gameObject.SetActive (false);
m_Image.gameObject.SetActive (false);
} else {
m_Text.gameObject.SetActive (true);
m_Image.gameObject.SetActive (true);
m_Text.text = count + 1 + " - " + Screen.width + " x " + Screen.height;
m_Image.color = ListModel.Instance.MusicList[count].Color;
}
}
}
3번 : 이미지 가장자리에 4방으로 2px의 여백을 주고 Filter Mode를 Bilinear로 세팅.
4번 : 이미지 가장자리에 4방으로 2px의 여백을 주고 Filter Mode를 pointer로 세팅.
보통 Sprite 이미지를 임포트 해서 Canvas 상에 올린 후 로테이션값을 조절해 사용하다보면 위 이미지에서 처럼 가장자리가 깨지거나 혹은 가장자리만 깨지는 현상을 경험할 수 있다. 결론부터 얘기해서 3번처럼 보이게 하기 위해서는 포토샵에서 아래처럼 이미지의 바깥쪽에 1~2px의 여백을 만들어 가져오면 해결된다. 가져온 이미지는 Filtermode를 Bilinear 또는 Trilinear로 선택해주고 Apply시켜준다.