โ€ป r-e-g-i-s-t-e-r ๊ธˆ์ง€์–ด์—ฌ์„œ ํ•œ๊ธ€๋กœ ์”€ ์•Œ์ž˜๋”ฑํ•˜๊ฒŒ ๋ฐ”๊ฟ”์„œ ์“ฐ์‚ผ


https://gall.dcinside.com/mgallery/board/view/?id=game_dev&no=128264&search_head=30&page=1

[์–ธ๋ฆฌ์–ผ][์‰์ด๋”] ์ง„์งœ ์‰ฌ์šด ์…€ ์‰์ด๋” 3๋ถ„๋งŒ์— ๋ณด์™„ํ•˜๊ธฐ์ €๋ฒˆ์— ์•ผ๋ฉ”๋กœ ์…€ ์‰์ด๋” ์กฐ๋ฌด์‚ฌ๋ฅผ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ ์‚ฌ์‹ค ๊ฝค ํฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Œ....์–ผํ• ๋ณด๊ธฐ์—” ๋ฌธ์ œ ์—†์–ด ๋ณด์ผ ์ˆ˜๋„ ์žˆ์ง€๋งŒ์ด๋Ÿฐ ๋‚œ๋ฐ˜์‚ฌ ์žฌ์งˆ์˜ ๊ฒฝ์šฐ์—๋Š” ์ œ๋Œ€๋กœ ์‰์ด๋”ฉ ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฑฐ์‹ฌ~(๋Œ€์ค‘ ์ด๋ ‡๊ฒŒ ๋ณด์ด๋„๋ก ์ˆ˜์ •ํ–ˆ๋‹ค๋Š” ๋œปgall.dcinside.com


CelShader.usf์—๋‹ค๊ฐ€ ์ €๋ฒˆ์— ๋งŒ๋“  ์…€ ์‰์ด๋”๋ฅผ ์ž‘์„ฑํ• ๊ฑฐ์ž„

.usf๋Š” ์–ธ๋ฆฌ์–ผ ์ „์šฉ hlsl ์‰์ด๋” ํฌ๋งท์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋จ

#include "/Engine/Public/Platform.ush"
#include "/Engine/Private/Common.ush"
#include "/Engine/Private/ScreenPass.ush"
Texture2D SceneColorTexture;
Texture2D DiffuseColorTexture;
Texture2D LUTTexture;
SamplerState InputSampler;
float EmissiveColorDetectingThreshold;
SCREEN_PASS_TEXTURE_VIEWPORT(ViewParams)
float2 PosToUV(float2 InPos)
{
const float2 ViewportUV = (InPos - ViewParams_ViewportMin.xy) * ViewParams_ViewportSizeInverse.xy;
return ViewportUV * ViewParams_UVViewportSize + ViewParams_UVViewportMin;
}
float3 Desaturate(float3 InColor)
{
return dot(InColor, float3(0.3f, 0.59f, 0.11f));
}
float4 MainPS(float4 InPos : SV_POSITION) : SV_Target0
{
const float2 UV = PosToUV(InPos.xy);
float4 SceneColor = Texture2DSample(SceneColorTexture, InputSampler, UV);
float3 LightColor = saturate(Desaturate(SceneColor.rgb) - EmissiveColorDetectingThreshold) * SceneColor.rgb;
float LightMask = ceil(saturate(Pow2(LightColor.r - LightColor.g) + Pow2(LightColor.r - LightColor.b)));
float4 DiffuseColor = Texture2DSample(DiffuseColorTexture, InputSampler, UV);
float DiffuseMask = ceil(saturate(Desaturate(DiffuseColor.rgb).r));
float3 ModifiedDiffuseColor = normalizeFast(lerp(SceneColor.rgb, DiffuseColor.rgb, DiffuseMask - LightMask) * (1 - SceneColor.a));
float3 OutputColor = ModifiedDiffuseColor * Texture2DSample(LUTTexture, InputSampler, float2(saturate(lengthFast(SceneColor.rgb).r), 0)).rgb;
OutputColor += SceneColor.rgb * SceneColor.a;
return float4(OutputColor, 0);
}
cs

๋Œ€์ถฉ ๋‹ค ์ง ๋“ฏ


์ด์ œ ์ด ์‰์ด๋”์ฝ”๋“œ๋ฅผ c++ ์— ๋ฐ”์ธ๋”ฉ ์‹œ์ผœ์ค„ ๊ฑฐ์ž„

viewimage.php?id=2abcdd23dad63db0&no=24b0d769e1d32ca73cea81fa11d02831e8c8ccee733edc9dd120524d4522b2795badb71b87d0108f24285f63f79063ef3b3ea9460f629b2589c54c7826bdaf3493dbe752

๋ชจ๋“ˆ Public, Private ํด๋”์— ๊ฐ๊ฐ CustomShader.h์™€ CustomShader.cpp๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์‚ผ




//CustomShader.h
#pragma once
#include "Renderer/Private/ScreenPass.h"
#include "SceneViewExtension.h"
//๋””๋ฒ„๊น…์šฉ ๋กœ๊ทธ์นดํ…Œ๊ณ ๋ฆฌ ์„ ์–ธ
DECLARE_LOG_CATEGORY_EXTERN(LogCustomShader, All, All);
/**
* ์‰์ด๋” ์ „์—ญ๋ณ€์ˆ˜๋ฅผ ํ•œ๋ฒˆ์— ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์กฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋งคํฌ๋กœ
* (.usf์—์„œ ์„ ์–ธํ•œ ์ „์—ญ๋ณ€์ˆ˜์™€ ์ด๋ฆ„์ด ์ผ์น˜ํ•ด์•ผํ•จ)
*/
BEGIN_SHADER_PARAMETER_STRUCT(FCelShaderParameters, ) //์ธ์ž1: ๊ตฌ์กฐ์ฒด ์ด๋ฆ„, ์ธ์ž2: API(ํ•„์š” ์‹œ)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SceneColorTexture) //์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ ์ „์—ญ๋ณ€์ˆ˜ ์„ ์–ธ
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, DiffuseColorTexture)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, LUTTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, InputSampler)
SHADER_PARAMETER(float, EmissiveColorDetectingThreshold)
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, ViewParams)
RENDER_TARGET_BINDING_SLOTS() //SV_Target์— ๋ฐ”์ธ๋”ฉํ•  ์Šฌ๋กฏ์ž„
END_SHADER_PARAMETER_STRUCT() //๊ตฌ์กฐ์ฒด ๋
/**
* ๊ธ€๋กœ๋ฒŒ ์‰์ด๋” ํด๋ž˜์Šค
* ์ด ํด๋ž˜์Šค ๋‚ด์—์„œ RHI๋ฅผ ์ด์šฉํ•ด์„œ ์ง์ ‘ ๋ Œ๋”๋ง ํŒŒ์ดํ”„๋ผ์ธ์„ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Œ
*/
class FCelShaderPS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FCelShaderPS);
SHADER_USE_PARAMETER_STRUCT(FCelShaderPS, FGlobalShader);
using FParameters = FCelShaderParameters;
};
/**
* ํฌ์ŠคํŠธํ”„๋กœ์„ธ์Šค ํ™•์žฅ ํด๋ž˜์Šค
* PrePostProcessPass_RenderThread ๋งŒ ์‚ฌ์šฉํ•  ๊ฑฐ์ง€๋งŒ
* ๋‚˜๋จธ์ง€ ํ•จ์ˆ˜๊ฐ€ ์ˆœ์ˆ˜ ๊ฐ€์ƒ ํ•จ์ˆ˜์—ฌ์„œ ์ผ๋‹จ ์ƒ์„ฑ์€ ํ•ด์ค˜์•ผํ•จ
*/
class FCelShaderViewExtension : public FSceneViewExtensionBase
{
public:
FCelShaderViewExtension(const FAuto๋ ˆ์ง€์Šคํ„ฐ& Auto๋ ˆ์ง€์Šคํ„ฐ, UTexture* LUTTexture, float EmissiveThreshold);
virtual void SetupViewFamily(FSceneViewFamily& InViewFamily) override {}
virtual void SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView) override {}
virtual void BeginRenderViewFamily(FSceneViewFamily& InViewFamily) override {}
virtual void PrePostProcessPass_RenderThread(FRDGBuilder& GraphBuilder, const FSceneView& View, const FPostProcessingInputs& Inputs) override;
private:
UTexture* LUTTexture;
float EmissiveThreshold;
public:
FORCEINLINE void SetEmissiveThreshold(const float& Value) { EmissiveThreshold = Value; }
};
cs

