Microsoft MVP성태의 닷넷 이야기
Graphics: 16. 3D 공간에서 두 점이 이루는 각도 구하기 [링크 복사], [링크+제목 복사],
조회: 29908
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)

3D 공간에서 두 점이 이루는 각도 구하기

예를 들어, 다음과 같이 3D 공간에서 면과 점이 있다고 가정해 보겠습니다.

angle_between_two_0.png
(오른손 좌표계 시스템의 x-y-z 축을 사용하고 있습니다.)

이때 점 C와 점 A가 이루는 각도는 어떻게 될까요? 간단하게 점과 점의 위치를 빼서 벡터를 만들고,

점 C와 카메라의 벡터 = 점 C - 점 A
                    = (-1.4, -2.9, -5)

그 벡터가 이루는 각을 3차원에 따라 각 축 별로 3개의 각도를 구할 수 있습니다.

  • x-축을 기준으로 y-z 평면의 각
  • y-축을 기준으로 x-z 평면의 각
  • z-축을 기준으로 x-y 평면의 각

역시 시각화를 해보는 게 좋겠지요? ^^ GeoGebra 앱에서 "Home" 모양의 아이콘을 누르면,

angle_between_two_1.png

차례대로 "y축을 기준으로 x-z 평면", "z축을 기준으로 x-y 평면", "x축을 기준으로 y-z 평면" 상에서의 물체를 볼 수 있는 기능이 제공됩니다.

자... 멋진 툴이 있으니, 그럼 우선 첫 번째 아이콘인 "y축을 기준으로 x-z 평면"을 다음과 같이 볼 수 있습니다. ^^

angle_between_two_2_y.png

보는 바와 같이 x-z 평면에서 벡터가 이루는 각을 쉽게 확인할 수 있습니다. 점 A에서 x-축으로 수선의 발을 그렸을 때,

angle_between_two_3.png

직각 삼각형이 되고 이때 우리가 아는 벡터 A의 x, z 성분의 값으로 인해 아크 탄젠트 함수를 사용하면 점 A에서 이루는 각도를 구할 수 있습니다.

각 A = arc_tangent(vx, vz);

C# 코드로 구해 보면 다음과 같습니다.

Vector3 v3 = new Vector3(-1.4f, -2.9f, -5f);

{
    double yAngle = Math.Atan2(v3.X, v3.Z);
    Console.WriteLine(RadianToDegree(yAngle));
}

실행해 보면, -164.357753796137도가 나오는데, 벡터가 음의 방향이어서 그런 것일 뿐 180도를 빼면 약 15.6도가 나옵니다. 동일한 각도를 Geogebra 기하를 이용해서도 구해 볼까요? ^^

2차원 좌표계에서 x, z의 성분으로 점을 표시한 후 그와 연결한 벡터를 그리고 그 사잇각을 다음과 같이 구할 수 있습니다.

angle_between_two_4.png

잘 맞아 들어가는군요. ^^




마찬가지 방식으로 "z축을 기준으로 x-y 평면"과,

angle_between_two_2_z.png

"x축을 기준으로 y-z 평면" 상의 모습을 확인하며,

angle_between_two_2_x.png

각도를 구해 보면 이렇습니다.

Vector3 v3 = new Vector3(-1.4f, -2.9f, -5f);
Console.WriteLine("xAngle");
{
    double xAngle = Math.Atan2(v3.Y, v3.Z);
    Console.WriteLine(RadianToDegree(xAngle));
}

Console.WriteLine("yAngle");
{
    double yAngle = Math.Atan2(v3.X, v3.Z);
    Console.WriteLine(RadianToDegree(yAngle));
}

Console.WriteLine("zAngle");
{
    double zAngle = Math.Atan2(v3.Y, v3.X);
    Console.WriteLine(RadianToDegree(zAngle));
}

/*
출력 결과

xAngle
-149.886266031276
yAngle
-164.357753796137
zAngle
-115.769326504636
*/

(첨부 파일은 이 글에서 예제로 사용한 geogebra 파일입니다.)




참고로, 2개의 벡터가 이루는 각은 아크코사인을 이용해 구할 수 있습니다.

vector v1 = ...;
vector v2 = ...;

vector nv1 = normalize(v1);
vector nv2 = normalize(v2);

float angle = acos(mul(nv1, nv2));

일반적으로 acos의 정의역이 -1 ~ 1이기 때문에 정규화된 벡터의 내적 연산으로 NaN 값을 반환하는 경우는 없습니다. 문제는 0 벡터인 경우 normalize 하는 과정에서 NaN이 나온다는 것입니다.

