대학생활/수업

게임프로그래밍고급 4~5주차

se.jeon 2023. 4. 12. 13:50
728x90
반응형

지난 시간의 복습

내적

두개의 벡터를 하나의 스칼라 값으로 표현한 연산.

- 두 벡터 사이의 사이각을 계산 가능하다.

- 플레이어가 바라보는 방향을 기준으로 상대방이 앞인지 뒤인지 판단 가능하다.

- 플레이어가 바라보는 시야각 안에 들어왔는지 판단 가능하다.

 

외적

두 개의 벡터에서 벡터 한 개를 만드는 연산.

두 개의 벡터 A, B에 수직이고, A, B로 이루어진 평행사변형의 넓이와 동일한 면적을 가진 벡터.

- A와 B벡터의 외적은 벡터 A와도 수직이고, 벡터 B와도 수직이다.

- 평면의 법선 벡터를 구할 때 사용된다.

- 플레이어를 기준으로 상대방이 오른쪽에 있는지 왼쪽에 있는지 판별한다.

- 삼각형 안에 점이 포함되어 있는지 판단할 때 사용된다.

 

행렬

- Transpose Matrix (전치 행렬)

- Identity Matrix (단위 행렬)

- Inverse Matrix (역행렬)

- 행렬의 덧셈 & 뺄셈

- 행렬의 곱셈

 

삼각함수

- 삼각형의 개념 : 세개의 점과 세개의 변으로 이루어진 다각형, 내각의 합은 180도. 평면상에 존재한다.

- 피타고라스의 정리 : 직각삼각형을 기준으로, 빗변의 제곱의 합이 다른 두 변의 제곱과 같다.

- sin = 높이/빗변

- cos = 밑변/빗변

- tan = 높이/밑변

- unit circle : 단위원, 반지름의 길이가 1인 원

- 삼각함수의 그래프

 

절차적 모델링의 의미

절차적 모델링 (Procedural Modeling)

모델러가 3D Max와 같은 툴을 사용해서 모델링을 만드는 것이 아니라, 프로그래머가 알고리즘을 사용하여 모델링을 만드는 것. 자동화시킨 알고리즘을 통해서 모델을 제작한다.

- 게임의 지형 생성, 식물의 조형, 도시의 구성을 구현한다.

- 게임 플레이 중 스테이지의 구조 변동을 통한 콘텐츠의 디자인이 가능하다.

 

컴퓨터를 이용한 디자인 처리

파라미터를 이용해서 특정 모델의 구조나 크기를 변경 가능하다.

유연하게 조작 가능한 모델을 콘텐츠에 삽입 가능하다.

   - 나무 생성, 특정 위치에 빌딩이 늘어선 마을 구성.

   - 다양한 형태의 모델을 미리 넣으면, 데이터의 용량이 커진다.

   - 몇 가지 모델의 다양성을 통해서 늘리는 방법이 가능하다.

 

Mesh Class

모델 데이터를 관리하는 유니티 클래스

- 모든 정점은 하나의 배열로 저장된다.

- 개별 삼각형은 정점 배열의 인덱스로 저장된다.

- 모든 삼각형들은 인덱스(음이 아닌 정수)의 긴 배열로 저장된다.

- 정점 3개마다 하나의 삼각형 (0, 1, 2 & 3, 4, 5)

 

Model Data

삼각형들로 구성되어져 있는 형태, 정점, UV 좌표, 법선 벡터

 

Quad

4개의 정점, 2개의 삼각형으로 구성된 가장 기초적인 도형 중 하나.

- 정점 데이터 : 4개

- UV 데이터 : 4개

- 법선 데이터 : 4개

- 삼각형 : 2개

 

CCW (Counter Clock Wide)

3개의 점을 이은 직선의 방향을 알고자 할 때 유용한 기하 알고리즘.
   경우의 수는 외적을 통하여 구할 수 있으며, 총 3가지가 있다. (시계, 반시계, 직선)

   외적의 결과에 따라 의미하는 바가 다르다.

     - 음수 : 시계 방향

     - 0 : 직선

      - 양수 : 반시계 방향

 

Quad 정의 순서

- Mesh 클래스를 이용한 인스턴스 생성

- Quad의 4개의 정점을 Vector3 배열로 생성

- UV 좌표 데이터

- 법선 데이터

- 인덱스 데이터

 

Mesh 인스턴스 생성

// mesh 인스턴스 생성
var mesh = new Mesh();

// 메쉬 크기
float size = 10.0f;

// 메쉬 크기의 절반
var hsize = size * 0.5f;

Quad의 4개의 정점을 Vector3 배열로 생성

var vertices = new Vector3[]
{
    new Vector3( hsize, hsize, 0f), // 0번 정점, quad 오른쪽 위의 위치
    new Vector3(-hsize, hsize, 0f), // 1번 정점, quad 왼쪽 위의 위치
    new Vector3(-hsize, -hsize, 0f), // 2번 정점, quad 오른쪽 아래의 위치
    new Vector3( hsize, -hsize, 0f) // 3번 정점, quad 왼쪽 아래의 위치
};

UV 좌표계