.h์—๋Š” ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๋ฉด ๋ผ ๋Œ€๋ถ€๋ถ„ ์„ ์–ธ์ด๋ผ ํฌ๊ฒŒ ํ—ท๊ฐˆ๋ฆด ๊ฑด ์—†์„๊ฑฐ์•ผ

ํŒŒ๋ผ๋ฏธํ„ฐ ์„ ์–ธํ•  ๋•Œ float2๋Š” FVector2f, float4๋Š” FVector4f ์ด๋Ÿฐ ์‹์œผ๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•จ


#include "CustomShader.h"
#include "PixelShaderUtils.h"
#include "PostProcess/PostProcessing.h"
//๋กœ๊ทธ์นดํ…Œ๊ณ ๋ฆฌ ์ •์˜
DEFINE_LOG_CATEGORY(LogCustomShader)
/*
* ๊ธ€๋กœ๋ฒŒ ์‰์ด๋” ํด๋ž˜์Šค ๋‚ด์— ๋งคํฌ๋กœ ์„ ์–ธ์— ๋Œ€ํ•œ ๊ตฌํ˜„ ๋งคํฌ๋กœ
* ๋ชจ๋“ˆ ์„ค์ •์„ ์ „ ๊ธ€๊ณผ ๋™์ผํ•˜๊ฒŒ ์„ค์ • ํ–ˆ๋Œ€๋ฉด
* ๊ฐ€์ƒ ๊ฒฝ๋กœ /CustomShaderModule/Private/๊ฐ€ ๋‚˜ํƒ€๋‚ด๋Š” ์‹ค์ œ๊ฒฝ๋กœ๋Š”
* ../CustomShaderModule/Shaders/Private/์ž„
*
* 3๋ฒˆ์งธ ์ธ์ž๋Š” usf์—์„œ ๋ฐ”์ธ๋”ฉํ•  ํ•จ์ˆ˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜๋ฉด ๋ผ
* 4๋ฒˆ์งธ ์ธ์ž๋Š” ์‰์ด๋”์˜ ํƒ€์ž…์„ ์ด๋„˜์œผ๋กœ ์ง€์ •ํ•ด์ฃผ๋ฉด๋Œ SF_Vertex ์ด๋Ÿฐ ์‹์œผ๋ฃจ
*/
IMPLEMENT_GLOBAL_SHADER(FCelShaderPS, "/CustomShaderModule/Private/CelShader.usf", "MainPS", SF_Pixel);
//๋กœ๊ทธ๋Š” ๊ทธ๋ƒฅ ๋””๋ฒ„๊น…์šฉ์ผ ๋ฟ์ธ ๊ฑฐ์‹ฌ
FCelShaderViewExtension::FCelShaderViewExtension(const FAuto๋ ˆ์ง€์Šคํ„ฐ& Auto๋ ˆ์ง€์Šคํ„ฐ, UTexture* LUTTexture, float EmissiveThreshold)
: FSceneViewExtensionBase(Auto๋ ˆ์ง€์Šคํ„ฐ), LUTTexture(LUTTexture), EmissiveThreshold(EmissiveThreshold)
{
UE_LOG(LogCustomShader, Warning, TEXT("Initialize New CelShaderExtension."))
UE_LOG(LogCustomShader, Warning, TEXT("Texture: %s"), *LUTTexture->GetName())
UE_LOG(LogCustomShader, Warning, TEXT("Threshold: %f"), EmissiveThreshold)
}
/*
* ์ด ํ•จ์ˆ˜๊ฐ€ ์ด ๊ธ€์˜ ํ•ต์‹ฌ ์š”์†Œ์ž„
* ์—ฌ๊ธฐ์—์„œ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ตฌ์กฐ์ฒด ๋ฐ”์ธ๋”ฉ ๋ฐ
* ๋ Œ๋” ํŒจ์Šค์— ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ์ปค์Šคํ…€ ์‰์ด๋”๋ฅผ ์˜ฌ๋ฆด๊ฑฐ์•ผ
*/
void FCelShaderViewExtension::PrePostProcessPass_RenderThread(FRDGBuilder& GraphBuilder, const FSceneView& View, const FPostProcessingInputs& Inputs)
{
//์ด ๋งคํฌ๋กœ๋ฅผ ์„ ์–ธํ•˜๋ฉด ๋ Œ๋”๋…๊ฐ™์€ ๋žœ๋”๋ง ๋””๋ฒ„๊ฑฐ์—์„œ ์บ์น˜ํ•  ์ˆ˜ ์žˆ์Œ
RDG_EVENT_SCOPE(GraphBuilder, "CelShader");
//์—ฌ๊ธฐ์„œ ์‰์ด๋” ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  RDG๋ฅผ ์ด์šฉํ•ด์„œ ํŒŒ๋ผ๋ฏธํ„ฐ ์ธ์Šคํ„ด์Šค๋„ ๋งŒ๋“ค๊ฒƒ์ž„
FGlobalShaderMap* GlobalShaderMap = GetGlobalShaderMap(GMaxRHIFeatureLevel);
TShaderMapRef<FCelShaderPS> CelShaderPS(GlobalShaderMap);
FCelShaderPS::FParameters* CelShaderParameters = GraphBuilder.AllocParameters<FCelShaderPS::FParameters>();
//์—ฌ๊ธฐ์„œ ํฌ์ŠคํŠธํ”„๋กœ์„ธ์‹ฑ์„ ํ•  ์”ฌํ…์Šค์ณ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๊ณ 
checkSlow(View.bIsViewInfo);
const FIntRect Viewport = static_cast<const FViewInfo&>(View).ViewRect;
FScreenPassTexture SceneColor((*Inputs.SceneTextures)->SceneColorTexture, Viewport);
//์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ๋ฐ›์•„์˜จ ํ…์Šค์ณ๋„ RDG์— ๋“ฑ๋กํ•ด์ค˜
FRDGTexture* LUTTextureRDG = ๋ ˆ์ง€์Šคํ„ฐExternalTexture(GraphBuilder, LUTTexture->GetResource()->GetTextureRHI(), TEXT("LUT Texture"));
// ์ด๋ถ€๋ถ„๋„ ๋‚˜๋ฆ„ ์ค‘์š”ํ•œ๋ฐ ๋ทฐํฌํŠธ ํฌ๊ธฐ์— ๋งž๊ฒŒ ์ƒ๋Œ€์ ์ธ UV๊ฐ’์„ ์–ป๊ธฐ ์œ„ํ•ด ์„ธํŒ…ํ•˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์ž„
const FScreenPassTextureViewport SceneColorTextureViewport(SceneColor);
const FScreenPassTextureViewportParameters SceneTextureViewportParams = GetScreenPassTextureViewportParameters(SceneColorTextureViewport);
// ์ด ๋ถ€๋ถ„์— ํŒŒ๋ผ๋ฏธํ„ฐ ๊ตฌ์กฐ์ฒด์—์„œ ์„ ์–ธํ•œ ๋ณ€์ˆ˜์— ๋น ์ง์—†์ด ๊ฐ’์„ ๋„ฃ์–ด์ค˜์•ผํ•จ
CelShaderParameters->SceneColorTexture = (*Inputs.SceneTextures)->SceneColorTexture;
CelShaderParameters->DiffuseColorTexture = (*Inputs.SceneTextures)->GBufferCTexture;
CelShaderParameters->LUTTexture = LUTTextureRDG;
CelShaderParameters->InputSampler = TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
CelShaderParameters->EmissiveColorDetectingThreshold = EmissiveThreshold;
CelShaderParameters->ViewParams = SceneTextureViewportParams;
CelShaderParameters->RenderTargets[0] = FRenderTargetBinding(SceneColor.Texture, ERenderTargetLoadAction::ELoad);
//ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ •์ด ์™„๋ฃŒ๋œ ํ›„ ๋น„๋กœ์†Œ ๋ Œ๋”ํŒจ์Šค์— ์‰์ด๋”๋ฅผ ์˜ฌ๋ฆด ์ˆ˜ ์žˆ์Œ
FPixelShaderUtils::AddFullscreenPass(GraphBuilder, GlobalShaderMap, FRDGEventName(TEXT("Cel Shading")), CelShaderPS, CelShaderParameters, Viewport);
}
cs

