映画のフィルムっぽいノイズを生成するシェーダー
https://gyazo.com/3b71a16b17580b81f77ee3c8f64539c6
説明
randomでg_time / 1000しているのは、g_timeが大きくなるとうまく動かないから(おそらく桁落ちしている?)
code:filmNoise.hlsl
//
// Textures
//
Texture2D g_texture0 : register(t0);
SamplerState g_sampler0 : register(s0);
namespace s3d
{
//
// VS Output / PS Input
//
struct PSInput
{
float4 position : SV_POSITION;
float4 color : COLOR0;
float2 uv : TEXCOORD0;
};
}
//
// Constant Buffer
//
cbuffer PSConstants2D : register(b0)
{
float4 g_colorAdd;
float4 g_sdfParam;
float4 g_sdfOutlineColor;
float4 g_sdfShadowColor;
float4 g_internal;
}
cbuffer FirmNoiseBuf : register(b1)
{
float g_time;
}
float random(float2 p)
{
return frac(sin(dot(p + g_time / 1000, float2(12.9898, 78.233))) * 43758.5453123);
}
float2 hash(float2 p)
{
p = float2(dot(p + g_time, float2(127.1, 311.7)), dot(p + g_time, float2(269.5, 183.3)));
return frac(sin(p) * 43758.5453);
}
float fade(float t)
{
return t * t * (3.0 - 2.0 * t);
}
float noise(float2 p)
{
float2 i = floor(p);
float2 f = frac(p);
// Four corners in 2D of a tile
float a = random(i);
float b = random(i + float2(1.0, 0.0));
float c = random(i + float2(0.0, 1.0));
float d = random(i + float2(1.0, 1.0));
float2 u = f * f * (3.0 - 2.0 * f);
return lerp(a, b, u.x) +
(c - a) * u.y * (1.0 - u.x) +
(d - b) * u.x * u.y;
}
float perlinNoise(float2 p)
{
float2 i = floor(p);
float2 f = frac(p);
float2 u = float2(fade(f.x), fade(f.y));
float2 g00 = hash(i + float2(0.0, 0.0));
float2 g10 = hash(i + float2(1.0, 0.0));
float2 g01 = hash(i + float2(0.0, 1.0));
float2 g11 = hash(i + float2(1.0, 1.0));
float n00 = dot(g00, f - float2(0.0, 0.0));
float n10 = dot(g10, f - float2(1.0, 0.0));
float n01 = dot(g01, f - float2(0.0, 1.0));
float n11 = dot(g11, f - float2(1.0, 1.0));
float nx0 = lerp(n00, n10, u.x);
float nx1 = lerp(n01, n11, u.x);
return lerp(nx0, nx1, u.y);
}
float fbm(float2 uv, int octaves)
{
float value = 0.0;
float amplitude = 0.5;
float frequency = 1.0;
for (int i = 0; i < octaves; ++i)
{
value += amplitude * noise(uv * frequency);
uv *= 2.0;
amplitude *= 0.5;
}
return value;
}
float turbulence(float2 uv, int octaves)
{
float value = 0.0;
float amplitude = 1.0;
float frequency = 1.0;
for (int i = 0; i < octaves; ++i)
{
value += amplitude * abs(perlinNoise(uv * frequency));
uv *= 2.0;
amplitude *= 0.5;
}
return value;
}
float4 sepiaRandomLine(float x, float threshold)
{
float r = random(float2(x, 0));
float randomline = (r > threshold) ? 1.0 : 0.0;
return float4(0.93, 0.79, 0.69, 1.0) * randomline;
}
float4 sepiaNoiseFill(float2 uv, float threshold)
{
float normalized = (turbulence(uv * 8, 5) > threshold) ? 1.0 : 0.0;
return float4(0.93, 0.79, 0.69, 1.0) * normalized;
}
float4 applySepia(float4 texColor, float amount)
{
float3 sepia = float3(
dot(texColor.rgb, float3(0.393, 0.769, 0.189)),
dot(texColor.rgb, float3(0.349, 0.686, 0.168)),
dot(texColor.rgb, float3(0.272, 0.534, 0.131))
);
texColor.rgb = lerp(texColor.rgb, sepia, amount);
return texColor;
}
float4 PS(s3d::PSInput input) : SV_TARGET
{
float2 uv = input.uv;
float4 sepiaNoise = sepiaNoiseFill(uv, 0.48);
float4 sepiaStripe = sepiaRandomLine(uv.x, 0.999);
float4 texColor = applySepia(g_texture0.Sample(g_sampler0, input.uv), 0.6);
return (texColor * input.color) + sepiaNoise + sepiaStripe + g_colorAdd;
}
code:Main.cpp
# include <Siv3D.hpp>
// 定数バッファ (PS_1)
struct FilmNoise
{
float time;
};
void Main()
{
const Texture windmill{ U"example/windmill.png" };
const PixelShader ps = HLSL{ U"example/shader/hlsl/filmNoise.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/swirl.frag", {{U"PSConstants2D", 0}, {U"Perlin", 1}} };
if (not ps)
{
throw Error{ U"Failed to load a shader file" };
}
// 定数バッファ
ConstantBuffer<FilmNoise> cb;
while (System::Update())
{
cb->time = static_cast<float>(Scene::Time());
{
// 定数バッファを、ピクセルシェーダの定数バッファスロット 1 に設定
Graphics2D::SetPSConstantBuffer(1, cb);
const ScopedCustomShader2D shader{ ps };
windmill.draw(10, 10);
}
}
}
作者
BetAmoto