[DirectX11] 070 OBB(Oriented Bounding Box) collision
DirectX11에서 OBB (Oriented Bounding Box) 충돌 검사는 다른 물체와의 충돌을 감지하는데 사용되는 방법 중 하나이다. 이를 위해 OBB의 충돌 분리 축(the separating axis) 이론이 사용된다. OBB는 충돌 검사를 수행하기 위해 일반적으로 모델의 경계 상자로 사용된다. 이 상자는 일반적으로 물체의 모양에 맞게 회전할 수 있다. 이러한 OBB의 충돌 검사는 OBB의 축을 기준으로 수행된다.
OBB(Oriented Bounding Box) collision
Shader | |
Framework | |
Objects | |
Collider.h .cpp | |
UnitTest | |
Objects | |
ObbCollisionDemo.h .cpp 생성 | |
Main.h .cpp |
OBB 충돌 - 분리축 이론
OBB는 충돌 검사를 수행하기 위해 일반적으로 모델의 경계 상자로 사용된다. 이 상자는 일반적으로 물체의 모양에 맞게 회전할 수 있다. 이러한 OBB의 충돌 검사는 OBB의 축을 기준으로 수행된다.
분리 축 이론은 두 OBB가 충돌하는지 여부를 결정하기 위해 두 OBB 사이의 축을 비교한다. 두 축이 서로 분리되어 있다면, 두 OBB는 충돌하지 않는다. 즉, 최소한의 분리 축을 찾는 것이 중요하다.
이를 수행하기 위해, 두 OBB의 모든 축(총 15개)을 비교한다. 각각의 축에 대해 두 OBB의 투영(projection)을 계산하고, 이러한 투영이 서로 겹치는지를 확인한다. 만약 모든 축에서 투영이 겹치면, 두 OBB는 충돌한다. 하지만 하나의 축에서라도 겹치지 않는다면, 두 OBB는 충돌하지 않는다.
분리 축 이론은 물체의 복잡한 형태를 갖는 경우에도 적용할 수 있으며, 속도와 정확도 모두가 뛰어나다는 장점이 있다.
https://m.blog.naver.com/kys9096/221200798891
OBB 충돌 체크 - part 1 (분리축 이론과 벡터의 내적)
본격적인 알고리즘 구현 이전에, 앞서 언급했던 분리축 이론과 벡터의 내적을 한번 짚고 넘어가보자. 분리...
blog.naver.com
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=55smile&logNo=221671747433
분리축이론(SAT)과 OBB 충돌
우리는 게임을 만들때 일반적으로 충돌박스라는것을 만들어서 체크를 한다. 이는 구가될수도있고, 면이될수...
blog.naver.com
https://sanghoon23.tistory.com/m/82
[DX] ##6. AABB, OBB 충돌 SAT 분리축 이론( Separating Axis Theorem )
Frustum Culling ( 절두체 선별 ) 에 앞서서 해당 범위에 오브젝트들이 포함되어있는지 어떻게 판별할까 ?? 그 방법에 대해서 몇 가지 알아보고 넘어가자. *AABB ( Axis - Aligned Bounding Box ) => 축 정렬 경계
sanghoon23.tistory.com
Collider
Collider.h
#pragma once struct Ray { Ray() : Position(0, 0, 0), Direction(0, 0, 0) { } Ray(Vector3& position, Vector3& direction) :Position(position), Direction(direction) { } Vector3 Position; Vector3 Direction; }; struct ColliderObject { class Transform* Init = NULL; class Transform* Transform = NULL; class Collider* Collider = NULL; }; class Collider { private: struct Bounding; public: Collider(Transform* transform, Transform* init = NULL); ~Collider(); void Update(); void Render(Color color = Color(0, 1, 0, 1)); Transform* GetTransform() { return transform; } bool Intersection(Ray& ray, float* outDistance); bool Intersection(Collider* other); //충돌체 검사 private: //분리축 검사 bool SeperatingPlane(Vector3& position, Vector3& direction, Bounding& box1, Bounding& box2); bool Collision(Bounding& box1, Bounding& box2); //외적 Vector3 Cross(Vector3& vec1, Vector3& vec2); private: //충돌검사를 할 바운딩박스 struct Bounding { Vector3 Position; Vector3 AxisX; Vector3 AxisY; Vector3 AxisZ; Vector3 HalfSize; //반사이즈 } bounding; private: Transform* init = NULL; Transform* transform; Vector3 lines[8]; };
Collider.cpp
#include "Framework.h" #include "Collider.h" Collider::Collider(Transform * transform, Transform * init) : transform(transform), init(init) { lines[0] = Vector3(-0.5f, -0.5f, -0.5f); //Min lines[1] = Vector3(-0.5f, +0.5f, -0.5f); lines[2] = Vector3(+0.5f, -0.5f, -0.5f); lines[3] = Vector3(+0.5f, +0.5f, -0.5f); lines[4] = Vector3(-0.5f, -0.5f, +0.5f); lines[5] = Vector3(-0.5f, +0.5f, +0.5f); lines[6] = Vector3(+0.5f, -0.5f, +0.5f); lines[7] = Vector3(+0.5f, +0.5f, +0.5f); //Max } Collider::~Collider() { } void Collider::Update() { //매 프레임마다 바운딩 생성 Transform temp; temp.World(transform->World()); if (init != NULL) temp.World(init->World() * transform->World()); //초기값에서부터 얼마만큼 이동했는지 temp.Position(&bounding.Position); //이동된 위치 D3DXVec3Normalize(&bounding.AxisX, &temp.Right());//바운딩박스의 X축 오른쪽 방향 D3DXVec3Normalize(&bounding.AxisY, &temp.Up()); //바운딩박스의 Y축 윗방향 D3DXVec3Normalize(&bounding.AxisZ, &temp.Forward());//바운딩박스의 Z축은 전방 방향 Vector3 scale; temp.Scale(&scale); bounding.HalfSize = scale * 0.5f; } void Collider::Render(Color color) { Transform temp; temp.World(transform->World()); if (init != NULL) temp.World(init->World() * transform->World()); Matrix world = temp.World(); Vector3 dest[8]; for (UINT i = 0; i < 8; i++) D3DXVec3TransformCoord(&dest[i], &lines[i], &world); //Front DebugLine::Get()->RenderLine(dest[0], dest[1], color); DebugLine::Get()->RenderLine(dest[1], dest[3], color); DebugLine::Get()->RenderLine(dest[3], dest[2], color); DebugLine::Get()->RenderLine(dest[2], dest[0], color); //Backward DebugLine::Get()->RenderLine(dest[4], dest[5], color); DebugLine::Get()->RenderLine(dest[5], dest[7], color); DebugLine::Get()->RenderLine(dest[7], dest[6], color); DebugLine::Get()->RenderLine(dest[6], dest[4], color); //Side DebugLine::Get()->RenderLine(dest[0], dest[4], color); DebugLine::Get()->RenderLine(dest[1], dest[5], color); DebugLine::Get()->RenderLine(dest[2], dest[6], color); DebugLine::Get()->RenderLine(dest[3], dest[7], color); } bool Collider::Intersection(Ray & ray, float * outDistance) { *outDistance = 0.0f; Vector3 dest[8]; Transform temp; temp.World(transform->World()); if (init != NULL) temp.World(init->World() * transform->World()); Matrix world = temp.World(); Vector3 minPosition, maxPosition; D3DXVec3TransformCoord(&minPosition, &lines[0], &world); D3DXVec3TransformCoord(&maxPosition, &lines[7], &world); if (fabsf(ray.Direction.x) == 0.0f) ray.Direction.x = 1e-6f; if (fabsf(ray.Direction.y) == 0.0f) ray.Direction.y = 1e-6f; if (fabsf(ray.Direction.z) == 0.0f) ray.Direction.z = 1e-6f; float minValue = 0.0f, maxValue = FLT_MAX; //Check X if (fabsf(ray.Direction.x) >= 1e-6f) { float value = 1.0f / ray.Direction.x; float minX = (minPosition.x - ray.Position.x) * value; float maxX = (maxPosition.x - ray.Position.x) * value; if (minX > maxX) { float temp = minX; minX = maxX; maxX = temp; } minValue = max(minX, minValue); maxValue = min(maxX, maxValue); if (minValue > maxValue) return false; } else if (ray.Position.x < minPosition.x || ray.Position.x > maxPosition.x) return false; //Check Y if (fabsf(ray.Direction.y) >= 1e-6f) { float value = 1.0f / ray.Direction.y; float minY = (minPosition.y - ray.Position.y) * value; float maxY = (maxPosition.y - ray.Position.y) * value; if (minY > maxY) { float temp = minY; minY = maxY; maxY = temp; } minValue = max(minY, minValue); maxValue = min(maxY, maxValue); if (minValue > maxValue) return false; } else if (ray.Position.y < minPosition.y || ray.Position.y > maxPosition.y) return false; //Check Z if (fabsf(ray.Direction.z) >= 1e-6f) { float value = 1.0f / ray.Direction.z; float minZ = (minPosition.z - ray.Position.z) * value; float maxZ = (maxPosition.z - ray.Position.z) * value; if (minZ > maxZ) { float temp = minZ; minZ = maxZ; maxZ = temp; } minValue = max(minZ, minValue); maxValue = min(maxZ, maxValue); if (minValue > maxValue) return false; } else if (ray.Position.z < minPosition.z || ray.Position.z > maxPosition.z) return false; *outDistance = minValue; return true; } bool Collider::Intersection(Collider * other) { //현재 가지고 있는 bounding 정보와 다른객체(other)이 가지고 있는 bounding 정보가 같은지 검사. return Collision(this->bounding, other->bounding); } bool Collider::SeperatingPlane(Vector3 & position, Vector3 & direction, Bounding & box1, Bounding & box2) { float val = fabsf(D3DXVec3Dot(&position, &direction)); float val2 = 0.0f; val2 += fabsf(D3DXVec3Dot(&(box1.AxisX * box1.HalfSize.x), &direction)); val2 += fabsf(D3DXVec3Dot(&(box1.AxisY * box1.HalfSize.y), &direction)); val2 += fabsf(D3DXVec3Dot(&(box1.AxisZ * box1.HalfSize.z), &direction)); val2 += fabsf(D3DXVec3Dot(&(box2.AxisX * box2.HalfSize.x), &direction)); val2 += fabsf(D3DXVec3Dot(&(box2.AxisY * box2.HalfSize.y), &direction)); val2 += fabsf(D3DXVec3Dot(&(box2.AxisZ * box2.HalfSize.z), &direction)); return val > val2; } bool Collider::Collision(Bounding & box1, Bounding & box2) { Vector3 position = box2.Position - box1.Position; //총 128개의 분리축을 검사하여야 하지만 중복되는 부분을 제외하면 15개. if (SeperatingPlane(position, box1.AxisX, box1, box2) == true) return false; if (SeperatingPlane(position, box1.AxisY, box1, box2) == true) return false; if (SeperatingPlane(position, box1.AxisZ, box1, box2) == true) return false; if (SeperatingPlane(position, box2.AxisX, box1, box2) == true) return false; if (SeperatingPlane(position, box2.AxisY, box1, box2) == true) return false; if (SeperatingPlane(position, box2.AxisZ, box1, box2) == true) return false; if (SeperatingPlane(position, Cross(box1.AxisX, box2.AxisX), box1, box2) == true) return false; if (SeperatingPlane(position, Cross(box1.AxisX, box2.AxisY), box1, box2) == true) return false; if (SeperatingPlane(position, Cross(box1.AxisX, box2.AxisZ), box1, box2) == true) return false; if (SeperatingPlane(position, Cross(box1.AxisY, box2.AxisX), box1, box2) == true) return false; if (SeperatingPlane(position, Cross(box1.AxisY, box2.AxisY), box1, box2) == true) return false; if (SeperatingPlane(position, Cross(box1.AxisY, box2.AxisZ), box1, box2) == true) return false; if (SeperatingPlane(position, Cross(box1.AxisZ, box2.AxisX), box1, box2) == true) return false; if (SeperatingPlane(position, Cross(box1.AxisZ, box2.AxisY), box1, box2) == true) return false; if (SeperatingPlane(position, Cross(box1.AxisZ, box2.AxisZ), box1, box2) == true) return false; return true; } //외적 Vector3 Collider::Cross(Vector3 & vec1, Vector3 & vec2) { float x = vec1.y * vec2.z - vec1.z * vec2.y; float y = vec1.z * vec2.x - vec1.x * vec2.z; float z = vec1.x * vec2.y - vec1.y * vec2.x; return Vector3(x, y, z); }
Obb Collision Demo
OBB Collsion을 화면에 그려주기 위해 collider 2개를 생성한다.
ObbCollisionDemo.h
#pragma once #include "Systems/IExecute.h" class ObbCollisionDemo : public IExecute { public: virtual void Initialize() override; virtual void Ready() override {} virtual void Destroy() override {} virtual void Update() override; virtual void PreRender() override {} virtual void Render() override; virtual void PostRender() override {} virtual void ResizeScreen() override {} private: Shader* shader; CubeSky* sky; Material* floor; MeshRender* grid; Transform* transform[2]; //충돌체의 위치를 정의할 transform 2개 Collider* collider[2]; //충돌체 2개 };
Transform* transform[2];
- 충돌체의 위치를 정의할 transform 2개
Collider* collider[2];
- 충돌체 2개
ObbCollisionDemo.cpp
#include "stdafx.h" #include "ObbCollisionDemo.h" void ObbCollisionDemo::Initialize() { Context::Get()->GetCamera()->RotationDegree(20, 0, 0); Context::Get()->GetCamera()->Position(1, 36, -85); shader = new Shader(L"55_Render.fx"); sky = new CubeSky(L"Environment/GrassCube1024.dds"); floor = new Material(shader); floor->DiffuseMap("White.png"); grid = new MeshRender(shader, new MeshGrid(5, 5)); grid->AddTransform(); //collider 2개 생성 후 위치 및 스케일 정의. transform[0] = new Transform(); transform[0]->Position(0.0f, 0.5f, 0.0f); transform[0]->Scale(2, 1, 1); collider[0] = new Collider(transform[0]); transform[1] = new Transform(); transform[1]->Position(2.0f, 0.5f, 0.0f); collider[1] = new Collider(transform[1]); } void ObbCollisionDemo::Update() { sky->Update(); grid->Update(); Vector3 position2; transform[1]->Position(&position2); if (Keyboard::Get()->Press(VK_RIGHT)) position2.x += 3.0f * Time::Delta(); else if (Keyboard::Get()->Press(VK_LEFT)) position2.x -= 3.0f * Time::Delta(); if (Keyboard::Get()->Press(VK_UP)) position2.z += 3.0f * Time::Delta(); else if (Keyboard::Get()->Press(VK_DOWN)) position2.z -= 3.0f * Time::Delta(); transform[1]->Position(position2); Vector3 rotation = Vector3(0, 0, 0); Vector3 rotation2 = Vector3(0, 0, 0); transform[0]->RotationDegree(&rotation); transform[1]->RotationDegree(&rotation2); ImGui::SliderFloat3("Rotation", (float *)rotation, -179, 179); ImGui::SliderFloat3("Rotation2", (float *)rotation2, -179, 179); transform[0]->RotationDegree(rotation); transform[1]->RotationDegree(rotation2); collider[0]->Update(); collider[1]->Update(); } void ObbCollisionDemo::Render() { sky->Render(); floor->Render(); grid->Render(); bool bCheck = collider[0]->Intersection(collider[1]); Color color; //충돌하면 Red, 충돌하지 않으면 Green color = bCheck ? Color(1, 0, 0, 1) : Color(0, 1, 0, 1); collider[0]->Render(color); collider[1]->Render(color); }
실행화면

'⭐ DirectX > DirectX11 3D' 카테고리의 다른 글
[DirectX11] 074 Instancing (0) | 2023.03.18 |
---|---|
[DirectX11] 071~73 Get MultiBones (0) | 2023.03.15 |
[DirectX11] 069 Collider (0) | 2023.03.13 |
[DirectX11] 068 Unprojection - 2D 좌표를 3D 좌표로 변환 (0) | 2023.03.13 |
[DirectX11] 067 Projection (0) | 2023.03.09 |
댓글
이 글 공유하기
다른 글
-
[DirectX11] 074 Instancing
[DirectX11] 074 Instancing
2023.03.18 -
[DirectX11] 071~73 Get MultiBones
[DirectX11] 071~73 Get MultiBones
2023.03.15 -
[DirectX11] 069 Collider
[DirectX11] 069 Collider
2023.03.13 -
[DirectX11] 068 Unprojection - 2D 좌표를 3D 좌표로 변환
[DirectX11] 068 Unprojection - 2D 좌표를 3D 좌표로 변환
2023.03.13
댓글을 사용할 수 없습니다.