평면의 방정식을 유도하고 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;
}
'게임제작기법연구' 카테고리의 다른 글
게임제작기법연구 15주차 (0) | 2020.07.20 |
---|---|
게임제작기법 연구 14주차 (0) | 2020.07.14 |
게임제작기법연구 12주차 (0) | 2020.06.29 |
게임제작기법연구 11주차 (0) | 2020.06.22 |
게임제작기법연구 10주차 (0) | 2020.06.16 |