목표
- 내적
- 내적의 직교성 판별
- 내적 활용 (앞뒤 구분, 시야 판별, 음영)
- 벡터 투영 공식
들어가기 전
본 글에서 직접적으로 설명하지 않지만, 언급하고 있는 내용입니다.
인프런 강의 중 이득우의 게임 엔진을 지탱하는 게임 수학을 참고하여 작성되었습니다.
벡터의 내적 (Dot Product)
벡터의 연산
1) 벡터의 기본 연산
- 벡터와 벡터의 덧셈 $(a, b, c) + (d, e, f) = (a+d, b+e, c+f)$
- 벡터와 스칼라의 곱셈 $k(a, b, c) = (ka, kb, kc)$
2) 유용한 연산
- 벡터와 벡터의 곱 $(a,b,c)\cdot (d,e,f)=(ad,be,cf)$
- 벡터의 내적 $(a,b,c)\cdot(d,e,f) = ad + be + cf$
- 벡터의 외적 (3차원에서만 성립)
내적이란?
벡터와 벡터의 곱을 서로 더하는 것이다. 벡터 내적의 결과 값은 스칼라
벡터의 내적은 차원에 상관없이 가능하며, 결과 값은 스칼라이다.

벡터 내적의 성질
- 교환 법칙 O

- 결합 법칙 X

- 분배 법칙 O

벡터 내적의 코사인 공식
벡터 내적에서 가장 중요한 공식이다.
두 벡터의 크기가 1인 경우(단위벡터), 두 벡터의 내적은 $cos\theta$와 대응된다.


벡터 내적의 직교성 판별
(두 벡터의 크기가 1일 때) $a \cdot b = cos\theta = 0$이면
$cos90^{\circ} = cos270^{\circ} = 0$ 이므로 내적 값이 0이면 직교함을 알 수 있다.

리지드 트랜스포메이션 (강체 변환)
물체의 형태가 변하지 않는 변환의 조건은 아래와 같다.
- 공간을 구성하는 모든 기저 벡터의 크기가 1
- 모든 기저 벡터가 서로 직교하고 있어야 함.
- 선형 변환의 행렬식(ad - bc) 값이 1
회전 변환은 이를 만족하기에 물체의 형태를 변환시키지 않는다.
아래는 행 기반 행렬의 회전 변환 행렬이다.

회전 변환이 리지드 트랜스포메이션을 만족한다는 증명
1) 공간 내 모든 기저 벡터의 크기는 1이다.
피타고라스 정리에 의해 $cos\theta^{2} + sin\theta^{2} = 1$을 만족한다.


2) 모든 기저 벡터가 서로 직교한다.
벡터 내적의 직교성 판별을 통해 두 내적의 값이 0이면 직교임을 알 수 있다.

3) 선형 변환의 행렬식 (ad - bc) 값이 1이다.


코사인 값 별 두 벡터의 상태
- 두 벡터 a,b가 직각이면 0 (내각 90도)
- 다른 방향 보고 있다면 -1 (내각 91 ~ 180도)
- 같은 방향 보고 있다면 1 (내각 0 ~ 89도)
벡터 내적의 활용
벡터의 내적은 두 벡터의 사이각(내각) 알기 위해, 두 벡터를 분해해 수직 및 평행한 벡터 알기 위해
, 두 벡터가 가리키는 방향의 차이를 알기 위해 활용된다.
1. 목표물의 앞 뒤 판별
두 벡터가 단위 벡터일 때, 두 벡터의 내적은 $cos\theta$이므로 이를 이용한다.
$cos\theta$는 [$-90^{\circ}, 90^{\circ}$] 범위는 양수이고, 그 이후는 음수이다.
즉, 바라보는 시야벡터(첫 번째 벡터)와 목표물을 향한 벡터(두 번째 벡터)를 내적한 결과 값이
양수이면 앞에 있고, 음수이면 뒤에 있음을 바로 알 수 있다. (각도를 직접 구할 필요 없음)


