Open18
OpenSiv3D v0.6 debug memo
# include <Siv3D.hpp> // OpenSiv3D v0.6.0
//SIV3D_SET(EngineOption::Renderer::OpenGL);
void Main()
{
const VertexShader vs2D = HLSL{ U"example/shader/hlsl/default2d.hlsl", U"VS" }
| GLSL{ U"example/shader/glsl/default2d.vert", {{U"VSConstants2D", 0}} };
const PixelShader ps2DShape = HLSL{ U"example/shader/hlsl/default2d.hlsl", U"PS_Shape" }
| GLSL{ U"example/shader/glsl/default2d_shape.frag", {{U"PSConstants2D", 0}} };
const PixelShader ps2DTexture = HLSL{ U"example/shader/hlsl/default2d.hlsl", U"PS_Texture" }
| GLSL{ U"example/shader/glsl/default2d_texture.frag", {{U"PSConstants2D", 0}} };
if ((not vs2D) || (not ps2DShape) || (not ps2DTexture))
{
return;
}
const Texture texure{ U"example/windmill.png" };
while (System::Update())
{
{
const ScopedCustomShader2D shader{ vs2D, ps2DShape };
Circle{ 600, 400, 100 }.draw(Palette::Orange);
}
{
const ScopedCustomShader2D shader{ vs2D, ps2DTexture };
texure.draw();
}
}
}
# include <Siv3D.hpp>
void Main()
{
const Texture windmill{ U"example/windmill.png" };
const PixelShader ps = HLSL{ U"example/shader/hlsl/rgb_to_bgr.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/rgb_to_bgr.frag", {{U"PSConstants2D", 0}} };
if (not ps)
{
throw Error{ U"Failed to load a shader file" };
}
while (System::Update())
{
{
// R と B を入れ替えるピクセルシェーダを開始
const ScopedCustomShader2D shader{ ps };
windmill.draw(10, 10);
}
}
}
# include <Siv3D.hpp>
void Main()
{
const Texture windmill{ U"example/windmill.png" };
const PixelShader ps = HLSL{ U"example/shader/hlsl/rgb_shift.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/rgb_shift.frag", {{U"PSConstants2D", 0}} };
if (not ps)
{
throw Error{ U"Failed to load a shader file" };
}
while (System::Update())
{
{
// RGB シフト用のシェーダを開始
const ScopedCustomShader2D shader{ ps };
windmill.draw(10, 10);
}
}
}
# include <Siv3D.hpp>
void Main()
{
const Texture windmill{ U"example/windmill.png" };
const PixelShader ps = HLSL{ U"example/shader/hlsl/grayscale.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/grayscale.frag", {{U"PSConstants2D", 0}} };
if (not ps)
{
throw Error{ U"Failed to load a shader file" };
}
while (System::Update())
{
{
// グレースケール化するピクセルシェーダを開始
const ScopedCustomShader2D shader{ ps };
windmill.draw(10, 10);
}
}
}
# include <Siv3D.hpp>
void Main()
{
const Texture windmill{ U"example/windmill.png" };
const PixelShader ps = HLSL{ U"example/shader/hlsl/posterize.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/posterize.frag", {{U"PSConstants2D", 0}} };
if (not ps)
{
throw Error{ U"Failed to load a shader file" };
}
while (System::Update())
{
{
// ポスタライズするピクセルシェーダを開始
const ScopedCustomShader2D shader{ ps };
windmill.draw(10, 10);
}
}
}
# include <Siv3D.hpp>
// 定数バッファ (PS_1)
struct PoissonDisk
{
// 1 ピクセルあたりの UV サイズ
Float2 pixelSize;
// サンプリング半径
float diskRadius;
};
void Main()
{
const Texture windmill{ U"example/windmill.png" };
const PixelShader ps = HLSL{ U"example/shader/hlsl/poisson_disk.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/poisson_disk.frag", {{U"PSConstants2D", 0}, {U"PoissonDisk", 1}} };
if (not ps)
{
throw Error{ U"Failed to load a shader file" };
}
// 定数バッファ
ConstantBuffer<PoissonDisk> cb;
cb->pixelSize = Float2{ 1.0, 1.0 } / windmill.size();
// サンプリング半径
double diskRadius = 0.0;
while (System::Update())
{
// サンプリング半径をスライダーで変更
if (SimpleGUI::Slider(U"diskRadius", diskRadius, 0.0, 8.0, Vec2{ 10, 340 }, 120, 200))
{
cb->diskRadius = static_cast<float>(diskRadius);
}
{
// 定数バッファを、ピクセルシェーダの定数バッファインデックス 1 に設定
Graphics2D::SetConstantBuffer(ShaderStage::Pixel, 1, cb);
// Poisson-Disk Sampling 用のシェーダを開始
const ScopedCustomShader2D shader{ ps };
windmill.draw(10, 10);
}
}
}
# include <Siv3D.hpp>
// 定数バッファ (PS_1)
struct Swirl
{
// 回転
float angle;
};
void Main()
{
const Texture windmill{ U"example/windmill.png" };
const PixelShader ps = HLSL{ U"example/shader/hlsl/swirl.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/swirl.frag", {{U"PSConstants2D", 0}, {U"Swirl", 1}} };
if (not ps)
{
throw Error{ U"Failed to load a shader file" };
}
// 定数バッファ
ConstantBuffer<Swirl> cb;
while (System::Update())
{
cb->angle = static_cast<float>(Math::Sin(Scene::Time()) * 720_deg);
{
// 定数バッファを、ピクセルシェーダの定数バッファインデックス 1 に設定
Graphics2D::SetConstantBuffer(ShaderStage::Pixel, 1, cb);
// 渦巻き効果のシェーダを開始
const ScopedCustomShader2D shader{ ps };
windmill.draw(10, 10);
}
}
}
# include <Siv3D.hpp>
void Main()
{
const Texture emoji{ U"🐈"_emoji };
const Texture windmill{ U"example/windmill.png", TextureDesc::Mipped };
const PixelShader ps = HLSL{ U"example/shader/hlsl/multi_texture_blend.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/multi_texture_blend.frag", {{U"PSConstants2D", 0}} };
if (not ps)
{
throw Error{ U"Failed to load a shader file" };
}
while (System::Update())
{
// windmill をピクセルシェーダのテクスチャスロット [1] にセット
Graphics2D::SetPSTexture(1, windmill);
{
// マルチテクスチャによるブレンドのシェーダを開始
const ScopedCustomShader2D shader{ ps };
emoji.scaled(2).drawAt(Scene::Center());
}
}
}
# include <Siv3D.hpp>
void Main()
{
// ウィンドウを 960x600 にリサイズ
Window::Resize(960, 600);
// シーンの背景色を淡い水色に設定
Scene::SetBackground(ColorF(0.8, 0.9, 1.0));
const Texture emoji{ Emoji::CreateSilhouetteImage(U"🍎"), TextureDesc::Mipped };
const Texture windmill{ U"example/windmill.png", TextureDesc::Mipped };
const PixelShader ps = HLSL{ U"example/shader/hlsl/multi_texture_mask.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/multi_texture_mask.frag", {{U"PSConstants2D", 0}} };
if (not ps)
{
throw Error{ U"Failed to load a shader file" };
}
// レンダーテクスチャを作成
const RenderTexture renderTexture{ 480, 320 };
while (System::Update())
{
// レンダーテクスチャをクリア
renderTexture.clear(ColorF(0.0, 1.0));
{
// レンダーターゲットを renderTexture に設定
const ScopedRenderTarget2D rt(renderTexture);
emoji.scaled(2).rotated(Scene::Time() * 60_deg).drawAt(renderTexture.size() / 2);
}
// 描画された renderTexture を表示
renderTexture.draw(0, 140);
// renderTexture をピクセルシェーダのテクスチャスロット [1] にセット
Graphics2D::SetPSTexture(1, renderTexture);
{
// マルチテクスチャによるマスクのシェーダを開始
const ScopedCustomShader2D shader{ ps };
windmill.draw(480, 140);
}
}
}
# include <Siv3D.hpp>
// 定数バッファ (PS_1)
struct GameOfLife
{
Float2 pixelSize;
};
void Main()
{
// ウィンドウを 1280x720 にリサイズ
Window::Resize(1280, 720);
// セルの数 (1280x720)
constexpr Size FieldSize{ 1280, 720 };
const PixelShader ps = HLSL{ U"example/shader/hlsl/game_of_life.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/game_of_life.frag", {{U"PSConstants2D", 0}, {U"GameOfLife", 1}} };
if (not ps)
{
throw Error{ U"Failed to load a shader file" };
}
// 定数バッファ
const ConstantBuffer<GameOfLife> cb{ { (Float2{1.0f, 1.0f} / FieldSize) } };
// レンダーテクスチャ 0
RenderTexture renderTexture0{ Image{FieldSize, Arg::generator = []() { return Color(RandomBool() * 255); }} };
// レンダーテクスチャ 1
RenderTexture renderTexture1{ FieldSize, ColorF{0.0} };
while (System::Update())
{
{
// テクスチャフィルタなし
const ScopedRenderStates2D sampler(SamplerState::ClampNearest);
// 現在の状態を画面に描く
renderTexture0.draw(ColorF{ 0.0, 1.0, 0.0 });
{
// ライフゲーム用のシェーダ
Graphics2D::SetConstantBuffer(ShaderStage::Pixel, 1, cb);
const ScopedCustomShader2D shader{ ps };
// 更新後の状態を描く rt1 に描く
const ScopedRenderTarget2D target{ renderTexture1 };
renderTexture0.draw();
}
}
// rt0 と rt1 を入れ替える
std::swap(renderTexture0, renderTexture1);
}
}
# include <Siv3D.hpp>
// 定数バッファ (PS_1)
struct GameOfLife
{
Float2 pixelSize;
};
void Main()
{
// ウィンドウを 1280x720 にリサイズ
Window::Resize(1280, 720);
// セルの数 (1280x720)
constexpr Size FieldSize(1280, 720);
const PixelShader ps = HLSL{ U"example/shader/hlsl/game_of_life.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/game_of_life.frag", {{U"PSConstants2D", 0}, {U"GameOfLife", 1}} };
if (not ps)
{
throw Error{ U"Failed to load a shader file" };
}
// 定数バッファ
const ConstantBuffer<GameOfLife> cb{ { (Float2{1.0f, 1.0f} / FieldSize) } };
// レンダーテクスチャ 0
RenderTexture renderTexture0{ Image{FieldSize, Arg::generator = []() { return Color(RandomBool() * 255); }} };
// レンダーテクスチャ 1
RenderTexture renderTexture1{ FieldSize, ColorF{0.0} };
// 2D カメラ
Camera2D camera{ Vec2{0, 0}, 4.0 };
while (System::Update())
{
// 2D カメラを更新
camera.update();
{
// テクスチャフィルタなし
const ScopedRenderStates2D sampler(SamplerState::ClampNearest);
{
// 2D カメラの設定から Transformer2D を作成
const auto t = camera.createTransformer();
// 現在の状態を画面に描く
renderTexture0.draw(ColorF{ 0.0, 1.0, 0.0 });
// 2D カメラの UI を描画
camera.draw(Palette::Orange);
}
{
// ライフゲーム用のシェーダ
Graphics2D::SetConstantBuffer(ShaderStage::Pixel, 1, cb);
const ScopedCustomShader2D shader{ ps };
// 更新後の状態を描く rt1 に描く
const ScopedRenderTarget2D target{ renderTexture1 };
renderTexture0.draw();
}
}
// rt0 と rt1 を入れ替える
std::swap(renderTexture0, renderTexture1);
}
}
# include <Siv3D.hpp>
// 渦巻き効果のピクセルシェーダ用の
// 定数バッファ (PS_1)
struct Swirl
{
// 回転
float angle;
};
void Main()
{
// ゲームの描画用のレンダーテクスチャ
MSRenderTexture renderTexture{ Scene::Size() };
// グレースケール化するピクセルシェーダ
const PixelShader psGrayscale = HLSL{ U"example/shader/hlsl/grayscale.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/grayscale.frag", {{U"PSConstants2D", 0}} };
if (not psGrayscale)
{
throw Error{ U"Failed to load a shader file" };
}
// 渦巻き効果のピクセルシェーダ
const PixelShader psSwirl = HLSL{ U"example/shader/hlsl/swirl.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/swirl.frag", {{U"PSConstants2D", 0}, {U"Swirl", 1}} };
if (not psSwirl)
{
throw Error{ U"Failed to load a shader file" };
}
// 渦巻き効果のピクセルシェーダ用の定数バッファ
ConstantBuffer<Swirl> cb;
// ガウスぼかしの中間で使うレンダーテクスチャ
RenderTexture rtA{ renderTexture.size() }, rtB{ renderTexture.size() };
RenderTexture rtA4{ renderTexture.size() / 4 }, rtB4{ renderTexture.size() / 4 };
RenderTexture rtA8{ renderTexture.size() / 8 }, rtB8{ renderTexture.size() / 8 };
// ゲーム画面に適用するエフェクト
size_t effectIndex = 0;
// 背景色
constexpr ColorF backgroundColor{ 0.3, 0.4, 0.5 };
// ブロックのサイズ
constexpr Size blockSize{ 40, 20 };
// ブロックの配列
Array<Rect> blocks;
// 横 (Scene::Width() / blockSize.x) 個、縦 5 個のブロックを配列に追加する
for (auto p : step(Size{ (Scene::Width() / blockSize.x), 5 }))
{
blocks << Rect{ (p.x * blockSize.x), (60 + p.y * blockSize.y), blockSize };
}
// ボールの速さ
constexpr double speed = 480.0;
// ボールの速度
Vec2 ballVelocity{ 0, -speed };
// ボール
Circle ball{ 400, 400, 8 };
// 自動プレイ用のパラメータ
double paddleCenter = 400;
double randomOffset = 0.0;
while (System::Update())
{
// 自動プレイ
paddleCenter = Math::Damp(paddleCenter, ball.x + ballVelocity.x * 1.2 + randomOffset, 0.9, Scene::DeltaTime());
// パドル
const RectF paddle{ Arg::center(paddleCenter, 500), 120, 10 };
// ボールを移動
ball.moveBy(ballVelocity * Scene::DeltaTime());
// ブロックを順にチェック
for (auto it = blocks.begin(); it != blocks.end(); ++it)
{
// ボールとブロックが交差していたら
if (it->intersects(ball))
{
// ボールの向きを反転する
(it->bottom().intersects(ball) || it->top().intersects(ball) ? ballVelocity.y : ballVelocity.x) *= -1;
// ブロックを配列から削除(イテレータが無効になるので注意)
blocks.erase(it);
// これ以上チェックしない
break;
}
}
// 天井にぶつかったらはね返る
if (ball.y < 0 && ballVelocity.y < 0)
{
ballVelocity.y *= -1;
}
// 左右の壁にぶつかったらはね返る
if ((ball.x < 0 && ballVelocity.x < 0) || (Scene::Width() < ball.x && ballVelocity.x > 0))
{
ballVelocity.x *= -1;
}
// パドルにあたったらはね返る
if (ballVelocity.y > 0 && paddle.intersects(ball))
{
// パドルの中心からの距離に応じてはね返る向きを変える
ballVelocity = Vec2((ball.x - paddle.center().x) * 10, -ballVelocity.y).setLength(speed);
randomOffset = Random(-40, 40);
}
// レンダーテクスチャをクリア
renderTexture.clear(backgroundColor);
{
// レンダーターゲットを renderTexture に設定
const ScopedRenderTarget2D target{ renderTexture };
for (auto y : Range(1, 5))
{
Line{ 0, y * 100, 800, y * 100 }.draw(1, Palette::Gray);
}
for (auto x : Range(1, 7))
{
Line{ x * 100, 0, x * 100, 600 }.draw(1, Palette::Gray);
}
// すべてのブロックを描画する
for (const auto& block : blocks)
{
block.stretched(-1).draw(HSV{ block.y - 40 });
}
// ボールを描く
ball.draw();
// パドルを描く
paddle.draw();
}
// resolve のために描画を完了させる
Graphics2D::Flush();
// multi-sample のテクスチャを resolve して
// multi-sample ではない、描画可能なテクスチャを得る
renderTexture.resolve();
if (effectIndex == 0) // ゲーム画面をそのまま描画
{
renderTexture.draw();
}
else if (effectIndex == 1) // ゲーム画面をグレースケール化して描画
{
// グレースケール化するピクセルシェーダを開始
const ScopedCustomShader2D shader(psGrayscale);
renderTexture.draw();
}
else if (effectIndex == 2) // ゲーム画面を渦巻き効果で描画
{
cb->angle = static_cast<float>(Math::Sin(Scene::Time()) * 240_deg);
// 定数バッファを設定
Graphics2D::SetConstantBuffer(ShaderStage::Pixel, 1, cb);
// 渦巻き効果のシェーダを開始
const ScopedCustomShader2D shader(psSwirl);
renderTexture.draw();
}
else if (effectIndex == 3) // ゲーム画面をガウスぼかしで描画
{
// [オリジナル]->[ガウスぼかし]->[1/4サイズ]->[ガウスぼかし]
Shader::GaussianBlur(renderTexture, rtB, rtA);
Shader::Downsample(rtA, rtA4);
Shader::GaussianBlur(rtA4, rtB4, rtA4);
Shader::Downsample(rtA4, rtA8);
Shader::GaussianBlur(rtA8, rtB8, rtA8);
rtA8.scaled(8).draw();
}
// エフェクトの種類の選択
SimpleGUI::RadioButtons(effectIndex, { U"Default", U"Grayscale", U"Swirl", U"GaussianBlur" }, Vec2{ 10, 10 });
}
}
# include <Siv3D.hpp>
void Main()
{
Window::Resize(1280, 720);
const VertexShader vs3D = HLSL{ U"example/shader/hlsl/default3d_forward.hlsl", U"VS" }
| GLSL{ U"example/shader/glsl/default3d_forward.vert", {{ U"VSPerView", 1 }, { U"VSPerObject", 2 }} };
const PixelShader ps3D = HLSL{ U"example/shader/hlsl/default3d_forward.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/default3d_forward.frag", {{ U"PSPerFrame", 0 }, { U"PSPerView", 1 }, { U"PSPerMaterial", 3 }} };
if ((not vs3D) || (not ps3D))
{
return;
}
const ColorF backgroundColor = ColorF{ 0.4, 0.6, 0.8 }.removeSRGBCurve();
const Texture uvChecker{ U"example/texture/uv.png", TextureDesc::MippedSRGB };
const MSRenderTexture renderTexture{ Scene::Size(), TextureFormat::R8G8B8A8_Unorm_SRGB, HasDepth::Yes };
DebugCamera3D camera{ renderTexture.size(), 30_deg, Vec3{ 10, 16, -32 } };
while (System::Update())
{
camera.update(2.0);
// 3D
{
Graphics3D::SetCameraTransform(camera);
const ScopedCustomShader3D shader{ vs3D, ps3D };
const ScopedRenderTarget3D target{ renderTexture.clear(backgroundColor) };
Plane{ 64 }.draw(uvChecker);
Box{ -8,2,0,4 }.draw(ColorF{ 0.8, 0.6, 0.4 }.removeSRGBCurve());
Sphere{ 0,2,0,2 }.draw(ColorF{ 0.4, 0.8, 0.6 }.removeSRGBCurve());
Cylinder{ 8, 2, 0, 2, 4 }.draw(ColorF{ 0.6, 0.4, 0.8 }.removeSRGBCurve());
}
// RenderTexture を 2D シーンに描画
{
Graphics3D::Flush();
renderTexture.resolve();
Shader::LinearToScreen(renderTexture);
}
}
}
# include <Siv3D.hpp>
struct PSFog
{
Float3 fogColor;
float fogCoefficient;
};
void Main()
{
Window::Resize(1280, 720);
const PixelShader ps = HLSL{ U"example/shader/hlsl/forward_fog.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/forward_fog.frag", {{ U"PSPerFrame", 0 }, { U"PSPerView", 1 }, { U"PSPerMaterial", 3 }, { U"PSFog", 4 }} };
if (not ps)
{
return;
}
const ColorF backgroundColor = ColorF{ 0.4, 0.6, 0.8 }.removeSRGBCurve();
const Texture uvChecker{ U"example/texture/uv.png", TextureDesc::MippedSRGB };
const MSRenderTexture renderTexture{ Scene::Size(), TextureFormat::R8G8B8A8_Unorm_SRGB, HasDepth::Yes };
DebugCamera3D camera{ renderTexture.size(), 30_deg, Vec3{ 10, 16, -32 } };
double fogParam = 0.6;
ConstantBuffer<PSFog> cb{ { backgroundColor.rgb(), 0.0f } };
while (System::Update())
{
camera.update(2.0);
const double fogCoefficient = Math::Eerp(0.001, 0.25, fogParam);
cb->fogCoefficient = static_cast<float>(fogCoefficient);
// 3D
{
Graphics3D::SetCameraTransform(camera);
Graphics3D::SetPSConstantBuffer(4, cb);
const ScopedCustomShader3D shader{ ps };
const ScopedRenderTarget3D target{ renderTexture.clear(backgroundColor) };
Plane{ 64 }.draw(uvChecker);
for (auto x : Range(-4, 4))
{
for (auto z : Range(-4, 4))
{
Box{ {x * 8, 4, z * 8} , {2, 8, 2} }.draw();
}
}
}
// RenderTexture を 2D シーンに描画
{
Graphics3D::Flush();
renderTexture.resolve();
Shader::LinearToScreen(renderTexture);
}
SimpleGUI::Slider(U"fogCoefficient: {:.3f}"_fmt(fogCoefficient), fogParam, Vec2{ 20, 20 }, 200, 160);
}
}
# include <Siv3D.hpp>
void Main()
{
Window::Resize(1280, 720);
const PixelShader ps3D = HLSL{ U"example/shader/hlsl/forward_triplanar.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/forward_triplanar.frag", {{ U"PSPerFrame", 0 }, { U"PSPerView", 1 }, { U"PSPerMaterial", 3 }} };
if (not ps3D)
{
return;
}
const ColorF backgroundColor = ColorF{ 0.4, 0.6, 0.8 }.removeSRGBCurve();
const Texture uvChecker{ U"example/texture/uv.png", TextureDesc::MippedSRGB };
const Texture woodTexture{ U"example/texture/wood.jpg", TextureDesc::MippedSRGB };
const MSRenderTexture renderTexture{ Scene::Size(), TextureFormat::R8G8B8A8_Unorm_SRGB, HasDepth::Yes };
DebugCamera3D camera{ renderTexture.size(), 30_deg, Vec3{ 10, 16, -32 } };
const Mesh mesh0{ MeshData::Octahedron(2) };
const Mesh mesh1{ MeshData::Dodecahedron(2) };
const Mesh mesh2{ MeshData::Icosahedron(2) };
bool triplanar = true;
while (System::Update())
{
camera.update(2.0);
// 3D
{
Graphics3D::SetCameraTransform(camera);
const ScopedRenderTarget3D target{ renderTexture.clear(backgroundColor) };
Plane{ 64 }.draw(uvChecker);
const auto shader =
triplanar ? ScopedCustomShader3D{ ps3D } : ScopedCustomShader3D{};
Box{ -8,2,0,4 }.draw(woodTexture);
Sphere{ 0,2,0,2 }.draw(woodTexture);
Cylinder{ 8, 2, 0, 2, 4 }.draw(woodTexture);
mesh0.draw({ -8, 2, 8 }, woodTexture);
mesh1.draw({ 0, 2, 8 }, woodTexture);
mesh2.draw({ 8, 2, 8 }, woodTexture);
}
// RenderTexture を 2D シーンに描画
{
Graphics3D::Flush();
renderTexture.resolve();
Shader::LinearToScreen(renderTexture);
}
SimpleGUI::CheckBox(triplanar, U"triplanar", Vec2{ 20,20 });
}
}
# include <Siv3D.hpp>
void Main()
{
Window::Resize(1280, 720);
const VertexShader vsTerrain = HLSL{ U"example/shader/hlsl/terrain_forward.hlsl", U"VS" }
| GLSL{ U"example/shader/glsl/terrain_forward.vert", {{ U"VSPerView", 1 }, { U"VSPerObject", 2 }} };
const PixelShader psTerrain = HLSL{ U"example/shader/hlsl/terrain_forward.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/terrain_forward.frag", {{ U"PSPerFrame", 0 }, { U"PSPerView", 1 }, { U"PSPerMaterial", 3 }} };
const PixelShader psNormal = HLSL{ U"example/shader/hlsl/terrain_normal.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/terrain_normal.frag", {{U"PSConstants2D", 0}} };
if ((not vsTerrain) || (not psTerrain) || (not psNormal))
{
return;
}
const ColorF backgroundColor = ColorF{ 0.4, 0.6, 0.8 }.removeSRGBCurve();
const Texture uvChecker{ U"example/texture/uv.png", TextureDesc::MippedSRGB };
const Texture terrainTexture{ U"example/texture/grass.jpg", TextureDesc::MippedSRGB };
const Texture rockTexture{ U"example/texture/rock.jpg", TextureDesc::MippedSRGB };
const Texture brushTexture{ U"example/particle.png" };
const MSRenderTexture renderTexture{ Scene::Size(), TextureFormat::R8G8B8A8_Unorm_SRGB, HasDepth::Yes };
const Mesh gridMesh{ MeshData::Grid({128, 128}, 128, 128) };
DebugCamera3D camera{ renderTexture.size(), 30_deg, Vec3{ 10, 16, -32 } };
RenderTexture heightmap{ Size{ 256, 256 }, ColorF{0.0}, TextureFormat::R32_Float };
RenderTexture normalmap{ Size{ 256, 256 }, ColorF{0.0, 0.0, 0.0}, TextureFormat::R16G16_Float };
while (System::Update())
{
camera.update(2.0);
// 3D
{
Graphics3D::SetCameraTransform(camera);
const ScopedCustomShader3D shader{ vsTerrain, psTerrain };
const ScopedRenderTarget3D target{ renderTexture.clear(backgroundColor) };
const ScopedRenderStates3D ss{ { ShaderStage::Vertex, 0, SamplerState::ClampLinear} };
Graphics3D::SetVSTexture(0, heightmap);
Graphics3D::SetPSTexture(1, normalmap);
Graphics3D::SetPSTexture(2, rockTexture);
gridMesh.draw(terrainTexture);
}
// RenderTexture を 2D シーンに描画
{
Graphics3D::Flush();
renderTexture.resolve();
Shader::LinearToScreen(renderTexture);
}
if (const bool gen = SimpleGUI::Button(U"Random", Vec2{270, 10});
(gen || (MouseL | MouseR).pressed())) // 地形を編集
{
// heightmap を編集
if (gen)
{
const PerlinNoiseF perlin{ RandomUint64() };
Grid<float> grid(256, 256);
for (auto p : step(grid.size()))
{
grid[p] = perlin.octave2D0_1(p / 256.0f, 5) * 16.0f;
}
const RenderTexture noise{ grid };
const ScopedRenderTarget2D target{ heightmap };
noise.draw();
}
else
{
const ScopedRenderTarget2D target{ heightmap };
const ScopedRenderStates2D blend{ BlendState::Additive };
brushTexture.scaled(1.0 + MouseL.pressed()).drawAt(Cursor::PosF(), ColorF{ Scene::DeltaTime() * 15.0 });
}
// normal map を更新
{
const ScopedRenderTarget2D target{ normalmap };
const ScopedCustomShader2D shader{ psNormal };
const ScopedRenderStates2D blend{ BlendState::Opaque, SamplerState::ClampLinear };
heightmap.draw();
}
}
heightmap.draw(ColorF{ 0.1 });
normalmap.draw(0, 260);
}
}
# include <Siv3D.hpp>
void Main()
{
Window::Resize(1280, 720);
Scene::SetResizeMode(ResizeMode::Keep);
const PixelShader psBright = HLSL{ U"example/shader/hlsl/extract_bright_linear.hlsl", U"PS" }
| GLSL{ U"example/shader/glsl/extract_bright_linear.frag", {{U"PSConstants2D", 0}} };
if (not psBright)
{
return;
}
const ColorF backgroundColor = ColorF{ 0.02 }.removeSRGBCurve();
const MSRenderTexture renderTexture{ Scene::Size(), TextureFormat::R16G16B16A16_Float, HasDepth::Yes };
RenderTexture rtA4{ renderTexture.size() / 4 }, rtB4{ renderTexture.size() / 4 };
RenderTexture rtA8{ renderTexture.size() / 8 }, rtB8{ renderTexture.size() / 8 };
RenderTexture rtA16{ renderTexture.size() / 16 }, rtB16{ renderTexture.size() / 16 };
DebugCamera3D camera{ renderTexture.size(), 30_deg, Vec3{ 10, 16, -32 } };
bool glowEffect = true;
while (System::Update())
{
camera.update(2.0);
// 3D
{
Graphics3D::SetCameraTransform(camera);
const ScopedRenderTarget3D target{ renderTexture.clear(backgroundColor) };
PhongMaterial phong;
phong.amibientColor = ColorF{ 1.0 };
phong.diffuseColor = ColorF{ 0.0 };
for (auto i : Range(0, 10))
{
phong.emissionColor = ColorF{ 1.0, 0.4, 0.4 }.removeSRGBCurve() * (i / 5.0);
Box{ {-20 + i * 4, 2, 8}, 2 }
.draw(phong);
phong.emissionColor = ColorF{ 0.4, 1.0, 0.4 }.removeSRGBCurve() * (i / 5.0);
Sphere{ {-20 + i * 4, 2, 0}, 1 }
.draw(phong);
phong.emissionColor = ColorF{ 0.4, 0.4, 1.0 }.removeSRGBCurve() * (i / 5.0);
Cylinder{ {-20 + i * 4, 2, -8}, 1, 2 }
.draw(phong);
}
}
// RenderTexture を 2D シーンに描画
{
Graphics3D::Flush();
renderTexture.resolve();
Shader::LinearToScreen(renderTexture);
}
if (glowEffect)
{
// 高輝度部分を抽出
{
const ScopedCustomShader2D shader{ psBright };
const ScopedRenderTarget2D target{ rtA4.clear(ColorF{0.0}) };
renderTexture.scaled(0.25).draw();
}
// 高輝度部分のぼかしテクスチャの生成
{
Shader::GaussianBlur(rtA4, rtB4, rtA4);
Shader::Downsample(rtA4, rtA8);
Shader::GaussianBlur(rtA8, rtB8, rtA8);
Shader::GaussianBlur(rtA8, rtB8, rtA8);
Shader::Downsample(rtA8, rtA16);
Shader::GaussianBlur(rtA16, rtB16, rtA16);
Shader::GaussianBlur(rtA16, rtB16, rtA16);
Shader::GaussianBlur(rtA16, rtB16, rtA16);
}
// Glow エフェクト
{
const ScopedRenderStates2D blend{ BlendState::AdditiveRGB };
{
const ScopedRenderTarget2D target{ rtA8 };
rtA16.scaled(2.0).draw(ColorF{ 3.0 });
}
{
const ScopedRenderTarget2D target{ rtA4 };
rtA8.scaled(2.0).draw(ColorF{ 1.0 });
}
rtA4.resized(Scene::Size()).draw(ColorF{ 1.0 });
}
}
SimpleGUI::CheckBox(glowEffect, U"Glow", Vec2{ 20,20 });
}
}
# include <Siv3D.hpp> // OpenSiv3D v0.6
void Main()
{
Window::Resize(1280, 720);
const ColorF backgroundColor = ColorF{ 0.4, 0.6, 0.8 }.removeSRGBCurve();
const Texture uvChecker{ U"example/texture/uv.png", TextureDesc::MippedSRGB };
const MSRenderTexture renderTexture{ Scene::Size(), TextureFormat::R8G8B8A8_Unorm_SRGB, HasDepth::Yes };
DebugCamera3D camera{ renderTexture.size(), 30_deg, Vec3{ 10, 16, -32 } };
const Mesh billboard{ MeshData::Billboard() };
const Mesh wideBillboard{ MeshData::Billboard({2, 1}) };
while (System::Update())
{
camera.update(2.0);
Graphics3D::SetCameraTransform(camera);
// 3D
{
const ScopedRenderTarget3D target{ renderTexture.clear(backgroundColor) };
Plane{ 64 }.draw(uvChecker);
Box{ -8,2,0,4 }.draw(ColorF{ 0.8, 0.6, 0.4 }.removeSRGBCurve());
Sphere{ 0,2,0,2 }.draw(ColorF{ 0.4, 0.8, 0.6 }.removeSRGBCurve());
Cylinder{ 8, 2, 0, 2, 4 }.draw(ColorF{ 0.6, 0.4, 0.8 }.removeSRGBCurve());
billboard.draw(camera.billboard(Vec3{ -8, 4, -4 }, 1), uvChecker);
billboard.draw(camera.billboard(Vec3{ 0, 4, -4 }, 2), uvChecker);
billboard.draw(camera.billboard(Vec3{ 8, 4, -4 }, 4), uvChecker);
wideBillboard.draw(camera.billboard(Vec3{ -8, 4, 4 }, { 2, 1 }), uvChecker);
wideBillboard.draw(camera.billboard(Vec3{ 0, 4, 4 }, { 4, 2 }), uvChecker);
wideBillboard.draw(camera.billboard(Vec3{ 8, 4, 4 }, { 8, 4 }), uvChecker);
}
// RenderTexture を 2D シーンに描画
{
Graphics3D::Flush();
renderTexture.resolve();
Shader::LinearToScreen(renderTexture);
}
}
}