For me
[DirectX12] 25) Picking 본문
Picking = Raycasting
좌표 파이프라인을 반대로 다시 돌아가면 된다.
Actual Viewport → Normalized Coordination Space → View Space
View Space에서 Picking을 진행하게 됨
Ray와 물체가 충돌하는지에 대해서 확인이 필요함
BaseCollider
더보기
#pragma once
#include "Component.h"
enum class ColliderType
{
Sphere,
};
class BaseCollider : public Component
{
public:
BaseCollider(ColliderType colliderType);
virtual ~BaseCollider();
virtual bool Intersects(Vec4 rayOrigin, Vec4 rayDir, OUT float& distance) = 0;
private:
ColliderType _colliderType = {};
};
SphereCollider.h
더보기
#pragma once
#include "BaseCollider.h"
class SphereCollider : public BaseCollider
{
public:
SphereCollider();
virtual ~SphereCollider();
virtual void FinalUpdate() override;
virtual bool Intersects(Vec4 rayOrigin, Vec4 rayDir, OUT float& distance) override;
void SetRadius(float radius) { _radius = radius; }
void SetCenter(Vec3 center) { _center = center; }
private:
// Local 기준
float _radius = 1.f;
Vec3 _center = Vec3(0, 0, 0);
BoundingSphere _boundingSphere;
};
SphereCollider.cpp
더보기
#include "pch.h"
#include "SphereCollider.h"
#include "GameObject.h"
#include "Transform.h"
SphereCollider::SphereCollider() : BaseCollider(ColliderType::Sphere)
{
}
SphereCollider::~SphereCollider()
{
}
void SphereCollider::FinalUpdate()
{
_boundingSphere.Center = GetGameObject()->GetTransform()->GetWorldPosition();
Vec3 scale = GetGameObject()->GetTransform()->GetLocalScale();
_boundingSphere.Radius = _radius * max(max(scale.x, scale.y), scale.z);
}
bool SphereCollider::Intersects(Vec4 rayOrigin, Vec4 rayDir, OUT float& distance)
{
return _boundingSphere.Intersects(rayOrigin, rayDir, OUT distance);
}
SceneManager.cpp
Pick 메소드
- Main Camera, Width, Height 를 가져옴
- 이후 ViewSpace 에서 Picking에 필요한 공식을 적용
- 다시 WorldSpace를 돌아가기 위해 view 행렬을 가져온 뒤 역행렬을 구함
- ViewSpace 기준으로 Ray를 정의함(rayOrigin : 카메라 기준, rayDir 방향)
- 역행렬을 이용하여 WorldSpace 기준으로 Ray를 정의함
- WorldSpace에서의 연산
- 충돌테스트
더보기
shared_ptr<GameObject> SceneManager::Pick(int32 screenX, int32 screenY)
{
shared_ptr<Camera> camera = GetActiveScene()->GetMainCamera();
float width = static_cast<float>(GEngine->GetWindow().width);
float height = static_cast<float>(GEngine->GetWindow().height);
Matrix projectionMatrix = camera->GetProjectionMatrix();
// ViewSpace에서 Picking 진행
float viewX = (+2.0f * screenX / width - 1.0f) / projectionMatrix(0, 0);
float viewY = (-2.0f * screenY / height + 1.0f) / projectionMatrix(1, 1);
Matrix viewMatrix = camera->GetViewMatrix();
Matrix viewMatrixInv = viewMatrix.Invert();
auto& gameObjects = GET_SINGLE(SceneManager)->GetActiveScene()->GetGameObjects();
float minDistance = FLT_MAX;
shared_ptr<GameObject> picked;
for (auto& gameObject : gameObjects)
{
if (gameObject->GetCollider() == nullptr)
continue;
// ViewSpace에서의 Ray 정의
Vec4 rayOrigin = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
Vec4 rayDir = Vec4(viewX, viewY, 1.0f, 0.0f);
// WorldSpace에서의 Ray 정의
rayOrigin = XMVector3TransformCoord(rayOrigin, viewMatrixInv);
rayDir = XMVector3TransformNormal(rayDir, viewMatrixInv);
rayDir.Normalize();
// WorldSpace에서 연산
float distance = 0.f;
if (gameObject->GetCollider()->Intersects(rayOrigin, rayDir, OUT distance) == false)
continue;
if (distance < minDistance)
{
minDistance = distance;
picked = gameObject;
}
}
return picked;
}
'DirectX12' 카테고리의 다른 글
[DirectX12] 26) Mesh / Animation (0) | 2023.01.22 |
---|---|
[DirectX12] 24) Terrain (0) | 2023.01.20 |
[DirectX12] 23) Tesellation (0) | 2023.01.20 |
[DirectX12] 22) Instancing (0) | 2023.01.20 |
[DirectX12] 21) Particle System (0) | 2023.01.19 |