/*---------------------------------------------------------------------------* Project: Horizon File: math_Geometry.h Copyright (C)2009-2010 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Revision: 24054 $ *---------------------------------------------------------------------------*/ #ifndef NN_MATH_GEOMETRY_H_ #define NN_MATH_GEOMETRY_H_ #include #include #include namespace nn { namespace math { // 線や面等のジオメトリオブジェクトを定義しておく // 名前予約 struct LINE2; struct RAY2; struct SEGMENT2; struct CIRCLE2; struct TRIANGLE2; struct LINE3; struct RAY3; struct SEGMENT3; struct SPHERE; struct TRIANGLE3; struct PLANE; struct CYLINDER; struct CONE; struct AABB; struct CAPSULE; enum IntersectionResult { INTERSECTION_NONE = 0, INTERSECTION_1 = 1, INTERSECTION_2 = 2, INTERSECTION_LINE3_ON_PLANE = 2, INTERSECTION_RAY3_ON_PLANE = INTERSECTION_LINE3_ON_PLANE, INTERSECTION_SEGMENT3_ON_PLANE = INTERSECTION_LINE3_ON_PLANE, INTERSECTION_OUTSIDE = 0, INTERSECTION_INSIDE = 1, INTERSECTION_INTERSECT = 2 }; /* ======================================================================= クラス定義 ======================================================================== */ /* ------------------------------------------------------------------------ LINE3: L: P + td パラメトリック形式の線(3D)である。Pが起点でdが線の方向である。 使用時にdは正規化されていることが前提となっている。 ------------------------------------------------------------------------ */ struct LINE3 { public: typedef LINE3 self_type; public: LINE3() {} LINE3(const f32* p, bool isNormalized = false) : P(p), d(p + 3) { if (!isNormalized) Normalize(); } LINE3(const VEC3& Pt, const VEC3& dir, bool isNormalized = false) : P(Pt), d(dir) { if (!isNormalized) Normalize(); } operator f32*() { return &P.x; } operator const f32*() const { return &P.x; } bool operator==(const self_type& rhs) const { return P == rhs.P && d == rhs.d; } bool operator!=(const self_type& rhs) const { return P != rhs.P || d != rhs.d; } // 線分を、線分の始点を始点とする線に変換する。 void Set(const SEGMENT3* S); void Normalize() { (void)VEC3Normalize(&d, &d); } public: VEC3 P; VEC3 d; // 直接代入する場合は正規化しておくこと }; /* ------------------------------------------------------------------------ RAY3 R: P + td (ただし、t >= 0) 起点からdの方向だけに向かう線である。Pが起点でdが線の方向である。 使用時にdは正規化されていることが前提となっている。 ------------------------------------------------------------------------ */ struct RAY3 { public: typedef RAY3 self_type; public: RAY3() {} RAY3(const f32* p, bool isNormalized = false) : P(p), d(p + 3) { if (!isNormalized) Normalize(); } RAY3(const VEC3& Pt, const VEC3& dir, bool isNormalized = false) : P(Pt), d(dir) { if (!isNormalized) Normalize(); } operator f32*() { return &P.x; } operator const f32*() const { return &P.x; } bool operator==(const self_type& rhs) const { return P == rhs.P && d == rhs.d; } bool operator!=(const self_type& rhs) const { return P != rhs.P || d != rhs.d; } void Normalize() { (void)VEC3Normalize(&d, &d); } public: VEC3 P; VEC3 d; // 直接代入する場合は正規化しておくこと }; /* ------------------------------------------------------------------------ SEGMENT3 S: (1 - t)P0 + tP1 (ただし、0 <= t <= 1) P0とP1を繋ぐ線分である。 ------------------------------------------------------------------------ */ struct SEGMENT3 { public: typedef SEGMENT3 self_type; public: SEGMENT3() {} SEGMENT3(const f32* p) : P0(p), P1(p + 3) {} SEGMENT3(const VEC3& pt0, const VEC3& pt1) : P0(pt0), P1(pt1) {} operator f32*() { return &P0.x; } operator const f32*() const { return &P0.x; } bool operator==(const self_type& rhs) const { return P0 == rhs.P0 && P1 == rhs.P1; } bool operator!=(const self_type& rhs) const { return P0 != rhs.P0 || P1 == rhs.P1; } public: VEC3 P0; VEC3 P1; }; inline void LINE3::Set(const SEGMENT3* S) { P = S->P0; VEC3Sub(&d, &S->P1, &S->P0); Normalize(); } /* ------------------------------------------------------------------------ SPHERE S: |P - C| <= r Cを中心の位置、rを半径とする球である。 ------------------------------------------------------------------------ */ struct SPHERE { public: typedef SPHERE self_type; public: SPHERE() {} SPHERE(const f32* p) : C(p), r(*(p + 3)) {} SPHERE(const VEC3& center, f32 radius) : C(center), r(radius) {} operator f32*() { return &C.x; } operator const f32*() const { return &C.x; } bool operator==(const self_type& rhs) const { return C == rhs.C && r == rhs.r; } bool operator!=(const self_type& rhs) const { return C != rhs.C || r != rhs.r; } // 点の集合を包含する球をセットする。 void Set(const VEC3* arrayPoint, unsigned int numPoints); public: VEC3 C; f32 r; }; /* ------------------------------------------------------------------------ PLANE (N.x)x + (N.y)y + (N.z)z + d = 0 平面の陰関数表現をパラメータとして持っている。 法線ベクトルNは正規化されている必要がある。 ------------------------------------------------------------------------ */ struct PLANE { public: typedef PLANE self_type; public: PLANE() {} PLANE(const f32* p, bool isNormalized = false) : N(p), d(*(p + 3)) { if (!isNormalized) Normalize(); } PLANE(f32 A, f32 B, f32 C, f32 D, bool isNormalized = false) : N(A, B, C), d(D) { if (!isNormalized) Normalize(); } PLANE(const VEC3& P0, const VEC3& P1, const VEC3& P2) { Set(&P0, &P1, &P2); } operator f32*() { return &N.x; } operator const f32*() const { return &N.x; } bool operator==(const self_type& rhs) const { return N == rhs.N && d == rhs.d; } bool operator!=(const self_type& rhs) const { return N != rhs.N || d != rhs.d; } // Pが平面の法線方向にある場合は正に、そうでない場合は負になります。 f32 Test(const VEC3& P) const { return d + VEC3Dot(&N, &P); } void Normalize() { f32 r = FrSqrt(VEC3SquareLen(&N)); (void)VEC3Scale(&N, &N, r); d *= r; } void Set(const VEC3* P0, const VEC3* P1, const VEC3* P2); public: VEC3 N; // 直接代入する場合は正規化しておくこと f32 d; }; /* ------------------------------------------------------------------------ CAPSULE 線分と線分に対する距離でカプセルが定義される。 ------------------------------------------------------------------------ */ struct CAPSULE { public: typedef CAPSULE self_type; public: CAPSULE() {} CAPSULE(const f32* p) : S(p), r(*(p + 6)) {} CAPSULE(const SEGMENT3& S_, f32 r_) : S(S_), r(r_) {} CAPSULE(const VEC3& P0, const VEC3& P1, f32 r_) : S(P0, P1), r(r_) {} operator f32*() { return &S.P0.x; } operator const f32*() const { return &S.P0.x; } bool operator==(const self_type& rhs) const { return S == rhs.S && r == rhs.r; } bool operator!=(const self_type& rhs) const { return S != rhs.S || r != rhs.r; } public: SEGMENT3 S; f32 r; }; /* ------------------------------------------------------------------------ AABB xyz軸に沿ったボックスです。2つの点PminとPmaxで定義されます。 Pminのそれぞれの座標はPmaxの座標よりも小さい必要があります。 ------------------------------------------------------------------------ */ struct AABB { public: typedef AABB self_type; public: AABB() {} AABB(const f32* p, bool isNormalized = false) : Pmin(p), Pmax(p + 3) { if (!isNormalized) Normalize(); } AABB(const VEC3& min, const VEC3& max, bool isNormalized = false) : Pmin(min), Pmax(max) { if (!isNormalized) Normalize(); } operator f32*() { return &Pmin.x; } operator const f32*() const { return &Pmin.x; } bool operator==(const self_type& rhs) const { return Pmin == rhs.Pmin && Pmax == rhs.Pmax; } bool operator!=(const self_type& rhs) const { return Pmin != rhs.Pmin || Pmax != rhs.Pmax; } void Set(const VEC3* arrayPoint, unsigned int numPoints); void Set(const AABB* box, const MTX34* M); void Normalize(); public: VEC3 Pmin; VEC3 Pmax; }; /* ------------------------------------------------------------------------ CYLINDER 半径rで原点からZ軸にhだけの高さを持つ円柱と解釈される。 lineやplaneとの交差判定は座標変換してから行う必要がある。 ------------------------------------------------------------------------ */ struct CYLINDER { public: typedef CYLINDER self_type; public: CYLINDER() {} CYLINDER(const f32* p) : r(*p), h(*(p + 1)) {} CYLINDER(f32 radius, f32 height) : r(radius), h(height) {} public: f32 r; f32 h; }; /* ------------------------------------------------------------------------ CONE 半径rで原点からZ軸にhだけの高さを持つ円錐と解釈される。 lineやplaneとの交差判定は座標変換してから行う必要がある。 ------------------------------------------------------------------------ */ struct CONE { public: typedef CONE self_type; public: CONE() {} CONE(const f32* p) : r(*p), h(*(p + 1)) {} CONE(f32 radius, f32 height) : r(radius), h(height) {} public: f32 r; f32 h; }; /* ------------------------------------------------------------------------ FRUSTUM 主にカリングに使用するためのフラスタムの定義 ------------------------------------------------------------------------ */ class FRUSTUM { public: typedef FRUSTUM self_type; public: //--------------------------------------------------------------------------- //! @brief コンストラクタです。 //--------------------------------------------------------------------------- FRUSTUM() {} //--------------------------------------------------------------------------- //! @brief コンストラクタです。 //! //! @param[in] fovyRad 縦方向の視野角(Radian)。 //! @param[in] aspect アスペクト比(幅/高さ) //! @param[in] n ニアクリッピング面までの距離。 //! @param[in] f ファークリッピング面までの距離。 //! @param[in] camera カメラ行列。 //--------------------------------------------------------------------------- FRUSTUM(f32 fovyRad, f32 aspect, f32 n, f32 f, const MTX34& camera) { Set(fovyRad, aspect, n, f, camera); } //--------------------------------------------------------------------------- //! @brief コンストラクタです。 //! //! @param[in] top ニアクリッピング面での視錐台上辺の Y 座標。 //! @param[in] bottom ニアクリッピング面での視錐台下辺の Y 座標。 //! @param[in] left ニアクリッピング面での視錐台左辺の X 座標。 //! @param[in] right ニアクリッピング面での視錐台右辺の X 座標。 //! @param[in] n ニアクリッピング面までの距離。 //! @param[in] f ファークリッピング面までの距離。 //! @param[in] camera カメラ行列。 //--------------------------------------------------------------------------- FRUSTUM(f32 top, f32 bottom, f32 left, f32 right, f32 n, f32 f, const MTX34& camera) { Set(top, bottom, left, right, n, f, camera); } private: MTX34 cam; /* ビュー座標系用のデータメンバ */ PLANE leftPlane; PLANE rightPlane; PLANE topPlane; PLANE bottomPlane; f32 znear; f32 zfar; /* ワールド座標系用のデータメンバ */ AABB box; // フラスタムを包含するAABBで粗い判定に用いる PLANE planes[6]; // left, right, near, far, up, downの順(Optimized View Frustum Culling Algorithmより) public: //--------------------------------------------------------------------------- //! @brief FRUSTUM に設定を反映する Set 関数です。 //! //! @param[in] top ニアクリッピング面での視錐台上辺の Y 座標。 //! @param[in] bottom ニアクリッピング面での視錐台下辺の Y 座標。 //! @param[in] left ニアクリッピング面での視錐台左辺の X 座標。 //! @param[in] right ニアクリッピング面での視錐台右辺の X 座標。 //! @param[in] n ニアクリッピング面までの距離。 //! @param[in] f ファークリッピング面までの距離。 //! @param[in] camera カメラ行列。 //--------------------------------------------------------------------------- void Set(f32 top, f32 bottom, f32 left, f32 right, f32 n, f32 f, const MTX34& camera); //--------------------------------------------------------------------------- //! @brief FRUSTUM に設定を反映する Set 関数です。 //! //! @param[in] fovyRad 縦方向の視野角(Radian)。 //! @param[in] aspect アスペクト比(幅/高さ) //! @param[in] n ニアクリッピング面までの距離。 //! @param[in] f ファークリッピング面までの距離。 //! @param[in] camera カメラ行列。 //--------------------------------------------------------------------------- void Set(f32 fovyRad, f32 aspect, f32 n, f32 f, const MTX34& camera) { f32 tanRad = TanRad(0.5f * fovyRad); f32 ny = tanRad * n; f32 nx = ny * aspect; Set(ny, -ny, -nx, nx, n, f, camera); } public: // SPHEREはワールド座標系 bool IntersectSphere(const SPHERE* S) const; // AABBはワールド座標系 bool IntersectAABB(const AABB* B) const; // AABBはワールド座標系 IntersectionResult IntersectAABB_Ex(const AABB* B) const; }; // // 3Dジオメトリ間の距離 // // 点 f32 DistSqPoint3ToLine3(const VEC3* P, const LINE3* L, f32* t); f32 DistSqPoint3ToRay3(const VEC3* P, const RAY3* R, f32* t); f32 DistSqPoint3ToSegment3(const VEC3* P, const SEGMENT3* S, f32* t); f32 DistSqPoint3ToPlane(const VEC3* P, const PLANE* J, VEC3* Q); f32 DistSqSphereToPlane(const SPHERE* S, const PLANE* J); f32 DistSqPoint3ToPolyline3(const VEC3* P, const VEC3* vertices, unsigned int nVertices); f32 DistSqPoint3ToAABB(const VEC3* P, const AABB* B, VEC3* q); // 線・レイ・線分 f32 DistSqLine3ToLine3(const LINE3* L0, const LINE3* L1, f32* s, f32* t); f32 DistSqSegment3ToSegment3(const SEGMENT3* S0, const SEGMENT3* S1, f32* s, f32* t); f32 DistSqLine3ToRay3(const LINE3* L, const RAY3* R, f32* s, f32* t); f32 DistSqLine3ToSegment3(const LINE3* L0, const SEGMENT3* S, f32* s, f32* t); f32 DistSqRay3ToRay3(const RAY3* R0, const RAY3* R1, f32* s, f32* t); f32 DistSqRay3ToSegment3(const RAY3* R0, const SEGMENT3* S, f32* s, f32* t); // // 3Dジオメトリ間の交差 // IntersectionResult IntersectionLine3Plane(const LINE3* L, const PLANE* J, f32* t, VEC3* I); IntersectionResult IntersectionRay3Plane(const RAY3* R, const PLANE* J, f32* t, VEC3* I); IntersectionResult IntersectionSegment3Plane(const SEGMENT3* S, const PLANE* J, f32* t, VEC3* I); IntersectionResult IntersectionLine3Sphere(const LINE3* L, const SPHERE* sphere, f32* t0, f32* t1); IntersectionResult IntersectionRay3Sphere(const RAY3* R, const SPHERE* sphere, f32* t0, f32* t1); bool IntersectionRay3Sphere(const RAY3* R, const SPHERE* sphere); IntersectionResult IntersectionSegment3Sphere(const SEGMENT3* S, const SPHERE* sphere, f32* t0, f32* t1); bool IntersectionRay3AABB(const RAY3* R, const AABB* box, f32* t); bool IntersectionAABB(const AABB* a, const AABB* b); bool IntersectionSphereAABB(const SPHERE* sphere, const AABB* aabb); bool IntersectionSphere(const SPHERE* s0, const SPHERE* s1); bool IntersectionPlaneAABB(const PLANE* J, const AABB* B); bool IntersectionCapsule(const CAPSULE* C0, const CAPSULE* C1); bool IntersectionRay3Capsule(const RAY3* R, const CAPSULE* C); bool IntersectionLine3Capsule(const LINE3* L, const CAPSULE* C); bool IntersectionPlaneCapsule(const PLANE* J, const CAPSULE* C); inline bool IntersectionSphereFrustum(const SPHERE* S, const FRUSTUM* F) { return F->IntersectSphere(S); } inline bool IntersectionAABBFrustum(const AABB* B, const FRUSTUM* F) { return F->IntersectAABB(B); } inline IntersectionResult IntersectionAABBFrustumEx(const AABB* B, const FRUSTUM* F) { return F->IntersectAABB_Ex(B); } // // 3Dジオメトリのマージ // SPHERE* MergeSphere(SPHERE* s2, const SPHERE* s0, const SPHERE* s1); AABB* MergeAABB(AABB* a2, const AABB* a0, const AABB* a1); }} // nn::math #endif