OBJ로 만든 GIS 데이터를 다운로드하여 Unity에 표시
소개
12/3에 만든 OBJ 파일을 Unity에 표시해 봅니다. OBJ 파일은 Unity Editor가 표준으로 읽을 수있는 형식이므로,
그대로 Asset으로 로드하면 특별히 문제가 되지 않습니다. 적당한 머티리얼만 설정해 버리면 게임내의 에셋으로서 사용할 수 있습니다.
그렇다면 흥미롭지 않으므로 여기에서는 런타임에 다운로드하여 현장에 구축한다는 것을 해보겠습니다.
그렇다고는 해도, 이것도 동적으로 메쉬의 작성과, OBJ의 퍼스등의 합작 기술이므로 큰 일 없네요.
이 근처는 느슨하게 흘려 가고 싶은 느낌으로.
다운로드하고 표시
다운로드
UnityWebRequest에서 가져옵니다. 샘플 코드 그대로 감.
IEnumerator objLoad()
{
UnityWebRequest req = UnityWebRequest.Get("URL to FILE/test.obj");
yield return req.SendWebRequest();
여담입니다만, github의 gist는, 이런 Web 액세스의 테스트용의 파일 두는 장소로서 편리하네요. 이번에도 그런 느낌으로 시험하고 있습니다.
OBJ 퍼스
한 줄씩 읽어 갑니다.
정점 좌표와 정점 인덱스를 그대로 읽어 배열에 격납합니다.
List<Vector3> vertices = new List<Vector3>();
List<int> indices = new List<int>();
if(req.isHttpError || req.isNetworkError){
Debug.Log(req.error);
} else {
var strs = req.downloadHandler.text.Split('\n');
foreach(string str in strs){
if(str.StartsWith("g")){
} else if(str.StartsWith("v")){
var tokens = str.Split(' ');
vertices.Add(new Vector3(float.Parse(tokens[1]), float.Parse(tokens[2]), float.Parse(tokens[3])));
} else if(str.StartsWith("f")){
var tokens = str.Split(' ');
indices.Add(int.Parse(tokens[1])-1);
indices.Add(int.Parse(tokens[2])-1);
indices.Add(int.Parse(tokens[3])-1);
}
}
}
Debug.Log(vertices.Count);
Debug.Log(indices.Count);
만약을 위해, 마지막으로 읽어들인 정점수와 인덱스수를 디버그 로그했습니다.
이런 것을 파서라고 말할 수 있을까 하는 정도 간단하네요.
덧붙여서, 인덱스의 read로 -1 하고 있는 것은, OBJ 파일이 1 오리진으로, Unity가 0 오리진이기 때문입니다.
처음에는 여기에서 멈췄다.
배열이 1부터 시작하는 것이 이상하다고 이야기는 있을지도 모릅니다만, 세상 그러한 언어도 있거나 합니다.
예를 들면 Lua라든지군요.
또, 옛 N88-BASIC에는, 배열의 오리진을 0,1로 변경하는 OPTION BASE란 명령이 있었습니다. VB에도 있는 것 같습니다.
정점 설정
방금 저장한 정점 좌표와 정점 인덱스의 배열을 설정합니다.
var meshFilter = gameObject.GetComponent<MeshFilter>();
var mesh = new Mesh();
mesh.SetVertices(vertices);
mesh.SetIndices(indices.ToArray(),MeshTopology.Triangles,0);
mesh.RecalculateNormals();
mesh.RecalculateBounds();
meshFilter.mesh = mesh;
}
마지막으로, 법선과 바운딩 박스의 재계산도 시킵니다.
이것을 같은 GameObject에 첨부된 MeshFilter 컴퍼넌트에 투입해 끝입니다.
코루틴 호출
테스트이므로, 빨리 Start로부터 코루틴 호출해 버려, 표시시켜 버립니다.
void Start()
{
StartCoroutine(objLoad());
}
전체 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class OBJImport : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
StartCoroutine(objLoad());
}
// Update is called once per frame
void Update()
{
}
IEnumerator objLoad()
{
UnityWebRequest req = UnityWebRequest.Get("https://gist.githubusercontent.com/oho-sugu/875b568ee5bcfdaabbd08d313f07fb0d/raw/682a8439c9ec3296d7e90e30b3dc9aa6e4e53202/test.obj");
yield return req.SendWebRequest();
List<Vector3> vertices = new List<Vector3>();
List<int> indices = new List<int>();
if(req.isHttpError || req.isNetworkError){
Debug.Log(req.error);
} else {
var strs = req.downloadHandler.text.Split('\n');
foreach(string str in strs){
if(str.StartsWith("g")){
} else if(str.StartsWith("v")){
var tokens = str.Split(' ');
vertices.Add(new Vector3(float.Parse(tokens[1]), float.Parse(tokens[2]), float.Parse(tokens[3])));
} else if(str.StartsWith("f")){
var tokens = str.Split(' ');
indices.Add(int.Parse(tokens[1])-1);
indices.Add(int.Parse(tokens[2])-1);
indices.Add(int.Parse(tokens[3])-1);
}
}
}
Debug.Log(vertices.Count);
Debug.Log(indices.Count);
var meshFilter = gameObject.GetComponent<MeshFilter>();
var mesh = new Mesh();
mesh.SetVertices(vertices);
mesh.SetIndices(indices.ToArray(),MeshTopology.Triangles,0);
mesh.RecalculateNormals();
mesh.RecalculateBounds();
meshFilter.mesh = mesh;
}
}
이것을 적당히 히에라루키에 만든 Cube 나름대로 부착하여 실행합시다.
결과
중간에 높은 빌딩군이 롯폰기 힐즈군요.
이제 힐즈 GO를 만들 수 있습니다
도전
파일 사이즈도 커지므로, 바이너리 포맷을 생각하는 것이 좋다고 생각합니다.
Reference
이 문제에 관하여(OBJ로 만든 GIS 데이터를 다운로드하여 Unity에 표시), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/oho-sugu/items/e7441b1f1aebee143628
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
다운로드
UnityWebRequest에서 가져옵니다. 샘플 코드 그대로 감.
IEnumerator objLoad()
{
UnityWebRequest req = UnityWebRequest.Get("URL to FILE/test.obj");
yield return req.SendWebRequest();
여담입니다만, github의 gist는, 이런 Web 액세스의 테스트용의 파일 두는 장소로서 편리하네요. 이번에도 그런 느낌으로 시험하고 있습니다.
OBJ 퍼스
한 줄씩 읽어 갑니다.
정점 좌표와 정점 인덱스를 그대로 읽어 배열에 격납합니다.
List<Vector3> vertices = new List<Vector3>();
List<int> indices = new List<int>();
if(req.isHttpError || req.isNetworkError){
Debug.Log(req.error);
} else {
var strs = req.downloadHandler.text.Split('\n');
foreach(string str in strs){
if(str.StartsWith("g")){
} else if(str.StartsWith("v")){
var tokens = str.Split(' ');
vertices.Add(new Vector3(float.Parse(tokens[1]), float.Parse(tokens[2]), float.Parse(tokens[3])));
} else if(str.StartsWith("f")){
var tokens = str.Split(' ');
indices.Add(int.Parse(tokens[1])-1);
indices.Add(int.Parse(tokens[2])-1);
indices.Add(int.Parse(tokens[3])-1);
}
}
}
Debug.Log(vertices.Count);
Debug.Log(indices.Count);
만약을 위해, 마지막으로 읽어들인 정점수와 인덱스수를 디버그 로그했습니다.
이런 것을 파서라고 말할 수 있을까 하는 정도 간단하네요.
덧붙여서, 인덱스의 read로 -1 하고 있는 것은, OBJ 파일이 1 오리진으로, Unity가 0 오리진이기 때문입니다.
처음에는 여기에서 멈췄다.
배열이 1부터 시작하는 것이 이상하다고 이야기는 있을지도 모릅니다만, 세상 그러한 언어도 있거나 합니다.
예를 들면 Lua라든지군요.
또, 옛 N88-BASIC에는, 배열의 오리진을 0,1로 변경하는 OPTION BASE란 명령이 있었습니다. VB에도 있는 것 같습니다.
정점 설정
방금 저장한 정점 좌표와 정점 인덱스의 배열을 설정합니다.
var meshFilter = gameObject.GetComponent<MeshFilter>();
var mesh = new Mesh();
mesh.SetVertices(vertices);
mesh.SetIndices(indices.ToArray(),MeshTopology.Triangles,0);
mesh.RecalculateNormals();
mesh.RecalculateBounds();
meshFilter.mesh = mesh;
}
마지막으로, 법선과 바운딩 박스의 재계산도 시킵니다.
이것을 같은 GameObject에 첨부된 MeshFilter 컴퍼넌트에 투입해 끝입니다.
코루틴 호출
테스트이므로, 빨리 Start로부터 코루틴 호출해 버려, 표시시켜 버립니다.
void Start()
{
StartCoroutine(objLoad());
}
전체 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class OBJImport : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
StartCoroutine(objLoad());
}
// Update is called once per frame
void Update()
{
}
IEnumerator objLoad()
{
UnityWebRequest req = UnityWebRequest.Get("https://gist.githubusercontent.com/oho-sugu/875b568ee5bcfdaabbd08d313f07fb0d/raw/682a8439c9ec3296d7e90e30b3dc9aa6e4e53202/test.obj");
yield return req.SendWebRequest();
List<Vector3> vertices = new List<Vector3>();
List<int> indices = new List<int>();
if(req.isHttpError || req.isNetworkError){
Debug.Log(req.error);
} else {
var strs = req.downloadHandler.text.Split('\n');
foreach(string str in strs){
if(str.StartsWith("g")){
} else if(str.StartsWith("v")){
var tokens = str.Split(' ');
vertices.Add(new Vector3(float.Parse(tokens[1]), float.Parse(tokens[2]), float.Parse(tokens[3])));
} else if(str.StartsWith("f")){
var tokens = str.Split(' ');
indices.Add(int.Parse(tokens[1])-1);
indices.Add(int.Parse(tokens[2])-1);
indices.Add(int.Parse(tokens[3])-1);
}
}
}
Debug.Log(vertices.Count);
Debug.Log(indices.Count);
var meshFilter = gameObject.GetComponent<MeshFilter>();
var mesh = new Mesh();
mesh.SetVertices(vertices);
mesh.SetIndices(indices.ToArray(),MeshTopology.Triangles,0);
mesh.RecalculateNormals();
mesh.RecalculateBounds();
meshFilter.mesh = mesh;
}
}
이것을 적당히 히에라루키에 만든 Cube 나름대로 부착하여 실행합시다.
결과
중간에 높은 빌딩군이 롯폰기 힐즈군요.
이제 힐즈 GO를 만들 수 있습니다
도전
파일 사이즈도 커지므로, 바이너리 포맷을 생각하는 것이 좋다고 생각합니다.
Reference
이 문제에 관하여(OBJ로 만든 GIS 데이터를 다운로드하여 Unity에 표시), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/oho-sugu/items/e7441b1f1aebee143628
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
파일 사이즈도 커지므로, 바이너리 포맷을 생각하는 것이 좋다고 생각합니다.
Reference
이 문제에 관하여(OBJ로 만든 GIS 데이터를 다운로드하여 Unity에 표시), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/oho-sugu/items/e7441b1f1aebee143628텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)