Directional Light Shadow
1. 그림자 깊이 맵을 이용함 ( 수업에서 사용 ) -> 난이도가 쉽고, 성능이 좋다. 깊이맵의 해상도가 중요하다.. 떨어지면 그림자가 모자이크?처럼 나와서 좀 떨어진다.
2. 스텐실 버퍼를 활용 -> 연산이 더 들어가는 대신에 정밀하다.
랜더매니저에 DepthMap MRT 추가
랜더타겟은 한 장짜리고, 기존에 사용하더 ㄴ깊이맵을 사용 안한다
DepthMap MRT -> 랜더타겟 한 장, 깊이텍스쳐 한 장으로 구성 (스왑체인이랑 비슷)
(랜더타겟과 깊이텍스쳐의 해상도는 반드시 같아야한다)
render_dynamic_shadowdepth -> 동적 그림자 생성이 추가됨
renderMgr.cpp
void CRenderMgr::render_dynamic_shadowdepth()
{
m_MRT[(UINT)MRT_TYPE::SHADOW]->OMSet(); -> shadow MRT를 출력타겟으로 지정
for (size_t i = 0; i < m_vecLight3D.size(); ++i)
{
if (LIGHT_TYPE::DIRECTIONAL == m_vecLight3D[i]->GetLightType())
m_vecLight3D[i]->render_depthmap();
}
}
CLight3D.cpp
void CLight3D::render_depthmap()
{
m_pLightCam->Camera()->SortShadowObject();
m_pLightCam->Camera()->render_depthmap();
}
light3d 안에 gameobject가 들어있음
깊이맵은 광원에 카메라를 달아서 광원에서 물체를 그리려고 하는 것이다.
메인카메라 시점에서 그림을 그리려는 것이 아니다.
광원 시점에서 바라본 물체를 Shadow MRT의 랜더타겟에 그리겠따는 것.
그러려면 전혀 다른 카메라가 한 대 필요하고, 그 카메라는 광원이 바라보는 위치를 바라보고 있어야한다.
즉, 광원의 위치에 카메라가 있어야 한다.
light3d에 모듈단위로 카메라를 넣어둔 것이다.
카메라라는 기능은 컴포넌트로 구현을 했다.
카메라 컴포넌트를 주는 것은 아니다 그러면 레벨 내에서 카메라 역할을 하게 된다.
그럼 마치 UI 카메라가 된 것 처럼 레벨에 존재하는 또다른 카메라가 되어버린다.
그런데 그런게 아닌 광원이 카메라를 가지고 있어야한다.
광원 기능 중에서 광원 시점에서 물체를 그리는 쉐도우 기능이 필요하기 때문에
게임 오브젝트에서 컴포넌트로 또 카메라를 주는 것이 아니라 light3d 안에 카메라를 하나 붙여놓은 것이다.
Light3D.h
CGameObject* m_pLightCam; // 광원 시점용 카메라
CLight3D.cpp
CLight3D::CLight3D()
: CComponent(COMPONENT_TYPE::LIGHT3D)
, m_LightInfo{}
{
SetLightType(LIGHT_TYPE::POINT);
m_pLightCam = new CGameObject;
m_pLightCam->AddComponent(new CTransform);
m_pLightCam->AddComponent(new CCamera);
}
카메라 기능 할 수 있는 걸 만들어서 트렌스폼에다 카메라 컴포넌트 하나를 넣어두었다.
컴포넌트가 카메라 기능을 수행하기 위해서 간단한 게임오브젝트를 생성시켰다.
CLight3D.cpp
void CLight3D::finaltick()
{
m_LightInfo.vWorldPos = Transform()->GetWorldPos();
m_LightInfo.vWorldDir = Transform()->GetWorldDir(DIR_TYPE::FRONT);
Transform()->SetRelativeScale(Vec3(m_LightInfo.Radius * 2.f, m_LightInfo.Radius * 2.f, m_LightInfo.Radius * 2.f));
// 광원의 카메라도 광원과 동일한 Transform 이 되도록 업데이트 한다.
m_pLightCam->Transform()->SetRelativePos(Transform()->GetWorldPos());
m_pLightCam->Transform()->SetRelativeRot(DecomposeRotMat(Transform()->GetWorldRotation()));
m_pLightCam->finaltick_module();
m_iLightIdx = CRenderMgr::GetInst()->RegisterLight3D(this);
}
광원 카메라 트렌스폼에 CLight3D의 본인의 트렌스폼의 정보를 CLight3D오브젝트 트렌스폼에 넣어줬다.
파이널틱 모듈로 만든 이유는, 원래 파이널틱을 하면 레이어에 등록을 시킨다
매프레임마다 그 ㄱ레이어 소속이라고 계속 등록을 한다.
근데 이거는 등록되면 안된다
CLight3D.cpp
void CLight3D::SetLightDirection(Vec3 _vDir)
{
m_LightInfo.vWorldDir = _vDir;
m_LightInfo.vWorldDir.Normalize();
Vec3 vFront = m_LightInfo.vWorldDir;
Vec3 vUp = Vec3(0.f, 1.f, 0.f);
Vec3 vRight = XMVector3Cross(vUp, vFront);
vRight.Normalize();
vUp = XMVector3Cross(vFront, vRight);
vUp.Normalize();
Matrix matRot = XMMatrixIdentity();
matRot._11 = vRight.x; matRot._12 = vRight.y; matRot._13 = vRight.z;
matRot._21 = vUp.x; matRot._22 = vUp.y; matRot._23 = vUp.z;
matRot._31 = vFront.x; matRot._32 = vFront.y; matRot._33 = vFront.z;
Vec3 vRot = DecomposeRotMat(matRot);
// 광원이 가리키는 방향이 Transform 의 Front 가 되도록 회전시켜준다.
Transform()->SetRelativeRot(vRot);
}
setlightdirection
프론트를 바라보려면 얼마나 돌려야하는지 계산을 한다
회전행렬을 곱했더니 f r u 벡터가 나온다는거니까 회전행렬 자체가 f r u 로 구성된다는 것이다..
왼손좌표계 기준으로 축별로 나눠놓음.. 수학이라 생각하면된다고 함.
func.cpp -> decomposerotmat
방향을 셋팅해주면 알아서 알아서 회전행렬이 되도록 트렌스폼이 잡힌다는 얘기..
랜더링하기 전에 쉐도우 뎁스맵을 뽑아서 광원에 달려있는 카메라를 사용..
쉐도우 뎁스맵에는 광원에 달려있는 카메라가 바라보는 시점을 그리도록 한다.
랜더링을 결국 CLight3D가 갖고있는 카메라에게 랜더링을 돌리라고 한다
랜더링 기준이 항상 카메라.
CLight3D의 카메라는 원근투영법을 사용안한다 직교투영을 한다
--
동적물체 정적물체 쉐도우 다르게~~
고정된물체는 동적맵에서 그리면 너무 연산량이 많아서 손해!
미리 한번만 딱 그려놓고 리소스를 로딩해서 쓰면 된다.
동적 쉐도우는 움직이는 물체만!
태양광에 의한 그림자 말고 모닥불을 그렸을 때 거기에 포인트 라이트 줬을 때 받는 그림자는??
=> 상당히 어려워짐.. 빛이 가까우니까 .. 실시간으로 달라진다 . 원근 투영으로 육면으로 찍어야한다.
천장에도 그림자져야하고 그렇기 때문에.. 큐브형태로 만들어내야한다.
방법이 있다! 그동안은 랜더타겟 여러장 셋팅해도 카메라뷰가 똑같았다. 그래서 모든 물체가 같은 지점에 맵핑이 되었는데 지오메트리 쉐이더를 활용하면 타겟별로 다르게 맵핑할 수 있다.
너무어려워서 수업용은 아니라고.. 생각해서 안하심!
'DirectX 11 3d' 카테고리의 다른 글
230629 FBX 애니메이션 로딩 (0) | 2023.07.14 |
---|---|
230626 FBX 정적 매쉬 로딩 (0) | 2023.07.13 |
230619 Mapmapping (0) | 2023.06.26 |
230615 LandScape - Splating(색칠) (0) | 2023.06.26 |
230609 LandScape Heightmap (0) | 2023.06.25 |