初投稿の記事になります。
至らぬところ多々あると思いますが、優しい目で見ていただけると嬉しいです
映写機ってなんかおしゃれだよねー
皆さんも思いませんか?映写機ってなんかエモいというか演出として良いものだと私は思います。
え?「映写機ってなんぞや?」
あらまぁ、ご存じない?
多分名称を知らないだけでは?おそらく皆さん見たことあるでしょう。
映写機といえばこんな感じ、これを参考に作っていきます
見たことあるでしょう?リンク先の映像にはないですけど、「カタカタ」という音を立てながら、色あせた背景にフィルムのような黒の帯が左右にある。(今回はゲーム内でユーザーの気を散らす目的で制作するので物理的な妨害となる左右帯は作りません)
さぁ、映写機の演出についてのイメージを立ててもらったところでシェーダー使って作っていきましょう!!
作るぞ~!
1. まずは画面をあの色あせたセピア色にしていきましょう。
const float3 sepiaR = { 0.393f, 0.769f, 0.189f };
const float3 sepiaG = { 0.349f, 0.686f, 0.168f };
const float3 sepiaB = { 0.272f, 0.534f, 0.131f };
//本来出力されるカラー
float4 col = tex.Sample(texSampler, PSInput.uv);
//セピア色に調整
float3 sepiaCol;
sepiaCol.r = min(1.0f, col.r * sepiaR.r + col.g * sepiaR.g + col.b * sepiaR.b);
sepiaCol.g = min(1.0f, col.r * sepiaG.r + col.g * sepiaG.g + col.b * sepiaG.b);
sepiaCol.b = min(1.0f, col.r * sepiaB.r + col.g * sepiaB.g + col.b * sepiaB.b);
セピアになるといい気に古めかしさが増しますね。
参考元を見てみると、全体がセピア一色ではなく画面端付近が少し暗くなっています。
2. とりあえず画面端が暗く、画面中央が明るくなるようにしてみます。
// UV中心からの距離
float2 center = float2(0.5f, 0.5f);
float2 diff = PSInput.uv - center;
float dist = length(diff); // 0.0(中心)~ 約0.707(隅)
// フェード効果(中心に近いほど減衰)
float edge = smoothstep(0.1, 0.8, dist);
// 最終色:時間に応じて赤がフェードイン・アウト
float4 black = float4(1.0, 1.0, 1.0, 1.0) * edge;
float3 useCol = sepiaCol - black.rgb;
return float4(useCol, 1.0f);
暗すぎますね。これでは左右帯と同義になるどころか上下まで増えてより凶悪になってしまいました。。
カラーを黒(1.0,1.0,1.0)ではなく灰色(0.5,0.5,0.5)に調節しときましょう。
3. 次にランダムの黒の縦線のノイズを入れてみます。
これが入るとフィルムの経年劣化の感じがでていいですよね。
//c++側
//blackUVのX値
float randomNoiseLineX = static_cast<float>(rand() % 100) / 100.0f;
//Shader側
cbuffer cbParam : register(b4)
{
float2 blackUV;
}
//~(中略)~
float3 useCol = sepiaCol - black.rgb;
float diffNoiseLine = abs(PSInput.uv.x - blackUV.x);
if (diffNoiseLine < 0.002f)
{
useCol = (0.0f, 0.0f, 0.0f);
}
rand()関数を使用して、0.0~1.0までに収めたい!
しかし0.1単位でとってしまうと画面の一割を持っていかれるので、0.01単位に換算するようにしました。
いい感じですね。
あともう1つそれぽっさを加えるものを作っていきます。
4. それは「セピアの明るさのばらつき」です。
これもまた経年劣化を表すのに最適なものです。
映画のフィルムは月日が経つにつれ、日焼けして正常な明度ではなくなっていきます。
難しく考えたくないので、C++側から白の強さを受け取り色に加味していきましょう。
//c++側
//blackUVのX値
float randomNoiseLineX = static_cast<float>(rand() % 100) / 100.0f;
//白の強さ
float whitePoe = static_cast<float>(rand() % 100) / 1000.0f;
//Shader側
cbuffer cbParam : register(b4)
{
float2 blackUV;
float whitePow;
}
//~(中略)~
//白の強さ加算
sepiaCol += (whitePow, whitePow, whitePow);
//~(以下略)~
画面が白を強くなりすぎるのを防ぐため、static_cast<float>(rand() % 100) / 1000.0f; と分母を1000.0fにすることで、値を0.0~0.1に収めています。

いいですねぇ(愉悦)
まとめ
今回はこれで完成とします。
もっと凝れる部分はありますが、満足できるラインになったので良しとします。
決して他の作業が溜まっていて忙しくなったとかそんなんじゃn...
これからも、自分が好きな映像演出をシェーダで作成していこうと思います。
終わり。