vector v = vector(0, 0, 0, 0);
vector normal = normalize(v); // normal == NaN

왜냐하면 정규화라는 것이 벡터 크기로 나누는 것인데,

${
\hat v = \left ( \frac{ v_x }{ \Vert v \Vert }, \frac{ v_y }{ \Vert v \Vert }, \frac{ v_z }{ \Vert v \Vert } \right )
}$

분모가 0이 되므로 normalize의 결과가 NaN이 나옵니다. 이 때문에 mul 연산도 NaN이 되고, acos까지 NaN으로 끝납니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 8/1/2018]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 91  92  93  94  95  96  97  [98]  99  100  101  102  103  104  105  ...
NoWriterDateCnt.TitleFile(s)
11481정성태4/10/201831961개발 환경 구성: 357. CUDA의 인덱싱 관련 용어 - blockIdx, threadIdx, blockDim, gridDim
11480정성태4/9/201821968.NET Framework: 736. C# - API를 사용해 Azure에 접근하는 방법 [2]파일 다운로드1
11479정성태4/9/201817681.NET Framework: 735. Azure - PowerShell로 Access control(IAM)에 새로운 계정 만드는 방법
11478정성태11/8/201919883디버깅 기술: 115. windbg - 덤프 파일로부터 PID와 환경변수 등의 정보를 구하는 방법 [1]
11477정성태4/8/201817372오류 유형: 460. windbg - sos 명령어 수행 시 c0000006 오류 발생
11476정성태4/8/201818886디버깅 기술: 114. windbg - !threads 출력 결과로부터 닷넷 관리 스레드(System.Threading.Thread) 객체를 구하는 방법
11475정성태3/28/201821138디버깅 기술: 113. windbg - Thread.Suspend 호출 시 응용 프로그램 hang 현상에 대한 덤프 분석
11474정성태3/27/201819271오류 유형: 459. xperf: error: TEST.Event: Invalid flags. (0x3ec).
11473정성태3/22/201824510.NET Framework: 734. C# - Thread.Suspend 호출 시 응용 프로그램 hang 현상파일 다운로드2
11472정성태3/22/201818459개발 환경 구성: 356. GTX 1070, GTX 960, GT 640M의 cudaGetDeviceProperties 출력 결과
11471정성태3/20/201821879VC++: 125. CUDA로 작성한 RGB2RGBA 성능 [1]파일 다운로드1
11470정성태3/20/201823852오류 유형: 458. Visual Studio - CUDA 프로젝트 빌드 시 오류 C1189, expression must have a constant value
11469정성태3/19/201816850오류 유형: 457. error MSB3103: Invalid Resx file. Could not load file or assembly 'System.Windows.Forms, ...' or one of its dependencies.
11468정성태3/19/201816438오류 유형: 456. 닷넷 응용 프로그램 실행 시 0x80131401 예외 발생
11467정성태3/19/201815977오류 유형: 455. Visual Studio Installer - 업데이트 실패
11466정성태3/18/201817053개발 환경 구성: 355. 한 대의 PC에서 2개 이상의 DirectX 게임을 실행하는 방법
11463정성태3/15/201819466.NET Framework: 733. 스레드 간의 read/write 시에도 lock이 필요 없는 경우파일 다운로드1
11462정성태3/14/201822314개발 환경 구성: 354. HTTPS 호출에 대한 TLS 설정 확인하는 방법 [1]
11461정성태3/13/201824899오류 유형: 454. 윈도우 업데이트 설치 오류 - 0x800705b4 [1]
11460정성태3/13/201817393디버깅 기술: 112. windbg - 닷넷 메모리 덤프에서 전역 객체의 내용을 조사하는 방법
11459정성태3/13/201818162오류 유형: 453. Debug Diagnostic Tool에서 mscordacwks.dll을 찾지 못하는 문제
11458정성태2/21/201819234오류 유형: 452. This share requires the obsolete SMB1 protocol, which is unsafe and could expose your system to attack. [1]
11457정성태2/17/201823940.NET Framework: 732. C# - Task.ContinueWith 설명 [1]파일 다운로드1
11456정성태2/17/201829651.NET Framework: 731. C# - await을 Task 타입이 아닌 사용자 정의 타입에 적용하는 방법 [7]파일 다운로드1
11455정성태2/17/201818563오류 유형: 451. ASP.NET Core - An error occurred during the compilation of a resource required to process this request.
11454정성태2/12/201827434기타: 71. 만료된 Office 제품 키를 변경하는 방법
... 91  92  93  94  95  96  97  [98]  99  100  101  102  103  104  105  ...