본문 바로가기

DirectX11 3D/기본 문법

<DirectX11 3D> 106 - Bloom

 

필요한 개념


Bloom : 뽀샤시한 효과(태양이 비치면 빛이 퍼지는 현상)
밝은 면을 추출한 다음 블러를 먹이고 그걸 합산하는 방식을 사용, 글래어라고도 함

RenderTargetView가 5개가 필요(diffuse 때문에)
1단계 : Luminosity(밝은 면을 추출)
2단계 : BlurX후 BlurY
3단계 : 1,2 단계의 결과를 합침

 

Gaussian 함수


GaussianBlur를 먹여서 사용을 할 것이다.(이전에는 고정값으로 사용했지만, 지금은 세팅해주는 함수 만들고 가우시안 함수만든다)
식은 인터넷 가우시안함수 참고하면 된다.

 

가우스 함수 식

 

가우스 함수 : 임의의 실수 x에 대하여 x보다 크지 않은 최대의 정수(버림 함수)

2.25 ~ 4.25 상에서 3.25를 x로 설정한다면

2.25 ~ 3.25 사이의 값인 3이 될 것이다. 3.25 - 0.25를 버려서 3이됨

 

정수로만 짤라져서

 

 

(1 그래프)

이런 그래프가 나온다.

y = 2.5라면 y = 2가 됨..

y = 1.25라면 y = 1이 됨

 

 

 

 

 

 

가우시안 함수는 이전 선형들과 달리 부드럽게 값을 먹일 수 있다.(위에 그림을 보면 알 수 있다.)

Tip)
Pass로 구분하고 하나의 함수로 여러개를 쓸때 사용
float4 PS_Blur(VertexOutput input, uniform int index) : SV_Target

pass P1
{
  // 이런식으로 안에 값을 주면 저 함수의 index 파라미터로 값이 넘어간다.
  SetPixelShader(CompileShader(ps_5_0, PS_Blur(1)));
}

BlurCount가 적어야 더 밝고 강하게 들어가고, 많으면 어두워짐

결과를 보면 선들이 부드러워지고, 뽀샤시해진다. 빛나는 것처럼 보임


ColorGrading : 색상 보정해주는 기술, 색 공간으로 나오게 한다음 rgb로 한다음 최종적인 색 보정을 해주는(찾고 싶으면 찾아보심)

 

 

 

BloomDemo.h


더보기
#pragma once
#include "Systems/IExecute.h"

// Mrt로

class BloomDemo : public IExecute
{
public:
	virtual void Initialize() override;
	virtual void Ready() override {}
	virtual void Destroy() override {}
	virtual void Update() override;
	virtual void PreRender() override;
	virtual void Render() override;
	virtual void PostRender() override;
	virtual void ResizeScreen() override {}

private:
	void Billboards();
	void Mesh();
	void Airplane();
	void Kachujin();
	void KachujinCollider();
	void KachujinWeapon();
	void PointLighting();
	void SpotLighting();

	void Pass(UINT mesh, UINT model, UINT anim);

private:
	void SetBlur();

	void GetBlurParameter(vector<float>& weights, vector<Vector2>& offsets, float x, float y);
	float GetGaussFunction(float val);

private:
	float threshold = 0.05f;

	// 블러를 몇번 할지
	UINT blurCount = 15;

	vector<float> weightX; // 가중치
	vector<Vector2> offsetX; // 얼마만큼 이동할지

	vector<float> weightY;
	vector<Vector2> offsetY;

private:
	Shader* shader;

	// 5개가 필요(diffuse 때문에)
	// 1단계 : Luminosity(밝은 면을 추출)
	// 2단계 : BlurX후 BlurY
	// 3단계 : 1,2 단계의 결과를 합침
	RenderTarget* renderTarget[5];
	DepthStencil* depthStencil;
	Viewport* viewport;
	Render2D* render2D;
	PostEffect* postEffect;


	Billborad* billboard;

	CubeSky* sky;

	Material* floor;
	Material* stone;
	Material* brick;
	Material* wall;

	MeshRender* cube;
	MeshRender* cylinder;
	MeshRender* sphere;
	MeshRender* grid;

	ModelRender* airplane = NULL;


	ModelAnimator* kachujin = NULL;
	Transform* colliderInitTransforms;
	ColliderObject** colliders;

	ModelRender* weapon = NULL;
	Transform* weaponInitTransform;

