티스토리 툴바



Cross Product(외적)


∥A×B∥ = ∥A∥∥B∥sinα


α는 A와 B의 사잇각이다. 위 식의 결과 값은 A, B 두 벡터로 이루어질 수 있는 평행 사변형의 넓이 값이다.

다음은 위의 식을 응용해서 3개의 꼭지점(벡터)이 주어진 삼각형의 넓이를 구하는 함수를 만들어보았다.
float GetTheAreaOfTheTriangle(const D3DXVECTOR3& v3A, const D3DXVECTOR3& v3B, const D3DXVECTOR3& v3C)
{
	D3DXVECTOR3 v3X = v3A - v3C;
	D3DXVECTOR3 v3Y = v3B - v3C;

	D3DXVECTOR3 v3Crossed;
	D3DXVec3Cross(&v3Crossed, &v3X, &v3Y);

	return D3DXVec3Length(&v3Crossed) * 0.5f;
}

A, B 벡터를 포함하는 평면에 대해 수직인 벡터를 구할 때 쓰인다. 


이 때에 수직인 벡터는 두 방향이 나오게 되는데,

좌표계의 법칙을 따라서 왼손 좌표계 혹은 오른손 좌표계에 따라 다르게 결정된다.

그것을 쉽게 판단 하려면 엄지, 검지, 중지를 순서대로 벡터를 나열하면 된다. A×B = N 이라고 할때,

엄지: A, 검지: B, 중지: N 의 순서대로, 엄지와 검지로 x-y 축의 평면을 만들고, 중지를 꺾어서 z 축을 만들면 된다.

OpenGL 이라면 오른손 좌표계이므로 오른손으로 방향을 판단하면 될 것이고,

DirectX 라면 왼손 좌표계로 왼손에서 할당하여 판단하면 될 것이다.

또한 A×B = N 일때, B×A = -N 이된다.

따라서 내적과는 다르게 교환 법칙은 성립하지 않고, 결합 및 분배 법칙은 성립한다.
Trackback 0 Comment 0

Dot Product(내적)


A·B = ∥A∥∥B∥cosα


이론적인 핵심 수식은 위와 같으며, 수식에서 보이듯이 내적의 결과는 스칼라 값이다.

가끔식 헷갈리는 경우가 있는데 내적은 교환, 결합, 분배 법칙이 성립하므로 다음 두 코드는 동일하다.
D3DXVec3Dot(&v3A, &v3B);
D3DXVec3Dot(&v3B, &v3A);
두 벡터가 정규화 되었을 때에 수식에 들어가는 cos이 그대로 노출 되므로,

두 벡터의 각이 0이면 내적 결과가 1이 되며, 90도일 때는 결과가 0이 된다. 마찬가지로 180도이면 -1이된다.

3D 공간상에서 두 벡터의 내적을 통해 다룰 수 있는 성질을 나열해 본다면 다음과 같다.

첫 번째로, 두 벡터가 같은 방향을 바라보는지 알 수 있게 해준다.


 위 수식에서 길이는 항상 양수일 것이고 cos을 응용해서 같은 방향을 가리키는지 알아보는 함수를 작성해본다면 다음과 같다.
bool IsSameDirection(const D3DXVECTOR3& v3A, const D3DXVECTOR3& v3B)
{
	float fDotResult = D3DXVec3Dot(&v3A, &v3B);
	return (0 < fDotResult);
}
좀 더 생각해보면 수직(직각, 90도)일 때에는 내적의 값이 0이 나오게 된다.


두 번째로, 두 벡터 사이의 각도를 알 수 있게 해준다.


그것을 함수로 작성해보면 다음과 같을 것이다.
float GetAngle(const D3DXVECTOR3& v3A, const D3DXVECTOR3& v3B)
{
	float fDotResult = D3DXVec3Dot(&v3A, &v3B);
	float fALength = D3DXVec3Length(&v3A);
	float fBLength = D3DXVec3Length(&v3B);

	return acosf(fDotResult / (fALength * fBLength));
}

