Math - 3D
[TOC]
좌표계
엄지, 검지, 중지를 x, y, z축으로 가정한다.
- 오른손 좌표계(y-up) : 오른손으로 y축이 위로 x축이 오른쪽으로 가게한다. 그러면 중지가 나를 가리키고 이 방향이 z축의 양의 방향이다.
- OpenGL(y-up), Max(z-up)
- 왼손 좌표계(y-up) : 왼손으로 y축이 위로 x축이 오른쪽으로 가게한다(오른손과 동일). 그러면 중지가 앞을 가리키고 이 방향이 z축의 양의 방향이다.
- 유니티(y-up), DirectX(y-up), Unreal(z-up)
평면
평면의 활용
- 게임에서 바닥, 벽에 충돌 여부 판정
- 물체가 카메라 시야에 들어왔는지 판정
평면의 조건
- 직선상에 있지 않은 점이 3개
- 2개이면 평면이 만들어지지 않고 4개이면 평면이 평평하지 않을 수 있다.
- 점 3개가 직선상에 있거나 모두 같은 위치에 있으면 평면을 만들 수 없다.
- 평면의 법선 벡터와 평면 위의 좌표 하나
법선 벡터(Normal Vector)
한 평면이나 직선에 대하여 수직인 벡터를 말한다.
법선 벡터를 알면 평면의 기울기를 알 수 있다.
법선 벡터와 평면 상의 한 점으로 평면을 정의할 수 있다.
법선 벡터로 평면의 앞, 뒤를 알 수 있다.
평면 방정식
평면은 평면 위의 점과 평면에 수직인 법선으로 정의할 수 있다.
이는 평면 위의 점을 지나고 법선 벡터에 수직인 벡터를 구하는 방정식으로 해석할 수 있고 이를 구하는 방정식이 평면의 방정식이다.
\[\text{평면의 벡터 방정식} \\ \begin{matrix} O &:& 원점 \\ \vec{n}(a, b, c) &:& \text{평면에 수직인 법선 벡터} \\ A(x_1, y_1, z_1) &:& \text{평면상의 점} \\ P(x, y, z) &:& \text{평면상의 점} \\ \\ \end{matrix} \\ \begin{matrix} \vec{AP} \cdot \vec{n} = 0 \\ (\vec{OP} - \vec{OA}) \cdot \vec{n} = 0 \\ (\vec{p} - \vec{a}) \cdot \vec{n} = 0 \\ \\ \end{matrix} \\ \text{위 평면상의 벡터 방정식을 성분에 의한 내적으로 표현한다} \\ \begin{matrix} (x - x_1, y - y_1, z - z_1) \cdot (a, b, c) = 0 \\ a(x - x_1) + b(y - y_1) + c(z - z_1) = 0 \\ \\ \text{위 식은 } A(x_1, y_1, z_1)\text{를 지나고(시작점으로 하고) } \vec{n}(a, b, c)\text{에 수직인 벡터를 구하는 평면의 방정식이다.} \\ \\ \end{matrix} \\\]평면 방정식 결과의 의미
점의 좌표를 평면 방정식에 대입했을 때
| 결과 | 점의 위치 |
|---|---|
| 0 | 평면 상에 있다. |
| 양수 | 법선 벡터쪽에 있다. |
| 음수 | 법선 벡터 반대쪽에 있다. |
평면 방정식의 일반형
\[\begin{matrix} 0 &=& a(x-x_1) + b(y-y_1) + c(z-z_1) \\ &=& ax + by + cz +(-ax_1 - by_1 - cz_1) \\\\ d &=& (-ax_1 - by_1 - cz_1) \\ &=& -(ax_1 + by_1 + cz_1) \\ &=& -N \cdot Q \\\\ & \therefore& ax + by + cz + d = 0 \\ \end{matrix}\] \[\begin{matrix} \text{x, y, z에 대한 일차식으로 표현} \\ \text{x, y, z의 계수인 a, b, c가 평면의 법선 벡터} \\ \text{이 방정식을 만족하는 해는 평면상에 있다} \end{matrix}\] \[\begin{matrix} a = 0, b \ne 0, c \ne 0 \\ \text{x축에 대해 평행인 평면이 만들어진다.} \\ \\ a = 0, b = 0, c \ne 0 \\ \text{xy 평면에 대해 평행인 평면이 만들어진다.} \\ \\ \end{matrix}\]평면의 법선 벡터 : N(a, b, c) 평면 위의 좌표 : Q(x₁, y₁, z₁)
위 방정식에 따라 평면은 a, b, c, d 4개의 수로 만들 수 있고 벡터는 3개의 수로 만들 수 있다.
확실하게 평면상에 있는 좌표
\[(-\frac{d}{3a}, -\frac{d}{3b}, -\frac{d}{3c})\]확실하게 평면상에 있는 좌표
\[\require{cancel} \begin{matrix} ax + by + cz + d &=& a(-\frac{d}{3a}) + b(-\frac{d}{3b}) + c(-\frac{d}{3c}) + d \\ &=& \cancel{a}(-\frac{d}{3\cancel{a}}) + \cancel{b}(-\frac{d}{3\cancel{b}}) + \cancel{c}(-\frac{d}{3\cancel{c}}) + d \\ &=& -\frac{d}{3} -\frac{d}{3} -\frac{d}{3} + d \\ &=& -d + d \\ &=& 0 \end{matrix}\]증명 : 평면 방정식에 좌표 대입
평면과 점 사이의 거리
\[\require{cancel} \begin{matrix} &&\text{법선 벡터가 정규화 됐을 경우} \\ \lVert W \rVert &=& \cos \alpha \lVert V \rVert \\ &=& \hat{V} \cdot \hat{N} \times \lVert V \rVert \\ &=& \frac{V}{\sqrt{V_x^2+V_y^2+V_z^2}} \cdot \hat{N} \times \sqrt{V_x^2+V_y^2+V_z^2} \\ &=& \frac{V}{\cancel{\sqrt{V_x^2+V_y^2+V_z^2}}} \cdot \hat{N} \times \cancel{\sqrt{V_x^2+V_y^2+V_z^2}} \\ &=& V \cdot \hat{N} \\ && \text{(V벡터를 N벡터에 투영한 값과 같다)} \\\\ &=& V_x\hat{N}_x + V_y\hat{N}_y + V_z\hat{N}_z \\ &=& (P_x-Q_x)\hat{N}_x + (P_y-Q_y)\hat{N}_y + (P_z-Q_z)\hat{N}_z \\ &=& (P_x\hat{N}_x + P_y\hat{N}_y + P_z\hat{N}_z) - (Q_x\hat{N}_x + Q_y\hat{N}_y + Q_z\hat{N}_z) \\ &=& (P_x\hat{N}_x + P_y\hat{N}_y + P_z\hat{N}_z) - \hat{N} \cdot Q \\ &=& (P_x\hat{N}_x + P_y\hat{N}_y + P_z\hat{N}_z) + d \\\\ && \therefore \text{d를 구하고 }P_x, P_y, P_z\text{에 공간상의 점의 좌표를 대입하면 거리를 구할 수 있다.} \end{matrix}\] \[\text{법선 벡터가 정규화되지 않았을 경우} \\ d = -N \cdot Q \\ \lVert W \rVert = \frac{(P_xN_x + P_yN_y + P_zN_z) + d}{\lVert N \rVert}\]평면의 법선 벡터 : N
공간 상의 한 점 : P
평면 위의 한 점 : Q
P → Q 벡터 : V
평면과 좌표 사이의 가장 짧은 거리 벡터 : W
V와 W의 내각 : α
평면에 수직으로 선분 그리기 구현
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlaneEquation : MonoBehaviour {
public Transform Plane;
public Transform SpacePoint;
// 공간상의 한 점에서 평면에 수직으로 선분 그리기
private void OnDrawGizmos()
{
/*
법선 벡터 : N(Nx, Ny, Nz)
평면상의 한 점 : P(Px, Py, Pz)
평면의 방정식 : Nx*x + Ny*y + Nz*z + d = 0
d = -N·Q = -(Nx*Px + Ny*Py + Nz*Pz)
*/
Vector3 n = Plane.up.normalized; // 평면의 법선 벡터
Vector3 p = Plane.position; // 평면상의 한 점
Vector3 s = SpacePoint.position; // 공간상의 한 점
// d값은 변하지 않기 때문에 미리 계산하는게 좋다.
float d = -(n.x * p.x + n.y * p.y + n.z * p.z);
// 공간 상의 점과 평면의 거리
float distance = n.x * s.x + n.y * s.y + n.z * s.z + d;
// 공간 상의 점과 평면을 연결하는 가장 짧은 벡터
Vector3 shortestVector = -n * distance;
Debug.Log(distance);
if (distance > 0)
{
Gizmos.color = Color.red;
} else if (distance < 0)
{
Gizmos.color = Color.blue;
} else
{
Gizmos.color = Color.white;
}
Gizmos.DrawWireSphere(SpacePoint.position, SpacePoint.localScale.x);
Gizmos.DrawLine(SpacePoint.position, SpacePoint.position + shortestVector);
}
}