DirectX

37. DirectX11 3D 입문_Geometry

devRiripong 2024. 2. 6.
반응형

Cube, Sphere, Grid도 만들어 보자.

 

1. Cube 그리기

Cube를 전략적으로 하나씩 생각해 보자.

 

정점이 몇 개 필요할까?

단순히 색상만 표현하려면 8개로 충분하다.

근데 UV 매핑까지 할 것이다.

면마다 하나씩 그림을 붙이는 걸 목표로 한다.

그런 경우는 점이 8면 uv 좌표를 세팅하게 될 텐데

정점을 줄일 수 없고, 4개씩 6면체에 그릴 수밖에 없다.

즉 24개가 있어야 한다.

void GeometryHelper::CreateCube(shared_ptr<Geometry<VertexTextureData>> geometry)
{
	float w2 = 0.5f;
	float h2 = 0.5f;
	float d2 = 0.5f;

	vector<VertexTextureData> vtx(24);

	// 앞면
	vtx[0] = VertexTextureData{ Vec3(-w2, -h2, -d2), Vec2(0.0f, 1.0f) };
	vtx[1] = VertexTextureData{ Vec3(-w2, +h2, -d2), Vec2(0.0f, 0.0f) };
	vtx[2] = VertexTextureData{ Vec3(+w2, +h2, -d2), Vec2(1.0f, 0.0f) };
	vtx[3] = VertexTextureData{ Vec3(+w2, -h2, -d2), Vec2(1.0f, 1.0f) };
	// 뒷면
	vtx[4] = VertexTextureData{ Vec3(-w2, -h2, +d2), Vec2(1.0f, 1.0f) };
	vtx[5] = VertexTextureData{ Vec3(+w2, -h2, +d2), Vec2(0.0f, 1.0f) };
	vtx[6] = VertexTextureData{ Vec3(+w2, +h2, +d2), Vec2(0.0f, 0.0f) };
	vtx[7] = VertexTextureData{ Vec3(-w2, +h2, +d2), Vec2(1.0f, 0.0f) };
	// 윗면
	vtx[8] = VertexTextureData{ Vec3(-w2, +h2, -d2), Vec2(0.0f, 1.0f) };
	vtx[9] = VertexTextureData{ Vec3(-w2, +h2, +d2), Vec2(0.0f, 0.0f) };
	vtx[10] = VertexTextureData{ Vec3(+w2, +h2, +d2), Vec2(1.0f, 0.0f) };
	vtx[11] = VertexTextureData{ Vec3(+w2, +h2, -d2), Vec2(1.0f, 1.0f) };
	// 아랫면
	vtx[12] = VertexTextureData{ Vec3(-w2, -h2, -d2), Vec2(1.0f, 1.0f) };
	vtx[13] = VertexTextureData{ Vec3(+w2, -h2, -d2), Vec2(0.0f, 1.0f) };
	vtx[14] = VertexTextureData{ Vec3(+w2, -h2, +d2), Vec2(0.0f, 0.0f) };
	vtx[15] = VertexTextureData{ Vec3(-w2, -h2, +d2), Vec2(1.0f, 0.0f) };
	// 왼쪽면
	vtx[16] = VertexTextureData{ Vec3(-w2, -h2, +d2), Vec2(0.0f, 1.0f) };
	vtx[17] = VertexTextureData{ Vec3(-w2, +h2, +d2), Vec2(0.0f, 0.0f) };
	vtx[18] = VertexTextureData{ Vec3(-w2, +h2, -d2), Vec2(1.0f, 0.0f) };
	vtx[19] = VertexTextureData{ Vec3(-w2, -h2, -d2), Vec2(1.0f, 1.0f) };
	// 오른쪽면
	vtx[20] = VertexTextureData{ Vec3(+w2, -h2, -d2), Vec2(0.0f, 1.0f) };
	vtx[21] = VertexTextureData{ Vec3(+w2, +h2, -d2), Vec2(0.0f, 0.0f) };
	vtx[22] = VertexTextureData{ Vec3(+w2, +h2, +d2), Vec2(1.0f, 0.0f) };
	vtx[23] = VertexTextureData{ Vec3(+w2, -h2, +d2), Vec2(1.0f, 1.0f) };

	geometry->SetVertices(vtx);

	vector<uint32> idx(36);

	// 앞면
	idx[0] = 0; idx[1] = 1; idx[2] = 2;
	idx[3] = 0; idx[4] = 2; idx[5] = 3;
	// 뒷면
	idx[6] = 4; idx[7] = 5; idx[8] = 6;
	idx[9] = 4; idx[10] = 6; idx[11] = 7;
	// 윗면
	idx[12] = 8; idx[13] = 9; idx[14] = 10;
	idx[15] = 8; idx[16] = 10; idx[17] = 11;
	// 아랫면
	idx[18] = 12; idx[19] = 13; idx[20] = 14;
	idx[21] = 12; idx[22] = 14; idx[23] = 15;
	// 왼쪽면
	idx[24] = 16; idx[25] = 17; idx[26] = 18;
	idx[27] = 16; idx[28] = 18; idx[29] = 19;
	// 오른쪽면
	idx[30] = 20; idx[31] = 21; idx[32] = 22;
	idx[33] = 20; idx[34] = 22; idx[35] = 23;

	geometry->SetIndices(idx);
}

