-
-
Save Reputeless/9064220b9fc72caf1e3c07acf3d09da6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # include <Siv3D.hpp> | |
| struct SpotLight | |
| { | |
| Float3 position; // ライト位置 | |
| float cutoff; // cos(カットオフ角) | |
| Float3 direction; // スポット軸方向 | |
| float exponent; // フォールオフ指数 | |
| Float3 color; // ライト色 | |
| float _unused = 0.0f; | |
| }; | |
| struct PSSpotLight | |
| { | |
| SpotLight spotLights[2]; | |
| }; | |
| 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 PixelShader ps3D = HLSL{ U"spotlight.hlsl", U"PS" } | |
| | GLSL{ U"spotlight.frag", {{ U"PSPerFrame", 0 }, { U"PSPerView", 1 }, { U"PSPerMaterial", 3 }, { U"PSSpotLight", 4 }} }; | |
| if (not ps3D) | |
| { | |
| return; | |
| } | |
| ConstantBuffer<PSSpotLight> cbSpotLight; | |
| Graphics3D::SetSunColor(ColorF{ 0.2 }.removeSRGBCurve()); | |
| Graphics3D::SetGlobalAmbientColor(ColorF{ 0.1 }.removeSRGBCurve()); | |
| while (System::Update()) | |
| { | |
| camera.update(2.0); | |
| Graphics3D::SetCameraTransform(camera); | |
| { | |
| auto& spotLight0 = cbSpotLight->spotLights[0]; | |
| spotLight0.position = Float3{ 0, 4, -4 }; | |
| spotLight0.cutoff = Math::Cos(30_deg); | |
| spotLight0.direction = Float3{ 0, -1, 0 }.normalized(); | |
| spotLight0.exponent = 40.0f; | |
| spotLight0.color = ColorF{ 1, 0, 0 }.removeSRGBCurve().rgb(); | |
| } | |
| { | |
| auto& spotLight1 = cbSpotLight->spotLights[1]; | |
| spotLight1.position = Float3{ 12, 6, -8 }; | |
| spotLight1.cutoff = Math::Cos(30_deg); | |
| spotLight1.direction = Float3{ -0.5, -1, 0.5 }.normalized(); | |
| spotLight1.exponent = 10.0f; | |
| spotLight1.color = ColorF{ 0, 0, 1 }.removeSRGBCurve().rgb(); | |
| } | |
| // 3D 描画 | |
| { | |
| // カスタムシェーダ使用 | |
| const ScopedCustomShader3D shader{ ps3D }; | |
| Graphics3D::SetPSConstantBuffer(4, cbSpotLight); | |
| 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()); | |
| } | |
| // 3D シーンを 2D シーンに描画 | |
| { | |
| Graphics3D::Flush(); | |
| renderTexture.resolve(); | |
| Shader::LinearToScreen(renderTexture); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Copyright (c) 2008-2025 Ryo Suzuki. | |
| // Copyright (c) 2016-2025 OpenSiv3D Project. | |
| // Licensed under the MIT License. | |
| # version 410 | |
| // | |
| // Textures | |
| // | |
| uniform sampler2D Texture0; | |
| struct Spotlight | |
| { | |
| vec3 position; | |
| float cutoff; | |
| vec3 direction; | |
| float exponent; | |
| vec3 color; | |
| float _unused; | |
| }; | |
| // | |
| // PSInput | |
| // | |
| layout(location = 0) in vec3 WorldPosition; | |
| layout(location = 1) in vec2 UV; | |
| layout(location = 2) in vec3 Normal; | |
| // | |
| // PSOutput | |
| // | |
| layout(location = 0) out vec4 FragColor; | |
| // | |
| // Constant Buffer | |
| // | |
| layout(std140) uniform PSPerFrame // slot 0 | |
| { | |
| vec3 g_globalAmbientColor; | |
| vec3 g_sunColor; | |
| vec3 g_sunDirection; | |
| }; | |
| layout(std140) uniform PSPerView // slot 1 | |
| { | |
| vec3 g_eyePosition; | |
| }; | |
| layout(std140) uniform PSPerMaterial // slot 3 | |
| { | |
| vec3 g_ambientColor; | |
| uint g_hasTexture; | |
| vec4 g_diffuseColor; | |
| vec3 g_specularColor; | |
| float g_shininess; | |
| vec3 g_emissionColor; | |
| }; | |
| layout(std140) uniform PSSpotLight // slot 4 | |
| { | |
| Spotlight g_spotLights[2]; | |
| }; | |
| // | |
| // Functions | |
| // | |
| vec4 GetDiffuseColor(vec2 uv) | |
| { | |
| vec4 diffuseColor = g_diffuseColor; | |
| if (g_hasTexture == 1) | |
| { | |
| diffuseColor *= texture(Texture0, uv); | |
| } | |
| return diffuseColor; | |
| } | |
| vec3 CalculateDiffuseReflection(vec3 n, vec3 l, vec3 lightColor, vec3 diffuseColor, vec3 ambientColor) | |
| { | |
| vec3 directColor = lightColor * max(dot(n, l), 0.0f); | |
| return ((ambientColor + directColor) * diffuseColor); | |
| } | |
| vec3 CalculateSpecularReflection(vec3 n, vec3 h, float shininess, float nl, vec3 lightColor, vec3 specularColor) | |
| { | |
| float highlight = pow(max(dot(n, h), 0.0f), shininess) * float(0.0f < nl); | |
| return (lightColor * specularColor * highlight); | |
| } | |
| vec3 CalculateSpotlightReflection( | |
| Spotlight spot, | |
| vec3 n, | |
| vec3 worldPos, | |
| vec3 viewDir, | |
| vec4 diffCol, | |
| vec3 ambCol) | |
| { | |
| // ライト方向とスポット減衰 | |
| vec3 L = normalize(spot.position - worldPos); | |
| float cosAngle = dot(-L, normalize(spot.direction)); | |
| float spotAtten = (cosAngle > spot.cutoff) | |
| ? pow(cosAngle, spot.exponent) | |
| : 0.0; | |
| // 拡散 | |
| vec3 diff = CalculateDiffuseReflection( | |
| n, L, | |
| spot.color, | |
| diffCol.rgb, | |
| ambCol | |
| ) * spotAtten; | |
| // 鏡面 | |
| vec3 H = normalize(viewDir + L); | |
| float NdotL = max(dot(n, L), 0.0); | |
| vec3 spec = CalculateSpecularReflection( | |
| n, H, | |
| g_shininess, | |
| NdotL, | |
| spot.color, | |
| g_specularColor | |
| ) * spotAtten; | |
| return diff + spec; | |
| } | |
| void main() | |
| { | |
| vec3 n = normalize(Normal); | |
| vec3 viewDir = normalize(g_eyePosition - WorldPosition); | |
| vec4 diffuseColor = GetDiffuseColor(UV); | |
| vec3 ambCol = g_ambientColor * g_globalAmbientColor; | |
| vec3 sunDiff = CalculateDiffuseReflection( | |
| n, normalize(g_sunDirection), | |
| g_sunColor, | |
| diffuseColor.rgb, | |
| ambCol | |
| ); | |
| vec3 H_sun = normalize(viewDir + normalize(g_sunDirection)); | |
| vec3 sunSpec = CalculateSpecularReflection( | |
| n, H_sun, | |
| g_shininess, | |
| max(dot(n, normalize(g_sunDirection)), 0.0), | |
| g_sunColor, | |
| g_specularColor | |
| ); | |
| vec3 spotAccum = vec3(0.0); | |
| for (int i = 0; i < 2; ++i) | |
| { | |
| spotAccum += CalculateSpotlightReflection( | |
| g_spotLights[i], | |
| n, | |
| WorldPosition, | |
| viewDir, | |
| diffuseColor, | |
| ambCol | |
| ); | |
| } | |
| vec3 finalColor = sunDiff + sunSpec + spotAccum + g_emissionColor; | |
| FragColor = vec4(finalColor, diffuseColor.a); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //----------------------------------------------- | |
| // | |
| // This file is part of the Siv3D Engine. | |
| // | |
| // Copyright (c) 2008-2025 Ryo Suzuki | |
| // Copyright (c) 2016-2025 OpenSiv3D Project | |
| // | |
| // Licensed under the MIT License. | |
| // | |
| //----------------------------------------------- | |
| // | |
| // Textures | |
| // | |
| Texture2D g_texture0 : register(t0); | |
| SamplerState g_sampler0 : register(s0); | |
| namespace s3d | |
| { | |
| // | |
| // VS Input | |
| // | |
| struct VSInput | |
| { | |
| float4 position : POSITION; | |
| float3 normal : NORMAL; | |
| float2 uv : TEXCOORD0; | |
| }; | |
| // | |
| // VS Output / PS Input | |
| // | |
| struct PSInput | |
| { | |
| float4 position : SV_POSITION; | |
| float3 worldPosition : TEXCOORD0; | |
| float2 uv : TEXCOORD1; | |
| float3 normal : TEXCOORD2; | |
| }; | |
| } | |
| struct Spotlight | |
| { | |
| float3 position; | |
| float cutoff; | |
| float3 direction; | |
| float exponent; | |
| float3 color; | |
| float _unused; | |
| }; | |
| // | |
| // Constant Buffer | |
| // | |
| cbuffer VSPerView : register(b1) | |
| { | |
| row_major float4x4 g_worldToProjected; | |
| } | |
| cbuffer VSPerObject : register(b2) | |
| { | |
| row_major float4x4 g_localToWorld; | |
| } | |
| cbuffer VSPerMaterial : register(b3) | |
| { | |
| float4 g_uvTransform; | |
| } | |
| cbuffer PSPerFrame : register(b0) | |
| { | |
| float3 g_globalAmbientColor; | |
| float3 g_sunColor; | |
| float3 g_sunDirection; | |
| } | |
| cbuffer PSPerView : register(b1) | |
| { | |
| float3 g_eyePosition; | |
| } | |
| cbuffer PSPerMaterial : register(b3) | |
| { | |
| float3 g_ambientColor; | |
| uint g_hasTexture; | |
| float4 g_diffuseColor; | |
| float3 g_specularColor; | |
| float g_shininess; | |
| float3 g_emissionColor; | |
| } | |
| cbuffer PSSpotLight : register(b4) | |
| { | |
| Spotlight g_spotLights[2]; | |
| } | |
| // | |
| // Functions | |
| // | |
| s3d::PSInput VS(s3d::VSInput input) | |
| { | |
| s3d::PSInput result; | |
| const float4 worldPosition = mul(input.position, g_localToWorld); | |
| result.position = mul(worldPosition, g_worldToProjected); | |
| result.worldPosition = worldPosition.xyz; | |
| result.uv = (input.uv * g_uvTransform.xy + g_uvTransform.zw); | |
| result.normal = mul(input.normal, (float3x3)g_localToWorld); | |
| return result; | |
| } | |
| float4 GetDiffuseColor(float2 uv) | |
| { | |
| float4 diffuseColor = g_diffuseColor; | |
| if (g_hasTexture) | |
| { | |
| diffuseColor *= g_texture0.Sample(g_sampler0, uv); | |
| } | |
| return diffuseColor; | |
| } | |
| float3 CalculateDiffuseReflection(float3 n, float3 l, float3 lightColor, float3 diffuseColor, float3 ambientColor) | |
| { | |
| const float3 directColor = lightColor * saturate(dot(n, l)); | |
| return ((ambientColor + directColor) * diffuseColor); | |
| } | |
| float3 CalculateSpecularReflection(float3 n, float3 h, float shininess, float nl, float3 lightColor, float3 specularColor) | |
| { | |
| const float highlight = pow(saturate(dot(n, h)), shininess) * float(0.0 < nl); | |
| return (lightColor * specularColor * highlight); | |
| } | |
| // スポットライト(拡散+鏡面反射) | |
| float3 CalculateSpotlightReflection( | |
| float3 n, | |
| float3 worldPos, | |
| float3 viewDir, | |
| float4 diffCol, | |
| float3 ambCol, | |
| float shininess, | |
| float3 specCol, | |
| Spotlight spot) | |
| { | |
| float3 L = normalize(spot.position - worldPos); | |
| float cosAngle = dot(-L, normalize(spot.direction)); | |
| float spotAtten = (cosAngle > spot.cutoff) ? pow(abs(cosAngle), spot.exponent) : 0.0; | |
| float3 diff = CalculateDiffuseReflection(n, L, spot.color, diffCol.rgb, ambCol) * spotAtten; | |
| float3 H = normalize(viewDir + L); | |
| float NdotL = dot(n, L); | |
| float3 spec = CalculateSpecularReflection(n, H, shininess, NdotL, spot.color, specCol) * spotAtten; | |
| return diff + spec; | |
| } | |
| float4 PS(s3d::PSInput input) : SV_TARGET | |
| { | |
| float3 n = normalize(input.normal); | |
| float3 eyeDir = normalize(g_eyePosition - input.worldPosition); | |
| float4 diffuseColor = GetDiffuseColor(input.uv); | |
| float3 ambCol = g_ambientColor * g_globalAmbientColor; | |
| float3 sunDiff = CalculateDiffuseReflection(n, g_sunDirection, g_sunColor, diffuseColor.rgb, ambCol); | |
| float3 H_sun = normalize(eyeDir + g_sunDirection); | |
| float3 sunSpec = CalculateSpecularReflection(n, H_sun, g_shininess, dot(n, g_sunDirection), g_sunColor, g_specularColor); | |
| float3 spotAccum = float3(0, 0, 0); | |
| [unroll] | |
| for (int i = 0; i < 2; ++i) | |
| { | |
| spotAccum += CalculateSpotlightReflection( | |
| n, input.worldPosition, eyeDir, | |
| diffuseColor, ambCol, | |
| g_shininess, g_specularColor, | |
| g_spotLights[i]); | |
| } | |
| const float3 finalColor = sunDiff + sunSpec + spotAccum + g_emissionColor; | |
| return float4(finalColor, diffuseColor.a); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment