Deferred rendering

ㅋㅋ·2022년 7월 28일
0

DirectX12강의

목록 보기
30/39

position + normal + diffuse(color) + diffuse light + specular light

5개의 텍스쳐를 저장 후 한번에 계산

물체를 그릴 때 모든 빛을 검사하여 영향을 받는 광원을 찾아서 그리는게 아닌

빛을 그릴 때 물체를 찾아서 그림 =>

볼륨 메쉬를 통하여 픽셀화 후 해당 영역에 물체가 있을 때만 빛 계산


light shader 파일

struct VS_IN
{
    float3 pos : POSITION;
    float2 uv : TEXCOORD;
};

struct VS_OUT
{
    float4 pos : SV_Position;
    float2 uv : TEXCOORD;
};

struct PS_OUT
{
    float4 diffuse : SV_Target0;
    float4 specular : SV_Target1;
};

light 쉐이더는 물체 좌표와 uv 좌표만을 입력 받는다.


VS_OUT VS_DirLight(VS_IN input)
{
    ...

    output.pos = float4(input.pos * 2.f, 1.f);
    output.uv = input.uv;

    return output;
}

PS_OUT PS_DirLight(VS_OUT input)
{
    ...

    float3 viewPos = g_tex_0.Sample(g_sam_0, input.uv).xyz;
    if (viewPos.z <= 0.f)
        clip(-1);

    float3 viewNormal = g_tex_1.Sample(g_sam_0, input.uv).xyz;

    LightColor color = CalculateLightColor(g_int_0, viewNormal, viewPos);
    output.diffuse = color.diffuse + color.ambient;
    output.specular = color.specular;

    return output;
}

directional light와 point light의 계산 방식이 다름

directinal인 경우 빛의 볼륨 메쉬가 사각형으로 화면 전체를 커버할 수 있도록 함

view 좌표계 기준으로 물체가 카메라 뒤에 있거나 물체가 없는 좌표라면 clip 함수로 곧바로 반환한다.(쉐이더 내장 함수)

VS_OUT VS_PointLight(VS_IN input)
{
    ...

    output.pos = mul(float4(input.pos, 1.f), g_matWVP);
    output.uv = input.uv;

    return output;
}

PS_OUT PS_PointLight(VS_OUT input)
{
    ...

    float2 uv = float2(input.pos.x / g_vec2_0.x, input.pos.y / g_vec2_0.y);
    float3 viewPos = g_tex_0.Sample(g_sam_0, uv).xyz;
    if (viewPos.z <= 0.f)
    	...

    int lightIndex = g_int_0;
    float3 viewLightPos = mul(float4(g_light[lightIndex].position.xyz, 1.f), g_matView).xyz;
    float distance = length(viewPos - viewLightPos);
    if (distance > g_light[lightIndex].range)
    	...

    float3 viewNormal = g_tex_1.Sample(g_sam_0, uv).xyz;

    LightColor color = CalculateLightColor(g_int_0, viewNormal, viewPos);

    output.diffuse = color.diffuse + color.ambient;
    output.specular = color.specular;

    return output;
}

픽셀 쉐이더로 들어오는 position 값은 screen 좌표계 기준임

그렇기 때문에 좌표를 uv 좌표로 변환 후 사용하여 position 텍스쳐 체크

position 텍스쳐에 물체가 있다면

월드 공간에서의 광원과 물체의 거리를 계산하여 광원의 영향에 받는 물체인지 체크

float4 PS_Final(VS_OUT input) : SV_Target
{
    ...

    float4 lightPower = g_tex_1.Sample(g_sam_0, input.uv);
    if (lightPower.x == 0.f && lightPower.y == 0.f && lightPower.z == 0.f)
    	...

    float4 color = g_tex_0.Sample(g_sam_0, input.uv);
    float4 specular = g_tex_2.Sample(g_sam_0, input.uv);

    output = (color * lightPower) + specular;
    return output;
}

diffuse 텍스쳐들과 specular 텍스쳐를 모두 합쳐서 계산하는 쉐이더

빛을 받은 좌표만을 계산하게 된다.


shader 클래스 수정

