1. LandScape Component 만들기
지형을 그려야해서 랜더링 기능이 있어야 하기 때문에 RenderComponent 상속 받는다.
#pragma once
#include "CRenderComponent.h"
class CLandScape :
public CRenderComponent
{
private:
UINT m_iFaceX;
UINT m_iFaceZ;
public:
void SetFace(UINT _iFaceX, UINT _iFaceZ);
virtual void finaltick() override;
virtual void render() override;
CLONE(CLandScape);
public:
CLandScape();
~CLandScape();
};
사용할 매쉬와 재질을 Setting 해줘야하는데, LandScape 는 기존에 만들어놓은 매쉬를 사용하지 않는다.
우리가 지형의 크기를 어떻게 설정해놓느냐에 따라서 매쉬의 모양이 그때그때 실시간으로 달라져야할 수 있기 때문이다.
그래서 LandScape 에는 매쉬를 셋팅하지 않고, 면 개수를 셋팅한다.
ex) 지형을 작게 만들고 싶다. (4 by 4)
void CLandScape::render()
{
if (GetMesh() == nullptr || GetMaterial() == nullptr)
return;
Transform()->UpdateData();
GetMaterial()->GetShader()->SetRSType(RS_TYPE::WIRE_FRAME);
GetMaterial()->UpdateData();
GetMesh()->render();
}
if (GetMesh() == nullptr || GetMaterial() == nullptr) => 처음에는 면 개수가 지정되어 있지 않아서 매쉬가 없어야 한다.
면 개수를 늘릴 수록 정점 개수가 많아진다.
지형을 표기할 때, x축과 z축은 고정되어 있고 y축만 바뀐다.
면 개수가 적으면 뾰족뾰족하게 각지게 느껴지기 때문에 자연스럽게 보여지기 위해서 면 개수를 늘려야한다.
* 높이맵(HightMap)
텍스쳐지만, 색상이 아닌 지형의 높이값이 저장되어 있다.
버텍스 쉐이더에서 모양을 만들어 내서 월드맵으로 보내는 것이다.
정점 수 > 픽셀 수 => 의미가 없다
정점 수 = HightMap의 해상도 => Best 1:1 매칭이 된다.
정점 수를 너무 늘려도 문제가 된다.
why? 화면에 들어오지도 않는 지형을 랜더링하기 위해 연산량이 엄청 올라가 엄청난 렉이 걸린다..
해결법 => 내가 필요한? 곳의 (ex. 플레이어) 근처에 있는 곳만 정점 수를 늘리고 (내가 보는 시야 범위 내),
그 외에는 정점 수를 줄인다.
도메인 쉐이더랑 홀쉐이더를 합친게 Tesselation 인데, 이를 이용해서 정점 수를 조절한다.
지오메트리 쉐이더는 정점을 생성하는 단계가 느리다.
Tesselation은 정점을 대량 생산하는데에 최적화가 되어있다.
지오메트리 쉐이더나 Tesselation 은 정점을 만들어낸다는 것에서 같은 기능을 한다.
파이프라인에서 I.A(Input assembler)에서 넘어오지 않은 매쉬, 정점을 만들어내서 레스터라이저에 넘기는 역할을 한다.
지오매트리 쉐이더는 정점 위치를 스스로 다 잡아서 인덱스에 넘겨줘야 하는데, Tesselation 은 직접 정하지 않는다.
Hull Shader 와 Domain Shader 사이에 Tesselator 단계가 있다.
Hull Shader
-> Tesselator 단계
Domain Shader
Hull Shader => 몇 분할을 할 것인지 알려준다.
Tesselator => Hull Shader 에서 넘긴 분할 수로 자체적인 알고리즘으로 정점들 위치를 잡아준다.
Domain Shader => Tesselator 에서 만들어진 정점들에 대해서 호출하는 쉐이더이다.
여기에서 NDC좌표계에서 투영행렬까지 곱해서 레스터라이저에 넘겨준다.
기존에는 버텍스 쉐이더에서 정점이 만들어지지 않을 것이라고 가정하고, 버텍스 쉐이더라서 투영행렬까지 곱해서 바로 레스터라이저에 넘겨줬다.
이제는 버텍스 쉐이더에서 호출된 애들은 전체가 아니다 => 앞으로 만들어질 애들이 호출이 되지 않았다.
즉, 버텍스 쉐이더가 할 일이 없어진다 ..
원본 정점만 받아서 버텍스 쉐이더에서 했던 일들이 Tessellation에서 진행된다.
2. LandScape 쉐이더 만들기
(1) landscape.fx => 디퍼드 버전으로 만들건데, 테스트를 위해 Forward 3d랑 비슷하게? 제작함.
(2) ResMgr 에 쉐이더, 재질 만들기
// ============================
// LandScapeShader
// RS_TYPE : CULL_BACK
// DS_TYPE : LESS
// BS_TYPE : DEFAULT
//
// Parameter
// g_tex_0 : Output Texture
// g_tex_1 : Normal Texture
// Domain : Opaque
// ============================
pShader = new CGraphicsShader;
pShader->SetKey(L"LandScapeShader");
pShader->CreateVertexShader(L"shader\\landscape.fx", "VS_LandScape");
pShader->CreatePixelShader(L"shader\\landscape.fx", "PS_LandScape");
pShader->SetRSType(RS_TYPE::CULL_BACK);
pShader->SetDSType(DS_TYPE::LESS);
pShader->SetBSType(BS_TYPE::DEFAULT);
pShader->SetDomain(SHADER_DOMAIN::DOMAIN_OPAQUE);
AddRes(pShader->GetKey(), pShader);
// LandScapeMtrl
pMtrl = new CMaterial(true);
pMtrl->SetShader(FindRes<CGraphicsShader>(L"LandScapeShader"));
AddRes(L"LandScapeMtrl", pMtrl);
RS_TYPE : CULL_BACK => landscape.fx지형이 뒤집혀졌을 때, 그릴 필요가 없음
3. TestLevel에 LandScape Object 추가
// LandScape Object
CGameObject* pLandScape = new CGameObject;
pLandScape->SetName(L"LandScape");
pLandScape->AddComponent(new CTransform);
pLandScape->AddComponent(new CMeshRender);
pLandScape->AddComponent(new CLandScape);
pLandScape->LandScape()->SetFace(4, 4);
pLandScape->Transform()->SetRelativeScale(Vec3(500.f, 500, 500));
pLandScape->MeshRender()->SetMesh(CResMgr::GetInst()->FindRes<CMesh>(L"RectMesh"));
pLandScape->MeshRender()->SetMaterial(CResMgr::GetInst()->FindRes<CMaterial>(L"LandScapeMtrl"));
SpawnGameObject(pLandScape, Vec3(0.f, 0.f, 0.f), 0);
* MRT 오류 (31분)
MRT 교체를 할 때, 바인딩 해준게 해제되지 않아서 레지스터가 아직도 남아있는걸로 뜰 수 있음.
RenderMgr에서 MRT_clear, CTexture::Clear(i) 를 해준다.
void CRenderMgr::render_clear()
{
MRT_Clear();
// Texture Register Clear
for (UINT i = 0; i < (UINT)TEX_PARAM::TEX_END; ++i)
{
CTexture::Clear(i);
}
}
4. Tesselation 쉐이더 만들기
(1) ResMgr 에 쉐이더, 재질 만들기
// ============================
// TessShader
// RS_TYPE : CULL_NONE
// DS_TYPE : LESS
// BS_TYPE : DEFAULT
// Domain : DOMAIN_OPAQUE
// ============================
pShader = new CGraphicsShader;
pShader->SetKey(L"TessShader");
pShader->CreateVertexShader(L"shader\\tess.fx", "VS_Tess");
pShader->CreatePixelShader(L"shader\\tess.fx", "PS_Tess");
pShader->SetRSType(RS_TYPE::WIRE_FRAME);
pShader->SetDSType(DS_TYPE::LESS);
pShader->SetBSType(BS_TYPE::DEFAULT);
pShader->SetDomain(SHADER_DOMAIN::DOMAIN_OPAQUE);
AddRes(pShader->GetKey(), pShader);
// TessMtrl
pMtrl = new CMaterial(true);
pMtrl->SetShader(FindRes<CGraphicsShader>(L"TessShader"));
AddRes(L"TessMtrl", pMtrl);
pShader->SetRSType(RS_TYPE::WIRE_FRAME); => 잘보이게 하기 위해 수정
(2) tess.fx
Domain Shader
1) Domain
2) Patch Constant Function
두개를 합쳐 Domain Shader 라고 부른다.
* Patch 란?
트라이앵글리스트를 사용하기 때문에, 폴리곤(삼각형) 하나를 Patch 라고 부른다.
#ifndef _TESS
#define _TEXX
#include "value.fx"
// ========================
// TessShader
// g_tex_0 : Color Texture
// ========================
struct VS_INOUT
{
float3 vPos : POSITION;
float2 vUV : TEXCOORD;
};
// ==============
// Vertex Shader
// ==============
VS_INOUT VS_Tess(VS_INOUT _in)
{
VS_INOUT output = (VS_INOUT) 0.f;
output = _in;
return output;
}
// ===========
// Hull Shader
// ===========
struct HS_OUT
{
};
HS_OUT HS_Tess( InputPatch<VS_INOUT, 3> _input
, uint i : SV_OutputControlPointID
, uint PatchID : SV_PrimitiveID)
{
HS_OUT output = (HS_OUT) 0.f;
// _input[i];
return output;
}
// ============
// Pixel Shader
// ============
float4 PS_Tess(HS_OUT _in) : SV_Target
{
float4 vObjectColor = float4(0.f, 1.f, 0.f, 1.f);
float4 vOutColor = float4(0.f, 0.f, 0.f, 1.f);
vOutColor.xyz = vObjectColor;
return vOutColor;
}
#endif
HS_OUT HS_Tess( InputPatch<VS_INOUT, 3> _input => 배열의 크기를 적어줘야한다.
, uint i : SV_OutputControlPointID
, uint PatchID : SV_PrimitiveID)
==> 3개로 구성되어 있는 InputPatch
버텍스 쉐이더가 6번 호출 되면, Hull Shader 도 6번 호출된다.
1번 호출될 때마다,
SV_OutputControlPointID => 인덱스
PatchID => 도형
본인 정보 접근 하려면 _input[i] 로 접근해야 한다.
5. TestLevel에 Tesselation Object 추가
// Tess Object
CGameObject* pLandScape = new CGameObject;
pLandScape->SetName(L"LandScape");
pLandScape->AddComponent(new CTransform);
pLandScape->AddComponent(new CMeshRender);
//pLandScape->AddComponent(new CLandScape);
//pLandScape->LandScape()->SetFace(4, 4);
pLandScape->Transform()->SetRelativeScale(Vec3(500.f, 500, 500));
pLandScape->MeshRender()->SetMesh(CResMgr::GetInst()->FindRes<CMesh>(L"RectMesh"));
pLandScape->MeshRender()->SetMaterial(CResMgr::GetInst()->FindRes<CMaterial>(L"TessMtrl"));
SpawnGameObject(pLandScape, Vec3(0.f, 0.f, 0.f), 0);
'DirectX 11 3d' 카테고리의 다른 글
230530 tess.fx 이어서 작업 (0) | 2023.05.30 |
---|---|
230526 Tesselation - Patch Constant Function (0) | 2023.05.26 |
230524 Decal에 Light 입히기 (0) | 2023.05.25 |
230522 MRT 개선(EmissiveTargetTex) 및 Decal 생성 (0) | 2023.05.22 |
230519 Stencil Buffer (0) | 2023.05.20 |