float GetAngleNormalized(const D3DXVECTOR3& v3A, const D3DXVECTOR3& v3B)
{
	assert(abs(D3DXVec3Length(&v3A) - 1.0f) < D3DX_16F_EPSILON);
	assert(abs(D3DXVec3Length(&v3B) - 1.0f) < D3DX_16F_EPSILON);

	float fDotResult = D3DXVec3Dot(&v3A, &v3B);
	return acosf(fDotResult);
}

A, B 벡터가 Normalized(정규화)되지 않았을 때와 정규화 되었을 때의 최적화 함수를 나타낸 것이다.

정규화 되지 않은 벡터를 처리하는 것이 더 안전하다.

한가지 짚고 넘어가야할 것은, 내적의 교환법칙으로 인하여 A, B 벡터의 순서에 상관없이 같은 내적값이 나오므로

이 말은 두 벡터를 포함한 평면에서 사잇각은 두 개이다. 작은 각과 큰 각이 나오게 되는데,

내적은 항상 작은 각만을 구해서 리턴하게 되며 A, B 벡터의 순서를 따지지 않는다. 결론은, 0도에서 180도까지만 나온다는 말이다.

따라서 A벡터를 기준으로 B벡터가 얼만큼의 각으로 돌아갔는지를 구하려면 좀더 계산이 필요하게 된다.

3차원에서 어느방향이 각도의 증가방향인지 알고 싶다면

왼손, 오른손 좌표계에 따라서 해당하는 손을 주먹을 쥐고 엄지를 폈을 때에 4손가락이 감기는 손톱뱡향이 각도의 증가 방향이 된다.

A, B 벡터를 순서대로 외적을 해주면 나오게 되는 방향으로 알 수가 있는데(외적은 다음 포스팅 참고),

이 때에 세 손가락을 직각으로 폈을 때의 엄지, 검지를 A, B 벡터의 순서로 잡고 A를 기준 방향으로 따지면

중지의 방향에 따라서 감소의 각으로 돌아갔는지 증가의 각으로 돌아갔는지 판단할 수 있게 된다.

물론 중지의 방향은 XYZ의 기준축과 평행할 수록 쉽게 판단할 수 있다.


세 번째로, A벡터를 B벡터에 대하여 평행 및 수직인 성분을 구할 수 있게 해준다.


 다음은 A벡터를 Axis(축)의 방향으로 평행한 벡터와 직각인 벡터로 쪼개는 함수이다.

예외처리는 A와 Axis 벡터가 평행한 경우이다. 이때는 결과가 false가 리턴되도록 알려준다.
bool Disassemble(const D3DXVECTOR3& IN v3A, const D3DXVECTOR3& IN v3Axis,
	D3DXVECTOR3& OUT v3Parallel, D3DXVECTOR3& OUT v3Orthogonal)
{
	D3DXVECTOR3 v3NormalizedAxis;
	D3DXVec3Normalize(&v3NormalizedAxis, &v3Axis);

	float fParallelLength = D3DXVec3Dot(&v3A, &v3NormalizedAxis);

	if (abs(fParallelLength) < D3DX_16F_EPSILON)
	{
		v3Parallel = v3NormalizedAxis * D3DXVec3Length(&v3A);
		v3Orthogonal.x = 0.0f;
		v3Orthogonal.y = 0.0f;
		v3Orthogonal.z = 0.0f;
		return false;
	}
	else
	{
		v3Parallel = v3NormalizedAxis * fParallelLength;
		v3Orthogonal = v3A - v3Parallel;
		return true;
	}
}


Trackback 0 Comment 0

Syntax Highlighter

Syntax Highlighter 3.0.83 적용..

다른 블로그에서는 대충 설치 후에 적어놓은 것들이라 따라해도 잘 안되었지만
아래 블로그에서는 제대로 적용이 되었다.
한가지 삽질은 편집모드 상에서는 보이지 않으므로 따로 블로그를 접근해서 새로고침하여 테스트 할것.

http://dis1.tistory.com/218


#include <stdio.h>
void main()
{
    int x = 0;
    printf("Hello World!\n");
}
Trackback 0 Comment 0