enum class SHADER_TYPE : uint8
{
	DEFERRED,
	FORWARD,
	LIGHTING,
};

enum class DEPTH_STENCIL_TYPE : uint8
{
	LESS,
	LESS_EQUAL,
	GREATER,
	GREATER_EQUAL,
	NO_DEPTH_TEST,
	NO_DEPTH_TEST_NO_WRITE,
	LESS_NO_WRITE,
};

enum class BLEND_TYPE : uint8
{
	DEFAULT,
	ALPHA_BLEND,
	ONE_TO_ONE_BLEND,
	END,
};

쉐이더 타입에 빛 쉐이더인 lighting 추가

depth stencil 타입에 깊이 테스트 및 기록 유무에 대한 타입들 추가

블렌드 타입 =>

픽셀 쉐이더에서 계산한 텍스쳐들과

render target 텍스쳐에 계산되어 있는 값들을 어떻게 섞을 것인지에 대한 옵션들


	switch (info.shaderType)
	{
	...
	case SHADER_TYPE::LIGHTING:
		_pipelineDesc.NumRenderTargets = 2;
		_pipelineDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
		_pipelineDesc.RTVFormats[1] = DXGI_FORMAT_R8G8B8A8_UNORM;
		break;
	}

쉐이더가 lighting 타입일 경우 diffuse와 specular 두 가지를 렌더

	switch (info.depthStencilType)
	{
	...
    
	case DEPTH_STENCIL_TYPE::NO_DEPTH_TEST:
		_pipelineDesc.DepthStencilState.DepthEnable = FALSE;
		_pipelineDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
		break;
	case DEPTH_STENCIL_TYPE::NO_DEPTH_TEST_NO_WRITE:
		_pipelineDesc.DepthStencilState.DepthEnable = FALSE;
		_pipelineDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
		break;
	case DEPTH_STENCIL_TYPE::LESS_NO_WRITE:
		_pipelineDesc.DepthStencilState.DepthEnable = TRUE;
		_pipelineDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
		_pipelineDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
		break;
	}

추가된 depth stencil 타입들을 구현


	switch (info.blendType)
	{
	case BLEND_TYPE::DEFAULT:
		rt.BlendEnable = FALSE;
		rt.LogicOpEnable = FALSE;
		rt.SrcBlend = D3D12_BLEND_ONE;
		rt.DestBlend = D3D12_BLEND_ZERO;
		break;
	case BLEND_TYPE::ALPHA_BLEND:
		rt.BlendEnable = TRUE;
		rt.LogicOpEnable = FALSE;
		rt.SrcBlend = D3D12_BLEND_SRC_ALPHA;
		rt.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
		break;
	case BLEND_TYPE::ONE_TO_ONE_BLEND:
		rt.BlendEnable = TRUE;
		rt.LogicOpEnable = FALSE;
		rt.SrcBlend = D3D12_BLEND_ONE;
		rt.DestBlend = D3D12_BLEND_ONE;
		break;
	}

블렌드 타입들에 대한 구현

기본 값은 lighting 쉐이더가 계산한 텍스쳐가 renter target 텍스쳐를 덮어 쓰도록 되어 있다.

D3D12_RENDER_TARGET_BLEND_DESC structure

LogicOpEnable => and, xor 등의 기본적인 논리 계산을 할 것인지 여부

BlendEnable과 LogicOpEnable은 둘다 켜질 수 없고 둘 중 하나만 가능


render target group 클래스 수정

enum class RENDER_TARGET_GROUP_TYPE : uint8
{
	SWAP_CHAIN, // BACK_BUFFER, FRONT_BUFFER
	G_BUFFER, // POSITION, NORMAL, COLOR
	LIGHTING, // DIFFUSE LIGHT, SPECULAR LIGHT
	END,
};

enum
{
	RENDER_TARGET_G_BUFFER_GROUP_MEMBER_COUNT = 3,
	RENDER_TARGET_LIGHTING_GROUP_MEMBER_COUNT = 2,
	RENDER_TARGET_GROUP_COUNT = static_cast<uint8>(RENDER_TARGET_GROUP_TYPE::END)
};

class RenderTargetGroup
{
	...

	void WaitTargetToResource();
	void WaitResourceToTarget();

