게임제작기법연구

게임제작기법연구 13주차

ckhyeok 2020. 7. 7. 09:09

평면의 방정식을 유도하고 d의 의미를 정리하시오.

평면의 방정식 $P = ax+by+cz+d = 0$

 

1. 평면에 노멀 벡터 N을 하나 만들어줍니다.

2. 평면 위에 두 점 P0, P를 지정해 줍니다.

3. P0 - P를 해서 벡터를 하나 만들어 줍니다.

4. 노멀 벡터 N와 P0 - P는 서로 직교합니다.

5. 내적 정의에서 $cos \theta$를 사용하므로 직교할 때 0이 됩니다.

$N \cdot (P_0 - P) = 0$

$N \cdot (P_0 - P)  = (a, b, c) \cdot (x - x_0, y - y_0, z - z_0)$

$= a(x - x_0) + b(y - y_0) + c(z - z_0)$

$= ax + by + cz - (ax_0 + by_0 + cz_0) = 0$

결론 : $P = ax+by+cz+d = 0$ 에서 $d = -(ax_0 + by_0 + cz_0)$

 

d의 의미

$d = -(ax_0 + by_0 + cz_0)$ 이며, $P$ 에서 $O$(원점)으로 부터의 최단거리를 뜻합니다.

투영 벡터 공식에 의해 $-N \cdot \overrightarrow{P_0} = d$ 로 표현할 수 있습니다.

$-N \cdot \overrightarrow{P_0} = -(ax_0 + by_0 + cz_0)$ 
단, $(\vert N \vert = 1)$ 일때.

[Frustum Culling - 구현]

1. Sphere 구조체를 정의하고 Cube에 Sphere 바운딩 볼륨을 지정하기

- sphere 구조체를 Mesh에 바운딩 볼륨을 넣어 설정합니다.

class Mesh
{
public:
	Mesh() = default;

	std::vector<Vector3> _Vertices;
	std::vector<int> _Indices;

	std::vector<Vector3>& GetVertices() { return _Vertices; }
	std::vector<int>& GetIndices() { return _Indices; }

	void CreateBound();
	Sphere GetSphereBound() const { return _SphereBound; }

private:
	Sphere _SphereBound;
};

 

2. 월드에 많은 수의 큐브를 랜덤으로 생성하시오. 

 

3. 입력을 사용해 카메라 트랜스폼을 조정하시오. 

void SoftRenderer::Update3D(float InDeltaSeconds)
{
	InputManager input = _GameEngine.GetInputManager();

	Transform& cam = _GameEngine.GetCamera()->GetTransform();
	if (input.GetXAxis())
		cam.AddWorldPosition(cam.GetForward() * 300.f * InDeltaSeconds);
	if (input.GetYAxis())
		cam.AddWorldPosition(-cam.GetForward() * 300.f * InDeltaSeconds);
}

 

4. View 좌표계 기반으로 Frustum Culling을 구현하고 결과를 움짤로 첨부하시오

	Matrix4x4 mat = viewMat * go->GetTransform().GetWorldModelingMatrix();
		Sphere Sphere = mesh->GetSphereBound();
		Sphere.Center = mat * Sphere.Center;
		Sphere.Radius = Sphere.Radius * go->GetTransform().GetWorldScale().Max();
		if (!camera->ViewSpaceFrustumCulling(Sphere))
		{
			viewFrustumCulledCount++;
			continue;
		}
		viewFrustumDrawedCount++;

5. Projection 좌표계 기반으로 Frustum Culling을 구현하고 결과를 움짤로 첨부하시오.  

	Matrix4x4 mat = viewMat * go->GetTransform().GetWorldModelingMatrix();
		Sphere Sphere = mesh->GetSphereBound();
		Sphere.Center = mat * Sphere.Center;
		Sphere.Radius = Sphere.Radius * go->GetTransform().GetWorldScale().Max();
		if (!camera->ProjectionSpaceFrustumCulling(Vector2(_ScreenSize.X, _ScreenSize.Y), goSphere))
			{
				ProjectionFrustumCulledCount++;
				continue;
			}
			ProjectionFrustumDrawedCount++;