* 본인은 몬스터(원근 투영)에 고정시킨 Hp바(직교투영)가
몬스터가 뒤에 있어도 보이는 현상을 해결하기 위해 내적값이 음수이면 컬링되도록 활용했다.
(코사인 그래프 사진 출처: 수학 공식 | 고등학교 > 삼각함수의 뜻과 그래프 – MATH FACTORY)
내적을 이용한 컬링
_uint CHpBar_Monster::LateTick(_double TimeDelta)
{
▩ 플레이어의 룩과 몬스터(=UI위치?) 룩을 내적해서 90도 넘어가면 컬링
CTransform* pPlayerTrans = dynamic_cast<CTransform*>(m_pGameInstance->Get_Component(LEVEL_STATIC, TEXT("Layer_Player"), TEXT("Component_Transform")));
_vector vPlayerPos = pPlayerTrans->Get_State(CTransform::STATE_POSITION);
_vector vOwnerPos = m_pOwner->Get_TransformCom()->Get_State(CTransform::STATE_POSITION);
_vector vOwnerLook = vOwnerPos - vPlayerPos;
_vector vPlayerLook = pPlayerTrans->Get_State(CTransform::STATE_LOOK);
// 내적으로 얻은 값은 라디안
_float fDotAngle = acosf(XMVectorGetX(XMVector3Dot(XMVector3Normalize(vOwnerLook), XMVector3Normalize(vPlayerLook))));
▩ 90도 이하면 출력
if(fDotAngle <= XMConvertToRadians(90.f))
m_pRendererCom->Add_RenderGroup(CRenderer::RENDER_UI, this);
return _uint();
}
2. 시야 판별
각 $a$가 시야각의 절반 값 $\frac{\beta}{2}$보다 작다면 목표물은 시야각 내에 위치한다.
- $cos\frac{\beta}{2}$ 값을 미리 구해 저장해둔다.
- 시선벡터와 목표물로 향하는 벡터의 크기를 1로 조정한다. 그렇다면 두 벡터의 내적은 $cos\alpha$가 된다.
- 코사인 함수는 $(0^{\circ}, 180^{\circ})$ 범위에서 각이 증가할수록 값이 감소한다.
- 따라서 두 코사인 함수 값을 비교해 $cos\alpha$ 값이 더 크면 시야범위 내에 있다고 파악한다.


(코사인 그래프 사진 출처: 수학 공식 | 고등학교 > 삼각함수의 뜻과 그래프 – MATH FACTORY)
3. 음영 계산
램버트 코사인 법칙
물체 표면이 반사하는 빛의 휘도는 표면 방향과 광원 방향의 사잇각(세타)의 코사인 값에 비례한다.


L이 표면의 법선 벡터 N에 가까워질수록 들어오는 빛의 양↑ 사잇값이 커질수록 들어오는 빛의 양↓
두 벡터를 정규화한 뒤, 내적하는 경우 $cos\theta$와 동일하다.
각이 커질수록 $cos\theta$는 작아지므로 이를 이용하여 각도를 구하지 않고도 음영을 지정할 수 있다.
디퍼드 셰이더
내적만을 사용해서 음영을 지정하는 가장 기본적인 셰이더

(출처 : https://docs.unity3d.com/Manual/shader-NormalDiffuse.html)
투영 벡터 공식
투영 벡터
두 개의 벡터 중 하나의 벡터가 다른 벡터에
벡터가 다른 하나의 벡터에 투영했을 때, 투영한 벡터의 크기와 값은 어떻게 되는지 파악하는 공식이다.
1. 벡터를 투영하면 어떻게 되는가?
벡터 u를 벡터 v에 투영했을 때, 크기만 다르고 벡터 v의 방향과 동일해진다. (겹쳐진다고 보면 됨.)

2. 투영한 벡터를 구하는 법
투영한 벡터는 대상 벡터와 방향은 동일하고, 크기만 다르기 때문에 구하는 법은 아래와 같다.


2.1. 정규화된 벡터 $\hat{v}$구하는 법 (방향 구하기)
$\hat{v}$은 정규화된(=크기가 1) 벡터를 의미한다.

2.2. 투영한 벡터 $v^{'}$크기 구하기
벡터 $v^{'}$의 크기는 코사인 함수를 사용해 구할 수 있다.

이를 위해서는 사잇각 $ \theta$를 알아야 한다.
이는 내적 공식을 이용해서 알 수 있다.

2.3. 투영 벡터를 구하는 최종 식
내적은 교환 법칙은 성립하나 결합 법칙은 성립되지 않는다는 점을 주의하자.

=

=

투영하려는 벡터의 크기가 1이라면 이 식은 다음과 같이 단순해진다.

'수학' 카테고리의 다른 글
| [게임 콘텐츠의 제작 원리] 아핀공간 (0) | 2025.01.09 |
|---|---|
| [기초수학] 직선/평면의 방정식, 두 직선의 교차점 (ft. 기울기) (0) | 2025.01.07 |
| [기초 수학] 행렬과 역행렬 (0) | 2025.01.02 |
| [기초수학] 선형성 (0) | 2024.12.30 |
| [기초수학] 삼각함수, 각도법과 호도법, 극 좌표계 (1) | 2024.12.29 |