Texture를 적용하기 위해서는 텍스처 맵핑 좌표계를 설정해야 한다.

2D 텍스처 좌표계는 U, V값을 통해서 결정된다.

   - 0~1 사이의 실수값이다.

   - X축은 U, Y축은 V

 

UV 좌표 데이터

var uv = new Vector2[] 
{
    new Vector2(1f, 1f), // 0번 정점의 uv 좌표
    new Vector2(0f, 1f), // 1번 정점의 uv 좌표
    new Vector2(0f, 0f), // 2번 정점의 uv 좌표
    new Vector2(1f, 0f) // 3번 정점의 uv 좌표
};

법선 데이터

var normals = new Vector3[] 
{
    new Vector3(0f, 0f, -1f), // 0번 정점의 법선
    new Vector3(0f, 0f, -1f), // 1번 정점의 법선
    new Vector3(0f, 0f, -1f), // 2번 정점의 법선
    new Vector3(0f, 0f, -1f) // 3번 정점의 법선
};

인덱스 데이터

var triangles = new int[] 
{
    0, 3, 1, // 첫번째 삼각형
    1, 3, 2 // 두번째 삼각형
}

최종 Mesh 인스턴스 설정

mesh.vertices = vertices;
mesh.uv = uv;
mesh.normals = normals;
mesh.triangles = triangles;

// mesh bounding box 다시 계산
mesh.RecalculateBounds();

// mesh filter에 설정
GetComponent<MeshFilter>().mesh = mesh;

Unity로 Mesh 만들기 실습

1. Quad 내용을 참고해 Unity를 이용해 triangle 한 개를 생성해 보세요.

2. 정점의 위치는 (3, 3, 0), (-3, 3, 0), (3, -3, 0).

- Project 생성

- GameObject 생성

- Mesh Filter 컴포넌트 추가 : Mesh 구성

https://docs.unity3d.com/kr/2020.3/Manual/class-MeshFilter.html

 

메시 필터 - Unity 매뉴얼

메시 필터(Mesh Filter) 는 에셋에서 메시를 가져와 화면에 렌더링하기 위해 메시 렌더러에 전달합니다.

docs.unity3d.com

- Mesh Renderer 컴포넌트 추가 : Mesh 렌더링

https://docs.unity3d.com/kr/2020.3/Manual/class-MeshRenderer.html

 

메시 렌더러 - Unity 매뉴얼

메시 렌더러는 메시 필터에서 지오메트리를 가져와 게임 오브젝트의 Transform 컴포넌트에서 정의된 위치에서 렌더링합니다.

docs.unity3d.com

 

절차적 모델링 정의 : Plane

여러개의 vertex와 UV가 모아져서 그려지게 된다.

- Quad를 나열하여서 만들어 놓은 형태

- 세로 방향의 정점의 수 : 3개

- 가로 방향의 정점의 수 : 3개

- 너비, 높이

 

Mesh 인스턴스 생성

// mesh 인스턴스 생성
var mesh = new Mesh();

// 메쉬 구성 요소 준비
var vertices = new List<Vector3>();
var uv = new List<Vector2>();
var normals = new List<Vector3>();

int widthSegments = 3;
int heightSegments = 3;

float width = 10.0f;
float height = 10.0f;

// 격자상에 정점을 배열할 위치의 비율(0,.0 ~ 0.1)을 산출하기 위한 행-열 개수의 역수
// widthSegments,heightSegments의 값이 이용되므로 유한 실수가 나오도록 조심
var winv = 1f / (widthSegments - 1);
var hinv = 1f / (heightSegments - 1);

정점 정보 구성

for (int y = 0; y < heightSegments; y++)
{
    // 행의 위치 비율(0.0 ~ 1.0)
    var ry = y * hinv;

    for (int x = 0; x < widthSegments; x++)
    {
        // 열의 위치 비율(0.0 ~ 1.0)
        var rx = x * winv;

        vertices.Add(new Vector3((rx - 0.5f) * width, 0f, (0.5f - ry) * height));
        uv.Add(new Vector2(rx, ry));
        normals.Add(new Vector3(0f, 1f, 0f));
    }
}

 

삼각형 정보 구성

var triangles = new List<int>();

for (int y = 0; y < heightSegments - 1; y++)
{
    for (int x = 0; x < widthSegments - 1; x++)
    {
        int index = y * widthSegments + x;
        var a = index;
        var b = index + 1;
        var c = index + 1 + widthSegments;
        var d = index + widthSegments;
        // 삼각형 2개는 Quad 1개임.
        triangles.Add(a);
        triangles.Add(b);
        triangles.Add(c);
        triangles.Add(c);
        triangles.Add(d);
        triangles.Add(a);
    }
}

최종 Mesh 인스턴스 설정

mesh.vertices = vertices.ToArray();
mesh.uv = uv.ToArray();
mesh.normals = normals.ToArray();
mesh.triangles = triangles.ToArray();

// mesh bounding box 다시 계산
mesh.RecalculateBounds();

// mesh filter에 설정
GetComponent<MeshFilter>().mesh = mesh;

 

728x90
반응형