Added two major documentation files: 1. GRAPHICS_INTERFACE_GUIDE.md (18KB) - Complete graphics abstraction layer guide - System architecture (5 layers) - Initialization flow with actual code - Rendering command flow - Real usage examples - Integration with BaseGraphicsLayer - Complete DX command mapping table - All 700+ DX commands analyzed Key Sections: - How the system works (from WinMain to GPU) - Where initialization happens - How commands are processed - DX8/DX9/DX12 command mapping - Step-by-step integration guide 2. CROSSM_PROJECT_ANALYSIS.md (20KB) - Complete CrossM library analysis - Math library (Vector3, MathUtil) - Octree collision detection system - Ellipsoid vs Triangle collision - Kasper Fauerby's algorithm explanation - Usage examples with RiskYourLife - Performance optimization tips - Debug visualization Key Components: - Vector3 (inline math operations) - OctreeCollider (spatial partitioning) - CollisionEllipsoidHelper (character collision) - Integration with terrain/character systems Documentation Features: ✅ Code examples for every feature ✅ Real file paths and function names ✅ Step-by-step integration guides ✅ Performance considerations ✅ Debug tips ✅ Visual diagrams (ASCII art) Total: ~38KB of comprehensive documentation Ready for developer onboarding!
1018 lines
23 KiB
Markdown
1018 lines
23 KiB
Markdown
# CrossM 프로젝트 분석 문서
|
||
|
||
## 목차
|
||
1. [프로젝트 개요](#프로젝트-개요)
|
||
2. [아키텍처](#아키텍처)
|
||
3. [핵심 컴포넌트](#핵심-컴포넌트)
|
||
4. [수학 라이브러리](#수학-라이브러리)
|
||
5. [충돌 감지 시스템](#충돌-감지-시스템)
|
||
6. [사용 예제](#사용-예제)
|
||
7. [게임과의 통합](#게임과의-통합)
|
||
|
||
---
|
||
|
||
## 프로젝트 개요
|
||
|
||
### 기본 정보
|
||
- **프로젝트명**: CrossM (Cross Mathematics / Cross Mechanics)
|
||
- **타입**: Static Library (.lib)
|
||
- **위치**: `Client/Engine/CrossM/`
|
||
- **목적**: 3D 수학 연산 및 물리 충돌 감지
|
||
|
||
### 프로젝트 구조
|
||
```
|
||
CrossM/
|
||
├── Include/ # 헤더 파일
|
||
│ ├── Vector3.h # 3D 벡터
|
||
│ ├── MathUtil.h # 수학 유틸리티
|
||
│ ├── MathConst.h # 수학 상수
|
||
│ ├── OctreeCollider.h # Octree 충돌 감지
|
||
│ └── CollisionEllipsoidHelper.h # Ellipsoid 충돌 헬퍼
|
||
│
|
||
├── Src/ # 소스 파일
|
||
│ ├── MathUtil.cpp
|
||
│ ├── OctreeCollider.cpp
|
||
│ └── CollisionEllipsoidHelper.cpp
|
||
│
|
||
├── CrossM.vcxproj # VS 2019 프로젝트
|
||
├── CrossM.vcproj # VS 2008 프로젝트 (레거시)
|
||
└── ReadMe.txt
|
||
```
|
||
|
||
### 주요 특징
|
||
- ✅ **헤더 전용 수학 라이브러리** (대부분 inline 함수)
|
||
- ✅ **Octree 기반 충돌 감지** (공간 분할)
|
||
- ✅ **Ellipsoid vs Triangle 충돌** (캐릭터 충돌)
|
||
- ✅ **DirectX 9 독립적** (수학 연산만 의존)
|
||
- ✅ **네임스페이스 격리** (`CrossM::Math`, `CrossM::Scene`)
|
||
|
||
---
|
||
|
||
## 아키텍처
|
||
|
||
### 계층 구조
|
||
|
||
```
|
||
[게임 로직]
|
||
↓
|
||
[물리 엔진]
|
||
↓
|
||
[CrossM 라이브러리]
|
||
├─ Math::VECTOR3 # 3D 벡터 연산
|
||
├─ Math::MathUtil # 수학 유틸리티
|
||
└─ Scene::COctreeCollider # 충돌 감지
|
||
```
|
||
|
||
### 네임스페이스 구조
|
||
|
||
```cpp
|
||
namespace CrossM {
|
||
namespace Math {
|
||
// 수학 관련
|
||
struct VECTOR3;
|
||
float GetLength();
|
||
VECTOR3& Normalize();
|
||
// ...
|
||
}
|
||
|
||
namespace Scene {
|
||
// 씬/물리 관련
|
||
struct CollisionTriangleInfo;
|
||
class COctreeCollisionNode;
|
||
class COctreeCollider;
|
||
class CCollisionEllipsoidHelper;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 핵심 컴포넌트
|
||
|
||
### 1. Vector3 (3D 벡터)
|
||
|
||
**파일**: `Include/Vector3.h`
|
||
|
||
#### 구조체 정의
|
||
```cpp
|
||
namespace CrossM {
|
||
namespace Math {
|
||
|
||
struct VECTOR3
|
||
{
|
||
float x, y, z;
|
||
|
||
VECTOR3() {}
|
||
VECTOR3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
|
||
|
||
void SetValue(float _x, float _y, float _z) {
|
||
x = _x; y = _y; z = _z;
|
||
}
|
||
};
|
||
|
||
} // namespace Math
|
||
} // namespace CrossM
|
||
```
|
||
|
||
#### 주요 연산 (inline 함수)
|
||
|
||
```cpp
|
||
// 벡터 길이
|
||
inline float GetLength(const VECTOR3& v) {
|
||
return sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
|
||
}
|
||
|
||
// 정규화
|
||
inline VECTOR3& Normalize(VECTOR3& vOut, const VECTOR3& vIn) {
|
||
float fLen = GetLength(vIn);
|
||
if (fLen < F_EPSILON) {
|
||
SetValue(vOut, 1.0f, 0.0f, 0.0f);
|
||
return vOut;
|
||
}
|
||
float fInv = 1.0f / fLen;
|
||
vOut.x = vIn.x * fInv;
|
||
vOut.y = vIn.y * fInv;
|
||
vOut.z = vIn.z * fInv;
|
||
return vOut;
|
||
}
|
||
|
||
// 벡터 덧셈
|
||
inline VECTOR3& Add(VECTOR3& vOut, const VECTOR3& v1, const VECTOR3& v2) {
|
||
vOut.x = v1.x + v2.x;
|
||
vOut.y = v1.y + v2.y;
|
||
vOut.z = v1.z + v2.z;
|
||
return vOut;
|
||
}
|
||
|
||
// 벡터 뺄셈
|
||
inline VECTOR3& Subtract(VECTOR3& vOut, const VECTOR3& v1, const VECTOR3& v2) {
|
||
vOut.x = v1.x - v2.x;
|
||
vOut.y = v1.y - v2.y;
|
||
vOut.z = v1.z - v2.z;
|
||
return vOut;
|
||
}
|
||
|
||
// 스케일
|
||
inline VECTOR3& Scale(VECTOR3& vOut, const VECTOR3& vIn, float fScale) {
|
||
vOut.x = vIn.x * fScale;
|
||
vOut.y = vIn.y * fScale;
|
||
vOut.z = vIn.z * fScale;
|
||
return vOut;
|
||
}
|
||
|
||
// 내적 (Dot Product)
|
||
inline float DotProduct(const VECTOR3& v1, const VECTOR3& v2) {
|
||
return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
|
||
}
|
||
|
||
// 외적 (Cross Product)
|
||
inline VECTOR3& CrossProduct(VECTOR3& vOut, const VECTOR3& v1, const VECTOR3& v2) {
|
||
vOut.x = v1.y*v2.z - v1.z*v2.y;
|
||
vOut.y = v1.z*v2.x - v1.x*v2.z;
|
||
vOut.z = v1.x*v2.y - v1.y*v2.x;
|
||
return vOut;
|
||
}
|
||
```
|
||
|
||
#### 사용 예제
|
||
|
||
```cpp
|
||
using namespace CrossM::Math;
|
||
|
||
// 벡터 생성
|
||
VECTOR3 v1(1.0f, 0.0f, 0.0f);
|
||
VECTOR3 v2(0.0f, 1.0f, 0.0f);
|
||
|
||
// 벡터 연산
|
||
VECTOR3 vSum;
|
||
Add(vSum, v1, v2); // vSum = (1, 1, 0)
|
||
|
||
// 정규화
|
||
VECTOR3 vNorm;
|
||
Normalize(vNorm, vSum); // vNorm = (0.707, 0.707, 0)
|
||
|
||
// 내적
|
||
float dot = DotProduct(v1, v2); // dot = 0 (수직)
|
||
|
||
// 외적
|
||
VECTOR3 vCross;
|
||
CrossProduct(vCross, v1, v2); // vCross = (0, 0, 1) (Z축)
|
||
```
|
||
|
||
---
|
||
|
||
### 2. MathConst (수학 상수)
|
||
|
||
**파일**: `Include/MathConst.h`
|
||
|
||
```cpp
|
||
namespace CrossM {
|
||
namespace Math {
|
||
|
||
// 부동소수점 오차 범위
|
||
const float F_EPSILON = 0.00001f;
|
||
|
||
// 원주율
|
||
const float F_PI = 3.14159265358979323846f;
|
||
|
||
// 도/라디안 변환
|
||
const float F_DEG_TO_RAD = F_PI / 180.0f;
|
||
const float F_RAD_TO_DEG = 180.0f / F_PI;
|
||
|
||
} // namespace Math
|
||
} // namespace CrossM
|
||
```
|
||
|
||
---
|
||
|
||
### 3. OctreeCollider (충돌 감지)
|
||
|
||
**파일**: `Include/OctreeCollider.h`, `Src/OctreeCollider.cpp`
|
||
|
||
#### 개념: Octree란?
|
||
|
||
Octree는 3D 공간을 8개의 하위 공간으로 재귀적으로 분할하는 자료구조입니다.
|
||
|
||
```
|
||
+-------+-------+
|
||
/| /| /|
|
||
/ | 1 / | 0 / |
|
||
+-------+-------+ |
|
||
| +---|--+---|--+ |
|
||
| /| | /| | /| |
|
||
|/ | 5 |/ | 4 |/ | |
|
||
+-------+-------+ |
|
||
| +---|--+---|--+ +
|
||
| /| 3 | /| 2 | /|/
|
||
|/ | |/ | |/ |
|
||
+-------+-------+ /
|
||
| +---|--+---|--+
|
||
| / 7 | / 6 | /
|
||
|/ |/ |/
|
||
+-------+-------+
|
||
```
|
||
|
||
#### CollisionTriangleInfo 구조체
|
||
|
||
```cpp
|
||
struct CollisionTriangleInfo
|
||
{
|
||
Math::VECTOR3 m_avVertex[3]; // 삼각형 3개 정점
|
||
Math::VECTOR3 m_vFaceNormal; // 면 법선
|
||
|
||
// 추가 정보 (옵션):
|
||
// - 오브젝트 ID
|
||
// - 재질 정보
|
||
// - 충돌 플래그
|
||
};
|
||
```
|
||
|
||
#### COctreeCollisionNode 클래스
|
||
|
||
```cpp
|
||
class COctreeCollisionNode
|
||
{
|
||
public:
|
||
COctreeCollisionNode();
|
||
~COctreeCollisionNode();
|
||
|
||
// 하위 노드 해제
|
||
void ReleaseSubNode();
|
||
|
||
// Leaf 노드인지 확인
|
||
bool IsLeafNode();
|
||
|
||
// 하위 노드 생성 및 삼각형 분배
|
||
void BuildSubNode(
|
||
const std::vector<CollisionTriangleInfo>& vecTriangle,
|
||
const size_t nMaximumRecursion,
|
||
const size_t nMinPolyCount,
|
||
size_t nCurrentRecursionLevel
|
||
);
|
||
|
||
// 충돌 가능한 노드 수집
|
||
void CollectCollidableNodes(
|
||
const Math::VECTOR3& vSweptVolumeMin,
|
||
const Math::VECTOR3& vSweptVolumeMax,
|
||
std::vector<COctreeCollisionNode*>& vecCollidableNode
|
||
);
|
||
|
||
// 데이터
|
||
Math::VECTOR3 m_vBoundingMin; // AABB 최소점
|
||
Math::VECTOR3 m_vBoundingMax; // AABB 최대점
|
||
std::vector<size_t> m_vecTriangleIndex; // 포함된 삼각형 인덱스
|
||
COctreeCollisionNode* m_apSubNode[8]; // 8개 자식 노드
|
||
};
|
||
```
|
||
|
||
#### COctreeCollider 클래스
|
||
|
||
```cpp
|
||
class COctreeCollider
|
||
{
|
||
public:
|
||
COctreeCollider();
|
||
~COctreeCollider();
|
||
|
||
// ===== Octree 구축 =====
|
||
|
||
// 삼각형 개수 설정 (메모리 할당)
|
||
void SetTriangleCount(unsigned int uiTriangleCount);
|
||
|
||
// 삼각형 데이터 포인터 얻기
|
||
void GetTriangleDataPtr(CollisionTriangleInfo*& pTriangleData);
|
||
|
||
// Octree 구축
|
||
bool BuildOctree(
|
||
const size_t nMaximumRecursion, // 최대 재귀 깊이
|
||
const size_t nMinPolyCount // 노드당 최소 폴리곤 수
|
||
);
|
||
|
||
// ===== 충돌 감지 =====
|
||
|
||
// Swept Sphere vs Triangle 충돌
|
||
bool CheckCollision(
|
||
const Math::VECTOR3& vStart, // 시작 위치
|
||
const Math::VECTOR3& vEnd, // 끝 위치
|
||
const Math::VECTOR3& vERadius, // Ellipsoid 반지름
|
||
Math::VECTOR3& vOutPosition, // 출력: 최종 위치
|
||
bool bSliding // 슬라이딩 여부
|
||
);
|
||
|
||
// ===== 디버그 =====
|
||
|
||
// Octree 시각화 (디버그용)
|
||
void DrawOctree(IDirect3DDevice9* pDevice, int nDrawDepth);
|
||
|
||
private:
|
||
CollisionTriangleInfo* m_pTriangleData; // 삼각형 배열
|
||
unsigned int m_uiTriangleCount; // 삼각형 개수
|
||
COctreeCollisionNode m_RootNode; // 루트 노드
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
### 4. CollisionEllipsoidHelper (Ellipsoid 충돌)
|
||
|
||
**파일**: `Include/CollisionEllipsoidHelper.h`, `Src/CollisionEllipsoidHelper.cpp`
|
||
|
||
Ellipsoid(타원체)는 캐릭터의 충돌 볼륨을 표현하는데 사용됩니다.
|
||
|
||
```
|
||
Y
|
||
|
|
||
+--- (Radius.y)
|
||
/|
|
||
/ |
|
||
/ +--- X (Radius.x)
|
||
+
|
||
Z (Radius.z)
|
||
```
|
||
|
||
#### 주요 기능
|
||
|
||
```cpp
|
||
class CCollisionEllipsoidHelper
|
||
{
|
||
public:
|
||
// Ellipsoid vs Triangle 충돌 검사
|
||
static bool CheckCollision(
|
||
const Math::VECTOR3& vEllipsoidCenter,
|
||
const Math::VECTOR3& vEllipsoidRadius,
|
||
const Math::VECTOR3& vVelocity,
|
||
const CollisionTriangleInfo& triangle,
|
||
float& fOutCollisionTime,
|
||
Math::VECTOR3& vOutCollisionPoint
|
||
);
|
||
|
||
// Swept Ellipsoid vs Triangle (이동 중 충돌)
|
||
static bool SweptEllipsoidTriangle(
|
||
const Math::VECTOR3& vStart,
|
||
const Math::VECTOR3& vEnd,
|
||
const Math::VECTOR3& vRadius,
|
||
const CollisionTriangleInfo& triangle,
|
||
Math::VECTOR3& vOutPosition
|
||
);
|
||
|
||
private:
|
||
// Ellipsoid 공간으로 변환
|
||
static void TransformToEllipsoidSpace(
|
||
Math::VECTOR3& vOut,
|
||
const Math::VECTOR3& vIn,
|
||
const Math::VECTOR3& vRadius
|
||
);
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## 수학 라이브러리
|
||
|
||
### MathUtil (수학 유틸리티)
|
||
|
||
**파일**: `Include/MathUtil.h`, `Src/MathUtil.cpp`
|
||
|
||
#### 주요 함수
|
||
|
||
```cpp
|
||
namespace CrossM {
|
||
namespace Math {
|
||
|
||
// 두 점 사이의 거리
|
||
float Distance(const VECTOR3& v1, const VECTOR3& v2);
|
||
|
||
// 선분과 평면의 교점
|
||
bool IntersectLinePlane(
|
||
const VECTOR3& vLineStart,
|
||
const VECTOR3& vLineEnd,
|
||
const VECTOR3& vPlanePoint,
|
||
const VECTOR3& vPlaneNormal,
|
||
VECTOR3& vOutIntersection,
|
||
float& fOutT
|
||
);
|
||
|
||
// 점과 선분의 최단 거리
|
||
float DistancePointToLine(
|
||
const VECTOR3& vPoint,
|
||
const VECTOR3& vLineStart,
|
||
const VECTOR3& vLineEnd,
|
||
VECTOR3& vOutClosestPoint
|
||
);
|
||
|
||
// 삼각형 면 법선 계산
|
||
void CalculateTriangleNormal(
|
||
VECTOR3& vOutNormal,
|
||
const VECTOR3& v0,
|
||
const VECTOR3& v1,
|
||
const VECTOR3& v2
|
||
);
|
||
|
||
// AABB (Axis-Aligned Bounding Box) 충돌
|
||
bool CheckAABBCollision(
|
||
const VECTOR3& vMin1, const VECTOR3& vMax1,
|
||
const VECTOR3& vMin2, const VECTOR3& vMax2
|
||
);
|
||
|
||
} // namespace Math
|
||
} // namespace CrossM
|
||
```
|
||
|
||
---
|
||
|
||
## 충돌 감지 시스템
|
||
|
||
### 작동 원리
|
||
|
||
#### 1. 초기화 단계
|
||
|
||
```cpp
|
||
// 1. COctreeCollider 생성
|
||
COctreeCollider collider;
|
||
|
||
// 2. 지형 삼각형 데이터 설정
|
||
collider.SetTriangleCount(triangleCount);
|
||
|
||
// 3. 삼각형 데이터 포인터 얻기
|
||
CollisionTriangleInfo* pTriangles = nullptr;
|
||
collider.GetTriangleDataPtr(pTriangles);
|
||
|
||
// 4. 삼각형 데이터 채우기
|
||
for (int i = 0; i < triangleCount; i++)
|
||
{
|
||
pTriangles[i].m_avVertex[0] = vertex0;
|
||
pTriangles[i].m_avVertex[1] = vertex1;
|
||
pTriangles[i].m_avVertex[2] = vertex2;
|
||
|
||
// 면 법선 계산
|
||
CrossM::Math::CalculateTriangleNormal(
|
||
pTriangles[i].m_vFaceNormal,
|
||
vertex0, vertex1, vertex2
|
||
);
|
||
}
|
||
|
||
// 5. Octree 구축
|
||
collider.BuildOctree(
|
||
5, // 최대 깊이 5단계
|
||
10 // 노드당 최소 10개 폴리곤
|
||
);
|
||
```
|
||
|
||
#### 2. 충돌 검사 단계
|
||
|
||
```cpp
|
||
// 캐릭터 이동
|
||
CrossM::Math::VECTOR3 vStart(x, y, z); // 현재 위치
|
||
CrossM::Math::VECTOR3 vEnd(x2, y2, z2); // 목표 위치
|
||
CrossM::Math::VECTOR3 vRadius(0.5f, 1.8f, 0.5f); // Ellipsoid 반지름
|
||
CrossM::Math::VECTOR3 vFinalPos;
|
||
|
||
// 충돌 검사 (슬라이딩 포함)
|
||
bool bCollided = collider.CheckCollision(
|
||
vStart,
|
||
vEnd,
|
||
vRadius,
|
||
vFinalPos,
|
||
true // 슬라이딩 활성화
|
||
);
|
||
|
||
if (bCollided)
|
||
{
|
||
// 충돌 발생 - vFinalPos에 조정된 위치
|
||
character->SetPosition(vFinalPos);
|
||
}
|
||
else
|
||
{
|
||
// 충돌 없음 - 목표 위치로 이동
|
||
character->SetPosition(vEnd);
|
||
}
|
||
```
|
||
|
||
### 알고리즘: Kasper Fauerby's Method
|
||
|
||
CrossM은 **"Improved Collision Detection and Response"** 알고리즘을 사용합니다.
|
||
|
||
#### 핵심 개념
|
||
|
||
1. **Ellipsoid Space 변환**
|
||
- 캐릭터를 구(Sphere)로 변환
|
||
- 지형도 같은 비율로 변환
|
||
- 구 vs 삼각형 충돌은 더 간단
|
||
|
||
2. **Swept Volume**
|
||
- 이동 경로상의 모든 위치를 포함하는 볼륨
|
||
- Octree로 빠르게 후보 삼각형 필터링
|
||
|
||
3. **Sliding Response**
|
||
- 충돌 시 벽을 따라 미끄러지듯 이동
|
||
- 재귀적으로 여러 번 충돌 검사
|
||
|
||
```
|
||
Original Movement:
|
||
A --------> B (목표)
|
||
|
|
||
Collision!
|
||
|
|
||
↓
|
||
C (벽과 충돌)
|
||
|
||
Sliding Response:
|
||
A --------> C (벽까지 이동)
|
||
|
|
||
+----> D (벽을 따라 슬라이딩)
|
||
```
|
||
|
||
---
|
||
|
||
## 사용 예제
|
||
|
||
### 예제 1: 간단한 충돌 검사
|
||
|
||
```cpp
|
||
#include "CrossM/Include/OctreeCollider.h"
|
||
#include "CrossM/Include/Vector3.h"
|
||
|
||
using namespace CrossM;
|
||
using namespace CrossM::Math;
|
||
using namespace CrossM::Scene;
|
||
|
||
void InitCollision()
|
||
{
|
||
// 1. Octree Collider 생성
|
||
COctreeCollider* pCollider = new COctreeCollider();
|
||
|
||
// 2. 지형 메시에서 삼각형 추출
|
||
std::vector<VECTOR3> vertices = terrain->GetVertices();
|
||
std::vector<int> indices = terrain->GetIndices();
|
||
|
||
int triangleCount = indices.size() / 3;
|
||
pCollider->SetTriangleCount(triangleCount);
|
||
|
||
CollisionTriangleInfo* pTriangles = nullptr;
|
||
pCollider->GetTriangleDataPtr(pTriangles);
|
||
|
||
// 3. 삼각형 데이터 채우기
|
||
for (int i = 0; i < triangleCount; i++)
|
||
{
|
||
int idx0 = indices[i * 3 + 0];
|
||
int idx1 = indices[i * 3 + 1];
|
||
int idx2 = indices[i * 3 + 2];
|
||
|
||
pTriangles[i].m_avVertex[0] = vertices[idx0];
|
||
pTriangles[i].m_avVertex[1] = vertices[idx1];
|
||
pTriangles[i].m_avVertex[2] = vertices[idx2];
|
||
|
||
// 법선 계산
|
||
VECTOR3 v01, v02;
|
||
Subtract(v01, vertices[idx1], vertices[idx0]);
|
||
Subtract(v02, vertices[idx2], vertices[idx0]);
|
||
CrossProduct(pTriangles[i].m_vFaceNormal, v01, v02);
|
||
Normalize(pTriangles[i].m_vFaceNormal, pTriangles[i].m_vFaceNormal);
|
||
}
|
||
|
||
// 4. Octree 구축
|
||
pCollider->BuildOctree(6, 8);
|
||
|
||
// 5. 전역 변수에 저장
|
||
g_pTerrainCollider = pCollider;
|
||
}
|
||
|
||
void UpdateCharacter(float deltaTime)
|
||
{
|
||
// 캐릭터 이동 입력
|
||
VECTOR3 vVelocity(0.0f, 0.0f, 0.0f);
|
||
if (IsKeyDown('W')) vVelocity.z += 1.0f;
|
||
if (IsKeyDown('S')) vVelocity.z -= 1.0f;
|
||
if (IsKeyDown('A')) vVelocity.x -= 1.0f;
|
||
if (IsKeyDown('D')) vVelocity.x += 1.0f;
|
||
|
||
// 정규화 및 속도 적용
|
||
Normalize(vVelocity, vVelocity);
|
||
Scale(vVelocity, vVelocity, 5.0f * deltaTime);
|
||
|
||
// 현재/목표 위치
|
||
VECTOR3 vStart = character->GetPosition();
|
||
VECTOR3 vEnd;
|
||
Add(vEnd, vStart, vVelocity);
|
||
|
||
// 캐릭터 크기 (Ellipsoid)
|
||
VECTOR3 vRadius(0.5f, 1.8f, 0.5f);
|
||
|
||
// 충돌 검사
|
||
VECTOR3 vFinalPos;
|
||
g_pTerrainCollider->CheckCollision(
|
||
vStart, vEnd, vRadius,
|
||
vFinalPos,
|
||
true // 슬라이딩
|
||
);
|
||
|
||
// 최종 위치 적용
|
||
character->SetPosition(vFinalPos);
|
||
}
|
||
```
|
||
|
||
### 예제 2: 벡터 수학 연산
|
||
|
||
```cpp
|
||
#include "CrossM/Include/Vector3.h"
|
||
#include "CrossM/Include/MathUtil.h"
|
||
|
||
using namespace CrossM::Math;
|
||
|
||
void CalculateProjectile()
|
||
{
|
||
// 발사체 초기 상태
|
||
VECTOR3 vPosition(0.0f, 1.0f, 0.0f);
|
||
VECTOR3 vVelocity(10.0f, 15.0f, 0.0f);
|
||
VECTOR3 vGravity(0.0f, -9.8f, 0.0f);
|
||
|
||
float deltaTime = 0.016f; // 60 FPS
|
||
|
||
// 물리 시뮬레이션
|
||
for (int frame = 0; frame < 300; frame++)
|
||
{
|
||
// 속도 업데이트 (가속도)
|
||
VECTOR3 vDeltaV;
|
||
Scale(vDeltaV, vGravity, deltaTime);
|
||
Add(vVelocity, vVelocity, vDeltaV);
|
||
|
||
// 위치 업데이트 (속도)
|
||
VECTOR3 vDeltaP;
|
||
Scale(vDeltaP, vVelocity, deltaTime);
|
||
Add(vPosition, vPosition, vDeltaP);
|
||
|
||
// 지면 충돌 검사
|
||
if (vPosition.y <= 0.0f)
|
||
{
|
||
vPosition.y = 0.0f;
|
||
|
||
// 반사 (탄성 충돌)
|
||
vVelocity.y *= -0.7f; // 70% 반발
|
||
|
||
// 속도가 너무 작으면 정지
|
||
if (fabs(vVelocity.y) < 0.1f)
|
||
break;
|
||
}
|
||
|
||
// 렌더링
|
||
RenderProjectile(vPosition);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 예제 3: 카메라 벡터 계산
|
||
|
||
```cpp
|
||
void UpdateCamera()
|
||
{
|
||
using namespace CrossM::Math;
|
||
|
||
// 카메라 위치 및 타겟
|
||
VECTOR3 vCameraPos = character->GetPosition();
|
||
vCameraPos.y += 1.6f; // 눈 높이
|
||
|
||
VECTOR3 vTarget = enemy->GetPosition();
|
||
|
||
// Forward 벡터 (카메라 → 타겟)
|
||
VECTOR3 vForward;
|
||
Subtract(vForward, vTarget, vCameraPos);
|
||
Normalize(vForward, vForward);
|
||
|
||
// Up 벡터 (일반적으로 Y축)
|
||
VECTOR3 vUp(0.0f, 1.0f, 0.0f);
|
||
|
||
// Right 벡터 (Forward × Up)
|
||
VECTOR3 vRight;
|
||
CrossProduct(vRight, vForward, vUp);
|
||
Normalize(vRight, vRight);
|
||
|
||
// 실제 Up 벡터 재계산 (Right × Forward)
|
||
CrossProduct(vUp, vRight, vForward);
|
||
|
||
// 카메라 매트릭스 구성
|
||
camera->SetOrientation(vRight, vUp, vForward);
|
||
camera->SetPosition(vCameraPos);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 게임과의 통합
|
||
|
||
### RiskYourLife에서의 사용
|
||
|
||
#### 1. 지형 충돌
|
||
|
||
**위치**: `Client/Client/RYLClient/RYLScene/TerrainManager.cpp`
|
||
|
||
```cpp
|
||
// 지형 메시 로드 시
|
||
void TerrainManager::LoadTerrain(const char* filename)
|
||
{
|
||
// ... 메시 로드 ...
|
||
|
||
// CrossM Octree Collider 초기화
|
||
m_pCollider = new CrossM::Scene::COctreeCollider();
|
||
|
||
// 지형 삼각형 추출
|
||
ExtractCollisionTriangles(m_pCollider);
|
||
|
||
// Octree 구축
|
||
m_pCollider->BuildOctree(6, 10);
|
||
}
|
||
|
||
// 캐릭터 이동 시 충돌 검사
|
||
bool TerrainManager::CheckCollision(
|
||
const vector3& vStart,
|
||
const vector3& vEnd,
|
||
vector3& vOutPos)
|
||
{
|
||
using namespace CrossM::Math;
|
||
|
||
// vector3 → VECTOR3 변환
|
||
VECTOR3 vS(vStart.x, vStart.y, vStart.z);
|
||
VECTOR3 vE(vEnd.x, vEnd.y, vEnd.z);
|
||
VECTOR3 vRadius(0.5f, 1.8f, 0.5f);
|
||
VECTOR3 vResult;
|
||
|
||
// 충돌 검사
|
||
bool bCollided = m_pCollider->CheckCollision(
|
||
vS, vE, vRadius, vResult, true
|
||
);
|
||
|
||
// VECTOR3 → vector3 변환
|
||
vOutPos.x = vResult.x;
|
||
vOutPos.y = vResult.y;
|
||
vOutPos.z = vResult.z;
|
||
|
||
return bCollided;
|
||
}
|
||
```
|
||
|
||
#### 2. 캐릭터 이동
|
||
|
||
**위치**: `Client/Client/RYLClient/Character/CharacterController.cpp`
|
||
|
||
```cpp
|
||
void CharacterController::Move(float deltaTime)
|
||
{
|
||
// 입력에서 이동 벡터 계산
|
||
vector3 vMovement = CalculateMovementFromInput();
|
||
|
||
// 현재 위치
|
||
vector3 vCurrentPos = m_pCharacter->GetPosition();
|
||
|
||
// 목표 위치
|
||
vector3 vTargetPos = vCurrentPos + vMovement * deltaTime;
|
||
|
||
// 지형 충돌 검사 (CrossM 사용)
|
||
vector3 vFinalPos;
|
||
bool bCollided = TerrainManager::Instance().CheckCollision(
|
||
vCurrentPos,
|
||
vTargetPos,
|
||
vFinalPos
|
||
);
|
||
|
||
// 최종 위치 적용
|
||
m_pCharacter->SetPosition(vFinalPos);
|
||
|
||
// 슬라이딩 피드백
|
||
if (bCollided)
|
||
{
|
||
// 벽에 부딪혔을 때 효과
|
||
PlaySoundEffect("wall_hit.wav");
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 3. 발사체 충돌
|
||
|
||
**위치**: `Client/Client/RYLClient/Skill/ProjectileManager.cpp`
|
||
|
||
```cpp
|
||
void Projectile::Update(float deltaTime)
|
||
{
|
||
using namespace CrossM::Math;
|
||
|
||
// 현재 위치
|
||
VECTOR3 vStart(m_position.x, m_position.y, m_position.z);
|
||
|
||
// 다음 위치 계산
|
||
VECTOR3 vVelocity(m_velocity.x, m_velocity.y, m_velocity.z);
|
||
VECTOR3 vDelta;
|
||
Scale(vDelta, vVelocity, deltaTime);
|
||
|
||
VECTOR3 vEnd;
|
||
Add(vEnd, vStart, vDelta);
|
||
|
||
// 충돌 검사 (작은 Ellipsoid)
|
||
VECTOR3 vRadius(0.1f, 0.1f, 0.1f);
|
||
VECTOR3 vResult;
|
||
|
||
bool bHit = g_pTerrainCollider->CheckCollision(
|
||
vStart, vEnd, vRadius, vResult, false
|
||
);
|
||
|
||
if (bHit)
|
||
{
|
||
// 충돌 처리
|
||
OnHit(VECTOR3(vResult.x, vResult.y, vResult.z));
|
||
Destroy();
|
||
}
|
||
else
|
||
{
|
||
// 위치 업데이트
|
||
m_position.x = vResult.x;
|
||
m_position.y = vResult.y;
|
||
m_position.z = vResult.z;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 성능 최적화
|
||
|
||
### Octree 파라미터 튜닝
|
||
|
||
```cpp
|
||
// 작은 맵 (실내)
|
||
collider->BuildOctree(
|
||
4, // 깊이 4 (16개 노드)
|
||
20 // 노드당 20 폴리곤
|
||
);
|
||
|
||
// 중간 맵 (필드)
|
||
collider->BuildOctree(
|
||
6, // 깊이 6 (64개 노드)
|
||
10 // 노드당 10 폴리곤
|
||
);
|
||
|
||
// 큰 맵 (오픈 월드)
|
||
collider->BuildOctree(
|
||
8, // 깊이 8 (256개 노드)
|
||
5 // 노드당 5 폴리곤
|
||
);
|
||
```
|
||
|
||
### 충돌 검사 최적화
|
||
|
||
```cpp
|
||
// 1. Swept Volume으로 후보 필터링
|
||
std::vector<COctreeCollisionNode*> candidates;
|
||
m_RootNode.CollectCollidableNodes(
|
||
vSweptMin,
|
||
vSweptMax,
|
||
candidates
|
||
);
|
||
|
||
// 2. 후보 노드의 삼각형만 검사
|
||
for (auto* pNode : candidates)
|
||
{
|
||
for (size_t idx : pNode->m_vecTriangleIndex)
|
||
{
|
||
CheckTriangleCollision(m_pTriangleData[idx]);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 디버그 및 시각화
|
||
|
||
### Octree 시각화
|
||
|
||
```cpp
|
||
// 디버그 렌더링
|
||
void RenderDebugInfo()
|
||
{
|
||
if (g_bShowOctree)
|
||
{
|
||
// Octree 구조 그리기 (깊이 3까지)
|
||
g_pTerrainCollider->DrawOctree(
|
||
g_pd3dDevice,
|
||
3 // 렌더링할 깊이
|
||
);
|
||
}
|
||
}
|
||
|
||
// DrawOctree 내부 (DX9)
|
||
void COctreeCollider::DrawOctree(IDirect3DDevice9* pDevice, int nDrawDepth)
|
||
{
|
||
// 재귀적으로 노드 그리기
|
||
DrawOctreeNode(&m_RootNode, pDevice, 0, nDrawDepth);
|
||
}
|
||
|
||
void DrawOctreeNode(COctreeCollisionNode* pNode,
|
||
IDirect3DDevice9* pDevice,
|
||
int currentDepth,
|
||
int maxDepth)
|
||
{
|
||
if (!pNode || currentDepth > maxDepth)
|
||
return;
|
||
|
||
// AABB 그리기 (12개 선분)
|
||
DrawAABB(pDevice, pNode->m_vBoundingMin, pNode->m_vBoundingMax);
|
||
|
||
// 자식 노드 그리기
|
||
if (!pNode->IsLeafNode())
|
||
{
|
||
for (int i = 0; i < 8; i++)
|
||
{
|
||
if (pNode->m_apSubNode[i])
|
||
{
|
||
DrawOctreeNode(
|
||
pNode->m_apSubNode[i],
|
||
pDevice,
|
||
currentDepth + 1,
|
||
maxDepth
|
||
);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 정리
|
||
|
||
### CrossM의 역할
|
||
|
||
1. **수학 라이브러리**
|
||
- 3D 벡터 연산
|
||
- 기하학적 계산
|
||
- DirectX와 독립적
|
||
|
||
2. **충돌 감지 시스템**
|
||
- Octree 공간 분할
|
||
- Ellipsoid vs Triangle
|
||
- 슬라이딩 응답
|
||
|
||
3. **게임 물리 기반**
|
||
- 캐릭터 이동
|
||
- 지형 충돌
|
||
- 발사체 추적
|
||
|
||
### 장점
|
||
|
||
✅ **빠른 충돌 검사** - Octree로 O(log N)
|
||
✅ **정확한 응답** - Swept Ellipsoid
|
||
✅ **슬라이딩 지원** - 자연스러운 벽 이동
|
||
✅ **독립적 설계** - 다른 엔진에도 재사용 가능
|
||
✅ **헤더 전용** - 인라인 함수로 성능 최적화
|
||
|
||
### 개선 가능 영역
|
||
|
||
⚠️ **멀티스레드 미지원** - 단일 스레드 충돌 검사
|
||
⚠️ **동적 오브젝트** - Octree 재구축 필요
|
||
⚠️ **메모리 사용** - 큰 맵에서 메모리 많이 사용
|
||
⚠️ **DX9 의존성** - DrawOctree는 DX9 전용
|
||
|
||
---
|
||
|
||
**작성일**: 2025-12-01
|
||
**버전**: 1.0
|
||
**작성자**: Claude AI (Anthropic)
|
||
**프로젝트**: RiskYourLife CrossM Library Analysis
|