	...

private:
	D3D12_RESOURCE_BARRIER			_targetToResource[8];
	D3D12_RESOURCE_BARRIER			_resourceToTarget[8];
};

render target group 타입에 lighting을 추가,

lightinh 쉐이더의 output은 2개로 버퍼의 개수로 2개로 정의

그리고 렌더 시 텍스쳐를 render target로 사용할 때와 resource 사용할 때를 동기화 하기 위해

barrier 추가 및 함수 수정


void Engine::CreateRenderTargetGroups()
{
	...
    
	{
		vector<RenderTarget> rtVec(RENDER_TARGET_LIGHTING_GROUP_MEMBER_COUNT);

		rtVec[0].target = GET_SINGLE(Resources)->CreateTexture(L"DiffuseLightTarget",
			DXGI_FORMAT_R8G8B8A8_UNORM, _window.width, _window.height,
			CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
			D3D12_HEAP_FLAG_NONE, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET);

		rtVec[1].target = GET_SINGLE(Resources)->CreateTexture(L"SpecularLightTarget",
			DXGI_FORMAT_R8G8B8A8_UNORM, _window.width, _window.height,
			CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
			D3D12_HEAP_FLAG_NONE, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET);

		_rtGroups[static_cast<uint8>(RENDER_TARGET_GROUP_TYPE::LIGHTING)] = make_shared<RenderTargetGroup>();
		_rtGroups[static_cast<uint8>(RENDER_TARGET_GROUP_TYPE::LIGHTING)]->Create(RENDER_TARGET_GROUP_TYPE::LIGHTING, rtVec, dsTexture);
	}
}

engine 클래스에서 redner target group을 만들 때 lighting 만드는 부분을 추가


cbuffer MATERIAL_PARAMS : register(b2)
{
    int     g_int_0;
    int     g_int_1;
    int     g_int_2;
    int     g_int_3;
    float   g_float_0;
    float   g_float_1;
    float   g_float_2;
    float   g_float_3;
    int     g_tex_on_0;
    int     g_tex_on_1;
    int     g_tex_on_2;
    int     g_tex_on_3;
    float2  g_vec2_0;
    float2  g_vec2_1;
    float2  g_vec2_2;
    float2  g_vec2_3;
};

쉐이더의 material 파라미터 수정

16 byte packing 맞추기 및 float2 추가


material 클래스 수정

쉐이더 파라미터 수정에 맞추어 struct MaterialParams를 수정

또한 추가된 float2(vec2)를 set하는 함수 추가


scene 클래스 수정

기존 GameObject만을 캐시하던 부분을 light와 camera 또한 캐시하도록 수정

void Scene::Render()
{
	...
    
	GEngine->GetRTGroup(RENDER_TARGET_GROUP_TYPE::G_BUFFER)->OMSetRenderTargets();
	
	shared_ptr<Camera> mainCamera = _cameras[0];
	mainCamera->SortGameObject();
	mainCamera->Render_Deferred();
	GEngine->GetRTGroup(RENDER_TARGET_GROUP_TYPE::G_BUFFER)->WaitTargetToResource();

	RenderLights();
	GEngine->GetRTGroup(RENDER_TARGET_GROUP_TYPE::LIGHTING)->WaitTargetToResource();

	RenderFinal();

	mainCamera->Render_Forward();

	for (auto& camera : _cameras)
	{
		...

		camera->SortGameObject();
		camera->Render_Forward();
	}
}

deferred 쉐이더로 계산해야될 오브젝트들을 렌더

=>

메인 카메라(0번)를 가져와 light 쉐이더로 계산

=>

5개의 텍스쳐들을 가지고 렌더

=>

forward 쉐이더를 사용할 다른 카메라들을 렌더


light 클래스 수정

class Light : public Component
{
public:
	...
    
	void Render();

	...

private:
	...

	int8 _lightIndex = -1;
	shared_ptr<class Mesh> _volumeMesh;
	shared_ptr<class Material> _lightMaterial;
};

light 또한 렌더되어야 하기 때문에 빛의 mesh 및 쉐이더 파라미터용 material을 추가

그리고 render 함수 정의

0개의 댓글