정점 24개를 만들어서 각각의 uv 좌표들을 연결하는 것이다.

TexutureDemo::Init에서

	//GeometryHelper::CreateQuad(_geometry); 
	GeometryHelper::CreateCube(_geometry);

이렇게 해주고

실행을 하고 옆으로 가서 보면

 

큐브 모양을 확인할 수 있다.

 

 

2. Sphere 그리기

Sphere부터 어려워진다.

void GeometryHelper::CreateSphere(shared_ptr<Geometry<VertexTextureData>> geometry)
{
	float radius = 0.5f; // 구의 반지름
	uint32 stackCount = 20; // 가로 분할
	uint32 sliceCount = 20; // 세로 분할

	vector<VertexTextureData> vtx;

	VertexTextureData v;

	// 북극
	v.position = Vec3(0.0f, radius, 0.0f);
	v.uv = Vec2(0.5f, 0.0f);
	vtx.push_back(v);

	float stackAngle = XM_PI / stackCount;
	float sliceAngle = XM_2PI / sliceCount;

	float deltaU = 1.f / static_cast<float>(sliceCount);
	float deltaV = 1.f / static_cast<float>(stackCount);

	// 고리마다 돌면서 정점을 계산한다 (북극/남극 단일점은 고리가 X)
	for (uint32 y = 1; y <= stackCount - 1; ++y)
	{
		float phi = y * stackAngle;

		// 고리에 위치한 정점
		for (uint32 x = 0; x <= sliceCount; ++x)
		{
			float theta = x * sliceAngle;

			v.position.x = radius * sinf(phi) * cosf(theta);
			v.position.y = radius * cosf(phi);
			v.position.z = radius * sinf(phi) * sinf(theta);

			v.uv = Vec2(deltaU * x, deltaV * y);

			vtx.push_back(v);
		}
	}

	// 남극
	v.position = Vec3(0.0f, -radius, 0.0f);
	v.uv = Vec2(0.5f, 1.0f);
	vtx.push_back(v);

	geometry->SetVertices(vtx);

	vector<uint32> idx(36);

	// 북극 인덱스
	for (uint32 i = 0; i <= sliceCount; ++i)
	{
		//  [0]
		//   |  \\
		//  [i+1]-[i+2]
		idx.push_back(0);
		idx.push_back(i + 2);
		idx.push_back(i + 1);
	}

	// 몸통 인덱스
	uint32 ringVertexCount = sliceCount + 1;
	for (uint32 y = 0; y < stackCount - 2; ++y)
	{
		for (uint32 x = 0; x < sliceCount; ++x)
		{
			//  [y, x]-[y, x+1]
			//  |		/
			//  [y+1, x]
			idx.push_back(1 + (y)*ringVertexCount + (x));
			idx.push_back(1 + (y)*ringVertexCount + (x + 1));
			idx.push_back(1 + (y + 1) * ringVertexCount + (x));
			//		 [y, x+1]
			//		 /	  |
			//  [y+1, x]-[y+1, x+1]
			idx.push_back(1 + (y + 1) * ringVertexCount + (x));
			idx.push_back(1 + (y)*ringVertexCount + (x + 1));
			idx.push_back(1 + (y + 1) * ringVertexCount + (x + 1));
		}
	}

	// 남극 인덱스
	uint32 bottomIndex = static_cast<uint32>(vtx.size()) - 1;
	uint32 lastRingStartIndex = bottomIndex - ringVertexCount;
	for (uint32 i = 0; i < sliceCount; ++i)
	{
		//  [last+i]-[last+i+1]
		//  |      /
		//  [bottom]
		idx.push_back(bottomIndex);
		idx.push_back(lastRingStartIndex + i);
		idx.push_back(lastRingStartIndex + i + 1);
	}

	geometry->SetIndices(idx);
}

북극 남극을 정하고, 도넛을 몇 개로 만들지 정한다.

각 도넛마다 중점으로 피자처럼 분할한 정점을 찍는다.

그리고 그 정점들을 연결하여 삼각형을 만든다.

프랭크 루나 책에 나온 코드를 그대로 쓴 것이다.

uv좌표는 어떤 모양으로 그려질지 자체가 핵심이다.

 

TextureDemo::Init으로 가서

//GeometryHelper::CreateQuad(_geometry); 
//GeometryHelper::CreateCube(_geometry); 
GeometryHelper::CreateSphere(_geometry);

이렇게 해준다.

 

