프로그래밍 공부
작성일
2023. 12. 13. 16:10
작성자
WDmil
728x90

 

다양한 쉐이더의 Bluer효과를 적용할것 이다.

 

Buffer를 통해 필요한 데이터를 전달하며, RenderTarget을 사용해 이미지를 구축하고.

 

해당 이미지를 통해 뷰포트에 대한 이미지를 재처리하여. 다양한 효과를 적용한다.

 

전에 작성하였던 Sepia와 GrayScale을베이스로 나머지를 전개해 나갈것 이다.

 


RenderTargetScene구현

#pragma once

class RenderTargetScene : public Scene
{
public:
	RenderTargetScene();
	~RenderTargetScene();

	// Scene을(를) 통해 상속됨
	void Update() override;
	void PreRender() override;
	void Render() override;
	void PostRender() override;
	void GUIRender() override;
private:
	void CreateObjects();
private:
	Quad* quad;

	Model* model;

	Traveler* traveler;
	Sphere* sphere;

	RenderTarget* renderTarget;
	DepthStencil* depthStencil;

	Quad* targetQuad;
	Quad* targetQuad2;

	FloatValueBuffer* valueBuffer;
};
#include "Framework.h"
#include "RenderTargetScene.h"

RenderTargetScene::RenderTargetScene()
{
	CreateObjects();

	renderTarget = new RenderTarget();
	depthStencil = new DepthStencil(); // 렌더타겟과 뎁스는 같은 크기를 써야한다.

	Texture* target = Texture::Add(L"Target", renderTarget->GetSRV());
	targetQuad = new Quad(Float2(CENTER_X, CENTER_Y));
	targetQuad->GetMaterial()->SetShader(L"PostEffect/PostLight.hlsl");
	targetQuad->GetMaterial()->SetDiffuseMap(target);
	targetQuad->SetTag("def");

	targetQuad->SetLocalPosition({ CENTER_X * 0.5f, CENTER_Y * 0.5f});

	targetQuad2 = new Quad(Float2(CENTER_X, CENTER_Y));
	targetQuad2->GetMaterial()->SetShader(L"PostEffect/Grayscale.hlsl");
	targetQuad2->GetMaterial()->SetDiffuseMap(target);
	targetQuad2->SetTag("def");
	targetQuad2->SetLocalPosition({ CENTER_X*0.5f, CENTER_Y*1.5f});

	valueBuffer = new FloatValueBuffer();
	valueBuffer->GetData()[1] = CENTER_X;
	valueBuffer->GetData()[2] = CENTER_Y;
}

RenderTargetScene::~RenderTargetScene()
{
	delete quad;
	delete model;
	delete traveler;
	delete sphere;
}

void RenderTargetScene::Update()
{
	quad->UpdateWorld();
	model->UpdateWorld();
	traveler->Update();
	sphere->UpdateWorld();
	targetQuad->UpdateWorld();
	targetQuad2->UpdateWorld();
}

void RenderTargetScene::PreRender()
{
	valueBuffer->SetPS(10);
	renderTarget->Set(depthStencil);

	quad->Render();
	model->Render();
	traveler->Render();
	sphere->Render();
}

void RenderTargetScene::Render()
{

}

void RenderTargetScene::PostRender()
{
	targetQuad->Render();
	targetQuad2->Render();
}

void RenderTargetScene::GUIRender()
{
	//quad->		GUIRender();
	//model->		GUIRender();
	//traveler->	GUIRender();
	//sphere->	GUIRender();
	//targetQuad->GUIRender();
	ImGui::DragFloat("Scale", &valueBuffer->GetData()[0]);
	ImGui::DragFloat("Scale1", &valueBuffer->GetData()[1]);
	ImGui::DragFloat("Scale2", &valueBuffer->GetData()[2]);
	targetQuad->GetMaterial()->GUIRender();
}

