'code'에 해당되는 글 1건

  1. 2014/02/23 글뻥 Unity3D Code로 Mesh 생성하기 (2)
근래에 새로운 프로젝트에 들어가는 바람에 강좌 업데이트가 안되서 죄송합니다.
모바일에서 3D게임이 조금씩 고급으로 치닫는 바람에 공부해야할게 너무나 많네요.

오늘은 간단히 Code로 Mesh를 생성해보겠습니다.

일단, Mesh라는 녀석을 정확히 한번 따져보겠습니다.
Mesh란 Wiki에 따르면 (http://en.wikipedia.org/wiki/Polygon_mesh) 이러합니다.

A polygon mesh is a collection of vertices, edges and faces that defines the shape of a polyhedral object in 3D computer graphics and solid modeling.

* 폴리곤 메쉬는 버티컬들과 엣지들과 면들을 3D컴퓨터 그래픽/솔리드모델링에서 사용하는 다면체의 모양의 집합이다.

뭐... 번역이 어려워서 글치 결국 폴리곤이라는 녀석을 모아 놓은게 폴리곤 메쉬 즉, 우리가 흔히 이야기하는 메쉬가 되겠습니다.

이럴때는 어려운 말 한마디 보다 다음의 Vertex-Vertex Meshes의 예를 한번 보죠.

* Vertex-Vertex Meshes의 예
사용자 삽입 이미지
점 9개가 보여서 하나의 육면체를 이루고 있습니다.
정확하게는 다음과 같이 구성되어 있습죠. 네네...
사용자 삽입 이미지


Vertex는 점입니다. 이 점들을 이은 선이 접선 또는 Edge하고 하고 이렇게 Edge가 보이면 면(Face)가 되고 Face가 2개 이상 모이면 면(Surface)가 됩니다. 다시 면들을 모으면 폴리곤 메쉬가 됩니다. (쉽죠?)

암튼 우리는 개발자니까(?)... 데이터구조에 관심을 가져봅시다.

첫 번째 예제를 보면 좌측에 Vertex List에 대한 데이터까지 상세하게 정의되어 있군요!
V0값은 Vector3좌표와 인접한 Vertex의 Index를 가지고 있습니다.

이제 이걸 기초로 메쉬 한번 만들어 봅시다.
물론 처음부터 육면체 만들자고 하면 서로 머리 복잡하니, Vertex 4개로 구성된 작은 4각형 메쉬를 만들겁니다.

먼저 빈 게임오브젝트 1개를 만들어 봅시다.
사용자 삽입 이미지
만들어진 빈 게임오브젝트에 Mesh Compoent인 Mesh Filter와 Mesh Renderer를 추가합니다.
사용자 삽입 이미지
- Mesh Filter는 Mesh의 데이터를 저장합니다.
- Mesh Renderer는 렌더링을 Mesh Filter에 있는 데이터로 렌더링을 담당하죠.

그리고 인식하기 쉽게 게임오브젝트의 이름을 "Mesh"라고 변경합니다.
아래의 예를 보면 Mesh Filter Components에는 "None (Mesh)"라고 되어 있는게 보이실 겁니다.

사용자 삽입 이미지
이제 여기 "Mesh Filter"에다가 데이터를 넣어 봅시다.

C# 스크립트를 하나 만들고 다음과 같이 코딩합니다.

using UnityEngine;
using System.Collections;
//List Collection을 사용하기 위해 Generic도 사용합니다.
using System.Collections.Generic;

public class MeshGen : MonoBehaviour {

    //ArrayList도 괜찮지만 편의상 List 객체로 선언해둡시다.
    //버텍스들의 위치를 저장할 객체입니다.
    public List<Vector3> _Vertex = new List<Vector3>();
    //다른 인접 버텍스의 Index값입니다.
    public List<int> _Tri = new List<int>();
    private Mesh mesh;

	// Use this for initialization
	void Start () {
        //시작하면 MeshFilter Compoent를 가져옵니다.
        mesh = GetComponent<MeshFilter>().mesh;

        //Position 값들인데, 편의상 풀었습니다.
        float x = transform.position.x;
        float y = transform.position.y;
        float z = transform.position.z;


        _Vertex.Add(new Vector3(x, y, z));
        _Vertex.Add(new Vector3(x + 1, y, z));
        _Vertex.Add(new Vector3(x + 1, y - 1, z));
        _Vertex.Add(new Vector3(x, y - 1, z));

         //이제부터는 버텍스 인덱스입니다.
         //이건 예제 코드 뒤에 설명하겠습니다.
         //1번 폴리곤
        _Tri.Add(0);
        _Tri.Add(1);
        _Tri.Add(3);
         //2번 폴리곤
        _Tri.Add(1);
        _Tri.Add(2);
        _Tri.Add(3);

        //메쉬를 청소해줍니다.
        mesh.Clear();
        //버텍스 데이터를 배열로 밀어 넣습니다.
        mesh.vertices = _Vertex.ToArray();
        //인접한 버텍스 데이터를 배열로 밀어 넣습니다.
        mesh.triangles = _Tri.ToArray();
        //메쉬를 생성합니다.
        mesh.Optimize();
        mesh.RecalculateNormals();
	}
}


실행해보면...
사용자 삽입 이미지
요롷콤 메쉬가 생성되어 있고,
Mesh 게임오브젝트 역시, 다음과 같이 값이 잘 들어가 있군요!
사용자 삽입 이미지
이제 인접 Index 값의 비밀을 알려드리죠.
비밀은 간단하게도 일종의 규칙입니다.
Polygon이 되려면 3개의 점이 있어야 합니다. 따라서, 그걸 간단히 3개씩 잘라서 사용하는 거죠.
사용자 삽입 이미지
실제로 다음과 같이 소스를 수정해보면...


        _Tri.Add(0);
        _Tri.Add(1);
        _Tri.Add(3);
        _Tri.Add(1);
        _Tri.Add(2);
        //_Tri.Add(3);


이런 상큼한 에러를 볼 수 있습니다.
사용자 삽입 이미지
"삼각형은 반드시 3의 배수여야 한다."

추가 설명은 여기까지 하고 이제 저 뻘건 녀석에게 옷을 입힐 차례입니다.
먼저 사용할 Texture가 있어야 겠지요?

깔끔한 128X128 px 짜리 체커입니다.
사용자 삽입 이미지



일반적으로 많이 사용하는 텍스쳐 Import후, Drag&Drop으로 게임오브젝트에 밀어 넣습니다.

사용자 삽입 이미지

플레이해보면... 어라?

사용자 삽입 이미지

예상과 다르게 시커먼 녀석만 올라왔네요.
이는 mesh데이터에 UV값을 넣지 않아서 생기는 현상입니다.
이제 UV값을 받을 수 있도록 소스를 추가해봅시다.


using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class MeshGen : MonoBehaviour {

    public List<Vector3> _Vertex = new List<Vector3>();
    public List<int> _Tri = new List<int>();
    public List<Vector2> _UV = new List<Vector2>();
    private Mesh mesh;

    //Cell간의 Gap입니다. 5by5짜리 텍스쳐니까 간단히 1/5 = 0.2!
    private float _cellGap = 0.2f;
    //cell들의 Index를 저장합니다.
    public List<Vector2> _cell = new List<Vector2>();

    void Start () {
        mesh = GetComponent<MeshFilter>().mesh;

        float x = transform.position.x;
        float y = transform.position.y;
        float z = transform.position.z;


        _Vertex.Add(new Vector3(x, y, z));
        _Vertex.Add(new Vector3(x + 1, y, z));
        _Vertex.Add(new Vector3(x + 1, y - 1, z));
        _Vertex.Add(new Vector3(x, y - 1, z));

        _Tri.Add(0);
        _Tri.Add(1);
        _Tri.Add(3);
        _Tri.Add(1);
        _Tri.Add(2);
        _Tri.Add(3);

         //셀은 2개만 사용할겁니다. 0,0에 있는 검은색과 0,1에 있는 흰색입니다.
        _cell.Add(new Vector2(0, 0));
        _cell.Add(new Vector2(0, 1));

         //텍스쳐의 좌표를 UV에 넣습니다.
         //만약 List 인덱스 0번이라면 (0,0), (0.2,0), (0, 0.2), (0.2, 0.2)의 값을 가지겠죠?
        _UV.Add(new Vector2(_cellGap * _cell[1].x, _cellGap * _cell[1].y + _cellGap));
        _UV.Add(new Vector2(_cellGap * _cell[1].x + _cellGap, _cellGap * _cell[1].y + _cellGap));
        _UV.Add(new Vector2(_cellGap * _cell[1].x + _cellGap, _cellGap * _cell[1].y));
        _UV.Add(new Vector2(_cellGap * _cell[1].x, _cellGap * _cell[1].y));

        mesh.Clear();
        mesh.vertices = _Vertex.ToArray();
        mesh.triangles = _Tri.ToArray();
        //UV값을 넣습니다.
        mesh.uv = _UV.ToArray(); 
        mesh.Optimize();
        mesh.RecalculateNormals();
        }
}


이제 끝!
실행결과 입니다.

사용자 삽입 이미지
2014/02/23 16:47 2014/02/23 16:47