【Unity】和紙表現【URP】

はじめに

今回は前回の波の演出を流用し、和紙の表現をポストエフェクトで作ってみました。

環境

Unity 2022.3.4f1
URP14.0.8

ポストエフェクトの掛け方

URPにはURP12からSwapBufferというポストエフェクトをかける時に機能があります。
今回はこちらを使用します。

以下は汎用的に使えるSwapBufferのサンプルです。

public class SamplePostEffectRendererFeature : ScriptableRendererFeature
{
    [SerializeField] private Material _material;

    private SamplePostEffectRenderPass _samplePostEffectRenderPass;

    public override void Create()
    {
        _samplePostEffectRenderPass = new SamplePostEffectRenderPass(_material);
    }

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        renderer.EnqueuePass(_samplePostEffectRenderPass);
    }
}

public class SamplePostEffectRenderPass : ScriptableRenderPass
{
    private readonly string _profileName = "SamplePostEffectRenderPass";
    
    private readonly Material _material;

    public SamplePostEffectRenderPass(Material material)
    {
        _material = material;
        renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
    }

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        if (renderingData.cameraData.isSceneViewCamera)
        {
            return;
        }

        var cmd = CommandBufferPool.Get(_profileName);

        using (new ProfilingScope(cmd, new ProfilingSampler(_profileName)))
        {
            Blit(cmd, ref renderingData, _material);
        }

        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
    }
}
Blit(cmd, ref renderingData, _material);

ここでポストエフェクトを適応してます。
これをRendererDataにセットし適応したいポストエフェクトのマテリアルをセットすれば反映されます。

Shader側でカメラのレンダーテクスチャが取りたい場合は

half4 color = SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearRepeat, i.texcoord);

のように_BlitTextureに書き込まれてます。

和紙のデコボコ感

和紙は洋紙と違い表面にデコボコがあります。
この表現は前回の記事の水面の光反射表現を用いたら簡単に表現できます。
水面の荒れてる表現を和紙のデコボコに使うと言うことですね。
上記の記事のように法線を作成後

half4 color = SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearRepeat, i.texcoord);

float3 toLightDirW = normalize(float3(0.0f, 1.0f, 1.0f));
float diffusePower = dot(normal, toLightDirW) * 2.0f;
color.rgb *= diffusePower;
return color;

のようにディフューズ計算をカメラテクスチャを用いてかけるだけで以下のようになります。

ディフューズをかけた後

デコボコ感が出ましたね。

仕上げ

まずは色をつけます

washiColor.rgb = lerp(washiColor.rgb, _Color.rgb, _ColorRate);

こんな感じになります

色付け

今回は紙が燃えてここエフェクトを消す形にしたいのでディゾルブを追加します。

half dissolveValue = SAMPLE_TEXTURE2D(_DissolveTex, sampler_DissolveTex, i.texcoord).r;
half dissolve = step(dissolveValue, _DissolveRate);
half dissolveOutline2 = step(dissolveValue - _Dissolve2OutlineOffset - 0.05f, _DissolveRate);
half synthesisColorDissolve = smoothstep(_DissolveRate, dissolveValue - _DissolveOutlineOffset,dissolveValue - _Dissolve2OutlineOffset);
half4 outputColor = lerp(washiColor * _DissolveOutlineColor, _Dissolve2OutlineColor, synthesisColorDissolve);
outputColor = lerp(baseColor, outputColor, dissolveOutline2);
outputColor = lerp(outputColor, washiColor, dissolve);

こんな感じになります

ディゾル

燃える際は炭になる黒い箇所と燃えてる箇所の二箇所が出るようにディゾルブのオフセットを二箇所かけてアウトラインを出してます。

また手前に表示したいものと奥に表示したいものの二つが分かれると思います。
その際は一時的にレンダーテクスチャにキャプチャしてポストエフェクト時に合成します。

CommandBuffer cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, new ProfilingSampler("GrabPass")))
{
     var sortFlags = renderingData.cameraData.defaultOpaqueSortFlags;
     var drawSettings = CreateDrawingSettings(m_ShaderTagId, ref renderingData, sortFlags);
     drawSettings.perObjectData = PerObjectData.None;

     context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref m_FilteringSettings);
}

上記のように特定のShaderTagだけ描画するコードをRenderPassに書き、ここで書き込んだRenderTextureを用いて描画します。

するとこのようにレイヤー分けができるようになります。

レイヤー分け

ディゾルブで消えてる白いキューブと消えない灰色のキューブが確認できると思います。

最後に

ここまでみていただきありがとうございました。
燃える表現はもっとブラッシュアップしたかったのですが、やはり完璧よりまず終わらせろと言うのが最も大事だと思います。
次からは記事に中身を減らしてでも記事を書く回数を増やしていこうと思います。