void RenderTargetScene::CreateObjects()
{
	quad = new Quad();
	quad->Load();

	model = new Model("StanfordBunny");
	model->Load();

	traveler = new Traveler();
	traveler->Load();

	sphere = new Sphere();
	//sphere->GetMaterial()->Load("TextData/Materials/1.mat");
	sphere->Load();
}

우선, RenderTargetScene을 구현해놓을 것 이다. 각 데이터는 위와같다.

 

비교용 데이터인 Quad와 Sphere, Model을 사용해서 쉐이더가 어떤 역할을 하는지, 어떤 작용을 하는지 살펴볼것 이다.

 


Mosaic

 

가장 기본적인 효과로 모자이크 효과이다.

 

주변의 픽셀을 조회해서 모자이크 효과를 넣는 방법이 있으나, 이번에 사용할 방법은 uv좌표를 재정립하는 방법이다.

//Tutorial.hlsl
#include "../VertexHeader.hlsli"
#include "../PixelHeader.hlsli"

struct PixelInput
{
	float4 pos : SV_POSITION;
	float2 uv : UV;
};

PixelInput VS(VertexUV input)
{
	PixelInput output;
	output.pos = mul(input.pos, world);
	output.pos = mul(output.pos, view);
	output.pos = mul(output.pos, projection);
	
	output.uv = input.uv;
	
	return output;
}
cbuffer ValueBuffer : register(b10)
{
	float scale;
}

float4 PS(PixelInput input) : SV_TARGET
{

	float2 uv = floor(input.uv * scale) / scale;
	
	return diffuseMap.Sample(samp, uv) * mDiffuse;
}

uv값을 scale로 백분율하여, 현재 UV값을 전체적으로 통합하는 작업이다.

 


Blur

 

주변 픽셀을 블러처리하여, 뿌옇게 보이게 하는 과정을 의미한다.

 

모자이크와는 다르게, 해당 픽셀과 픽셀 주변만 뿌옇게하는 효과가 있다.

 

//Tutorial.hlsl
#include "../VertexHeader.hlsli"
#include "../PixelHeader.hlsli"

struct PixelInput
{
	float4 pos : SV_POSITION;
	float2 uv : UV;
};

PixelInput VS(VertexUV input)
{
	PixelInput output;
	output.pos = mul(input.pos, world);
	output.pos = mul(output.pos, view);
	output.pos = mul(output.pos, projection);
	
	output.uv = input.uv;
	
	return output;
}
cbuffer ValueBuffer : register(b10)
{
	float scale;
	float2 imageSize;
}

static const float2 edges[8] =
{
	float2(-1, -1), float2(0, -1), float2(1, -1),
	float2(-1, +0),				   float2(1, +0),
	float2(-1, +1), float2(0, +1), float2(1, +1)
};

float4 PS(PixelInput input) : SV_TARGET
{
	float4 result = 0;
	for (int i = 0; i < scale; i++)
	{
		float2 div = (1 + i) / imageSize;
		for (int j = 0; j < 8; j++)
		{
			float2 uv = edges[j] * div + input.uv;
			result += diffuseMap.Sample(samp, uv);

		}

	}
	
	result /= scale * 8;
	
	return result * mDiffuse;
}

단, 주변픽셀을 전부 전방순회하기 때문에, 속도가 느려질 수는 있다. 전체 scale값만큼 순회를 하면서,

 

순회될 때 마다. 주변 픽셀에 더해지고, 더해진만큼 나누어버리면 평균화가 가능하다.

 


RadialBlur

 

일반적인 블러효과와 다르게 중심점을 기준으로 가속하는 듯한 효과를 주는 블러 효과이다.

 

어떠한 상태이상 또는 가속 감속 집중 효과를 나타낼 때 사용한다.

 

#include "../VertexHeader.hlsli"
#include "../PixelHeader.hlsli"

struct PixelInput
{
	float4 pos : SV_POSITION;
	float2 uv : UV;
};

PixelInput VS(VertexUV input)
{
	PixelInput output;
	output.pos = mul(input.pos, world);
	output.pos = mul(output.pos, view);
	output.pos = mul(output.pos, projection);
	
	output.uv = input.uv;
	
	return output;
}

