응애맘마조

230822 강의 본문

공부/3D강의

230822 강의

TH.Wert 2023. 8. 22. 18:35

블러에 대해서 강의를 했습니다. 그전에 먼저 페이드 인·아웃에 대해서 강의했습니다.

로딩씬을 공유해서 로딩 이미지와 메인 화면으로 이어지도록 했습니다. 페이드 인·아웃은 과제였습니다.

#pragma once
class LoadingScene : public Scene
{
private:
	Camera*		cam;
	UI*				ui;
	thread*			t1;

public:
	LoadingScene();
	~LoadingScene();
	virtual void Init() override;
	virtual void Release() override;
	virtual void Update() override;
	virtual void LateUpdate() override;
	virtual void Render() override;
	virtual void PreRender() override;
	virtual void ResizeScreen() override;
};
#include "stdafx.h"
#include "LoadingScene.h"
#include "Scene2.h"

string initObject;
int     initCount;

void Func22()
{
    SCENE->AddScene("SC2", new Scene2());
    SCENE->GetScene("SC2")->Init();
}


LoadingScene::LoadingScene()
{
}

LoadingScene::~LoadingScene()
{
}

void LoadingScene::Init()
{
    ui = UI::Create();
    ui->LoadFile("UI.xml");
    
    cam = Camera::Create();
    cam->LoadFile("Cam.xml");
    Camera::main = cam;

    Camera::main->width = App.GetWidth();
    Camera::main->height = App.GetHeight();
    Camera::main->viewport.width = App.GetWidth();
    Camera::main->viewport.height = App.GetHeight();

    //별도 스레드 동작
    t1 = new thread(Func22);
}

void LoadingScene::Release()
{
}

void LoadingScene::Update()
{
    post->RenderDetail();

    ImGui::Begin("Hierarchy");
    ui->RenderHierarchy();
    ImGui::End();

    ui->Find("None")->scale.x = initCount/ 9.0f;

    ui->Update();
    post->Update();
    Camera::main->Update();
    Camera::ControlMainCam();
}

void LoadingScene::LateUpdate()
{
    if (initCount == 9 and 
        SCENE->GetScene("LOADING")->state != SceneState::FADEOUT)
    {
        SCENE->ChangeScene("SC2", 2.0f);
    }

    if (SCENE->GetScene("LOADING")->state == SceneState::FADEOUT)
    {
        post->psp.color.x -= 0.5/2.0f * DELTA;
        post->psp.color.y -= 0.5/2.0f * DELTA;
        post->psp.color.z -= 0.5/2.0f * DELTA;
    }
}

void LoadingScene::Render()
{
    wstring str = Util::ToWString(initObject) + to_wstring(initCount);
    DWRITE->RenderText(str, RECT{0, 0, 800, 800}, 40, L"궁서체", Color(1, 0, 0, 1));

    post->Render();
}

void LoadingScene::PreRender()
{
    LIGHT->Set();
    Camera::main->Set();
    post->SetTarget();
    ui->Render();
}

void LoadingScene::ResizeScreen()
{
    Camera::main->width = App.GetWidth();
    Camera::main->height = App.GetHeight();
    Camera::main->viewport.width = App.GetWidth();
    Camera::main->viewport.height = App.GetHeight();
}

로딩씬의 클래스입니다. 여기서는 별도로 스레드를 하나 만들어서 동작하도록 했습니다. 많이 사용하지는 않는 기능이지만 쓰게 될 일이 있으면 쓰는 것이 좋을 것 같습니다. cpp에서 0.5로 값을 잡은 이유는 조명 효과에서 기본 값을 0으로 만들기 위해서입니다.

BaseColor.rgb += (_Color * 2 - 1);

해당 _Color값 안에 0.5를 넣으면 0이 되기 때문에 그렇습니다.

페이드인과 아웃이 제대로 된 영상

블러에 대해서는 여러 가지가 있습니다.

#include "Common.hlsl"

cbuffer PS_PostEffect : register(b11)
{
	int _Filter;
	float3 _Color;
    
	float2 _Screen;
	float _Radius;
	int count;
    
	int select;
	float width;
	float height;
	float _Padding;
}

static const float2 arr[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)
};

static const float weights[13] =
{
	0.0561f, 0.1353f, 0.2780f, 0.4868f, 0.7261f, 0.9231f,
    1.0f,
    0.9231f, 0.7261f, 0.4868f, 0.2780f, 0.1353f, 0.0561f
};

float4 CrossBlur(float2 uv)
{
	float4 color = 0;
    
	for (int i = 0; i < count; i++)
	{
		float divX = (1 + i) / width;
		float divY = (1 + i) / height;
        
		color += TextureD.Sample(SamplerD, float2(uv.x + divX, uv.y));
		color += TextureD.Sample(SamplerD, float2(uv.x - divX, uv.y));
		color += TextureD.Sample(SamplerD, float2(uv.x, uv.y + divY));
		color += TextureD.Sample(SamplerD, float2(uv.x, uv.y - divY));
	}
	color /= count * 4;
    
	return color;
}

float4 OctaBlur(float2 uv)
{
	float4 color = 0;
    
	for (int i = 0; i < count; i++)
	{
		float divX = (1 + i) / width;
		float divY = (1 + i) / height;
        
		for (int j = 0; j < 8; j++)
		{
			float x = arr[j].x * divX + uv.x;
			float y = arr[j].y * divY + uv.y;
            
			color += TextureD.Sample(SamplerD, float2(x, y));
		}
	}
	color /= count * 8;
    
	return color;
}

