From 748864b6566420105eb3201b4ec385e30c5e2303 Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Mon, 5 Jan 2026 21:21:54 +0000 Subject: [PATCH] feat: Implement normal computation and enhance lighting for floor, ceiling, cube, and wall shaders --- shaders/ceiling.frag | 14 +++++++++++++- shaders/ceiling.frag.spv | Bin 4044 -> 4964 bytes shaders/cube.frag | 23 +++++++++++++++++++++-- shaders/cube.frag.spv | Bin 3488 -> 5016 bytes shaders/floor.frag | 14 +++++++++++++- shaders/floor.frag.spv | Bin 4104 -> 5024 bytes shaders/wall.frag | 14 +++++++++++++- shaders/wall.frag.spv | Bin 4392 -> 5328 bytes 8 files changed, 60 insertions(+), 5 deletions(-) diff --git a/shaders/ceiling.frag b/shaders/ceiling.frag index befc15c..2123bdd 100644 --- a/shaders/ceiling.frag +++ b/shaders/ceiling.frag @@ -10,6 +10,12 @@ float hash(vec2 p) { const vec3 SURFACE_BASE = vec3(0.98, 0.96, 0.1); +vec3 ComputeNormal() { + vec3 dx = dFdx(fragWorldPos); + vec3 dy = dFdy(fragWorldPos); + return normalize(cross(dx, dy)); +} + const vec3 LIGHT_POSITIONS[8] = vec3[8]( vec3(13.0, 4.5, 13.0), vec3(-13.0, 4.5, 13.0), @@ -41,6 +47,7 @@ void main() { baseColor *= mix(0.94, 1.04, speckle); baseColor *= mix(1.0, 0.84, gridLine); + vec3 normal = ComputeNormal(); vec3 ambient = AMBIENT_STRENGTH * baseColor; vec3 lighting = vec3(0.0); @@ -49,9 +56,14 @@ void main() { float distance = length(lightDir); lightDir = normalize(lightDir); float attenuation = calculateAttenuation(distance); - lighting += LIGHT_COLOR * LIGHT_INTENSITY * attenuation; + float ndotl = abs(dot(normal, lightDir)); + lighting += LIGHT_COLOR * LIGHT_INTENSITY * attenuation * ndotl; } + vec3 keyDir = normalize(vec3(-0.15, 1.0, 0.25)); + float keyNdotL = abs(dot(normal, keyDir)); + lighting += vec3(0.85, 0.95, 1.0) * keyNdotL * 0.28; + vec3 finalColor = ambient + baseColor * lighting; finalColor = clamp(finalColor, 0.0, 1.0); diff --git a/shaders/ceiling.frag.spv b/shaders/ceiling.frag.spv index 56b23b6edd7d86822ea789870bcc7811cba56dc4..d2600fb6d80a489d215d8f896264482b45b4a083 100644 GIT binary patch literal 4964 zcmZ9OX>e6{8O9HUge4Tp($*?P(xRj-GNqKZ$Pfad1r=$qR;;4tCb>7ca&vD?ZV+l! z5Yei&X)P{PMWwEFZAAr_F0tZ9E!L$jpZs7yIeu_PN1f5}_d7Z7%`s=@nfHC3clod9 z+}kwsirGmrBWX?MB!5gMpGC<`lmx9MwcB^zx^vBFy?@Ph>#s3mLDG~anzN9)Sy(Yt zC|3=v1kZrqfeXns#vpi2bWV~93Y$^$HO(lk#0CqagYElE*KWjbCVw7wIQ3f?D@nR) zL&IbB;;!1rP@&Rp&fH`vdS9W^H&!Xsi(BgTVs)%gFW0K=rM0#pr#V@I?Jtkk3)Q~j zq}G&Nu6Dq9OFHM$NMT@4ZKTrQT^o&@RpuO=?9qYWTNo{N)he|SeAm#09T+M1-?o2} z@5nfYcyn?~#&?#h*|@Wk*P)FL7yI^AifNA?_;6vQFodT1 zJL5ToxSjsqr{%!=Cbv%RBey2_5^k7xtS!B5N$OvW--5ORTtdEgQEuJ}_#CX7XoJti z8do>}f{c6X?YjW0X6+(u^s{y`+*j;&S&$E$Y)3H9537_*!Cr*?oFb@b&Q8;-&`Q4BzpmI~w_& z@bQVU2HygI>fE_at67or*b1!a1jeH8&G@C#a~;870q1G->4uC?{JrBM=Diz#1@JLn z{;HHs@!R0}b-f{tcXmeqUih;Q4mbMu!A~zg+TermP4o6NxZje!;}ebf)!{y|t}%SI zfb-HUg#e{i+bas-<`|P>mNjSFQ)goC#UE0$I+v| zbg%35#ICX?gsx7 z{DI@QZ;m-U1h>XKWA^dv9s!x1tOU0(f@9p2Y3e@i{XN;Ye>=YMn}NODXEl3S`!b+5pIae+IhXvf(5&`MWADQN zP_xed#?+#J8Q*nB|2N}DfA?n)m=pc?;ph8T;A+-If3*$SeXQay%wj`WdGvZqs!z>z z1gP?C7rJ8+xC;ffY_kBDF{>2I0f%W^L{Rd;-iG4fpG5!v$ajoO-$G#KT<6-vb zF!o)Ub_n}#a^!CV_Oez#YCnW;t@H4`zYlmX+pr%7YUacmKa%OeKMMCw`JQ+_9|Pv7 z+w(}KMg9YDHSd(?|8d~?Yz4-wIgVA2norxz>8`%frAkKSaI!o0;|q z)_P-V`TOYIF?I@j8pK?_i=W@C@4?N9z4|`BIqI=jKfsT@GH%~9SoPS4$MMx-AD+N} z3_PCGeu%F=0b)K+;^+6~M{qTBV{g_2q45%?dd1>OpL=7Jl@^LJt% z@czxmI>*`Ai!(j$$n!JpQf%Cj7vMWT*KgeYcZ|z`v1K4~m*bo3SjPX$cxo{>dn^P# z3xM;v5F7u`F2{FX!B=HG_Vh*YmEdXSZ?6{vHTS|=dE~a^n|nUXy%Jx|T>Hu+_bPnr zgL}T__`B{ntAXp<2Fx|?nvJ~#7`q9W=bF`G&F$v7!o9VH~ z>)>lM-8*j1b-?pC7IoL-+b`;Fz+Vs4Bj-l^e9i{AdFs*orTF$Yc2_puMtsLJ=Gx@0 F?SIP)+X?^x literal 4044 zcmZ9ONpMtU6onrojX(fJ1cwp`PEZO_5C_CS0xGB|K|sU-=nS2-gzlJh5D^tb6bHZo z2XI1B#94Q2WsPgsE_7wN(^9Ln{J!pYn^$>Nr|v!H4*&RGcf;t*&qoCM#1^T;*EAb1UQ zPLk6U=1{XWIg}=1efgojIok^h7USp0ACDcV`s3)8BwhLbuHpWCrKi18=_w88E5&kY zPGP?3RuB+P^Wm8*ONyr)z6}54{?bHSmG_V164`z6qP()>-T+ zRp7a#6W(9!?W+_^y|^e1iB7TV=Mv{wjo(((t=8o>zIe5?fRq)AMsrLR>*F&vpjz?B&+UedN{zpTcQ- z-m|JFpH%&6_+!wT!G+{|FXZMm!^dLP#4PwYtZ{YY6R}Zad{P=$zXopZ6i_JaS{D2Q z`LENL&t+BCPEB*vBj+OgSAM^GMeynHB-y<*xNG`t&8gPlm%+>DH?+EjYw#V{x57Ej z#X639FoV0>}PJ&&4JTl-D$ zLgCjXG48E!p87cLkVB{cSTdFRW%$j&$9(znDm%;XfM@&PTaCB1MgO(%pN%ta znz66WH^N)TZ>aOl@P`kbuFtOv?i1_o##akCPw#s(a31bM0qg#%I}dFi@CjbV_s(3v z&GP#Z>+{7{zm&R4Rp;GJ$vqeviY+G0#|>)lq!U)_3Uy)^qT; z!ErysHUM?+y!>RU#XIl~-1<0+Z}DgD+gcy@JGh$flJE76dY^?TFGTK%@%02YGPWSDbfs;T?9cL&pN>CO1Y{qESyeNwZRwYLDZ z37l$e{eq&?39r%tj78rL7?~?i=*6Td)15H5PxOY!2*0mmAZ311)zaQAM1*`?@fH^Ve z4fx&(&)EC$08q2e{>Idz|AY8#Ao@RqAN_sbHUe{^|HJs%{*S=btc(6?k-r5$o1cfP zZ3gE1E~)8vV!Knn7uyH^W|#eMPuG&3>$U)Vz!zHIDHLu*SP?EXGl{#=eJueT?}{k;grJ75_Y-Zu|gN zEo$GySBrb~7XD$N9&>sd-!t5kuKOK)HFNE0OwBX%{M>h~^`6-g;J)vsUjA;X9mQI2 zOf7pSw!&ll_wl_?!9T#Cm*F4cJBNMg{Ep$9qaJhq2;V-(fMdRgRg0b<m1L)o}cQ6)4FM?HWeH9 z`9gf>HxU?j{~hCEVC*6gxtHLZ>sZGBV?4F&+`OkglYn!x@43LaO~yJm`_D}E7_S*V zBh@``b7leeq8UWp<@olCx-0N61L~1;C4M&ND!6&-(R((&{f+HU$D4!ic*b0t+_n7= DKv83C diff --git a/shaders/cube.frag b/shaders/cube.frag index eff525e..7dd61a4 100644 --- a/shaders/cube.frag +++ b/shaders/cube.frag @@ -4,6 +4,12 @@ layout(location = 0) in vec3 fragColor; layout(location = 1) in vec3 fragWorldPos; layout(location = 0) out vec4 outColor; +vec3 ComputeNormal() { + vec3 dx = dFdx(fragWorldPos); + vec3 dy = dFdy(fragWorldPos); + return normalize(cross(dx, dy)); +} + vec3 RainbowBand(float t) { t = fract(t); float scaled = t * 5.0; @@ -43,6 +49,19 @@ void main() { float bandPos = fragWorldPos.y * 0.35; float diagonal = (fragWorldPos.x + fragWorldPos.z) * 0.25; vec3 rainbow = RainbowBand(bandPos + diagonal); - vec3 shaded = mix(rainbow, fragColor, 0.08); - outColor = vec4(shaded, 1.0); + vec3 baseColor = mix(rainbow, fragColor, 0.08); + + vec3 normal = ComputeNormal(); + vec3 lighting = vec3(0.0); + + vec3 keyDir = normalize(vec3(-0.35, 1.0, -0.25)); + vec3 fillDir = normalize(vec3(0.45, 0.6, 0.2)); + float keyNdotL = abs(dot(normal, keyDir)); + float fillNdotL = abs(dot(normal, fillDir)); + + lighting += vec3(1.0, 0.92, 0.85) * keyNdotL * 0.9; + lighting += vec3(0.35, 0.45, 0.65) * fillNdotL * 0.4; + + vec3 finalColor = baseColor * (0.28 + lighting); + outColor = vec4(clamp(finalColor, 0.0, 1.0), 1.0); } diff --git a/shaders/cube.frag.spv b/shaders/cube.frag.spv index e4a4aa47d80e07c5d194c083c915679cb5a12adb..47301f4eecab609f594fa6ea15a7af583e77f5ad 100644 GIT binary patch literal 5016 zcmZ9NYm}8`6~|wg8AKSl1Y)<9gCs&@Q;G_NGu(v~Xi$sDu{z_N8BUxzXFM|#QY!-$ zEla11R$37zQfZ-O7rT+7r4@#Bqxx1K>Wg3P;##%({oZ-^>$}c7>%aE@zxRIj-tY4~ z=be_Ri_S=rDap)adh(ZK@|l}V#gpKhmfB5QuG!KxIyTUC$)#^KV^-3VCYm#wb*)%2 zT&mOz%mbeXr@$O?jnM?wLggem&cZgl#Wij8I+NJ?`tZp3Sb1B$Ff0ElH_V? z_t*EVE7b;;3|_Pfe@k)}{xKk*iygRWGT;7#jndGLdZRkfTOUQHISb6$D{oB}!bfi? zRm%gD`T}&NHc+NS8t=sRSIafR>Dn%AgJjn(gV!6S+E95icLjQHxmvC7nben~hZ^Ow zn_>Q1Y=3o}>`8qEc4WLUQcc&lBv+wJX{;sLitSH%YjU%k7xop}_`4lFP$>=7Yo#hQ ztv!KlOzuspKZ_nIHA=&2ye+vG+g}T9Yr~tEHQ6-L~W)x>_09 zHCCw&LDSj~V0V}IZm3Ym_d0?etW>KyT=U3eeA_^MYzs8?J(lH!)4bmW8W z3|5a$$nP)84b;Dr?$wt~a2WXLY>CMzm|pGZu9=!I$>U&iijhC&|9N&f8PHCa-fP z+BN1GvySJ~3p~I1+^+2f|4z7fFY-!o?^x&xytSZjgtr0j#YeFnz{h;`K42g3$^MLc zpNwm71Iv~@p3ZOn9l$5n-wAh~xR?HJtQYI=gU>kqV0Y-RpnYN=55e^XBJZpCt~+@6 zSm+1Q*LUvD_x13kJ{ENzLc7L1W3ldQ@PAb1=j*_BGS!RoI!~cJ z1M{8)QRf->^CwQ^>wbk^+BebTx923>vug#O>kC-#h%7p#K0l>I0eYHf#^O;5+M!8XtpO;|>rtJ`UF(IiG-=<8LBzJ_*;q zKkIWB+;#e+_uX*)n}NOEUwu*IQ*h@A{b{&4QS&o!bM(93{nxjWp6>HKU>4AC-1E|B zJ>#DP`a*vJ?(evloiTnt@OK<&=f9c$FM=tc3s}Q-=GwzEH@-6K@n!g#S=@P``EU{X<}{yR$R+5!`Qr{_y<-uHSD$%=1&Yd*a!;$H#y^ zb7Q~sMW5qvdq>Tu;ZFhm;rlsU|1%)^`~qI=^DJ7QxzR^oxTLDYv8UA{aUy= z?M&l5uLJJi24Jpn@4m6u17jP3dH>^`^cCNE7TTvBET{iW>{-C~pN)stiOcMtSM{t~#p=&=-T5ATn$8nc{_eG@Qd4fjnQH7G5jJuz!GVWfk$@p5V=kHqg@Je8B&uR;>o-y}R9kFe2>l@pORU7kt z-T{1%hxy%X$6lTJda?f^|5~ii%j6ro2J8UdDS7mGCp>!CUmdY`!F{Lbul^6~t!*9a z#XRqZ7w35oTHj9KJbhRn=P`C2cptEiJbGRakDkt>j@WzQ?rY4Wb{=b6$9gf(`{BiT z`qBDIzd;a$fM^lJbF5hI$|}r_bcX6JCC)kW4)MX1nxYKX7{H7*LNduo-wSC^B5Zi z`m7_5p5yT7={)L)eXtPo{;HiP>S&AeIcIVI+(&hsuU366);YA%YY*K1p>KlQQ#}p4 h7j%O7U-+TSr(eYX!VklzfG%K7>zM0z+nC?&{{tV@>XHBe literal 3488 zcmZ9NNpnECR5U0cjySKa zl9dZwxN(gOe*$awZgHSW%jda$PuH#7s#E8E&wS7K-R`ED%Wp|(Mw**ur|(kzS(s*G zN!Vs(x_|$n{aq8MhPyU*Z!lthYRUqQX(O*0t(+{4j_If(mypZI0%G;i1k^<3l&+E3 zg0+~_La({_4pL*NdU{W3Y5MC3?CgEF29-k??4Y# z%44{*+$=Y}& z%Wp~#!%La3DeXiLWw<$=6!QWD)d}j%%Jy-*RvI~6tyMB(7T1z!n}$bABh|4|1(@}m zLf7g$$oP5qc&S#hrZZhcPn;+X*WbS-+q1RzRx8z77SodLy*ha+OsStd&*WajGn0Eh zav!;86?_q=U*oz?KG{iR0#HE{Ec(-(Q` zz^&JpH~KvYzcSv_sM7^+zxrFF&U&~x#_5YX8^M>aO*ZO0l<^x4z6s7ez40EK;pP~p zFY0UouO4h`^xq0kX{u3YTgLkub+*IJF;1U#JhxuN^K9qF^r6GP5A1ykJ^=Qf1U~|9 zF7Tt^7Q}nuw`fhzb4Sj-%i6q0>-8Ucy!W4ht?B&s`yB1NX*XZ)w-xVe?3YMNQ@vYwOZ%AXW6a-J ze0OvG9!?_a;QnR=_ZyiiaP8*{T>r(K@20A|m_Xd0JL;i_^Z47U{Q@!aH*%YM+Qn4P zpe<^g0b9epMUA(>+9T#2urcm3V$OoKpUeBa3pP)C^nMSl-MeLP-&b4II0tr~;O~Qt ziJBi|I3?}oyAN&K>FFK1fcQV7UH=qXoAva6h)fmuM_|u?fX(Rt1o8Ys=3&+TDdHXR z`?Q96#@fR(&>ua%0Bbvt@8K)3HlMJ44c2DOuzi!;yfXvb0`J(ji226r_iowKJE!ko zDr`f%YtHGr`^-VM66c+1MZ9HPv8zSs+Yx=%aBuRcaVNM~<1Tp2sm~mDt6l6~J9F$#SLE1zuF0{xT%Tk2 zxH-q}a64jeXWW5U&${kY9=;y1_4T=1xjx@#7vg*T$Q|lK??$xwd;b^ld(l2OiPyIW zc?|JRiKE9O;OJq0dH5a$`%ckc{tx-qwvP2;o_=s~p2y+Z_94#mB-+P$^gV$*jaWw< zJ@a+d9^Zd0quO&rkXNDS@>eMV#jt+Q)hH4I$dBBaWWK;OOZ*^6-@lKJTyGd7_TG zIG=MC_vaqvalUH#UbJ(lqt|h;{ezEy>)%ZM|MUdhZ#e!lM#0)b;y>dxY%`E9#G2MI L_CNaR^LP7y6FVR| diff --git a/shaders/floor.frag b/shaders/floor.frag index 7fd4c2a..7c74dd4 100644 --- a/shaders/floor.frag +++ b/shaders/floor.frag @@ -10,6 +10,12 @@ float hash(vec2 p) { const vec3 SURFACE_BASE = vec3(0.02, 0.95, 0.72); +vec3 ComputeNormal() { + vec3 dx = dFdx(fragWorldPos); + vec3 dy = dFdy(fragWorldPos); + return normalize(cross(dx, dy)); +} + const vec3 LIGHT_POSITIONS[8] = vec3[8]( vec3(13.0, 4.5, 13.0), vec3(-13.0, 4.5, 13.0), @@ -42,6 +48,7 @@ void main() { float pattern = mix(0.82, 1.08, checker) * mix(0.96, 1.04, grit); baseColor *= pattern; + vec3 normal = ComputeNormal(); vec3 ambient = AMBIENT_STRENGTH * baseColor; vec3 lighting = vec3(0.0); @@ -50,9 +57,14 @@ void main() { float distance = length(lightDir); lightDir = normalize(lightDir); float attenuation = calculateAttenuation(distance); - lighting += LIGHT_COLOR * LIGHT_INTENSITY * attenuation; + float ndotl = abs(dot(normal, lightDir)); + lighting += LIGHT_COLOR * LIGHT_INTENSITY * attenuation * ndotl; } + vec3 keyDir = normalize(vec3(-0.3, 1.0, -0.4)); + float keyNdotL = abs(dot(normal, keyDir)); + lighting += vec3(0.9, 0.95, 1.0) * keyNdotL * 0.25; + vec3 finalColor = ambient + baseColor * lighting; finalColor = clamp(finalColor, 0.0, 1.0); diff --git a/shaders/floor.frag.spv b/shaders/floor.frag.spv index ad261680d1395a210ca8ec156ea5697392129fd5..9a9c3cac268b22f07765a594168c87b9417b85d6 100644 GIT binary patch literal 5024 zcmZ9O`*U1%8O9GywzN%X=>-t2wSg)XN{12(t+i>|wA4#&6RU!EHpwPgve^yE23t^U z!C*lIR76{}qOH~|iWi6q1&X2~2r7bj`3q$H(Gh24{CrN%yFKR2yz@TK^IpE!b9S3% zoqKAMoRYL8bCSO&)6c?W7D|FPJN4Ul?B20@yxzb1lC>9^F+XWa6U|vbT{B)ADVD1S zR$$L#f5T2E*BFCZP5vv5{hBr8#qxCFp&{O5a4KSTAj^*GtujV!d3et{hln8*&QCVtjvjyk4yKm8P|( zqI?814V} ztB@Q)b1K>PlGU6XMa$3k7`)nFt5@*Gr|`q2z3FK7eR!JhBxMH>rI0*{A1GIgm26|x zyg#*xdTe!?=Y8^wLflS&@7glVyC}C#?jyG*_+oCK_pdFziAjpj1kXlWj-5rm_f&4) za`+s)n$`xNi#M)r{%INajj->0yqdKO@zKxPMR04?FMx~B!rI$k*%JI!@Ix=&)3u5f zTYGkvqaHa+!MFYM{Oyj>1~xCoJQsXQ#y1d`yGLqKpT5M&zD>c`5PPX-YGd%V@Y-ag)_-wc1LXWgb%tjKw6!K~@Tj78m6@Y7GVHtH^i^K3eUd2RuOPw+{w_h|{MxjEBa z|1Fuml)78N?yXwP=TqP$>E0atwv^x58T0!z+#Gd%6@y=<`$XuHIXY2mcv-^~?Q@zCVXQ za^Zu=V=WKCtufD7)SUni3=A~Je;lsXi8+tRdjgy!`#SvAJO}drH)F2zPk6sO>b~o8 zzkh1+?)&|7{+IGS@m;aj$DDto6!7M@;X5$*O}-G{HG}(`mXCMO;8)Jz{woVXWNuszLleBUXx=vM=)#h#3Uy_>GvJ-P-{GtYWs zYU{H-90xDRV!og9=yh$XpX~J!xY|UjHzmHmYWCfOzb?bRw>Mxfa{?d7`yJB%i!t}( zZ^V3z--I`=ciijopTO*KKWn%d|H(|7#Q%pJ`992E){3L{3t(%Vli!ECG2e$a{2@%u zoLJ*MnI8O0@D-SM)BXE0W{$c&4`f>8e+8}<_x4_}=eY$lX3b&zy;#(I6&y8=@iokv zZJ4nbN8K9l)z>lm7(1HrxTD{IFTvD}AHl1|c;5tjw!yyzcKo|oqrJb4nWG--_zu`P zHDku@dkn80bNW8mvEr`%0DK>&9y#}et&5x=g3VKp`TPj%{n?-G`H#VB<~pu1HSdde z$1~Sk?|u0R=9%xKUjAUFJ%G2~m|Ffm?$2UV_=m8V%W-giuO5M$6MOY2*c|oPtH;2x zSC4`n^I^Pt?87g>YOxQ$1V4_chxRM5`V&~p=hxu;-uwoxW^U|_TIBy0?0XsfsWk5- ze;RH-zc1ds-(lvc$NoP9wvRE#coMG`J)Z@ub#r^{@q27<&O-kK+C@3@n`izXG56~N z%wE=;8)F%dv0eZ>R!??U{|r|13GGF&nmt4NOQy}jck{J>4*yrodh?AtH^+P)Z|uKx zScmyv%J-rL^O=iXM&2C!Jk0yoig%8u;?KM9n1JDjHecJv&RC=XFle9PRGapymP?LEBJXCk3D@odw|l~=J~TAMO{ROt&A9~g{EbE3rC|F--DTjln0n-_1Lt$r!_8BV W-fsfi-`Ig{ybWN-Gv?aluI+y~xZ&*p literal 4104 zcmZ9N*K-wh6vr1*fFvTQfI0#}EQ}PDpr8;SpkhHyM8$&2CAmqignKc$5$qsFP-y}d zz=B;73;N=#JnOUL-yq|oqt58~`E2&Yo$Sn+bH3kGe`R-T#?Bs>Bx91sWPI{{GW<+V z#=<0U^{HO7cHP|xIh>1x}8feV9zF4=x=I7pLb!_K<)+CGMw_B?| zT}O9+p=W)izptykGJp%dCTTO~Y30 z7i{eLNK4DVs{&sDKKASJ)$>@Dxl^(j`G~m?d++a8tqD9GoFqF|1a?hlJAP;ld?~nc zUQMfOn2T*+*XWG%(Dsp!_yyPvzkIYT@YUd!mVuG_zI10hmaLdZCG)OD%rQ=1;c(hPfEa#O%d(9MXC^~5)%Xn5`$v5j>t;a`RA*+l;iZ2GSZ zydFICTgS*e4}hO&eRTvs3_fsXa0G7v|1e`{1b2at9X+}{>h*$sVjp}bo>4^}OHSRdaoe`4grNZLII*e8joMelr%1 z!iz@Xwo%xBK|bGqL16FKy*X@s{{`W$8ioD# z=lh??@N#x%KDOT(ZTG=%OB=g&BYG*a81ehi%3gUU%Mkg%t=Q%bk)wY(VvKwfjNA&u zvuQx|H!+R;N<`joo8K_woWuQJiNqYMv7KWT5`AyNmJfV0c7Bdqz{beO9BZ&+4*fC5 ztr;J480Q?GyT0ggJGQe0z60BsUD?{#VjCkLJ@3S}r}t66b-h3G)|rdG8*zPivoD@g zd&bH8c%S#vL*G4!e!s!?kXwh?!@H;79^OIu8?xE%!)`?6^?PUKVl5A1J697`Je!9Q zYx@6LkN8bDCgLB#wnoH1iXHI}V{br=iF@%Fwl$5jzwd-x)Z2(H7kg5`_HMdv_h=I$ zw-GU4pIpQjvGeiWV7V^Dc;7iW?H;uM6m8$NEy!Q&avANnLj4D4vlaaW;-kMGtzT{5 z$I%0bHBK|9|CA>)u8RJf7;y!$mbu!I`!cq<&fz;fgm~xYpO&jvRZuj+o=l2 z;S9$;d;>fQk=K6+Ef={*vE}02k74`IkdK*;V|#`>vvt3NEoZDX^~rf=o}c@!Hs3RQ z7jfTrkS~5eSUzd$@EZEKltZ1mC}y}rUefpjph=l3-t=M&sF z*mBkk?%RwTi*DyjbP|0UG2eLo&SuY3Xnp@sVF}`Y+Fp%_&je&KapTbqh-cP>cE)k& z^D_QOmNzxyrl8|KPs4V;a}fRU?YRhB--SrTUW{$5z4ZS}Ke_yD-cz56h_hMuT*TQX zqn*t)%*^=c*9@MK@t(Iavk>>98Hv2v*w%}@%djs+VB_SY_LbPy*S9C@ OHwW8(`dpjXwfzUU9BH}$ diff --git a/shaders/wall.frag b/shaders/wall.frag index 8de4928..92a9e0b 100644 --- a/shaders/wall.frag +++ b/shaders/wall.frag @@ -10,6 +10,12 @@ float hash(vec2 p) { const vec3 SURFACE_BASE = vec3(0.98, 0.18, 0.08); +vec3 ComputeNormal() { + vec3 dx = dFdx(fragWorldPos); + vec3 dy = dFdy(fragWorldPos); + return normalize(cross(dx, dy)); +} + const vec3 LIGHT_POSITIONS[8] = vec3[8]( vec3(13.0, 4.5, 13.0), vec3(-13.0, 4.5, 13.0), @@ -43,6 +49,7 @@ void main() { baseColor *= mix(0.92, 1.05, grain); baseColor *= mix(1.0, 0.78, groove); + vec3 normal = ComputeNormal(); vec3 ambient = AMBIENT_STRENGTH * baseColor; vec3 lighting = vec3(0.0); @@ -51,9 +58,14 @@ void main() { float distance = length(lightDir); lightDir = normalize(lightDir); float attenuation = calculateAttenuation(distance); - lighting += LIGHT_COLOR * LIGHT_INTENSITY * attenuation; + float ndotl = abs(dot(normal, lightDir)); + lighting += LIGHT_COLOR * LIGHT_INTENSITY * attenuation * ndotl; } + vec3 keyDir = normalize(vec3(0.35, 0.9, 0.2)); + float keyNdotL = abs(dot(normal, keyDir)); + lighting += vec3(1.0, 0.9, 0.8) * keyNdotL * 0.2; + vec3 finalColor = ambient + baseColor * lighting; finalColor = clamp(finalColor, 0.0, 1.0); diff --git a/shaders/wall.frag.spv b/shaders/wall.frag.spv index 6a9108c6ae1a00066d6911a4df36e2285193491d..8ff5e0b4d52a1ac908659841dcc1273b02778440 100644 GIT binary patch literal 5328 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 literal 4392 zcmZ9OYj9NM8OIMK0U?N@pyCt>UYT;KfC_2@0WZOdHjyg5%Sp1EtZa5M*&yDbHrA>Y zYrO@>MkKLR3^XQc%!)bMRs+u-R zTN{m1Z7OY4>a~^Sb*7Ww#XLzeQkiU|wc%1|YjB3r$YEey+3mEdf=yE z)x-+;Jgjkb#P02 zm%)?dz?R@X)8~Wl^#(s5UO%Iw*JoIT@4CJ{&bS)uI_i8vOIYO`9X` z3poEDM|)S($+~sG8uN_VcLR17Fn)E;JrA`d@XN71z@L5PSAf{tjris|Ys9k`Ea&Rm z!Ka^m(wggLIKS51w?LLpf7Xicf*+ol$>Of}9nhSyc^2P?^XrS}9D*#L-qY$g3@?`- zZt*er;^X}-UV|U{c&fEt_Clb=KKUZ61>A=Qyazak`!%=a+d9CdBv{RE%7k0S38m|En8{!_H5 zHy-+@ns?!4_=XLWt+RavzO?hU7Jn5!{n?@|F~d>#%fLKiaaOP6&jP-C?_#~ToxpYf zgzW(8z9VwKQEKtd_>HnY&f>*z&vAD@Ew_rbxnWv{trqQ z)-`ZkDidlTIJg9Yx{ zJyqb&|6CjQ?@ZJiKT_cKJC^g!?9Lkebzmzyv=O@r_}%i`)XV;OepdqZ1u*$lz%z1> zjYaL(@vZf{6}7$i>QTEHKWdFFU{ZT-$#uV{_BYS@JR4)N##a3H`L<>8lR4MqImJ1y zMN^NtuEV$Y0=_J+e?4%nwZMMno8t_9SmXNr*zF+td;`C)z;DDiXPW)A?+##&dhEeX z_^ve{7=I|w{U*M#n?d9b;KzO$cLwjDdd#pBUoD>HTlm&^uD1aDnPcrB)_Bz3hTjKb z-f!cp?EN=kfmi5ZKR{&!cuba5moyjpBlv3Zyd`{ldUiu#7?@-JDr^~e&!3>bd^Fdrv%fL5=wHEipQ8UA z_|bnE{unSP`tQLn_OHU#tc(6?kzdCz=I@28)qwfqST+4SvHl&^_q%Wx_%GkH{aC+i z+JEz$_h9b@{*2#;HLi8t2KIhnk9XLI2eAi$+5_N!DTz4;lcd5 ze}k`Pu04&Zd1juU`>wU#Gy5%Y-w#kPe_BJp_J!bwLzI}|j<}s{V^mqqfZGauM$M3;J0ipi^ZCL@nU*`W2cuxBEvfkWS z%XqBy9=>Z0GOy?NXQ1XUw7=l1*)z1i=GtuR0AHeav3~>Bn{V9NT=N9h*#GIU3HU#S zYjp#E^T0;({D#d3p4kGdGtR}Hk?T+Ab!X+;5^UV(v+5p>&