	vector<MeshRender*> meshes;
	vector<ModelRender*> models;
	vector<ModelAnimator*> animators;
};

 

 

 

 

 

 

 

BloomDemo.cpp


더보기
#include "stdafx.h"
#include "BloomDemo.h"

void BloomDemo::Initialize()
{
	Context::Get()->GetCamera()->RotationDegree(20, 0, 0);
	Context::Get()->GetCamera()->Position(1, 36, -85);

	shader = new Shader(L"96_Billboard.fxo");

	float width = D3D::Width(), height = D3D::Height();
	
	renderTarget[0] = new RenderTarget((UINT)width, (UINT)height); // Diffuse
	renderTarget[1] = new RenderTarget((UINT)width, (UINT)height); // Luminosity(밝기)
	renderTarget[2] = new RenderTarget((UINT)width, (UINT)height); // BlurX
	renderTarget[3] = new RenderTarget((UINT)width, (UINT)height); // BlurY
	renderTarget[4] = new RenderTarget((UINT)width, (UINT)height); // Composite(합침), 1,2 단계 합침
	
	depthStencil = new DepthStencil((UINT)width, (UINT)height);
	viewport = new Viewport(width, height);
	
	render2D = new Render2D();
	render2D->GetTransform()->Scale(355, 200, 1);
	render2D->GetTransform()->Position(200, 120, 0);
	render2D->SRV(renderTarget[0]->SRV());
	
	postEffect = new PostEffect(L"106_Bloom.fxo");

	sky = new CubeSky(L"Environment/GrassCube1024.dds");

	Billboards();

	Mesh();
	Airplane();

	Kachujin();
	KachujinCollider();
	KachujinWeapon();

	PointLighting();
	SpotLighting();
}

void BloomDemo::Update()
{
	ImGui::InputFloat("Threshold", &threshold, 0.01f);
	postEffect->GetShader()->AsScalar("Threshold")->SetFloat(threshold);
	
	ImGui::InputInt("BlurCount", (int*)&blurCount, 2);
	blurCount %= 33;
	if (blurCount < 1)
		blurCount = 1;
	
	postEffect->GetShader()->AsScalar("BlurCount")->SetInt(blurCount);
	sky->Update();

	cube->Update();
	grid->Update();
	cylinder->Update();
	sphere->Update();

	airplane->Update();
	kachujin->Update();

	Matrix worlds[MAX_MODEL_TRANSFORMS];
	for (UINT i = 0; i < kachujin->GetTransformCount(); i++)
	{
		kachujin->GetAttachTransform(i, worlds);

		weapon->GetTransform(i)->World(weaponInitTransform->World() * worlds[40]);
	}

	weapon->UpdateTransforms();
	weapon->Update();

	billboard->Update();

	render2D->Update();
	postEffect->Update();
}

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);

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

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

	// 파라미터를 계산
	SetBlur();

	// Blur를 셰이더로 넘겨줌

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


		// Pass 2번 결과를 renderTarget[2]에 저장
		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());


		// Pass 3번 결과를 renderTarget[3]에 저장
		renderTarget[3]->PreRender(depthStencil);
		viewport->RSSetViewport();

		// x된거 renderTarget[2]를 가져다 씀
		postEffect->SRV(renderTarget[2]->SRV());
		postEffect->Pass(2);
		postEffect->Render();
	}

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

		// Luminosity와 x,y 이 두 개의 결과를 넘겨줌
		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::Billboards()
{
	billboard = new Billborad(shader);
	billboard->Pass(4);
	billboard->AddTexture(L"Terrain/grass_14.tga");
	billboard->AddTexture(L"Terrain/grass_07.tga");
	billboard->AddTexture(L"Terrain/grass_11.tga");
	
	for (UINT i = 0; i < 1200; i++)
	{
		Vector2 scale = Math::RandomVec2(1, 3);
		// 5(밑에 판 크기가 -5 ~ 5 -> 10) * 12(grid 크기) = 60
		Vector2 position = Math::RandomVec2(-60, 60);

		billboard->Add(Vector3(position.x, scale.y * 0.5f, position.y), scale, 0);
	}

	for (UINT i = 0; i < 300; i++)
	{
		Vector2 scale = Math::RandomVec2(1, 3);
		Vector2 position = Math::RandomVec2(-60, 60);

		billboard->Add(Vector3(position.x, scale.y * 0.5f, position.y), scale, 1);
	}

	for (UINT i = 0; i < 700; i++)
	{
		Vector2 scale = Math::RandomVec2(1, 3);
		Vector2 position = Math::RandomVec2(-60, 60);

		billboard->Add(Vector3(position.x, scale.y * 0.5f, position.y), scale, 2);
	}

}