float4 GaussianBlur(float2 uv)
{
	float divX = 1.0f / width;
	float divY = 1.0f / height;
    
	float sum = 0;
	float4 color = 0;
    
	for (int i = -6; i <= 6; i++)
	{
		float2 temp = uv + float2(divX * i * count, 0);
		color += weights[6 + i] * TextureD.Sample(SamplerD, temp);
        
		temp = uv + float2(0, divY * i * count);
		color += weights[6 + i] * TextureD.Sample(SamplerD, temp);
        
		sum += weights[6 + i] * 2;
	}
	color /= sum;
    
	return color;
}

float4 Mosaic(float2 uv)
{
	int x = (int) (uv.x * count);
	int y = (int) (uv.y * count);
    
	float2 temp;
	temp.x = (float) x / count;
	temp.y = (float) y / count;
    
	return TextureD.Sample(SamplerD, temp);
}

float4 RadialBlur(float2 uv)
{
	float2 radiusUV = uv - float2(0.5f, 0.5f);
	float r = length(radiusUV);
	radiusUV /= r;
    
	r = saturate(2 * r / width);
    
	float2 delta = -radiusUV * r * r * height / count;
    
	float4 color = 0;
    
	for (int i = 0; i < count; i++)
	{
		color += TextureD.Sample(SamplerD, uv);
		uv += delta;
	}
	color /= count;

	return color;
}

float4 Outline(float2 uv)
{
	float sum = 0;
    
	for (int i = 1; i <= count; i++)
	{
		for (int j = 0; j < 8; j++)
		{
			float2 temp = float2(1.0f / width * i, 1.0f / height * i);
			temp *= arr[j];
            
			float4 albedo = TextureD.Sample(SamplerD, uv + temp);
            
			sum += albedo.x;
		}
	}
	sum /= count * 8;
    
	if (sum > 0.0f && sum < 1.0f)
		return TextureD.Sample(SamplerD, uv) * 0.9f;
    
	return TextureD.Sample(SamplerD, uv);
}

float4 Water(float2 uv)
{
	uv.x = uv.x + (sin(uv.x * count) * 0.03);
	uv.y = uv.y + (sin(uv.y * count) * 0.03);
    
	float4 Color = TextureD.Sample(SamplerD, uv);
    
	return Color;
}

struct VertexInput
{
	float4 Position : POSITION0;
	float2 Uv : UV0;
};
struct PixelInput
{
	float4 Position : SV_POSITION;
	float2 Uv : UV0;
};

PixelInput VS(VertexInput input)
{
	PixelInput output;
    output.Uv = input.Uv;
    //  o           =  i X W
    output.Position = mul(input.Position, World);
    return output;
}

float4 PS(PixelInput input) : SV_TARGET
{
	
	float2 uv = input.Uv;
	float4 BaseColor;
	
	//블러 
	//매핑될 색깔의 좌표를 수정
	
	if (select == 0)
		BaseColor = TextureD.Sample(SamplerD, input.Uv);
	else if (select == 1)
		BaseColor = CrossBlur(input.Uv);
	else if (select == 2)
		BaseColor = OctaBlur(input.Uv);
	else if (select == 3)
		BaseColor = GaussianBlur(input.Uv);
	else if (select == 4)
		BaseColor = Mosaic(input.Uv);
	else if (select == 5)
		BaseColor = RadialBlur(input.Uv);
	else if (select == 6)
		BaseColor = Outline(input.Uv);
	else if (select == 7)
		BaseColor = Water(input.Uv);
    
    
    //샘플링한 rgb를 바꾸는 효과
    
	//모노
	if (_Filter == 1)
	{
		BaseColor.rgb = (BaseColor.r + BaseColor.g + BaseColor.b) / 3.0f;
	}
	//세피아
	else if (_Filter == 2)
	{
		float3 temp = (BaseColor.r + BaseColor.g + BaseColor.b) / 3.0f;
		BaseColor.r = dot(temp.rgb, float3(0.393f, 0.769f, 0.189f));
		BaseColor.g = dot(temp.rgb, float3(0.349f, 0.686f, 0.168f));
		BaseColor.b = dot(temp.rgb, float3(0.272f, 0.534f, 0.131f));
	}
	//색계단
	else if (_Filter == 3)
	{
		BaseColor.r *= count;
		BaseColor.g *= count;
		BaseColor.b *= count;
        
		BaseColor.r = floor(BaseColor.r);
		BaseColor.g = floor(BaseColor.g);
		BaseColor.b = floor(BaseColor.b);
        
		BaseColor.r /= count;
		BaseColor.g /= count;
		BaseColor.b /= count;
	}
	//색반전
	else if (_Filter == 4)
	{
        
		BaseColor.rgb = (1.0f - BaseColor.rgb);
	}
	//조명효과
	BaseColor.rgb += (_Color * 2 - 1);
    
	float dis = length(input.Position.xy - _Screen);
	if (dis > _Radius)
	{
		discard;
	}
    
	return BaseColor;
}

select에 따라 어떤 효과를 나타낼 것인지 결정하고 Filter에 따라 RGB를 바꾸는 효과를 나타내게 했습니다. 너무 많아서 캡처는 힘들 것 같고 주석으로 어떤 효과인지 적었습니다.

 

읽어주셔서 감사합니다.

'공부 > 3D강의' 카테고리의 다른 글

230824 강의  (0) 2023.08.24
230823 강의  (0) 2023.08.23
230818 강의  (0) 2023.08.21
230817 강의  (0) 2023.08.17
230816 강의  (0) 2023.08.16