응애맘마조
230531 강의 본문
충돌 처리에 대해 강의를 했었습니다.
#include "Common.hlsl"
struct VertexInput
{
float4 Position : POSITION0;
float4 Color : COLOR0;
};
struct PixelInput
{
float4 Position : SV_POSITION;
float4 Color : COLOR0;
};
PixelInput VS(VertexInput input)
{
PixelInput output;
output.Position = mul(input.Position, World);
output.Position = mul(output.Position, ViewProj);
output.Color = input.Color;
return output;
}
float4 PS(PixelInput input) : SV_TARGET
{
return float4(1, 0, 0, 1);
}
충돌 처리의 객체를 확인하기 위해 색상을 빨간색으로 했습니다. 항상 만들던 객체들은 모서리가 전부 검은색입니다.
#pragma once
enum class ColliderType
{
SPHERE,
BOX,
OBOX,
};
class Collider : public Transform
{
friend class GameObject;
public:
shared_ptr<Mesh> mesh;
shared_ptr<Shader> shader;
ColliderType type;
bool visible;
public:
Collider(ColliderType type);
~Collider();
void Update(class GameObject* ob);
void Render();
void RenderDetail();
bool Intersect(Collider* target);
bool Intersect(Ray Ray,Vector3& Hit);
};
#include "Framework.h"
Collider::Collider(ColliderType type)
{
this->type = type;
visible = true;
switch (type)
{
case ColliderType::SPHERE:
mesh = RESOURCE->meshes.Load("1.SphereCollider.mesh");
break;
case ColliderType::BOX:
mesh = RESOURCE->meshes.Load("1.BoxCollider.mesh");
break;
case ColliderType::OBOX:
mesh = RESOURCE->meshes.Load("1.BoxCollider.mesh");
break;
}
shader = RESOURCE->shaders.Load("1.Collider.hlsl");
}
Collider::~Collider()
{
SafeReset(mesh);
SafeReset(shader);
}
void Collider::Update(GameObject* ob)
{
parent = ob;
if (type == ColliderType::SPHERE)
{
scale.z = scale.y = scale.x;
}
Transform::Update();
if (type == ColliderType::BOX)
{
T = Matrix::CreateTranslation(GetWorldPos());
W = S * T;
}
}
void Collider::Render()
{
if (visible)
{
Transform::Set();
mesh->Set();
shader->Set();
D3D->GetDC()->DrawIndexed(mesh->indexCount, 0, 0);
}
}
void Collider::RenderDetail()
{
switch (type)
{
case ColliderType::SPHERE:
{
ImGui::Text("Sphere");
break;
}
case ColliderType::BOX:
{
ImGui::Text("Box");
break;
}
case ColliderType::OBOX:
{
ImGui::Text("OBox");
break;
}
}
ImGui::Checkbox("isVisible", &visible);
Transform::RenderDetail();
}
bool Collider::Intersect(Collider* target)
{
if (type == ColliderType::BOX)
{
BoundingBox box1;
box1.Center = GetWorldPos();
box1.Extents = Vector3(S._11, S._22, S._33);
if (target->type == ColliderType::BOX)
{
BoundingBox box2;
box2.Center = target->GetWorldPos();
box2.Extents = Vector3(target->S._11, target->S._22, target->S._33);
return box1.Intersects(box2);
}
else if (target->type == ColliderType::OBOX)
{
BoundingOrientedBox box2;
box2.Center = target->GetWorldPos();
box2.Extents = Vector3(target->S._11, target->S._22, target->S._33);
box2.Orientation = Quaternion::CreateFromRotationMatrix(target->RT);
return box1.Intersects(box2);
}
else
{
BoundingSphere box2;
box2.Center = target->GetWorldPos();
box2.Radius = target->S._11 ;
return box1.Intersects(box2);
}
}
else if (type == ColliderType::OBOX)
{
BoundingOrientedBox box1;
box1.Center = GetWorldPos();
box1.Extents = Vector3(S._11, S._22, S._33) ;
box1.Orientation = Quaternion::CreateFromRotationMatrix(RT);
if (target->type == ColliderType::BOX)
{
BoundingBox box2;
box2.Center = target->GetWorldPos();
box2.Extents = Vector3(target->S._11, target->S._22, target->S._33);
return box1.Intersects(box2);
}
else if (target->type == ColliderType::OBOX)
{
BoundingOrientedBox box2;
box2.Center = target->GetWorldPos();
box2.Extents = Vector3(target->S._11, target->S._22, target->S._33);
box2.Orientation = Quaternion::CreateFromRotationMatrix(target->RT);
return box1.Intersects(box2);
}
else
{
BoundingSphere box2;
box2.Center = target->GetWorldPos();
box2.Radius = target->S._11;
return box1.Intersects(box2);
}
}
else
{
BoundingSphere box1;
box1.Center = GetWorldPos();
box1.Radius = S._11;
if (target->type == ColliderType::BOX)
{
BoundingBox box2;
box2.Center = target->GetWorldPos();
box2.Extents = Vector3(target->S._11, target->S._22, target->S._33) ;
return box1.Intersects(box2);
}
else if (target->type == ColliderType::OBOX)
{
BoundingOrientedBox box2;
box2.Center = target->GetWorldPos();
box2.Extents = Vector3(target->S._11, target->S._22, target->S._33);
box2.Orientation = Quaternion::CreateFromRotationMatrix(target->RT);
return box1.Intersects(box2);
}
else
{
BoundingSphere box2;
box2.Center = target->GetWorldPos();
box2.Radius = target->S._11 ;
return box1.Intersects(box2);
}
}
return false;
}
bool Collider::Intersect(Ray Ray, Vector3& Hit)
{
Ray.direction.Normalize();
float Dis;
bool result = false;
if (type == ColliderType::BOX)
{
BoundingBox box1;
box1.Center = GetWorldPos();
box1.Extents = Vector3(S._11, S._22, S._33);
result =Ray.Intersects(box1, Dis);
Hit = Ray.position + Ray.direction * Dis;
}
else if (type == ColliderType::OBOX)
{
BoundingBox box1;
box1.Center = Vector3(0,0,0);
box1.Extents = Vector3(S._11, S._22, S._33) ;
Matrix inverse = S.Invert() * W;
inverse = inverse.Invert();
Ray.position = Vector3::Transform(Ray.position, inverse);
Ray.direction = Vector3::TransformNormal(Ray.direction, inverse);
Ray.direction.Normalize();
result = Ray.Intersects(box1, Dis);
Hit = Ray.position + Ray.direction * Dis;
Hit = Vector3::Transform(Hit, inverse.Invert());
}
else
{
BoundingSphere box1;
box1.Center = GetWorldPos();
box1.Radius = S._11;
result = Ray.Intersects(box1, Dis);
Hit = Ray.position + Ray.direction * Dis;
}
return result;
}
헤더와 cpp파일입니다.
AABB일 때와 OBB일 때의 충돌처리를 했습니다. AABB는 정렬된 축으로 충돌을 판정하기 때문에 rotation을 할 수 없도록 하고 OBB는 회전된 축으로 판정을 해야 하기 때문에 2D에서 했던 것처럼 투영을 해서 판정을 해야 되기 때문에 연산량이 많아지게 됩니다. 그래서 게임을 만들 때 AABB 안에 먼저 들어와 있는지 판정을 먼저 하고 OBB를 하는 것이 좋다고 합니다.
읽어주셔서 감사합니다.