void BloomDemo::Mesh()
{
	//Create Material
	{
		floor = new Material(shader);
		floor->DiffuseMap("Floor.png");
		floor->Specular(1, 1, 1, 20);
		floor->SpecularMap("Floor_Specular.png");
		floor->NormalMap("Floor_Normal.png");

		stone = new Material(shader);
		stone->DiffuseMap("Stones.png");
		stone->Specular(1, 1, 1, 20);
		stone->SpecularMap("Stones_Specular.png");
		stone->Emissive(1.0f, 1.0f, 1.0f, 0.3f);
		stone->NormalMap("Stones_Normal.png");


		brick = new Material(shader);
		brick->DiffuseMap("Bricks.png");
		brick->Specular(1, 0.3f, 0.3f, 20);
		brick->SpecularMap("Bricks_Specular.png");
		brick->Emissive(1.0f, 1.0f, 1.0f, 0.3f);
		brick->NormalMap("Bricks_Normal.png");

		wall = new Material(shader);
		wall->DiffuseMap("Wall.png");
		wall->Specular(1, 1, 1, 20);
		wall->SpecularMap("Wall_Specular.png");
		wall->Emissive(1.0f, 1.0f, 1.0f, 0.3f);
		wall->NormalMap("Wall_Normal.png");
	}

	//Create Mesh
	{
		Transform* transform = NULL;

		cube = new MeshRender(shader, new MeshCube());
		transform = cube->AddTransform();
		transform->Position(0, 5, 0);
		transform->Scale(20, 10, 20);

		grid = new MeshRender(shader, new MeshGrid(5, 5));
		transform = grid->AddTransform();
		transform->Position(0, 0, 0);
		transform->Scale(12, 1, 12);

		cylinder = new MeshRender(shader, new MeshCylinder(0.5f, 3.0f, 20, 20));
		sphere = new MeshRender(shader, new MeshSphere(0.5f, 20, 20));
		for (UINT i = 0; i < 5; i++)
		{
			transform = cylinder->AddTransform();
			transform->Position(-30, 6, -15.0f + (float)i * 15.0f);
			transform->Scale(5, 5, 5);

			transform = cylinder->AddTransform();
			transform->Position(30, 6, -15.0f + (float)i * 15.0f);
			transform->Scale(5, 5, 5);


			transform = sphere->AddTransform();
			transform->Position(-30, 15.5f, -15.0f + (float)i * 15.0f);
			transform->Scale(5, 5, 5);

			transform = sphere->AddTransform();
			transform->Position(30, 15.5f, -15.0f + (float)i * 15.0f);
			transform->Scale(5, 5, 5);
		}
	}

	sphere->UpdateTransforms();
	cylinder->UpdateTransforms();
	cube->UpdateTransforms();
	grid->UpdateTransforms();

	meshes.push_back(sphere);
	meshes.push_back(cylinder);
	meshes.push_back(cube);
	meshes.push_back(grid);
}

void BloomDemo::Airplane()
{
	airplane = new ModelRender(shader);
	airplane->ReadMesh(L"B787/Airplane");
	airplane->ReadMaterial(L"B787/Airplane");

	Transform* transform = airplane->AddTransform();
	transform->Position(2.0f, 9.91f, 2.0f);
	transform->Scale(0.004f, 0.004f, 0.004f);
	airplane->UpdateTransforms();

	models.push_back(airplane);
}

