DirectX 자체엔진 개발

[DirectX 11] Bloom

종제로 2022. 3. 11. 16:58

Bloom

 

개발 일자 : 2022년 3월 7일 ~ 10일

 

지난 번에 창문으로 햇빛이 들어오는 효과를 위해서 Emissive를 개발했고 아트에게 Emissive Map도 요청해서 받았으나, 적용해보니 생각보다 느낌이 살지 않아 Bloom을 개발하게 되었습니다.

결과는 만족스럽게 나왔고 어떤식으로 개발했는지 살펴보겠습니다.

Emissive VS Bloom

 


 

제가 참고한 Bloom 예시는 Halo3의 자료입니다.

이 자료에서 Bloom의 단계는 크게 9단계로 나뉩니다.

왼쪽에 Halo3 예시와 함께 제 엔진에서 적용된 화면을 같이 보겠습니다.

1. Original (원본)

 

2. Down Sample (4x4) + Bloom Curve 적용

먼저, 원본 렌더타겟에 4x4 다운샘플링을 합니다.

그 후 Bloom Curve를 적용시켜 일정 밝기 이상을 추출해줍니다.

코드는 책과 Halo3 자료를 참고했습니다.

float4 PS(VertexOut pin) : SV_Target
{
	float3 color = gTexture.Sample(samLinear, pin.Tex).xyz;

	float intensity = dot(color, float3(0.3f, 0.3f, 0.3f));
	float bloomIntensity = GetBloomCurve(intensity);
	float3 bloomColor = color * bloomIntensity / intensity;

	return float4(bloomColor.xyz, 1.0);
}
float GetBloomCurve(float x)
{
    float result = x;
    x *= 2.0f;

#ifdef BLOOMCURVE_METHOD_1
    result = x * 0.05 + max(0, x - gThreshold) * 0.5; // default gThreshold = 1.26
#endif

#ifdef BLOOMCURVE_METHOD_2
    result = x * x / 3.2;
#endif

#ifdef BLOOMCURVE_METHOD_3
    result = max(0, x - gThreshold); // default gThreshold = 1.0
    result *= result;
#endif 

    return result * 0.5f;
}

 

3. Down Sample Again (6x6)

 

4. Down Sample Again (6x6)

예시에서는 샘플러 스테이트의 필터를 POINT로 설정해 네모네모한 모습이고, 저는 LINEAR로 설정해 픽셀이 주변 픽셀들의 평균으로 계산되어 더 부드럽다는 차이가 있습니다.

 

5. 가우시안 블러

 

6. Up Sample (6x6)

 

7. (5)와 (6)을 더해 픽셀을 누적 + 가우시안 블러

 

8. Up Sample (6x6) + 픽셀 누적 + 가우시안 블러

 

9. Up Sample (4x4) 후 최종적으로 원본과 합성

 

Bloom에 관여하는 클래스는 2개입니다.

먼저, Scaler 클래스는 렌더 타겟을 Down,Up Sampling하는데 사용됩니다.

Scaler 클래스

- 스케일 함수, output으로 나갈 렌더 타겟 사이즈에 맞춰 뷰포트 크기를 자동으로 조정합니다.

void Scaler::Scale(RenderTarget* output, RenderTarget* input)
{
	// 뷰포트 크기 설정
	m_Viewport->Width = (float)output->GetWidth();
	m_Viewport->Height = (float)output->GetHeight();

	ID3D11DeviceContext* _dc = m_DX11Core->GetDC();

	_dc->ClearRenderTargetView(output->GetRTV(), reinterpret_cast<const float*>(&EColors::Black));

	ID3D11RenderTargetView* rt[] = { output->GetRTV() };
	_dc->OMSetRenderTargets(1, &rt[0], 0);

	// 뷰포트 세팅
	_dc->RSSetViewports(1, m_Viewport.get());

	Effects::DebugTexFX->SetWorldViewProj(EMath::Matrix::Identity);
	Effects::DebugTexFX->SetTexture(input->GetSRV());

	ID3DX11EffectTechnique* tech = Effects::DebugTexFX->ViewArgbTech;
	RenderTargetDrawer::DrawRenderTarget(_dc, tech);

	ID3D11ShaderResourceView* nullSRV[1] = { 0 };
	_dc->PSSetShaderResources(0, 1, nullSRV);
}

 

또, 기존의 BlurManager 클래스에 Bloom 함수를 추가하였습니다. 다음은 위에서 보여드린 과정을 코드로 나타낸 것입니다.

void BlurManager::Bloom(Scaler* scaler, RenderTarget* output, RenderTarget* input)
{
	// 먼저, 원본을 저장 (여기다 계속 픽셀을 누적시킬 것임)
	CopyOriginalRenderTarget(m_BloomOriginal.get(), input);
	CopyOriginalRenderTarget(m_BloomAccumulate_3.get(), input);

	// 4x4 DownSample + Bloom Curve 적용으로 밝은 부분 추출
	scaler->Scale(m_BloomDownScale4x4_0.get(), input);
	BloomCurve(m_BloomCurve_1.get(), m_BloomDownScale4x4_0.get());

	CopyOriginalRenderTarget(m_BloomAccumulate_2.get(), m_BloomCurve_1.get());

	// 6x6 DownSample
	scaler->Scale(m_BloomDownScale6x6_2.get(), m_BloomCurve_1.get());

	CopyOriginalRenderTarget(m_BloomAccumulate_0.get(), m_BloomDownScale6x6_2.get());

	// 6x6 DownSample
	scaler->Scale(m_BloomDownScale6x6_3.get(), m_BloomDownScale6x6_2.get());

	// Blur Again
	Blur(m_BloomDownScale6x6_3.get());

	/// Up Sampling
	// 6x6 UpSample + Accumulate(축적)
	scaler->Scale(m_BloomUpScale6x6_4.get(), m_BloomDownScale6x6_3.get());
	Accumulate(m_BloomAccumulate_1.get(), m_BloomAccumulate_0.get(), m_BloomUpScale6x6_4.get());

	// Blur
	Blur(m_BloomAccumulate_1.get());

	// 6x6 UpSample + Accumulate(축적) + Blur
	scaler->Scale(m_BloomUpScale6x6_5.get(), m_BloomAccumulate_1.get());

	Accumulate(m_BloomAccumulate_3.get(), m_BloomAccumulate_2.get(), m_BloomUpScale6x6_5.get());

	Blur(m_BloomAccumulate_3.get());

	// 4x4 UpSample + Accumulate(축적)
	scaler->Scale(m_BloomUpScale4x4_6.get(), m_BloomAccumulate_3.get());

	Accumulate_Per(output, m_BloomOriginal.get(), m_BloomUpScale4x4_6.get());
}

 

참고

  • HDR The Bungie Way 자료