큐브의 경우는 면마다 그림을 붙이는 게 목적이었지만,

Sphere는 이런 느낌이다.

 

TextureDemo::Render에서

_shader->DrawIndexed(0, 1, _indexBuffer->GetCount(), 0, 0);

두 번째 인자를 1로 해서 wireframe으로 해서 보면

 

이렇게 나온다.

구라는 게 결국 삼각형이었다.

 

더 정밀하게 하려면

void GeometryHelper::CreateSphere(shared_ptr<Geometry<VertexTextureData>> geometry)
{
	float radius = 0.5f; // 구의 반지름
	uint32 stackCount = 20; // 가로 분할
	uint32 sliceCount = 20; // 세로 분할

이 부분을 얼마나 정밀하게 하냐에 따라 더 세밀하게 하거나 대충 만들거나 할 수 있다.

 

한번 만들면 평생 쓸 일 없어서 자세히 분석할 거 까진 없다.

 

3. Grid 그리기

마지막으로 Grid로 넘어간다.

땅(terrain)을 깔아야 하는데 그때 사용되는 거 다.

총 몇 개짜리의 사각형으로 만들지가 관건이다. 10개를 만들려면 가로, 세로 정점은 11개여야 한다.

2차 배열로 할 수 있다.

 

다른 것과 다르게 크기를 지정해줘야 한다.

 

GeometryHelper.h에서

static void CreateGrid(shared_ptr<Geometry<VertexTextureData>> geometry, int32 sizeX, int32 sizeZ);
void GeometryHelper::CreateGrid(shared_ptr<Geometry<VertexTextureData>> geometry, int32 sizeX, int32 sizeZ)
{
	vector<VertexTextureData> vtx;

	for (int32 z = 0; z < sizeZ + 1; z++)
	{
		for (int32 x = 0; x < sizeX + 1; x++)
		{
			VertexTextureData v;
			v.position = Vec3(static_cast<float>(x), 0, static_cast<float>(z));
			v.uv = Vec2(static_cast<float>(x), static_cast<float>(sizeZ - z));

			vtx.push_back(v);
		}
	}

	geometry->SetVertices(vtx);

	vector<uint32> idx;

	for (int32 z = 0; z < sizeZ; z++)
	{
		for (int32 x = 0; x < sizeX; x++)
		{
			//  [0]
			//   |	\\
			//  [2] - [1]
			idx.push_back((sizeX + 1) * (z + 1) + (x));
			idx.push_back((sizeX + 1) * (z)+(x + 1));
			idx.push_back((sizeX + 1) * (z)+(x));
			//  [1] - [2]
			//   	\\  |
			//		  [0]
			idx.push_back((sizeX + 1) * (z)+(x + 1));
			idx.push_back((sizeX + 1) * (z + 1) + (x));
			idx.push_back((sizeX + 1) * (z + 1) + (x + 1));
		}
	}

	geometry->SetIndices(idx);
}

TextureDemo::Init에서

//GeometryHelper::CreateQuad(_geometry); 
	//GeometryHelper::CreateCube(_geometry); 
	//GeometryHelper::CreateSphere(_geometry); 
	GeometryHelper::CreateGrid(_geometry, 256, 256);

실행을 하면

 

 

이상하게 나온다.

wierefame으로 보면

 

 

Grid는 정상적으로 나오는 듯하다.

 

GeometryHelper::CreateGrid에서

v.uv = Vec2(static_cast<float>(x), static_cast<float>(z));

이렇게 SizeZ-z에서 z로 수정하고 실행하면

 

 

뒤집히긴 했지만 이미지가 보이긴 한다.

 

uv좌표에서 0, 0은 이미지의 왼쪽 상단에 위치하기 때문에 SizeZ-z에서 z로 수정하니 뒤집혀 보이게 된다.

 

한 칸은 이미지가 나오지만 나머지는 이상하게 나온다

 

04. Texture.fx의

SamplerState Sampler0;

여기에 뭔가 옵션을 설정할 수 있었는데

uv좌표는 0~1이 공식적인 uv 좌표인데 그 범위를 벗어나면 어떻게 할 것인가가 이런 부분을 설정하는 것이라 볼 수 있다.

1을 넘어가는 1~2면 어떻게 그릴 것인가와 관련된 옵션을 smapleState라는 클래스를 만들어서 하면 된다. 

1을 넘어가는 범위를 어떻게 할지 세팅하지 않았기 때문에 지금처럼 나오는 것이다.

반응형

'DirectX' 카테고리의 다른 글

39. DirectX11 3D 입문_HeightMap  (0) 2024.02.08
38. DirectX11 3D 입문_Sampling  (0) 2024.02.07
36. DirectX11 3D 입문_텍스처  (0) 2024.02.06
35. DirectX11 3D 입문_카메라  (0) 2024.02.05
34. DirectX11 3D 입문_Constant Buffer  (0) 2024.02.02

댓글