6. 둘의 결과가 왜 다르게 나오는지 설명하시오

- Projection Space Frustum Culling은 종횡비가 화면 크기에 영향을 받기 때문입니다.

- View Space Frustum Culling은 종횡비와 무관하기 때문에 결과가 다르게 나왔습니다.

[오일러 각]

1. 짐벌락 현상에 대해 설명하시오

- 같은 방향으로 오브젝트의 두 회전 축이 겹치는 현상입니다.


2. 오일러 각 표현의 장점과 단점에 대해 정리하시오

- 장점

1) 매우 직관적이다(유니티 기준 인터페이스에 사용)

2) 행렬에 비해 메모리가 매우 효율적이다.

- 단점

1) 짐벌락이 생길 수 있습니다.

2) 두개의 축 이상의 회전을 표현할 때 보간되지 않습니다.

 

3. 오일러 각 표현으로 저장된 두 데이터는 한 축만 사용할 때에는 덧셈이 성립되나,

   두 축 이상을 사용할 때에는 덧셈이 성립하지 않는다. 이유를 수학식으로 정리해 설명하시오.

 

$E_{1} = (0, 30, 0), \space E{2} = (0, 45, 0)$

$E_{1} = R_{yaw30} \cdot I \cdot I, \space E_{2} = R_{yaw45} \cdot I \cdot I$

결과 : $E_{2} \cdot E_{1} = R_{yaw45}$

 

$E_{3} = (30, 30, 0), \space E_{4} = (45, 45, 0)$

$E_3 = R_{yaw30} \cdot R_{pitch30} \cdot I, \space E_4 = R_{yaw45} \cdot R_{pitch45} \cdot I$

결과 : $E_4 \cdot E_3 = R_{yaw45} \cdot R_{pitch45} \cdot R_{yaw30} \cdot R_{pitch30} \neq R_{yaw75} \cdot R_{pitch75}$

[로드리게스 회전 공식]

로드리게스 회전 공식의 유도 과정을 정리하시오

$\overrightarrow{O^{\prime}P} = \overrightarrow{OP} - \overrightarrow{OO^{\prime}} = r - (r \cdot n)n$

 

$\begin{align} \overrightarrow{O^{\prime}Q} & = n \cdot \overrightarrow{O^{\prime}Q} \\\ & = n \cdot (r - (r \cdot n)n) \\\ & = n \cdot r - n \cdot ((r \cdot n)n) \\\ & = n \cdot r \space (\because n \cdot n = \vec 0) \end{align}$

 

$\begin{align} \overrightarrow{O^{\prime}P^{\prime}} & = \overrightarrow{O^{\prime}P} cos\theta + \overrightarrow{O^{\prime}Q} sin\theta \\\ & = (r - (r \cdot n)n)cos\theta + (n \cdot r)sin\theta \\\ & = rcos\theta - (r\cdot n)n cos\theta + (n \cdot r)sin\theta \end{align}$

 

$\begin{align} r' & = \overrightarrow{OO^{\prime}} + \overrightarrow{O^{\prime}P^{\prime}} \\\ & = (r \cdot n)n + rcos\theta - (r\cdot n)ncos\theta + (n \cdot r)sin\theta \\\ & = rcos\theta + (1 - cos\theta)(r\cdot n)n + (n\cdot r)sin\theta \end{align}$

로드리게스 회전 공식을 사용해 임의의 축에 대한 회전을 구현하시오.

Vector4 n = Vector4(20.f, 40.f, 60.f, 0.f).Normalize();		
	float cos = cosf(radius);
	for (int i = 0; i < vertexCount; ++i)
	{
		vertices[i] = vertices[i] * cos + n * (1 - cos) * vertices[i].Dot(n) + 
		  Vector4(Vector3(n).Cross(vertices[i]) * sinf(radius), 0);
	
   	 vertices[i].W = 1.f;
	}