🌠

Siv3D | シェーダを使った表現集 (2D)

2020/09/27に公開

1. UV 座標をずらして画像から球を作る

# include <Siv3D.hpp> // OpenSiv3D v0.6.3

struct SphereParam
{
	float offset;
};

void Main()
{
	Window::Resize(1280, 720);

	const PixelShader ps = HLSL{ U"sphere.hlsl" }
		| GLSL{ U"sphere.glsl", { { U"PSConstants2D", 0 }, { U"SphereParam", 1 } } };

	if (not ps)
	{
		throw Error{ U"Failed to load a shader file" };
	}

	ConstantBuffer<SphereParam> cb;

	const Texture textureB{ U"example/texture/earth.jpg", TextureDesc::Mipped };

	while (System::Update())
	{
		cb->offset = static_cast<float>(Scene::Time() * -0.1);
		Graphics2D::SetPSConstantBuffer(1, cb);

		{
			const ScopedRenderStates2D sampler{ SamplerState::RepeatLinear };
			const ScopedCustomShader2D shader{ ps };
			Circle{ Scene::Center(), 220 }(textureB).draw();
		}
	}
}
sphere.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 SphereParam : register(b1)
{
	float g_offset;
}

//
//	Functions
//
float4 PS(s3d::PSInput input) : SV_TARGET
{
	float2 centeredUV = (input.uv * 2.0 - 1.0);
	float z = sqrt(1.0 - saturate(dot(centeredUV.xy, centeredUV.xy)));
	float2 sphereUV = centeredUV / (z + 1.0);
	float2 uv = (sphereUV * 0.5 + 0.5);
	uv.x = uv.x / 2 + g_offset;
	float4 texColor = g_texture0.Sample(g_sampler0, uv);
	return (texColor * input.color) + g_colorAdd;
}
sphere.frag
# version 410

//
//	Textures
//
uniform sampler2D Texture0;

//
//	PSInput
//
layout(location = 0) in vec4 Color;
layout(location = 1) in vec2 UV;

//
//	PSOutput
//
layout(location = 0) out vec4 FragColor;

//
//	Constant Buffer
//
layout(std140) uniform PSConstants2D
{
	vec4 g_colorAdd;
	vec4 g_sdfParam;
	vec4 g_sdfOutlineColor;
	vec4 g_sdfShadowColor;
	vec4 g_internal;
};

layout(std140) uniform SphereParam
{
	float g_offset;
};

//
//	Functions
//
void main()
{
	vec2 centeredUV = (UV * 2.0f - 1.0f);
	float z = sqrt(1.0f - clamp(dot(centeredUV.xy, centeredUV.xy), 0.0f, 1.0f));
	vec2 sphereUV = centeredUV / (z + 1.0f);
	vec2 uv = (sphereUV * 0.5f + 0.5f);
	uv.x = uv.x / 2.0f + g_offset;
	vec4 texColor = texture(Texture0, uv);
	FragColor = ((texColor * Color) + g_colorAdd);
}

参考資料

Discussion