์‰์ด๋” ๊ด€๋ จ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ๋งคํฌ๋กœ๋กœ ๊ตฌ์„ฑ๋œ ์ฝ”๋“œ๊ฐ€ ๊ฝค ๋งŽ์•„์„œ ์ฒ˜์Œ์—” ์ข€ ์•„๋ฆฌ๊นŒ๋ฆฌ ํ•  ์ˆ˜๋„ ์žˆ์Œ ใ…‹ใ…‹


์ด์ œ ์ต์Šคํ…์…˜ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ๋ฐ”๋กœ ์‰์ด๋”๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด


//ShaderTestActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ShaderTestActor.generated.h"
class FCelShaderViewExtension;
UCLASS()
class CUSTOMSHADERMODULE_API AShaderTestActor : public AActor
{
GENERATED_BODY()
public:
AShaderTestActor();
UFUNCTION(CallInEditor, Category = "Cel Shader")
void ApplyCelShader();
UFUNCTION(CallInEditor, Category = "Cel Shader")
void CancelCelShader();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Cel Shader")
TObjectPtr<UTexture> LUTTexture;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Cel Shader")
float EmissiveThreshold = 1.2f;
float CachedEmissiveThreshold = -1.0f;
private:
TSharedPtr<FCelShaderViewExtension, ESPMode::ThreadSafe> CelShaderExtension;
};
//ShaderTestActor.cpp
#include "ShaderTestActor.h"
#include "CustomShader.h"
AShaderTestActor::AShaderTestActor()
{
PrimaryActorTick.bCanEverTick = false;
}
void AShaderTestActor::ApplyCelShader()
{
if (!LUTTexture || abs(EmissiveThreshold - CachedEmissiveThreshold) < 0.000001)
{
return;
}
if (CelShaderExtension.IsValid())
{
CelShaderExtension->SetEmissiveThreshold(EmissiveThreshold);
return;
}
CelShaderExtension = FSceneViewExtensions::NewExtension<FCelShaderViewExtension>(LUTTexture, EmissiveThreshold);
}
void AShaderTestActor::CancelCelShader()
{
if (CelShaderExtension.IsValid())
{
CelShaderExtension.Reset();
}
}
cs

๋Œ€์ถฉ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ต์Šคํ…์…˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์•กํ„ฐ๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์—ˆ์–ด

์ด์ œ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด์ž



a16711aa372a6ce87eb1d19528d52703f92ae4246d32e28c

์•กํ„ฐ๋ฅผ ๋ฐฐ์น˜ํ•˜๊ณ  ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ ์ ํ•˜๊ฒŒ ๋„ฃ์–ด์ฃผ๊ณ  Apply Cel Shader ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด


a16711aa372a6de87eb1d19528d52703032a87ffeb7b959a

์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ ๊ฐ™๋„ค ^^


๊ถ๊ธˆํ•œ ๊ฑฐ์žˆ์œผ๋ฉด ๋Œ“ ์ฃผ์‚ผ ํ‚ผํ‚ผ