상세 컨텐츠

본문 제목

Mesh(1) - 원기둥, 원

DirectX

by 부레두 2024. 7. 31. 22:41

본문

0. 개요

그리드 생성에서 높이 설정까지 완성한 다음으로 복잡한 기하도형에 해당하는 원, 원기둥을 그리는 방법과 더불어 한 씬에 여러 물체를 배치( 여러 월드 변환 행렬을 사용하는 법 )와 CubeMap 생성에 대해 공부한다.

 

원기둥과 원은 구면좌표계로 점의 위치가 정의되는데, 여기 간단하게 구면좌표계의 구성 요소에 대해 설명을 적는다.

 

  1. r (반지름): 원점(0, 0, 0)에서 점까지의 거리. 항상 0 이상의 값을 가진다.
  2. θ (세타, polar angle): z축과 점을 연결하는 선이 이루는 각도. 일반적으로 0에서 π(180도) 사이의 값을 가진다.
  3. φ (파이, azimuthal angle): x축과 xy평면에서 점을 연결하는 선이 이루는 각도. 일반적으로 0에서 2π(360도) 사이의 값을 가진.

1. 원기둥 ( Cylinder )

원기둥은 밑면, 윗면 반지름, 높이, 조각(slice) 개수와 더미 개수(stack)로 정의된다.

원기둥의 모든 정점은 원기둥의 고리에 놓여있는데 원기둥을 이루기 위해 하나씩 쌓이는 작은 원을 더미, Stack Count라 하면 각 고리는 뚜껑을 구성하는 조각의 수, SliceCount 개 만큼의 정점으로 이루어진다.

각각의 Count가 원기둥의 정점 밀도를 정한다.

왼쪽은 Slice가 8, Stack이 4개 / 오른쪽은 16개, 8개

 

더보기

> 원기둥 생성 코드

// 정점 위치 계산
vector<MeshVertex> v;
v.push_back(MeshVertex(0, radius, 0, 0, 0, 0, 1, 0));

float phiStep = Math::PI / stackCount;
float thetaStep = Math::PI * 2.0f / sliceCount;

for (UINT i = 1; i <= stackCount - 1; i++)
{
	float phi = i * phiStep;

	for (UINT k = 0; k <= sliceCount; k++)
	{
		float theta = k * thetaStep;

		Vector3 p = Vector3
		(
			(radius * sinf(phi) * cosf(theta)),
			(radius * cos(phi)),
			(radius * sinf(phi) * sinf(theta))
		);

		Vector3 n;
		D3DXVec3Normalize(&n, &p);

		Vector2 uv = Vector2(theta / (Math::PI * 2), phi / Math::PI);
			
		v.push_back(MeshVertex(p.x, p.y, p.z, uv.x, uv.y, n.x, n.y, n.z));
	}
}
v.push_back(MeshVertex(0, -radius, 0, 0, 0, 0, -1, 0));

// 정점 인덱스 값 계산
vector<UINT> i;
for (UINT k = 1; k <= sliceCount; k++)
{
	i.push_back(0);
	i.push_back(k + 1);
	i.push_back(k);
}

UINT baseIndex = 1;
UINT ringVertexCount = sliceCount + 1;
for (UINT k = 0; k < stackCount - 2; k++)
{
	for (UINT j = 0; j < sliceCount; j++)
	{
		i.push_back(baseIndex + k * ringVertexCount + j);
		i.push_back(baseIndex + k * ringVertexCount + j + 1);
		i.push_back(baseIndex + (k + 1) * ringVertexCount + j);

		i.push_back(baseIndex + (k + 1) * ringVertexCount + j);
		i.push_back(baseIndex + k * ringVertexCount + j + 1);
		i.push_back(baseIndex + (k + 1) * ringVertexCount + j + 1);
	}
}

UINT southPoleIndex = v.size() - 1;
baseIndex = southPoleIndex - ringVertexCount;

for (UINT k = 0; k < sliceCount; k++)
{
	i.push_back(southPoleIndex);
	i.push_back(baseIndex + k);
	i.push_back(baseIndex + k + 1);
}

2. 원

원은 하나의 구를 반지름과 조각 갯수 및 더미 갯수로 정의한다. 원기둥과의 차이점은 고리의 반지름이 삼각함수에 따라 비선형으로 변한다는것이다.

더보기

> 구 생성 코드

vector<MeshVertex> v;
v.push_back(MeshVertex(0, radius, 0, 0, 0, 0, 1, 0));

float phiStep = Math::PI / stackCount;
float thetaStep = Math::PI * 2.0f / sliceCount;

for (UINT i = 1; i <= stackCount - 1; i++)
{
	float phi = i * phiStep;

	for (UINT k = 0; k <= sliceCount; k++)
	{
		float theta = k * thetaStep;

		Vector3 p = Vector3
		(
			(radius * sinf(phi) * cosf(theta)),
			(radius * cos(phi)),
			(radius * sinf(phi) * sinf(theta))
		);

		Vector3 n;
		D3DXVec3Normalize(&n, &p);

		Vector2 uv = Vector2(theta / (Math::PI * 2), phi / Math::PI);
			
		v.push_back(MeshVertex(p.x, p.y, p.z, uv.x, uv.y, n.x, n.y, n.z));
	}
}
v.push_back(MeshVertex(0, -radius, 0, 0, 0, 0, -1, 0));


// 인덱스 계산	
vector<UINT> i;
for (UINT k = 1; k <= sliceCount; k++)
{
	i.push_back(0);
	i.push_back(k + 1);
	i.push_back(k);
}

UINT baseIndex = 1;
UINT ringVertexCount = sliceCount + 1;
for (UINT k = 0; k < stackCount - 2; k++)
{
	for (UINT j = 0; j < sliceCount; j++)
	{
		i.push_back(baseIndex + k * ringVertexCount + j);
		i.push_back(baseIndex + k * ringVertexCount + j + 1);
		i.push_back(baseIndex + (k + 1) * ringVertexCount + j);

		i.push_back(baseIndex + (k + 1) * ringVertexCount + j);
		i.push_back(baseIndex + k * ringVertexCount + j + 1);
		i.push_back(baseIndex + (k + 1) * ringVertexCount + j + 1);
	}
}

UINT southPoleIndex = v.size() - 1;
baseIndex = southPoleIndex - ringVertexCount;

for (UINT k = 0; k < sliceCount; k++)
{
	i.push_back(southPoleIndex);
	i.push_back(baseIndex + k);
	i.push_back(baseIndex + k + 1);
}

3. 메시 배치

생성해둔 메시의 구조를 이용해 크기(Scale), 회전(Rotate), 위치(Transform) 변환 행렬를 포함해 텍스쳐까지 다르게 지정해 같은 구조의 도형도 다른 위치, 다른 크기, 다른 색으로 월드에 배치할 수 있다.

 

'DirectX' 카테고리의 다른 글

Model(1) - 기초 설명  (1) 2024.10.10
Mesh(2) - CubeMap  (0) 2024.08.07
Terrain(2) - Normal 값을 통한 음영  (1) 2024.07.18
Terrain(1) - 높이 설정  (0) 2024.07.18
Texture(3) - 좌표지정모드  (0) 2024.07.11

관련글 더보기