void BloomDemo::Kachujin()
{
	kachujin = new ModelAnimator(shader);
	kachujin->ReadMesh(L"Kachujin/Mesh");
	kachujin->ReadMaterial(L"Kachujin/Mesh");
	kachujin->ReadClip(L"Kachujin/Sword And Shield Idle");
	kachujin->ReadClip(L"Kachujin/Sword And Shield Walk");
	kachujin->ReadClip(L"Kachujin/Sword And Shield Run");
	kachujin->ReadClip(L"Kachujin/Sword And Shield Slash");
	kachujin->ReadClip(L"Kachujin/Salsa Dancing");


	Transform* transform = NULL;

	transform = kachujin->AddTransform();
	transform->Position(0, 0, -30);
	transform->Scale(0.075f, 0.075f, 0.075f);
	kachujin->PlayTweenMode(0, 0, 1.0f);

	transform = kachujin->AddTransform();
	transform->Position(-15, 0, -30);
	transform->Scale(0.075f, 0.075f, 0.075f);
	kachujin->PlayTweenMode(1, 1, 1.0f);

	transform = kachujin->AddTransform();
	transform->Position(-30, 0, -30);
	transform->Scale(0.075f, 0.075f, 0.075f);
	kachujin->PlayTweenMode(2, 2, 0.75f);

	transform = kachujin->AddTransform();
	transform->Position(15, 0, -30);
	transform->Scale(0.075f, 0.075f, 0.075f);
	kachujin->PlayBlendMode(3, 0, 1, 2);
	kachujin->SetBlendAlpha(3, 1.5f);

	transform = kachujin->AddTransform();
	transform->Position(30, 0, -32.5f);
	transform->Scale(0.075f, 0.075f, 0.075f);
	kachujin->PlayTweenMode(4, 4, 0.75f);

	kachujin->UpdateTransforms();

	animators.push_back(kachujin);
}

void BloomDemo::KachujinCollider()
{
	UINT count = kachujin->GetTransformCount();
	colliders = new  ColliderObject * [count];

	colliderInitTransforms = new Transform();
	colliderInitTransforms->Position(-2.9f, 1.45f, -50.0f);
	colliderInitTransforms->Scale(5, 5, 75);

	for (UINT i = 0; i < count; i++)
	{
		colliders[i] = new ColliderObject();

		//colliders[i]->Init = new Transform();
		//colliders[i]->Init->Position(0, 0, 0);
		//colliders[i]->Init->Scale(10, 30, 10);

		colliders[i]->Transform = new Transform();
		//colliders[i]->Collider = new Collider(colliders[i]->Transform, colliders[i]->Init);
		colliders[i]->Collider = new Collider(colliders[i]->Transform, colliderInitTransforms);
	}
}

void BloomDemo::KachujinWeapon()
{
	weapon = new ModelRender(shader);
	weapon->ReadMesh(L"Weapon/Sword");
	weapon->ReadMaterial(L"Weapon/Sword");

	UINT count = kachujin->GetTransformCount();
	for (UINT i = 0; i < count; i++)
		weapon->AddTransform();

	weapon->UpdateTransforms();
	models.push_back(weapon);


	weaponInitTransform = new Transform();
	weaponInitTransform->Position(-2.9f, 1.45f, -6.45f);
	weaponInitTransform->Scale(0.5f, 0.5f, 0.75f);
	weaponInitTransform->Rotation(0, 0, 1);
}

void BloomDemo::PointLighting()
{
	PointLight light;
	light =
	{
		Color(0.0f, 0.0f, 0.0f, 1.0f), //Ambient
		Color(0.0f, 0.0f, 1.0f, 1.0f), //Diffuse
		Color(0.0f, 0.0f, 0.7f, 1.0f), //Specular
		Color(0.0f, 0.0f, 0.7f, 1.0f), //Emissive
		Vector3(-30, 10, -30), 5.0f, 0.9f // 위치, 범위, 강도
	};
	Lighting::Get()->AddPointLight(light);

	light =
	{
		Color(0.0f, 0.0f, 0.0f, 1.0f),
		Color(1.0f, 0.0f, 0.0f, 1.0f),
		Color(0.6f, 0.2f, 0.0f, 1.0f),
		Color(0.6f, 0.3f, 0.0f, 1.0f),
		Vector3(15, 10, -30), 10.0f, 0.3f
	};
	Lighting::Get()->AddPointLight(light);

	light =
	{
		Color(0.0f, 0.0f, 0.0f, 1.0f), //Ambient
		Color(0.0f, 1.0f, 0.0f, 1.0f), //Diffuse
		Color(0.0f, 0.7f, 0.0f, 1.0f), //Specular
		Color(0.0f, 0.7f, 0.0f, 1.0f), //Emissive
		Vector3(-5, 1, -17.5f), 5.0f, 0.9f
	};
	Lighting::Get()->AddPointLight(light);

	light =
	{
		Color(0.0f, 0.0f, 0.0f, 1.0f),
		Color(0.0f, 0.0f, 1.0f, 1.0f),
		Color(0.0f, 0.0f, 0.7f, 1.0f),
		Color(0.0f, 0.0f, 0.7f, 1.0f),
		Vector3(-10, 1, -17.5f), 5.0f, 0.9f
	};
	Lighting::Get()->AddPointLight(light);
}

