From 84108c44f5a6dc51812c5e379d589a0d269762cb Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sat, 4 Apr 2026 00:21:15 -0700 Subject: [PATCH] fix(rendering): alpha-to-coverage for hair, skip eye glow geosets, add missing include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Enable alpha-to-coverage on alphaTestPipeline for smooth hair edges when MSAA is active (both init and recreatePipelines paths) - Shader uses fwidth()-based alpha rescaling for clean coverage - Skip group 17/18 geosets (DK/NE eye glow) when no geoset filter is set — prevents blue eye glow on all NPCs - Add missing include for dirname() on Linux --- assets/shaders/character.frag.glsl | 9 ++++++- assets/shaders/character.frag.spv | Bin 17488 -> 17796 bytes src/main.cpp | 1 + src/rendering/character_renderer.cpp | 34 ++++++++++++++++++++------- 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/assets/shaders/character.frag.glsl b/assets/shaders/character.frag.glsl index b28fa314..669eb84f 100644 --- a/assets/shaders/character.frag.glsl +++ b/assets/shaders/character.frag.glsl @@ -126,7 +126,14 @@ void main() { vec4 texColor = texture(uTexture, finalUV); - if (alphaTest != 0 && texColor.a < 0.5) discard; + if (alphaTest != 0) { + // Screen-space sharpened alpha for alpha-to-coverage anti-aliasing. + // Rescales alpha so the 0.5 cutoff maps to exactly the texel boundary, + // giving smooth edges when MSAA + alpha-to-coverage is active. + float aGrad = fwidth(texColor.a); + texColor.a = clamp((texColor.a - 0.5) / max(aGrad, 0.001) * 0.5 + 0.5, 0.0, 1.0); + if (texColor.a < 1.0 / 255.0) discard; + } if (colorKeyBlack != 0) { float lum = dot(texColor.rgb, vec3(0.299, 0.587, 0.114)); float ck = smoothstep(0.12, 0.30, lum); diff --git a/assets/shaders/character.frag.spv b/assets/shaders/character.frag.spv index 43789272f26cf2430fef49603a82af4bbb54dbe4..7277d275ce297eb3c61a83248ddb3d65fc8af675 100644 GIT binary patch literal 17796 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 Hz5jm!!;cd^ literal 17488 zcmZ{r2bf(|)rJpDCZS6WO&|e92#E9!384fekYGYr;?2yRWZ+J5N(fB?NKuiZfPx|r zkg6h}fQUd)!7f((tyob(v49E|{`Woie8XX$|KHAf_P4&Z_S$RLbIv7pti08vqFAX| zy;!q&aOI*b>l7=)6mS#Ede-cDvv(LC>E2=2-FDPrt)ip!)8{qC8pQ-^rLWQ3uiplfh&!SKjwt>%JO zZ+~+^ckfWMYovEcQ@>See!cx&ty~=o;OIzm_CWU`jjoY_p>0av z)r(E32OC3;R;#geP8S&s_YU+Q(HPujNzcw@A3ZzS4RJb(ji^VLh&zjo!Ap9ZrykTh zG=E-c?<_Wywx>R=!p7*vU~Jc5esk%84gm<$Q5>fo z=T6r3MDR#+X|r`uvwygE#1QZkieBntx(7y%EcMP}gu2ncsMTx_x%9E`zQ$6!D`VOC zz{QQBBN`*kq25MIej=7KD0pD7(PbAC`JWuiT{K#QiyQNs!^WS;{K~r*x&~SULx(p{ zo7rk~ol@G`aolmE{jJ`*zw6xW>m43uXUrTJcvY;zs=}pm9n3S;Nih$*J!IT zbXfn$*aRdG_hz%dv9Q%Va$u;h(PAmba$jZ4Hh0buWz6=NRs|0Z^v&yPwAiJujA^wt ze+1K2?m)KFSRSi`7dLwsEgqqVV;W3df0vDu=NjPtWH4`JsM)`0WHFp;c?Pw`HCsmA z*V|vMM`v+9djDwOScmS1E8$v=)0#sEH3tpip1vBcYjlXXBeQF!GX6E#<|4MenVR*U z)6+BDbRzBZZtCu4You}XF{RJ_=v6EjeO4(Rc!eu_El1fJE$7GnAHqJ`p5j9@4N$c0 zC?2DBFWT4B)PqCKB?dO1XV4ox?6tA6bQaISEo}A-3^m)N?OudCwG7;jwVs;c;qt7gDo#nkbvv;Jj8mpt2hP{0@JBl4_ zJM+jgm!sNvL2v&O^ohlM^y+Roc3`Mg-2t7&G4OMnLx&7C`l@}}<{Xp$)}B-S_+#D& zPWJ8{;AVGU%6m>*Zrgbr>?WsvsMjlDtet1Iv~#i5dCzOfALt?1e^ME*6TZ>6u$MWg zEZW+6c~;G9?!fR^e9vdkz@nOOJ73Qx{9LZ$zV(@xE3B|MM zubhPm#q;Pbp0k;cm(aU=dwQb3j9$%08E+z+U~!|>;}Vge97@!vpw?3p#O*c9Ed zG+JZV2<72-Hinzs&U|~^+rqVmU(t6#cONEpPt~TaGpFdI?MJ&;b(zm;wyCYv zRp{Nl9D$u5t$`=*sETZW`RxmVh? zb8rm$J%Yq9YyU)z%i2Fx;9g_dOUUQ@%M}+-g@i;RP25UwD-hhkYk;KY|Oj6V^p`jk`lZr z{*GC{Ddgu^Epi*8yT@&BeC_TnedVXJitcUgw$o-V?mao%uU}#FwEYIuwwG6*Tx20#$8Ue?-luZfH>$9EMZ3E9 zD}SY~zxQih_kLC12>V08Dry7?Z8KCte2dqfUE^$>(@<^U(i<%C-VM^X2`dv9s_V^yLRnF8#H?7ybK7f4|@MWaZpm zjBXqKw56X*!IwVz!hX>&L%-(gSK?lSzS@&p?VCJqKsWd3x1)QvrTx9=lo{&oyNBC) zX;=3*7^$@X8A^R${s!IWlJoRiuwyp=#9v#2PnYPgZR>mMKMkzvy2ic;Vqo2lv3=2p zzTtgG?diIBK7DRjZ2u{+xvW66tNR?0+nua*bq`tO{t08Q`g;HRP3PRGyEpxwi|#!= zrKW55`z&_#t;gxpYPx5_@38o*`z;pT_VdT-ep|$D|2;Kbf4?hYH~*7sx_i{`in{%R zak}3Su^Z3th`R1~L|ykABD($g{Se*uemm6lXUFN!*L2(a?NImk+o7)e?GRmmza8qj z-wt)%Z-?mS<2OTe=fm%X=-T~Wh;Dqp7ouzT+aS7jzYXfT-v;V?v0ps1>(a-%)cdo$ z+)L{FVRQda25*3@QJv=v!Tc2mS2o+Y-{fsG4So}__wcQizA0GlANX!YZFvcs{A&?8 z_p~_uZVoo?*;O7}faTJk`irzlTWj0;-ZB;JGhSc!zIx)m4(u}_<9R)pzj8dc3|_@=6O<&?M-0&h`uA(_R)6&+vX@vx$Cnt*fy4M zyHuQXxLqrb-NVPxgT`Z}T*- z@cV+z$sFu6{C;5jGrsZUeGc!B7|VA0IG^4}@&_u~oXfyx0)E4vCHV2V2f3dNhzqcUH*ZfMK zS8>kcQDAk)dII%{i0>D^Q`mk5@!txTpTk>__rcr1a*D;ub=P0}0*I54^N6YbcCc;a zbAB3N{>t;C-CTTz$S3bEu=yo!H&~y`tGG?DKJvC-NG+$ocfcZW?tmV!dSdm0^|zhR zB6V%9?I~c_LfgsI>U*(<#%zH%r8b`JwCgv8TAOR1HLy0O@5+PVfl4>dJHWO%ma(ir z9|G$mZ@hkLx$N&@uzS$&BV)S1N8seMzemAx+25yvE$$C(OAtBthuGLY8_=>z71%EXJKpT)i@v0)a;|am{uuf?Nbzsv8g6+q-(BD4H<5ScY^U&u` zM9w_K_UV0bH`woLb?=LN(5E1|FFp;{M?U-bGhlheV&y)*gt566_d)1$FOp~O{op0o zBDu3a3$MR+*X}NAxy;i8;PLbHIXHQ9w!a6#wwqJkou3EGDHbbpb9@h>Xg5ao>?2^? zKaAu(V+B}Wi+SlImo{Gj+vZUuZN3P$4S!`DedLnom%z5kv*|G~f911DTgESMo9(H; zjO-A@s>QzX;aHZ&PjN@jSJB#`rI=YajjJV14qu z{|{In`RwQag83`=vvz;yHug(kZ5flvIi};0tiehqjATqJgXKyd6Rzc$l1~S=lOS^! zPe8Yge8$-cww>eDZZ0oF$S2Muu;Yrp3c5a7!&TAskx$&!z=^Bfxc-(QpEzrP>+`oJ zx;~k|wZQtwXZ~ITHm>)9cIPj)bt>B?aQgW>oAbFGeO<8UB=hMRSPxDak|dsS+at9CluT3uiZKEIje1FboYI)&OEg53YN>++YKzI zSnONq*d|l&j-r44TWAk-`P_+ng5@F?(boHKFF50CHy3}Slgpg!4VKIM&^}-}#bPdb zAKDjAyZdi0@qI_yuhQjQE4lsQ^wpLzOb6SK`#Wx#=U9HV1%h^JuNjOmy2o zm2LEqOPd41>Blj;zYcuO@I3^k9pJ<^U&ulh@5$dlgE7U_&kn=lh1q{1D4BtB#w3RI2LR_=BB@W zn8)$d$wQyx5IOS@Cyx`r<}m~3%*To7@|lmfg5@$FiDR8S-UhZGbJO2G%wqwy#re?Z zBt*_U#L46B;PH7h;N&wO3&C=kkHoP~9$jGjF*p6~!#tYQ$wQxRM9w_KIn#^5xnI2l zdeQ6m{mJP1$md=^1#C{*a<8|*ix6#jF7|^xdptqYr*`|? zgxa;XcJ5A~(b-`8$UFNA+Ao8X&-3LRu$*GCFQNJ9e=bV>ef&IhImHtHyi>mm-kADj zOy`3gd-MyyFVQf0UWjg<=MpddUIZtfJl_qLQ!ME>?*;FH*T>k2@m_E}_lwcxlzNQh z{yuo)=$BkC0k4iE*Gs|UbG-~sKDk~FmQ(8eB-i)D>tpP5SS!!r2f+5PEq+&k<(qblb@1 zo$w=I+s#C@o7+{?^4aqr1)Ixsy>D=+}d7oAZ1FSReVsS`PldV%-R@Eq*uE z{CvMiA0LC)mOgF<+g9H9Bi{{f0o%8>oX1Rk*M%)LsoqX=x`@!~S3HRBGGv9Cz zRGhAPul^j0?e*7ge8+PawYL8-;yn@n{ekP}9c}U7TJI*gR(-_GkYy5&7)D1HtK0)?X%b2ml@BIV8@etbS_wK z4)R~xsMpV_|Bl1rzwtDe^{73M8&J(a5(d{n(0g9*m_P z-{ZmhK2iCe0G89&e$?apR5|?JlGn(Z~7Lmicy$HbpEOBHo40^F|e3oqFR6JHMMC zuE}eub4T`qvnKkC)buIfrQ`HvH0r2PJeEk{$fqHy%S%bkBOC@`{ra^oYNUd*6$RseBPg0VApQ~qRlmT zp5@b~4=k7ejyM38>qqSi64dXB2Ed*;}WA&22kG zoBb_8%+a;i?pV*FekXDUawcLt@1wI3dHvlR>am>zmbo)+hO? zr~j+K_5MGIE|)v|Lty)pxBZpWa$?Wt=7_OYqy8}B{?2p%BNZoaF~^MST5x-Bwg0=@ zM=QJcoi_JYp7Ga#wJYYeKK1p8@wK_4I|lC*xx}~y zJU+&)aPoPdy&Wuf8)A%`spag`-0nb(n;bq4*2n+$tBA4-fvf|{^=1#C};`1r6 zoZ`CM&s~Uf>Up$JC?#hNcP=lDlYxqi!P^R&hG;oN1J`zO)Zx` zJ`3KcvfWRuuI)kUhmnUW-P|8R^vS;qcoeM9BS_wzz6h4@K(hb81a?1aGlvJL<;0Is zKaTi5@?~o8Gi%?0ze@cz#G?J{)Y`4h(K-1BVvM`kPt&NsRdL^>_AXWb3SunViqrN9 zux+D%8|?hvS;hJeSRZ+PCQ^SF@eD=(9@z2Z_sH*q^^w21it_`ov9x*D|B%{Ze%hWy zLR`P-KL)!V&a?KPAaeRSx7y_NcRhcK)YtQ8==x+me_r{>XFZ<+ z%h%WQ7wE3%Q%KfRE_3or@Rc?FS77Jt9P)Gye~rlLXM1gOj@$Ki9;}V$8vh1yo$^lm z+lt$kI(ta2zK5K@%+v3{jx+l2!Oo-kIB$PI^pQ8-(-oKTJd5rcNB<+(oU_0G1lC91 z_Rmnu>F>P%8L7|vU(oF%^ZwV$M?UlZH?Vwt-k(Qz-nAu{7r^yg{*JDne0=@^c0Drx z{{-tNZ@$k_%fE2?XY0#c{tAKm)%` #include #include +#include #include // Keep a persistent X11 connection for emergency mouse release in signal handlers. diff --git a/src/rendering/character_renderer.cpp b/src/rendering/character_renderer.cpp index 5cbfecd3..1d15508b 100644 --- a/src/rendering/character_renderer.cpp +++ b/src/rendering/character_renderer.cpp @@ -253,8 +253,9 @@ bool CharacterRenderer::initialize(VkContext* ctx, VkDescriptorSetLayout perFram }; // --- Build pipelines --- - auto buildCharPipeline = [&](VkPipelineColorBlendAttachmentState blendState, bool depthWrite) -> VkPipeline { - return PipelineBuilder() + auto buildCharPipeline = [&](VkPipelineColorBlendAttachmentState blendState, + bool depthWrite, bool alphaToCoverage = false) -> VkPipeline { + auto builder = PipelineBuilder() .setShaders(charVert.stageInfo(VK_SHADER_STAGE_VERTEX_BIT), charFrag.stageInfo(VK_SHADER_STAGE_FRAGMENT_BIT)) .setVertexInput({charBinding}, charAttrs) @@ -262,7 +263,10 @@ bool CharacterRenderer::initialize(VkContext* ctx, VkDescriptorSetLayout perFram .setRasterization(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE) .setDepthTest(true, depthWrite, VK_COMPARE_OP_LESS_OR_EQUAL) .setColorBlendAttachment(blendState) - .setMultisample(samples) + .setMultisample(samples); + if (alphaToCoverage) + builder.setAlphaToCoverage(true); + return builder .setLayout(pipelineLayout_) .setRenderPass(mainPass) .setDynamicStates({VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}) @@ -270,7 +274,7 @@ bool CharacterRenderer::initialize(VkContext* ctx, VkDescriptorSetLayout perFram }; opaquePipeline_ = buildCharPipeline(PipelineBuilder::blendDisabled(), true); - alphaTestPipeline_ = buildCharPipeline(PipelineBuilder::blendDisabled(), true); + alphaTestPipeline_ = buildCharPipeline(PipelineBuilder::blendDisabled(), true, true); alphaPipeline_ = buildCharPipeline(PipelineBuilder::blendAlpha(), false); additivePipeline_ = buildCharPipeline(PipelineBuilder::blendAdditive(), false); @@ -2385,6 +2389,12 @@ void CharacterRenderer::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, if (instance.activeGeosets.find(batch.submeshId) == instance.activeGeosets.end()) { continue; } + } else { + // Even without a geoset filter, skip eye glow (group 17) + // and group 18 unless explicitly opted in. These geosets are + // only for DK/NE eye glow and should be off by default. + uint16_t grp = batch.submeshId / 100; + if (grp == 17 || grp == 18) continue; } // Resolve texture for this batch (prefer hair textures for hair geosets). @@ -2950,6 +2960,10 @@ void CharacterRenderer::renderShadow(VkCommandBuffer cmd, const glm::mat4& light if (blendMode >= 2) continue; // skip transparent if (applyGeosetFilter && inst.activeGeosets.find(batch.submeshId) == inst.activeGeosets.end()) continue; + if (!applyGeosetFilter) { + uint16_t grp = batch.submeshId / 100; + if (grp == 17 || grp == 18) continue; + } vkCmdDrawIndexed(cmd, batch.indexCount, 1, batch.indexStart, 0, 0); } } @@ -3487,8 +3501,9 @@ void CharacterRenderer::recreatePipelines() { {5, 0, VK_FORMAT_R32G32B32A32_SFLOAT, static_cast(offsetof(CharVertexGPU, tangent))}, }; - auto buildCharPipeline = [&](VkPipelineColorBlendAttachmentState blendState, bool depthWrite) -> VkPipeline { - return PipelineBuilder() + auto buildCharPipeline = [&](VkPipelineColorBlendAttachmentState blendState, + bool depthWrite, bool alphaToCoverage = false) -> VkPipeline { + auto builder = PipelineBuilder() .setShaders(charVert.stageInfo(VK_SHADER_STAGE_VERTEX_BIT), charFrag.stageInfo(VK_SHADER_STAGE_FRAGMENT_BIT)) .setVertexInput({charBinding}, charAttrs) @@ -3496,7 +3511,10 @@ void CharacterRenderer::recreatePipelines() { .setRasterization(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE) .setDepthTest(true, depthWrite, VK_COMPARE_OP_LESS_OR_EQUAL) .setColorBlendAttachment(blendState) - .setMultisample(samples) + .setMultisample(samples); + if (alphaToCoverage) + builder.setAlphaToCoverage(true); + return builder .setLayout(pipelineLayout_) .setRenderPass(mainPass) .setDynamicStates({VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}) @@ -3508,7 +3526,7 @@ void CharacterRenderer::recreatePipelines() { " pipelineLayout=", (void*)pipelineLayout_); opaquePipeline_ = buildCharPipeline(PipelineBuilder::blendDisabled(), true); - alphaTestPipeline_ = buildCharPipeline(PipelineBuilder::blendDisabled(), true); + alphaTestPipeline_ = buildCharPipeline(PipelineBuilder::blendDisabled(), true, true); alphaPipeline_ = buildCharPipeline(PipelineBuilder::blendAlpha(), false); additivePipeline_ = buildCharPipeline(PipelineBuilder::blendAdditive(), false);