cbuffer ValueBuffer : register(b10)
{
	float3 scale;
}

float4 PS(PixelInput input) : SV_TARGET
{
	float2 radiusUV = input.uv - float2(0.5f, 0.5f);
	float r = length(radiusUV);
	radiusUV /= r;
	
	r = saturate(r / scale.y);
	
	float2 delta = -radiusUV * r * r * scale.z / scale.x;
	
	float4 result = 0;
	float2 uv = input.uv;
	
	for (int i = 0; i < scale.x; i++)
	{
		uv += delta;
		result += diffuseMap.Sample(samp, uv);
	}
	
	result /= scale.x;
	
	return result * mDiffuse;
}

 

묘하게 왜곡이 매우 심하게 들어가는 것 처럼 보인다.

 

주로, 스카이림에서 자주보는 블러효과가 만들어지는것 을 볼 수 있다.


PostLight

 

라이팅 효과를 따로 연산하지 않고, hlsl에서 데이터를 처리하여, 중심광원을 기준으로 어둡게 처리할 수 있다.

 

이렇게 라이팅 효과를 고정하면, 연산량이 줄어드는 효과가있다.

 

//Tutorial.hlsl
#include "../VertexHeader.hlsli"
#include "../PixelHeader.hlsli"

struct PixelInput
{
	float4 pos : SV_POSITION;
	float2 uv : UV;
};

PixelInput VS(VertexUV input)
{
	PixelInput output;
	output.pos = mul(input.pos, world);
	output.pos = mul(output.pos, view);
	output.pos = mul(output.pos, projection);
	
	output.uv = input.uv;
	
	return output;
}
cbuffer ValueBuffer : register(b10)
{
	float range;
	float2 imageSize;
}

float4 PS(PixelInput input) : SV_TARGET
{
	float4 baseColor = diffuseMap.Sample(samp, input.uv);
	
	float2 pixelCoord = input.uv * imageSize;
	
	float dist = distance(pixelCoord, imageSize * 0.5f);
	
	float3 color = baseColor.rgb - dist / range;
	
	return float4(color, baseColor.a) * mDiffuse;
}

 

 

주변거리에 따라 밝힌다고 생각할 수도 있지만, 사실 주변거리에 따라 색을 더해버려서 어둡게 만드는것 에 가깝다.

 


OutLine

 

외곽선 처리효과를 정의한다.

 

주변픽셀을 검사해서 알파값에 대한 값을 참조하고, 알파값이 일정비율을 만족하지 못하면,

8개의 픽셀을 검사했을 때, 알파값이 0보다 크거나, 9보다 작으면, mDiffuse값을 반환.

 

mDiffuse값은 현재 픽셀에 대한 Diffuse컬러를 의미한다.

 

알파값이 0보다 작거나, 9와 같거나 크다면, 그것은 빈공간 이기 때문에 0를 반환한다.

 

//Tutorial.hlsl
#include "../VertexHeader.hlsli"
#include "../PixelHeader.hlsli"

struct PixelInput
{
	float4 pos : SV_POSITION;
	float2 uv : UV;
};

PixelInput VS(VertexUV input)
{
	PixelInput output;
	output.pos = mul(input.pos, world);
	output.pos = mul(output.pos, view);
	output.pos = mul(output.pos, projection);
	
	output.uv = input.uv;
	
	return output;
}
cbuffer ValueBuffer : register(b10)
{
	float range;
	float2 imageSize;
}

float4 PS(PixelInput input) : SV_TARGET
{
	float count = 0;
	
	for (int y = -1; y <= 1; y++)
	{
		for (int x = -1; x <= 1; x++)
		{
			float2 offset = (float2(x, y) / imageSize) * (range + 1);
			float4 result = diffuseMap.Sample(samp, input.uv + offset);
			
			count += result.a;
		}
		
	}
	if (count > 0 && count < 9)
		return mDiffuse;
	
	return float4(0, 0, 0, 0);
}
728x90