void BloomDemo::SpotLighting()
{
	SpotLight light;
	light =
	{
		Color(0.3f, 1.0f, 0.0f, 1.0f),
		Color(0.7f, 1.0f, 0.0f, 1.0f),
		Color(0.3f, 1.0f, 0.0f, 1.0f),
		Color(0.3f, 1.0f, 0.0f, 1.0f),
		Vector3(-15, 20, -30), 25.0f,
		Vector3(0, -1, 0), 30.0f, 0.4f
	};
	Lighting::Get()->AddSpotLight(light);

	light =
	{
		Color(1.0f, 0.2f, 0.9f, 1.0f),
		Color(1.0f, 0.2f, 0.9f, 1.0f),
		Color(1.0f, 0.2f, 0.9f, 1.0f),
		Color(1.0f, 0.2f, 0.9f, 1.0f),
		Vector3(0, 20, -30), 30.0f,
		Vector3(0, -1, 0), 40.0f, 0.55f
	};
	Lighting::Get()->AddSpotLight(light);
}

void BloomDemo::Pass(UINT mesh, UINT model, UINT anim)
{
	for (MeshRender* temp : meshes)
		temp->Pass(mesh);

	for (ModelRender* temp : models)
		temp->Pass(model);

	for (ModelAnimator* temp : animators)
		temp->Pass(anim);
}

void BloomDemo::SetBlur()
{
	// x방향, y방향을 각각 콜
	float x = 1.0f / D3D::Width();
	float y = 1.0f / D3D::Height();

	// 각각 Blur함수를 빼오는 부분
	GetBlurParameter(weightX, offsetX, x, 0); // x축만 계산됨
	GetBlurParameter(weightY, offsetY, 0, y); // y축만 계산됨
}

// 가중치를 계산해 준다.
void BloomDemo::GetBlurParameter(vector<float>& weights, vector<Vector2>& offsets, float x, float y)
{
	// x,y에 대해 weight, offset을 만들어준다.
	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)
{
	// 가우시안 함수 간단히 해놓은 식(상수 1.0으로 고정)이다.(인터넷 찾아서 수식 비교해서 보면 됨)
	return (float)((1.0 / sqrt(2 * Math::PI * blurCount)) * exp(-(val * val) / (2 * blurCount * blurCount)));
}

 

 

 

 

 

 

 

 

 

106_Bloom.fx


더보기
#include "00_Global.fx"
#include "00_Light.fx"


float2 PixelSize;

struct VertexOutput
{
    float4 Positon : SV_Position;
    float2 Uv : Uv;
};

VertexOutput VS(float4 Position : Position)
{
    VertexOutput output;
    
    output.Positon = 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 input) : SV_Target
{
    return DiffuseMap.Sample(LinearSampler, input.Uv);
}

float Threshold = 0.6f;
// 밝은 면을 추출한다.
float4 PS_Luminosity(VertexOutput input) : SV_Target
{
    // color에서 밝다는 것은 일정값 이상이라는 뜻
    // 일정 값을 비율로 만든 후 saturate를 통해 일정 값 이상을 남긴다.
    float4 color = DiffuseMap.Sample(LinearSampler, input.Uv);
    
    // 비율로 한다음 0 ~ 1까지로 제한함
    // 즉, threshold보다 color가 작다면 어두운 값이 됨
    // Threshold보다 큰 색상만이 남는다.
    // 이렇게 해서 밝은 면 추출
    // Threshold 값 이상으로 추출되는 것이다.
    // 가장 밝은 값은 조명들이 된다.(색상을 서로 더해서 겹쳐지니까)
    return saturate((color - Threshold) / (1 - Threshold));
}


#define MAX_SAMPLE_COUNT 33 // 얼마만큼 최대로 샘플링을 할 수 있느냐
int SampleCount = 15; // 샘플 카운트 15번

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

// offset, weight에 따라 x,y값이 바뀌는 거니까, 그냥 이걸로 x,y 각각 구해줘도 됨
// 값에 따라 방향이 바뀌기 때문에
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);
    
    // 요것은 blur를 좀 더 낮추고 luminosity를 강조한 식이다.
    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)
}

 

 

 

 

 

 

 

 

 

 

 

결과