평면 ( 3개의 점 )과 직선 (원점과 방향)의 교차점을 구하는 방법이다.

수학적 개념보다 코드가 더 이해가 빠른거 같다.


Unity 상에서 C#코드를 통해 계산했습니다. (Intersect Triangle)


무한 평면 기준

    private bool IntersectTriangle(Vector3 RayOrigin, Vector3 RayDirection, Vector3 V0, Vector3 V1, Vector3 V2)
{
Vector3 edge1 = V1 - V0;
Vector3 edge2 = V2 - V0;

Vector3 pvec = Vector3.Cross(RayDirection, edge2);

dot = Vector3.Dot(edge1, pvec);

Vector3 tvec;
if (dot > 0) tvec = RayOrigin - V0;
else
{
tvec = V0 - RayOrigin;
dot = -dot;
}

if (dot < 0.0001f)
return false;

u = Vector3.Dot(tvec, pvec);
// if (u < 0.0f || u > dot)
// return false;

Vector3 qvec = Vector3.Cross(tvec, edge1);

v = Vector3.Dot(RayDirection, qvec);
// if (v < 0.0f || u + v > dot) return false;

t = Vector3.Dot(edge2, qvec);
float flnvDet = 1.0f / dot;

t *= flnvDet;
u *= flnvDet;
v *= flnvDet;

return true;
}

코드 자체의 원리는

1. 3개의 점을 통해서 2개의 직선을 구한다.

2. 2개의 직선을 외적해서 법선 벡터를 구한다.

3. 내적을 통해 직선의 방향을 결정한다.


3 - 1 유한 평면의 경우 내적을 통해 u를 계산, 평면의 좌, 우를 넘어갔는지 판단한다.

3 - 2 유한 평면의 경우 내적을 통해 v를 계산, 평면의 위, 아래를 넘어갔는지 판단한다.


if (IntersectTriangle(Line.position, Line.forward, P0.position, P1.position, P2.position))
{
Vector3 point = Line.position + (Line.forward * t);
Gizmos.DrawSphere(point, 0.1f);
}

true 일때만 교차점이 생기고 , 교차점은 직선의 원점 + 직선의 방향 * t로 구하면 된다.


유한 평면 기준

IntersectTriangle의 주석처리된 부분을 풀어주면 유한 평면에서만 충돌하는지 검사 가능



Vector3 Direction to Quaternion (Rotation)

방향 벡터를 이용해서 쿼터니언 (로테이션) 구하기


this.front.subVectors( this.finalTarget, this.resultPos );
this.front.normalize();

현재 좌표에서 바라볼 대상의 좌표를 뺀다.

정규화 (Normalize) 하면 대상을 바라보는 Look Vector (front)가 생긴다.


this.up.set( 0, 1, 0);

Up vector를 설정한다. (일반적으로 0, 1, 0인 상황)

만약 지구와 같은 구체주변을 맴돈다면


this.up.copy( this.object.position );
this.up.normalize();


자신의 좌표를 이용해서 Up벡터를 구한다. (지구의 중점이 0, 0, 0 이라는 기준으로)


this.right.crossVectors( this.up, this.front );
this.right.normalize();

up벡터와 front벡터를 Cross 시켜서 Right 벡터를 구한다.


this.up.crossVectors( this.front, this.right );
this.up.normalize();

front와 right를 이용해서 다시 Up벡터를 구한다.


일반적으론 이렇게 나온 right, up, front에 적용시키면 로테이션이 적용된다.

이번은 Matrix를 이용해서 Quaternion을 구해보자.


Matrix mBasis = new Matrix(vRight.X, vRight.Y, vRight.Z, 0.0f,
vUp.X, vUp.Y, vUp.Z, 0.0f,
vDirection.X, vDirection.Y, vDirection.Z, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);

Quaternion qrot = new Quaternion();
qrot.W = (float)Math.Sqrt(1.0f + mBasis.M11 + mBasis.M22 + mBasis.M33) / 2.0f;
double dfWScale = qrot.W * 4.0;
qrot.X = (float)((mBasis.M32 - mBasis.M23) / dfWScale);
qrot.Y = (float)((mBasis.M13 - mBasis.M31) / dfWScale);
qrot.Z = (float)((mBasis.M21 - mBasis.M12) / dfWScale);

이렇게 나온 쿼터니언 (Quaternion)을 이용해서 Rotation을 적용시키면 된다.

acos(x) 로 구했다가 난감한 경험이 있었다.


제대로된 Angle을 구하고 싶다면


let angle = Math.atan2( y, x ) * RAD2DEG; 하면 정상적인 각도가 나옴


디스플레이 화면 특성상 Y값이 밑으로 갈수록 증가하기 때문에


실제로는 다음과 같은 식으로 구현했다.


var RAD2DEG = 180 / Math.PI;
let angle = Math.atan2( -y, x ) * RAD2DEG;


벡터 : 방향과 크기를 가지고 있다.

스칼라 : 힘의 크기 또는 위치만을 가지고 있다.


우리가 지금까지 알고있는 개념은 전부 스칼라.

총알이 날라가고 있다. 이 총알의 좌표가 아니라 총알이 어느 방향으로 얼마만큼의 힘으로 가는지 표현해야한다.

이때 사용되는게 벡터의 개념 (어느 방향으로 얼만큼의 힘으로 가는지)


+ Recent posts