• Home
  • About
    • 게임 개발자 유정룡 photo

      게임 개발자 유정룡

      포트폴리오

    • Learn More
    • Email
    • Github
    • Bitbucket
  • Projects
    • All Projects
    • All Tags

Direct3D11 공부 19일차(Mesh - Sphere)

22 Jun 2021

Reading time ~3 minutes

Sphere

이번엔 구다. 지금까지는 일반적인 xyz 좌표로 점을 찍었지만, 구는 구면 좌표계를 통해 찍어야 한다.

일단 극좌표 부터 이해를 하자.

극좌표

이 좌표에서 극좌표는

이렇게 각도와 길이가 주어졌을 때 (5,θ) 로 표현이 가능하다.

그런데 어떻게 저 좌표로 구현이 가능할까?

cosθ = 3/5 이기 때문에 θ = cos^-1(3/5) 이렇게 치환이 가능하다.

따라서 (5,cos^-1(3/5))로 구할 수 있다.

거리가 5인 점들은 많지만, x축을 기준으로 했을때 각도가 θ인 좌표는 저기 뿐이기 때문이다.

원주좌표

설명은 Directx의 Y좌표가 Z 좌표로 하고 설명한다.

이 좌표가 흔하게 사용하는 좌표다

이렇게 위에서 배운 극좌표를 이용하면 이런 식으로 좌표를 구할 수 있다.

이렇게 하면 각 점들을 일반 좌표보다 빠른 속도로 구할 수 있다.

구면좌표

여기서 중요한 점이 있는데 θ는 상관 없지만, Φ의 경우에는 z축의 양의 방향으로부터의 각도

그러니까 항상 0 <= Φ <= π 이 범위를 갖는다.

z축의 좌표는 e * cos(Φ)

x축의 좌표는 e * sin(Φ) cosθ 가 된다.

y축의 좌표는 r * sin(θ) 이기 때문에 r 은 e * sin(Φ) 그러니 e * sin(Φ)* sin(θ)가 된다.

e은 직교 좌표계에서 √(x^2 * y^2 * z^2) = e 이기 때문에 e^2 = x^2 * y^2 * z^2 이 된다.

구를 그릴땐 마지막에 구면좌표를 이용해서 그린다.

MeshSphere.cpp

void MeshSphere::Create()
{
	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 * cosf(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));

	vertices = new MeshVertex[v.size()];
	vertexCount = v.size();

	copy(v.begin(), v.end(), stdext::checked_array_iterator<MeshVertex *>(vertices, vertexCount));

	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);
	}

	indices = new UINT[i.size()];
	indexCount = i.size();

	copy(i.begin(), i.end(), stdext::checked_array_iterator<UINT *>(indices, indexCount));
}

굉장히 많다…. 하나하나 차근차근 보자

맨 위와 아랫점은 반복문이 아니고 따로 설정하고,

한번에 스텝마다 각 축들을 원으로 그리면서 하나하나 찍는다. 한 줄을 다 찍었다면 다음엔 한칸 내려서 또 그린다.

이런 방법으로 쭉 정점을 찍고

IndexBuffer의 경우에는 사각형 찍는 방향과 동일한 방향으로 찍어준다.

이렇게 하면

이렇게 원으로 잘 나온다.

이걸 wireframe으로 보면

이렇게 수많은 삼각형으로 이뤄졌다.



DirectX Share Tweet +1