• Home
  • About
    • 게임 개발자 유정룡 photo

      게임 개발자 유정룡

      포트폴리오

    • Learn More
    • Email
    • Github
    • Bitbucket
  • Projects
    • All Projects
    • All Tags

Direct3D11 공부 42일차(Bloom)

04 Aug 2021

Reading time ~2 minutes

Bloom

뭔가 자고 일어난 느낌으로 뽀샤시해 보이는 느낌을 만들어보자

이 전에 만들었던 GaussianBlur를 사용한다.

Shader

106_bloom.fx
#include "00_Global.fx"
#include "00_Light.fx"

float2 PixelSize;

struct VertexOutput
{
    float4 Position : SV_Position;
    float2 Uv : UV;
};

VertexOutput VS(float4 Position : Position)
{
    VertexOutput output;
    
    output.Position = Position;
    output.Uv.x = Position.x * 0.5f + 0.5f;
    output.Uv.y = -Position.y * 0.5f + 0.5f;
    
    return output;
}

float4 PS_Diffuse(VertexOutput intput) : SV_Target
{
    return DiffuseMap.Sample(LinearSampler, intput.Uv);
}

float Threshold = 0.6f;
float4 PS_Luminosity(VertexOutput input) : SV_Target
{
    float4 color = DiffuseMap.Sample(LinearSampler, input.Uv);
    
    return saturate((color - Threshold) / (1 - Threshold));
}

#define MAX_SAMPLE_COUNT 33
int SampleCount = 15;

float2 Offsets[MAX_SAMPLE_COUNT];
float Weights[MAX_SAMPLE_COUNT];

float4 PS_Blur(VertexOutput input) : SV_Target
{
    float4 color = 0;
    
    for (int i = 0; i < SampleCount; i++)
        color += DiffuseMap.Sample(LinearSampler, input.Uv + Offsets[i]) * Weights[i];

    return color;
}

Texture2D LuminosityMap;
Texture2D BlurMap;
float4 PS_Composite(VertexOutput input) : SV_Target
{
    float4 luminosity = LuminosityMap.Sample(LinearSampler, input.Uv);
    float4 blur = BlurMap.Sample(LinearSampler, input.Uv);
    
    luminosity *= (1.0f - saturate(blur));
    
    return float4((luminosity + blur).rgb, 1.0f);
}

technique11 T0
{
    P_VP(P0, VS, PS_Diffuse)
    P_VP(P1, VS, PS_Luminosity)
    P_VP(P2, VS, PS_Blur)
    P_VP(P3, VS, PS_Composite)
}

우선 PS_Composite에서 밝은 색상을 좀 더 올려주고 어두운 색은 더 어둡게 표현해준다.

그런 뒤, 받아온 Weight와 Offset을 활용해서 PS_Blur에서 블러를 적용시켜 주고,

PS_Composite을 활용해서 두 값을 합쳐준다.

BloomDemo Class

BloomDemo.cpp

void BloomDemo::PreRender()
{
	viewport->RSSetViewport();

	// Render
	{
		renderTarget[0]->PreRender(depthStencil);

		sky->Render();

		Pass(0, 1, 2);

		wall->Render();
		sphere->Render();

		brick->Render();
		cylinder->Render();

		stone->Render();
		cube->Render();

		floor->Render();
		grid->Render();

		airplane->Render();

		kachujin->Render();
		weapon->Render();

		billboard->Render();
	}


	Vector2 PixelSize = Vector2(1.0f / D3D::Width(), 1.0f / D3D::Height());
	postEffect->GetShader()->AsVector("PixelSize")->SetFloatVector(PixelSize);

	// Luminocity
	{
		renderTarget[1]->PreRender(depthStencil);

		postEffect->Pass(1);
		postEffect->SRV(renderTarget[0]->SRV());
		postEffect->Render();
	}


	SetBlur();

	// BlurX
	{
		postEffect->GetShader()->AsScalar("Weights")->SetFloatArray(&weightX[0], 0, weightX.size());
		postEffect->GetShader()->AsVector("Offsets")->SetRawValue(&offsetX[0], 0, sizeof(Vector2) * offsetX.size());


		renderTarget[2]->PreRender(depthStencil);
		viewport->RSSetViewport();

		postEffect->SRV(renderTarget[1]->SRV());
		postEffect->Pass(2);
		postEffect->Render();
	}

	// BlurY
	{
		postEffect->GetShader()->AsScalar("Weights")->SetFloatArray(&weightY[0], 0, weightY.size());
		postEffect->GetShader()->AsVector("Offsets")->SetRawValue(&offsetY[0], 0, sizeof(Vector2) * offsetY.size());


		renderTarget[3]->PreRender(depthStencil);
		viewport->RSSetViewport();

		postEffect->SRV(renderTarget[2]->SRV());
		postEffect->Pass(2);
		postEffect->Render();
	}

	// Composite
	{
		renderTarget[4]->PreRender(depthStencil);
		viewport->RSSetViewport();

		postEffect->GetShader()->AsSRV("LuminosityMap")->SetResource(renderTarget[1]->SRV());
		postEffect->GetShader()->AsSRV("BlurMap")->SetResource(renderTarget[3]->SRV());
		postEffect->Pass(3);
		postEffect->Render();
	}
}

void BloomDemo::Render()
{

}

void BloomDemo::PostRender()
{
	postEffect->Pass(0);

	postEffect->SRV(renderTarget[4]->SRV());
	postEffect->Render();
	render2D->Render();
}

void BloomDemo::SetBlur()
{
	float x = 1.0f / D3D::Width();
	float y = 1.0f / D3D::Height();

	GetBlurParameter(weightX, offsetX, x, 0);
	GetBlurParameter(weightY, offsetY, 0, y);
}

void BloomDemo::GetBlurParameter(vector<float>& weights, vector<Vector2>& offsets, float x, float y)
{
	weights.clear();
	weights.assign(blurCount, float());

	offsets.clear();
	offsets.assign(blurCount, Vector2());

	weights[0] = GetGaussFunction(0); //1
	offsets[0] = Vector2(0, 0);


	float sum = weights[0];
	for (UINT i = 0; i < blurCount / 2; i++)
	{
		float temp = GetGaussFunction((float)(i + 1));

		weights[i * 2 + 1] = temp;
		weights[i * 2 + 2] = temp;
		sum += temp * 2;

		Vector2 temp2 = Vector2(x, y) * (i * 2 + 1.5f);
		offsets[i * 2 + 1] = temp2;
		offsets[i * 2 + 2] = -temp2;
	}

	for (UINT i = 0; i < blurCount; i++)
		weights[i] /= sum;
}

// 가우스 함수
float BloomDemo::GetGaussFunction(float val)
{
	return (float)((1.0 / sqrt(2 * Math::PI * blurCount)) * exp(-(val * val) / (2 * blurCount * blurCount)));
}

BlurCount를 정해준뒤 이 BlurCount로 offset과 weight를 계산 해준뒤, Shader에 값을 넘겨준다.

그런 뒤 밝기와 Blur를 받아와 넘겨준뒤 값을 섞어준다.

위에서 말한 효과가 나온다.



DirectX Share Tweet +1