画像を水面っぽく歪ませるシェーダー
説明
PerlinNoiseを使って水面っぽく歪ませるシェーダーを作りました。
https://gyazo.com/ff9a4a56aba688a7216a808b700bbcff
code:perlin.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 PerlinBuf : register(b1)
{
float g_time;
float g_x;
float g_y;
}
//struct Swirl
//{
// float angle;
//};
uniform float u_time;
float random(float2 p)
{
return frac(sin(dot(p, float2(12.9898, 78.233))) * 43758.5453123);
}
float2 hash(float2 p)
{
p = float2(dot(p, float2(127.1, 311.7)), dot(p, 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 = 0.5;
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 PS(s3d::PSInput input) : SV_TARGET
{
float2 uv = input.uv;
float2 q;
q.x = turbulence(uv * 1.0 + g_time * g_x, 4);
q.y = turbulence(uv * 1.0 + g_time * g_y, 4);
float4 texColor = g_texture0.Sample(g_sampler0, uv + q);
return (texColor * input.color) + g_colorAdd;
}
code:Main.cpp
# include <Siv3D.hpp>
// 定数バッファ (PS_1)
struct Perlin
{
float time;
float x;
float y;
};
void Main()
{
const Texture windmill{ U"example/windmill.png" };
const PixelShader ps = HLSL{ U"example/shader/hlsl/perlin.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<Perlin> cb;
double x = 1.0;
double y = 1.0;
while (System::Update())
{
cb->time = static_cast<float>(Scene::Time());
cb->x = static_cast<float>(x);
cb->y = static_cast<float>(y);
{
// 定数バッファを、ピクセルシェーダの定数バッファスロット 1 に設定
Graphics2D::SetPSConstantBuffer(1, cb);
const ScopedCustomShader2D shader{ ps };
windmill.draw(10, 10);
}
// 歪ませる方向
SimpleGUI::Slider(U"{:.2f}"_fmt(x), x, -1.0, 1.0, Vec2{ 500, 40 }, 60, 150);
SimpleGUI::Slider(U"{:.2f}"_fmt(y), y, -1.0, 1.0, Vec2{ 500, 140 }, 60, 150);
}
}
作者
たのれん