ピント調整
https://scrapbox.io/files/698af372453671c3061e73cf.png
ピント調整ごっこができるサンプルです。
Poisson-Disk Samplingでレンズぼかしを行っています。
Poisson-Disk SamplingのSiv3D公式チュートリアル
https://zenn.dev/reputeless/books/siv3d-documentation/viewer/tutorial-shader2d#35.10-poisson-disk-sampling
また、公式のexample/poisson_disk.hlslをそのまま使用すると、画像の輪郭部分が黒くなってしまうため、少しコードを調整したmy_poisson_disk.hlslを使用しています。
code:ピント調整.cpp
# include <Siv3D.hpp>
class PoissonDisk
{
public:
const PixelShader ps = HLSL{ U"my_poisson_disk.hlsl", U"PS" };
PoissonDisk()
{
if (not ps)
{
throw Error{ U"Failed to load a shader file" };
}
}
};
/// @brief スコープの間Poisson-Disk Samplingが行われる
class ScopedPoissonDisk
{
public:
/// @brief コンストラクタ
/// @param poissonDisk PoissonDisk
/// @param diskRadius ぼかしの大きさ
/// @param textureSize 画像サイズ
ScopedPoissonDisk(const PoissonDisk& poissonDisk,double diskRadius,const SizeF& textureSize)
:shader{poissonDisk.ps}
{
Graphics2D::SetPSConstantBuffer(1, ConstantBuffer<PoissonDiskData>{Float2{ 1.0, 1.0 } / textureSize, diskRadius});
}
private:
struct PoissonDiskData
{
Float2 pixelSize;
float diskRadius;
};
ScopedCustomShader2D shader;
};
/// @brief ぼかしの半径を計算(適当)
/// @param focusDistance 焦点距離
/// @param distance 物体の距離
/// @return ぼかしの強さ
double DiskRadius(double focusDistance,double distance)
{
constexpr double maxBlur = 6.0;//ぼかしの最大値
constexpr double strength = 5.0;//ぼかしの強さ
return Min(maxBlur, strength * Abs(focusDistance - distance) / distance);
}
void Main()
{
Window::Resize(1280, 720);
const Texture backgroundTexture(Image(U"example/bay.jpg").scale(1280, 720));
const Texture siv3dKun{ U"example/siv3d-kun.png" };
const Texture apple{ U"🍎"_emoji };
PoissonDisk poissonDisk;
double focusDistance = 1;
double appleDistance = 0;
while (System::Update())
{
{
ScopedPoissonDisk scoped{ poissonDisk,DiskRadius(focusDistance,30),backgroundTexture.size()};
backgroundTexture.draw();
}
{
ScopedPoissonDisk scoped{ poissonDisk,DiskRadius(focusDistance,5),siv3dKun.size() };
siv3dKun.drawAt(Scene::Center());
}
{
ScopedPoissonDisk scoped{ poissonDisk,DiskRadius(focusDistance,appleDistance),apple.size() / appleDistance };
apple.scaled(1/appleDistance).drawAt(Scene::Center()+Vec2{150,0});
}
SimpleGUI::Slider(U"焦点距離?", focusDistance,1, 30, Vec2{100, 40},130);
SimpleGUI::Slider(U"りんごの距離",appleDistance, 1, 5, Vec2{ 100, 100 },130);
}
}
code:my_poisson_disk.hlsl
//-----------------------------------------------
//
// This file is part of the Siv3D Engine.
//
// Copyright (c) 2008-2023 Ryo Suzuki
// Copyright (c) 2016-2023 OpenSiv3D Project
//
// Licensed under the MIT License.
//
//-----------------------------------------------
//
// 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 PoissonDisk : register(b1)
{
float2 g_pixelSize;
float g_diskRadius;
}
// C++
//struct PoissonDisk
//{
// Float2 pixelSize;
// float diskRadius;
//};
static const float2 poisson12 =
{
float2(-0.326212, -0.405805),
float2(-0.840144, -0.07358),
float2(-0.695914, 0.457137),
float2(-0.203345, 0.620716),
float2(0.96234, -0.194983),
float2(0.473434, -0.480026),
float2(0.519456, 0.767022),
float2(0.185461, -0.893124),
float2(0.507431, 0.064425),
float2(0.89642, 0.412458),
float2(-0.32194, -0.932615),
float2(-0.791559, -0.597705)
};
float4 PS(s3d::PSInput input) : SV_TARGET
{
float2 offsetScale = g_pixelSize * g_diskRadius;
float4 accum = g_texture0.Sample(g_sampler0, input.uv);
for (uint tap = 0; tap < 12; ++tap)
{
float2 uv = input.uv + (poissontap * offsetScale);
float4 color = g_texture0.Sample(g_sampler0, uv);
accum.rgb += color.rgb * color.a;
accum.a += color.a;
}
accum.rgb /= accum.a;
accum.a /= 13.0;
return (accum * input.color) + g_colorAdd;
}