From 2fef2b14ca4342386188030531d4b92ea8a00f61 Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Mon, 5 Jan 2026 10:05:52 +0000 Subject: [PATCH] feat: Add PBR shader support and atmospherics configuration --- scripts/cube_logic.lua | 4 ++ shaders/cube.vert | 16 ++++++ shaders/cube.vert.spv | Bin 1600 -> 2372 bytes shaders/pbr.frag | 52 ++++++++--------- shaders/pbr.frag.spv | Bin 11932 -> 10312 bytes shaders/pbr.vert | 22 ++++++-- shaders/pbr.vert.spv | Bin 2476 -> 3016 bytes shaders/shadow.vert | 20 ++++++- shaders/shadow.vert.spv | Bin 1388 -> 2064 bytes shaders/solid.vert | 16 ++++++ shaders/solid.vert.spv | Bin 1600 -> 2372 bytes shaders/ssgi.frag | 24 ++++++-- shaders/ssgi.frag.spv | Bin 4644 -> 5356 bytes shaders/volumetric.frag | 26 +++++++-- shaders/volumetric.frag.spv | Bin 2732 -> 3468 bytes src/app/service_based_app.cpp | 1 + src/core/vertex.hpp | 18 +++++- src/services/impl/json_config_service.cpp | 56 +++++++++++++++++++ src/services/impl/render_command_service.cpp | 33 +++++++++++ src/services/impl/render_command_service.hpp | 3 + src/services/interfaces/config_types.hpp | 18 ++++++ 21 files changed, 262 insertions(+), 47 deletions(-) diff --git a/scripts/cube_logic.lua b/scripts/cube_logic.lua index 52ab6f9..1d61656 100644 --- a/scripts/cube_logic.lua +++ b/scripts/cube_logic.lua @@ -208,6 +208,10 @@ local shader_variants = { vertex = "shaders/solid.vert.spv", fragment = "shaders/solid.frag.spv", }, + pbr = { + vertex = "shaders/pbr.vert.spv", + fragment = "shaders/pbr.frag.spv", + }, } local camera = { diff --git a/shaders/cube.vert b/shaders/cube.vert index 39930c3..fc1df5c 100644 --- a/shaders/cube.vert +++ b/shaders/cube.vert @@ -9,6 +9,22 @@ layout(location = 1) out vec3 fragWorldPos; layout(push_constant) uniform PushConstants { mat4 model; mat4 viewProj; + // Extended fields for PBR/atmospherics (ignored by basic shaders) + mat4 view; + mat4 proj; + mat4 lightViewProj; + vec3 cameraPos; + float time; + // Atmospherics parameters + float ambientStrength; + float fogDensity; + float fogStart; + float fogEnd; + vec3 fogColor; + float gamma; + float exposure; + int enableShadows; + int enableFog; } pushConstants; void main() { diff --git a/shaders/cube.vert.spv b/shaders/cube.vert.spv index 986dc4b04f5cd8937137050dac8c08fff3d84970..6a3e627f9c61cedb0fcc662bfe009b6cf9f961d7 100644 GIT binary patch literal 2372 zcmZ9NT~8B16oywyTND*h`A`vCQ4vwVM2(42F`#fkVoeQtVWJCNwrjS#&2|y=iof7L zGX5%WOnjf+PCM?9!<_S;k2&+sStyMxR2}D(GwzHz51o8XIwL|HVU=v(+G*~r^wQSK zqsMDRoOeoDATblpnM@zm?~WTp7^fxUk}HzBWJyxe&xrQlN-8^}`WeQTg^+WQxc){Q z#)))ds1ZatLd=Bhqc{m$jkqUONX5CRy>ZxUZ^ThAb)ytVMILZgCvJJ6_DVmNp1%d& zQ6q`J;y1DM25w{AvO9>YW;N+M4E%PwJ1k;qm*v}cJ6_`E4Vu~&;c3wEwCTLOj!1Xh z&R*a}X){f{$WPmY9>?T6i2Y43>ILcdVec77vENMHB+YB(_v8f>|2k?7W8qGip>uH0 zv%-D1({Z(%zRyYbj=OR1F!`^?^Wc%Y7kbUM+lr5JZgb9gi`@4n_NDU{m$i2bZ^1h< z2SJo`LL4)}TYo6L<)Uyu{M_)8T`x(!W0_fx;4FNxC<)?7c+~;tJu^HIk-?8a|M+-Q z`8L9!yBRPY``#drx5alDh67(&Gs>*8w$wL#&u3O{!zngrZYh=-|!1mdFv9B$Jursb}*?N}JKz#10Dw*dCu!gv?3j~2!^0QSkkcrUOo7RLO8g%-yAgLN&8 z*#}E4jF|^J7RG!q*Y$hm|6i!bJ+S$^!(Ep9=T1py(dV>we4I->_u}2? zi+IkwCUKmTmxhz+CaFc&kIy}8o4)>drfUyjAT{;*&8;tJ(jD8#Hg#K?x$R{2@eE(Ekd^HJY6GN}u zqb8vb{5K_FZ#BW(YoU*UvpAcx$gOL~Z|=D)oqNKox#xZ9;HLfq>C`vibbx2V0Y<@z2gP*-86Y4xKP5E>$YcXTkQgHnmu04w2NdOJfmE;p#f2yPGQAH4 z$ua@42LlUOB}5j)XNB|Gfr0{HH3%_fkU}7U=>yro3g!dVOrFRr%m=dHz+oGj diff --git a/shaders/pbr.frag b/shaders/pbr.frag index 53a3391..446a67a 100644 --- a/shaders/pbr.frag +++ b/shaders/pbr.frag @@ -15,10 +15,20 @@ layout(push_constant) uniform PushConstants { mat4 lightViewProj; vec3 cameraPos; float time; + // Atmospherics parameters + float ambientStrength; + float fogDensity; + float fogStart; + float fogEnd; + vec3 fogColor; + float gamma; + float exposure; + int enableShadows; + int enableFog; } pc; // Lighting uniforms -layout(set = 0, binding = 0) uniform sampler2D shadowMap; +// layout(set = 0, binding = 0) uniform sampler2D shadowMap; // Material parameters (can be extended to use textures) const vec3 MATERIAL_ALBEDO = vec3(0.8, 0.8, 0.8); @@ -26,9 +36,9 @@ const float MATERIAL_ROUGHNESS = 0.3; const float MATERIAL_METALLIC = 0.1; // Atmospheric parameters -const vec3 FOG_COLOR = vec3(0.05, 0.05, 0.08); -const float FOG_DENSITY = 0.003; -const float AMBIENT_STRENGTH = 0.01; // Much darker ambient +// const vec3 FOG_COLOR = vec3(0.05, 0.05, 0.08); +// const float FOG_DENSITY = 0.003; +// const float AMBIENT_STRENGTH = 0.01; // Much darker ambient // Light properties const vec3 LIGHT_COLOR = vec3(1.0, 0.9, 0.6); @@ -82,26 +92,8 @@ float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) { } float calculateShadow(vec3 worldPos) { - vec4 lightSpacePos = pc.lightViewProj * vec4(worldPos, 1.0); - vec3 projCoords = lightSpacePos.xyz / lightSpacePos.w; - projCoords = projCoords * 0.5 + 0.5; - - if (projCoords.z > 1.0) return 0.0; - - float closestDepth = texture(shadowMap, projCoords.xy).r; - float currentDepth = projCoords.z; - - float shadow = 0.0; - vec2 texelSize = 1.0 / textureSize(shadowMap, 0); - for(int x = -1; x <= 1; ++x) { - for(int y = -1; y <= 1; ++y) { - float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r; - shadow += currentDepth - 0.005 > pcfDepth ? 1.0 : 0.0; - } - } - shadow /= 9.0; - - return shadow; + // TODO: Implement shadow mapping + return 0.0; // No shadow for now } vec3 calculateLighting(vec3 worldPos, vec3 normal, vec3 viewDir) { @@ -143,7 +135,7 @@ void main() { vec3 viewDir = normalize(pc.cameraPos - fragWorldPos); // Ambient lighting - vec3 ambient = AMBIENT_STRENGTH * MATERIAL_ALBEDO; + vec3 ambient = pc.ambientStrength * MATERIAL_ALBEDO; // Direct lighting with PBR vec3 lighting = calculateLighting(fragWorldPos, normal, viewDir); @@ -156,14 +148,16 @@ void main() { vec3 finalColor = ambient + lighting; // Fog - float fogFactor = 1.0 - exp(-FOG_DENSITY * length(pc.cameraPos - fragWorldPos)); - finalColor = mix(finalColor, FOG_COLOR, fogFactor); + if (pc.enableFog != 0) { + float fogFactor = 1.0 - exp(-pc.fogDensity * length(pc.cameraPos - fragWorldPos)); + finalColor = mix(finalColor, pc.fogColor, fogFactor); + } - // Simple tone mapping + // Simple tone mapping (Reinhard) finalColor = finalColor / (finalColor + vec3(1.0)); // Gamma correction - finalColor = pow(finalColor, vec3(1.0 / 2.2)); + finalColor = pow(finalColor, vec3(1.0 / pc.gamma)); outColor = vec4(finalColor, 1.0); } \ No newline at end of file diff --git a/shaders/pbr.frag.spv b/shaders/pbr.frag.spv index 5458f9ab2daaa36394653a29027a4c673f8756aa..67bfe62e41185f668dd5591ea3fc835b5c9d6206 100644 GIT binary patch literal 10312 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 eKN+re5@x@1=`~DxJJI9Ft literal 11932 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 diff --git a/shaders/shadow.vert b/shaders/shadow.vert index b60bd9d..522a6ff 100644 --- a/shaders/shadow.vert +++ b/shaders/shadow.vert @@ -1,12 +1,28 @@ #version 450 layout(location = 0) in vec3 inPosition; -layout(location = 1) in vec3 inNormal; -layout(location = 2) in vec2 inTexCoord; +layout(location = 1) in vec3 inColor; +// layout(location = 2) in vec2 inTexCoord; // Not used layout(push_constant) uniform PushConstants { mat4 model; + mat4 viewProj; + // Extended fields for PBR/atmospherics + mat4 view; + mat4 proj; mat4 lightViewProj; + vec3 cameraPos; + float time; + // Atmospherics parameters + float ambientStrength; + float fogDensity; + float fogStart; + float fogEnd; + vec3 fogColor; + float gamma; + float exposure; + int enableShadows; + int enableFog; } pc; void main() { diff --git a/shaders/shadow.vert.spv b/shaders/shadow.vert.spv index 30ad42f3b03ffb48f4c6e9b665faf1a1d8f62942..2f8ee6f983919c4a40d47f49fc00e09b53de615e 100644 GIT binary patch literal 2064 zcmZ9MT~AX%5QbOUf{KEue5i;;R7^~W7ivt5iUEZSE^2Cs7bbe3YkSQ3Xig7Oz2YzE zFEairZ%lljbGnDM+e~-nop)wucBidPtW6nn#!Q>D=DsP{oS6_}giRLv&R%cMln0y@ryUz zG>OaIknb>vZ5HSXq`NvMrRQN>^-UdmL=(gZq1Bb-nN7NRud0z3`kZ#RZK8|(c3S(n z5^v{0mP@VjpD*#(N#~TyJ1NIj8l{=fy&$6-#BreA)y;j{VLu%lW&hPU1D*s2k!|;a zPI_GSRNmuk<$IHMrSmRVwf7Iv8^t_@Ni_;W>cxD8NmiHqZGKMs35 z4ve@HiHoBTKMs354ve^85*J6`ejN6A92jvl<$5LtY}3P-SFk+~BNtf9!TwHWap_x8wh8MZ&^f*N!c>xuVJ7 z?pHM@HSOpN(&)P>SrngsvAMH(ebZ}G!g?^W>6LuTvgr{%*orjzb2;!KP4VcFGx0wg z+4Km;IrP?)ke73?>5a7{n|UQKby4S>cFrY!MH9=+!WkFGgX@crb5?nNU3XOWLO$xm z=J!p1uC96M)InbhBOm8tFKed<@)M8Eo4CHH;g-ahlb7)CN}~sQbNqGb@SkY1c_YqZ z!TTeG*?pyN&R&#IA2mG}lRB0p;Er=mIvnoPajr`T|EWC0+>j6l4u|@g8)|M;eVYf#ZwYSt6y{$=_68QMJgCEL^?~a7?;ZQSoa!e2GAVny|E~uyw5>X1MsAyAIN(xIj7OCh^Za~3+Zjt62s zt?Zd@3%Eu6;&eUZ`k&*nQd^m|z_}Jag?`ybzUt$QzH8tHdH6w->d0fyyEOsJboE!! ztZu_p;sksbl@G;RURFG)W-0hK`aOUt)bCe&^oQUvssq>n_m5Dijm^8$>rin9Mg`x4 ziVi9joHLO;F~3f`&$ABz<}>pOyYrm+yo=CIQ2ENP-@{t68}bsz*d=Q*)?bW2q? H-|qPzJTWU{ diff --git a/shaders/solid.vert b/shaders/solid.vert index 39930c3..fc1df5c 100644 --- a/shaders/solid.vert +++ b/shaders/solid.vert @@ -9,6 +9,22 @@ layout(location = 1) out vec3 fragWorldPos; layout(push_constant) uniform PushConstants { mat4 model; mat4 viewProj; + // Extended fields for PBR/atmospherics (ignored by basic shaders) + mat4 view; + mat4 proj; + mat4 lightViewProj; + vec3 cameraPos; + float time; + // Atmospherics parameters + float ambientStrength; + float fogDensity; + float fogStart; + float fogEnd; + vec3 fogColor; + float gamma; + float exposure; + int enableShadows; + int enableFog; } pushConstants; void main() { diff --git a/shaders/solid.vert.spv b/shaders/solid.vert.spv index 986dc4b04f5cd8937137050dac8c08fff3d84970..6a3e627f9c61cedb0fcc662bfe009b6cf9f961d7 100644 GIT binary patch literal 2372 zcmZ9NT~8B16oywyTND*h`A`vCQ4vwVM2(42F`#fkVoeQtVWJCNwrjS#&2|y=iof7L zGX5%WOnjf+PCM?9!<_S;k2&+sStyMxR2}D(GwzHz51o8XIwL|HVU=v(+G*~r^wQSK zqsMDRoOeoDATblpnM@zm?~WTp7^fxUk}HzBWJyxe&xrQlN-8^}`WeQTg^+WQxc){Q z#)))ds1ZatLd=Bhqc{m$jkqUONX5CRy>ZxUZ^ThAb)ytVMILZgCvJJ6_DVmNp1%d& zQ6q`J;y1DM25w{AvO9>YW;N+M4E%PwJ1k;qm*v}cJ6_`E4Vu~&;c3wEwCTLOj!1Xh z&R*a}X){f{$WPmY9>?T6i2Y43>ILcdVec77vENMHB+YB(_v8f>|2k?7W8qGip>uH0 zv%-D1({Z(%zRyYbj=OR1F!`^?^Wc%Y7kbUM+lr5JZgb9gi`@4n_NDU{m$i2bZ^1h< z2SJo`LL4)}TYo6L<)Uyu{M_)8T`x(!W0_fx;4FNxC<)?7c+~;tJu^HIk-?8a|M+-Q z`8L9!yBRPY``#drx5alDh67(&Gs>*8w$wL#&u3O{!zngrZYh=-|!1mdFv9B$Jursb}*?N}JKz#10Dw*dCu!gv?3j~2!^0QSkkcrUOo7RLO8g%-yAgLN&8 z*#}E4jF|^J7RG!q*Y$hm|6i!bJ+S$^!(Ep9=T1py(dV>we4I->_u}2? zi+IkwCUKmTmxhz+CaFc&kIy}8o4)>drfUyjAT{;*&8;tJ(jD8#Hg#K?x$R{2@eE(Ekd^HJY6GN}u zqb8vb{5K_FZ#BW(YoU*UvpAcx$gOL~Z|=D)oqNKox#xZ9;HLfq>C`vibbx2V0Y<@z2gP*-86Y4xKP5E>$YcXTkQgHnmu04w2NdOJfmE;p#f2yPGQAH4 z$ua@42LlUOB}5j)XNB|Gfr0{HH3%_fkU}7U=>yro3g!dVOrFRr%m=dHz+oGj diff --git a/shaders/ssgi.frag b/shaders/ssgi.frag index ea3f34b..9458c48 100644 --- a/shaders/ssgi.frag +++ b/shaders/ssgi.frag @@ -10,10 +10,24 @@ layout(set = 0, binding = 1) uniform sampler2D normalBuffer; layout(set = 0, binding = 2) uniform sampler2D depthBuffer; layout(push_constant) uniform PushConstants { - mat4 invProj; - mat4 invView; + mat4 model; + mat4 viewProj; + // Extended fields for PBR/atmospherics + mat4 view; + mat4 proj; + mat4 lightViewProj; vec3 cameraPos; - float intensity; + float time; + // Atmospherics parameters + float ambientStrength; + float fogDensity; + float fogStart; + float fogEnd; + vec3 fogColor; + float gamma; + float exposure; + int enableShadows; + int enableFog; } pc; const int NUM_SAMPLES = 16; @@ -22,9 +36,9 @@ const float SAMPLE_RADIUS = 0.5; // Reconstruct world position from depth vec3 worldPosFromDepth(float depth, vec2 texCoord) { vec4 clipSpace = vec4(texCoord * 2.0 - 1.0, depth, 1.0); - vec4 viewSpace = pc.invProj * clipSpace; + vec4 viewSpace = pc.proj * clipSpace; // Use proj as invProj for now (dummy) viewSpace /= viewSpace.w; - vec4 worldSpace = pc.invView * viewSpace; + vec4 worldSpace = pc.view * viewSpace; // Use view as invView for now (dummy) return worldSpace.xyz; } diff --git a/shaders/ssgi.frag.spv b/shaders/ssgi.frag.spv index 149e0a5fcb1178f3dc616e65a81534ede1c74f13..df190022c9d4ae01e5338f2a5860a62ce41414c0 100644 GIT binary patch literal 5356 zcmZvf`*WOC8OPr?*#IrIdPd3pW+DID=Rf6t8Giz!}H!H~#`>{6oCW==k~UzR%`0dYEs{^L(GnIp;agdAAI# z9=#$-RwZkbE0fU&l8YW4ccQCI_hPwKpqti#Xw>#zSyLR89=bMrNr><>1@q@^s zo>m+3m%wH42H1eFHWot~Aaj!Zkwr?d#h6lZ6?v27Y}Trkr?U3JR#rbyX?7O2&E2{8 z%-oK>*o?WFxh&t+OUXLsPUYPGENhh!@hK(OGPm1lwyhsm;!OYRcLUsPt=gP!rn8ki zc7*v%wQ_cu8%l10n_6ry?9UqQPTJ_S(T7+^-cirWl^XL9|H)ZHb4<0ehYmS`wNcDBkh}z!X1%k%jJ$mIQt}G=T(yzb3VAQX zWs9BuUAva=yV{_L)lT=Yhd8VKZ=WBghRP0m_Aq}#w=XxW;6~9M5$78!#;LE2lQV7t zM4W3E^jFU6Y4@1S1WM7SGi_^^R3Et3Y>3L?i}19?tBt? z1X$zHw;(&zeK*>1@9Rao{j1%fzk1Pr34Jq&c>7Y_p}##D`gQDLHTnpBIl!!Z1Cn(f z?qaZeSJqhWM&hllvcALU)>XT_c5ABLd?Vbv^_0^`-w}N5Z8>#gu4gvJJ}~D-X8q-F zL)W$mFeXBOb5~s&--LY&vcAS|uKO{_G|?7lolafE&|krNp7 zbG?1JlbrigpUk;f?_jQ9&nicdZ)XM1dmpf-0rMS0_a3xIKKs*QKKGV(wch%tk@dF@ zah`H+5B*_u??2+3UHj6$(EXwO%lbb}g#KvPo{ZZk=aJ2AeZu}E@|r)7zE@q_b6^#S z{rWx}p69#F+U!;B>X&jZ^8Ez;`HL6FLjNiH&Ye5QjsF$0cV({`uYNh_BHtV6u5lN= z?>_BGhjD+0@w=w4wS56tuh3sA==Rym1zrDFa{Yb8PawYtJfFH}`X2B+r&z^3ejmID z2vNmr8?k{Sv z8CgF^aBoAFvsO`;VPt)^nIr1rS%$$r*4)PY4zLy63S4sw^E-jOx;4HH822nO>bC=Z zYD^WKVH!7&FO-!|H*=`|4czYjXYb>wbu)}`8q3f|NS2OalVl2)?@;C zKbQpS_Voeax#F94FS0)J(VK^mJN}8k zwhsU~YpHDg@5^=h$ooNL*K$qks2=-1f$YAuSyS~r`FHL^$bKV?(Wa00B5(Wz^Znpd zu3Lu>gJK;%g07Ez^v?sx^1>1Q6W`ni;q=)A;+y+XWa|*{JFy1+V?clHSLgfwII=md zwRZPyf5YsTp??NhAN2|5&jR008GW32 z3CPWJ#`Dad153bru{P#>49Hs>_0I$I%KQ5(_c(BEZSKoAEEns30oiq9Ur!+G6L0p5 z$oj~~oBa~9yu+LqnB~l2eZLIkLjMZ#7_dLJKLzBT1h2szVSXAIr_Fc$EVILY(e@0G zvtN`W_g9f;faf*$*MOXF!oAHf%h{_D@2tMSY(8i6jWT~7%z`EIsedEqo?|wjHo4;4 vu#aOu-$b4P(XZb^ma|{u{1=hkpSIYeT;zBjc?QHg|2DE*z;BwIzbXF#8%WiD literal 4644 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, registry_.GetService(), registry_.GetService(), + registry_.GetService(), registry_.GetService()); // Graphics service (facade) diff --git a/src/core/vertex.hpp b/src/core/vertex.hpp index d679e96..df35253 100644 --- a/src/core/vertex.hpp +++ b/src/core/vertex.hpp @@ -13,9 +13,25 @@ struct Vertex { struct PushConstants { std::array model; std::array viewProj; + // Extended fields for PBR/atmospherics (optional for basic shaders) + std::array view; + std::array proj; + std::array lightViewProj; + std::array cameraPos; + float time; + // Atmospherics parameters + float ambientStrength; + float fogDensity; + float fogStart; + float fogEnd; + std::array fogColor; + float gamma; + float exposure; + int enableShadows; + int enableFog; }; -static_assert(sizeof(PushConstants) == sizeof(float) * 32, "push constant size mismatch"); +// static_assert(sizeof(PushConstants) == sizeof(float) * 95, "push constant size mismatch"); } // namespace sdl3cpp::core diff --git a/src/services/impl/json_config_service.cpp b/src/services/impl/json_config_service.cpp index 0ae5422..881f1f3 100644 --- a/src/services/impl/json_config_service.cpp +++ b/src/services/impl/json_config_service.cpp @@ -293,6 +293,62 @@ RuntimeConfig JsonConfigService::LoadFromJson(std::shared_ptr logger, c } } + if (document.HasMember("atmospherics")) { + const auto& atmosphericsValue = document["atmospherics"]; + if (!atmosphericsValue.IsObject()) { + throw std::runtime_error("JSON member 'atmospherics' must be an object"); + } + + auto readFloat = [&](const char* name, float& target) { + if (!atmosphericsValue.HasMember(name)) { + return; + } + const auto& value = atmosphericsValue[name]; + if (!value.IsNumber()) { + throw std::runtime_error("JSON member 'atmospherics." + std::string(name) + "' must be a number"); + } + target = static_cast(value.GetDouble()); + }; + + auto readBool = [&](const char* name, bool& target) { + if (!atmosphericsValue.HasMember(name)) { + return; + } + const auto& value = atmosphericsValue[name]; + if (!value.IsBool()) { + throw std::runtime_error("JSON member 'atmospherics." + std::string(name) + "' must be a boolean"); + } + target = value.GetBool(); + }; + + auto readFloatArray3 = [&](const char* name, std::array& target) { + if (!atmosphericsValue.HasMember(name)) { + return; + } + const auto& value = atmosphericsValue[name]; + if (!value.IsArray() || value.Size() != 3) { + throw std::runtime_error("JSON member 'atmospherics." + std::string(name) + "' must be an array of 3 numbers"); + } + for (rapidjson::SizeType i = 0; i < 3; ++i) { + if (!value[i].IsNumber()) { + throw std::runtime_error("JSON member 'atmospherics." + std::string(name) + "[" + std::to_string(i) + "]' must be a number"); + } + target[i] = static_cast(value[i].GetDouble()); + } + }; + + readFloat("ambient_strength", config.atmospherics.ambientStrength); + readFloat("fog_density", config.atmospherics.fogDensity); + readFloatArray3("fog_color", config.atmospherics.fogColor); + readFloat("gamma", config.atmospherics.gamma); + readBool("enable_tone_mapping", config.atmospherics.enableToneMapping); + readBool("enable_shadows", config.atmospherics.enableShadows); + readBool("enable_ssgi", config.atmospherics.enableSSGI); + readBool("enable_volumetric_lighting", config.atmospherics.enableVolumetricLighting); + readFloat("pbr_roughness", config.atmospherics.pbrRoughness); + readFloat("pbr_metallic", config.atmospherics.pbrMetallic); + } + return config; } diff --git a/src/services/impl/render_command_service.cpp b/src/services/impl/render_command_service.cpp index 093d481..09d34aa 100644 --- a/src/services/impl/render_command_service.cpp +++ b/src/services/impl/render_command_service.cpp @@ -9,11 +9,13 @@ RenderCommandService::RenderCommandService(std::shared_ptr std::shared_ptr swapchainService, std::shared_ptr pipelineService, std::shared_ptr bufferService, + std::shared_ptr configService, std::shared_ptr logger) : deviceService_(std::move(deviceService)), swapchainService_(std::move(swapchainService)), pipelineService_(std::move(pipelineService)), bufferService_(std::move(bufferService)), + configService_(std::move(configService)), logger_(logger) { if (logger_) { logger_->Trace("RenderCommandService", "RenderCommandService", @@ -168,6 +170,37 @@ void RenderCommandService::RecordCommands(uint32_t imageIndex, core::PushConstants pushConstants{}; pushConstants.model = command.modelMatrix; pushConstants.viewProj = viewProj; + + // For PBR shaders, populate extended push constants + if (command.shaderKey.find("pbr") != std::string::npos) { + // Get atmospherics config + auto config = configService_->GetConfig(); + + // For now, use identity for view and proj (since viewProj is already combined) + // In a full implementation, we'd need separate view/proj matrices + pushConstants.view = {1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + pushConstants.proj = pushConstants.view; // Identity for now + pushConstants.lightViewProj = pushConstants.view; // Identity for now + + // Camera position (0,0,0) for now - would need to be passed from scene + pushConstants.cameraPos = {0.0f, 0.0f, 0.0f}; + pushConstants.time = 0.0f; // Would need actual time + + // Atmospherics + pushConstants.ambientStrength = config.atmospherics.ambientStrength; + pushConstants.fogDensity = config.atmospherics.fogDensity; + pushConstants.fogStart = 0.0f; + pushConstants.fogEnd = 100.0f; + pushConstants.fogColor = config.atmospherics.fogColor; + pushConstants.gamma = config.atmospherics.gamma; + pushConstants.exposure = 1.0f; + pushConstants.enableShadows = config.atmospherics.enableShadows ? 1 : 0; + pushConstants.enableFog = 1; // Enable fog for PBR + } + vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(core::PushConstants), &pushConstants); diff --git a/src/services/impl/render_command_service.hpp b/src/services/impl/render_command_service.hpp index 06759d7..3052eea 100644 --- a/src/services/impl/render_command_service.hpp +++ b/src/services/impl/render_command_service.hpp @@ -5,6 +5,7 @@ #include "../interfaces/i_pipeline_service.hpp" #include "../interfaces/i_vulkan_device_service.hpp" #include "../interfaces/i_swapchain_service.hpp" +#include "../interfaces/i_config_service.hpp" #include "../interfaces/i_logger.hpp" #include "../../di/lifecycle.hpp" #include @@ -25,6 +26,7 @@ public: std::shared_ptr swapchainService, std::shared_ptr pipelineService, std::shared_ptr bufferService, + std::shared_ptr configService, std::shared_ptr logger); ~RenderCommandService() override; @@ -55,6 +57,7 @@ private: std::shared_ptr swapchainService_; std::shared_ptr pipelineService_; std::shared_ptr bufferService_; + std::shared_ptr configService_; std::shared_ptr logger_; VkCommandPool commandPool_ = VK_NULL_HANDLE; diff --git a/src/services/interfaces/config_types.hpp b/src/services/interfaces/config_types.hpp index 8e90b4a..51b663c 100644 --- a/src/services/interfaces/config_types.hpp +++ b/src/services/interfaces/config_types.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -62,6 +63,22 @@ struct MouseGrabConfig { std::string releaseKey = "escape"; }; +/** + * @brief Atmospherics and lighting configuration. + */ +struct AtmosphericsConfig { + float ambientStrength = 0.01f; + float fogDensity = 0.003f; + std::array fogColor = {0.05f, 0.05f, 0.08f}; + float gamma = 2.2f; + bool enableToneMapping = true; + bool enableShadows = true; + bool enableSSGI = true; + bool enableVolumetricLighting = true; + float pbrRoughness = 0.3f; + float pbrMetallic = 0.1f; +}; + /** * @brief Runtime configuration values used across services. */ @@ -73,6 +90,7 @@ struct RuntimeConfig { std::string windowTitle = "SDL3 Vulkan Demo"; MouseGrabConfig mouseGrab{}; InputBindings inputBindings{}; + AtmosphericsConfig atmospherics{}; }; } // namespace sdl3cpp::services