From 75114d77ef4dce1a9934842c53399079286a1ce4 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 3 Aug 2020 16:47:08 -0700 Subject: [PATCH] add normal map sampling --- Effects/PBREffect.fx | 74 ++++++++++++++++++++++++++++++++++++++++-- Effects/PBREffect.fxb | Bin 7636 -> 7940 bytes Importer.cs | 26 +++++++-------- 3 files changed, 83 insertions(+), 17 deletions(-) diff --git a/Effects/PBREffect.fx b/Effects/PBREffect.fx index ca66512..1ea26fa 100644 --- a/Effects/PBREffect.fx +++ b/Effects/PBREffect.fx @@ -57,7 +57,7 @@ PixelShaderInput main_vs(VertexShaderInput input) output.TexCoord = input.TexCoord; output.PositionWS = mul(input.Position, World).xyz; - output.NormalWS = mul(input.Normal, WorldInverseTranspose); + output.NormalWS = mul(input.Normal, (float3x3)WorldInverseTranspose).xyz; output.Position = mul(input.Position, WorldViewProjection); return output; @@ -103,6 +103,24 @@ float GeometrySmith(float3 N, float3 V, float3 L, float roughness) return ggx1 * ggx2; } +// Easy trick to get tangent-normals to world-space to keep PBR code simplified. +float3 GetNormalFromMap(float3 worldPos, float2 texCoords, float3 normal) +{ + float3 tangentNormal = SAMPLE_TEXTURE(NormalTexture, texCoords).xyz * 2.0 - 1.0; + + float3 Q1 = ddx(worldPos); + float3 Q2 = ddy(worldPos); + float2 st1 = ddx(texCoords); + float2 st2 = ddy(texCoords); + + float3 N = normalize(normal); + float3 T = normalize(Q1*st2.y - Q2*st1.y); + float3 B = -normalize(cross(N, T)); + float3x3 TBN = float3x3(T, B, N); + + return normalize(mul(tangentNormal, TBN)); +} + // The case where we have no texture maps for any PBR data float4 None(PixelShaderInput input) : SV_TARGET0 { @@ -258,11 +276,63 @@ float4 AlbedoMetallicRoughnessMapPS(PixelShaderInput input) : SV_TARGET return float4(color, 1.0); } +float4 AlbedoMetallicRoughnessNormalMapPS(PixelShaderInput input) : SV_TARGET +{ + float3 albedo = pow(SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord), 2.2).rgb; + float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; + float metallic = metallicRoughness.r; + float roughness = metallicRoughness.g; + + float3 N = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); + float3 V = normalize(EyePosition - input.PositionWS); + + float3 F0 = float3(0.04, 0.04, 0.04); + F0 = lerp(F0, albedo, metallic); + + float3 Lo = float3(0.0, 0.0, 0.0); + + for (int i = 0; i < 4; i++) + { + float3 lightDir = LightPositions[i] - input.PositionWS; + float3 L = normalize(lightDir); + float3 H = normalize(V + L); + + float distance = length(lightDir); + float attenuation = 1.0 / (distance * distance); + float3 radiance = LightColors[i] * attenuation; + + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, roughness); + float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); + + float3 numerator = NDF * G * F; + float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); + float3 specular = numerator / max(denominator, 0.001); + + float3 kS = F; + float3 kD = float3(1.0, 1.0, 1.0) - kS; + + kD *= 1.0 - metallic; + + float NdotL = max(dot(N, L), 0.0); + Lo += (kD * albedo / PI + specular) * radiance * NdotL; + } + + float3 ambient = float3(0.03, 0.03, 0.03) * albedo * AO; + float3 color = ambient + Lo; + + color = color / (color + float3(1.0, 1.0, 1.0)); + float exposureConstant = 1.0 / 2.2; + color = pow(color, float3(exposureConstant, exposureConstant, exposureConstant)); + + return float4(color, 1.0); +} + Technique PBR { Pass Pass1 { VertexShader = compile vs_3_0 main_vs(); - PixelShader = compile ps_3_0 AlbedoMetallicRoughnessMapPS(); + PixelShader = compile ps_3_0 AlbedoMetallicRoughnessNormalMapPS(); } } diff --git a/Effects/PBREffect.fxb b/Effects/PBREffect.fxb index 217a521768636b170ebc8c9919761b087ead88ba..f901f3efcd0aefef3522815494b3ebe31d5492d9 100644 GIT binary patch literal 7940 zcmeHMPl%+|5r5y;-%j`L_ByLEYQjRAWDgUNxSM#$L3IDjg2EUlyW1)#=wznX>Cihp zbkA%QJba5H9u{ol96WgVCU^+bbJ#-;B8Ds?0bv6{1jTrmKnDWJ!NUf2FWdfpRjPk@N#i3yKcJ}mkMRFC^rNj`H5S^Z8_%z- zb{fFUi4&592wF{$2EKI#11=U2ZixWHTKiLjqa}op$`9-8nng z+G)pCGWkZkOo!3<4DI+U@XP45W1G$~cHB!r-*(}-AN|DHX1CjHFPSCgk2K(&0N+>H z@g(?9qu;$#XKsn<_(PzZwA;}io1bs3hK7J*m6_UdzsOO0;VoP#m5DGTICGkpN_7TWYY_*c+t7`>5x zvyFCe?>`Ub*bDp)^bX0Pv>) zeg$xio9^3bz>5K%0^SVp&jEiC;8iU6=YgYIfL{&pw*g-Y@J|6>3Ggb;*pxqKG~s^0 zvjM&a_+o&60k|5(<`m%R0Pg|b4Dbr#>0l63?|7Il+w?Hq@mo%gmV)*o`WuS6HvzAq z^F7XY1>=H^?-MreI~#K}8(5{8$>yqHi)4I=X0$~X6s6(t`tTKZ{PfXdtONhWLC~nr z*M&9K3BLy(aBG`iij? zgOcEF{i3H`z_SEO1llHGw)cbJCBxMf%kF7QP{eB|06>?#&i$o{& zY76tHjRheT%y#qONbc{C>bLh={;u+GYkRAXu48OXJ7&Gh-DiIG%pvz^bH3B=w$H58 zrcVC2_VCQ9ncAtvxrIijcD#LdxrxHOcKFaw4!iy@okK`XW?bRlCLcM1$AiwL50M^$ z{+G*D($LdC?fK+KeDuoeBz+&~uf6}D2kv|KpU|Q02M7a9 zkYYc33P)+=${vo>*u&uNxyocl9>P%oCxAgjD34;~r5Fe&E zrZFNwV9YIYq?1?i3T$xF$!l^PgKZ+W8}mGkG1v#bLGP)Yuihgc>C}mnk#el$`6#3M z>OI6#LcWsND7@zndS1#A<~U%{nF#NPz&}bUOFVWTLZ0|QWOsoEI6Vd%5;w^;!B>OK z_&FB2dKS5jjCPVAK0BYdI^pn%Im;OgygO9mSjy>aC+*jI7UgVK&yd~hV?46VK==cyk!)-oD-~+Cg{JK_M zFEWtulHYtn9^&k@nL0TKeE^bI!?e>>YF$ z`bi@XZ8VrXipRo_^<~7(7UK{6A@k$qfVmiB*Tg4q8RtGvpFD~Ab)5FpbDw)2@o{9`Db%f;nlg!nC*U;RNu8=q$T3?Bf}68NM%a8HH6wVU%$gWZ}~d;fekErwx?Z1DzD|Hqfq&G|t1Eha8vBt2oa~VK>fa zR^;7Ccxh)ju*=rK`8XEZZ0q3|`{m=C}%RNLvw7&aTYx7?dBhDqaE zNMk(HPVz8@3Dc)x98Y{haSU5B+VO21S9sRHjbp^6-jvox%Ktd7o9hJdn|RZ1WX56O2*kM#_8~JJxiTk9&UJeV}p9f5^P# zLA{;V6e?3EP56mdP!k%?`kysM$=Q34-(Y+nYrV{UAWRzT3VlzvyfouBOa+#AB)ZhFS5=rTLk-@et-b%+E$+JmC&R9?TPg}BSWnAU|6WQx7e8fYKZ%=*t&B8<6IVUWl%qYhu@JK z>%$>9edGO$!3VGaSGtb-m+Ace4gSyXUp@m2-$EgV@c&snm(eex^A4qi`x2x5 zS!jCKVl=&D?e|OI#P^PaZMUS2zf&D|<9Y5TZyox5|DB)W?m_MX;1BpxVVtiNcML+u zLddg4e$sJ|;^7E9We>+G;(7~rWvHW~E$n>{JySdu95LqcL~z7L#<~!D8){Jl4T_6U(1SE^je*gdg literal 7636 zcmeI1L2R7G6~||HKYKU9!9Z!7R!Cj7Ik*xkNy~u)rB32VAerJOF>pWv*WTbo8?Uu% zhamN^6+QHTRJZjZhaSFG9FR9sbLasfRgEgtQz~&QYB?Cm2M!!Kq*9QoZ2!NRdEbuL zPEnA{iLsvNy*F>(d-LYa`{w($bZBt3o#wWqesV^5qVPmjNq$+T{_P#TwHB6I*6GLKL>_dMSveaZg(y&wD$UO z3!&KX%XAozKK0{0(KiJ6u}kMZemu;?*v8b~CpdGl+3hylE9QyCqnF5zOYXD$cwX}7 z1z+E*v+%@p{3+25?|#8Ei;J!G)DiK_mkBl`wwij=V?26P+TQGl*cKcWZ&a^2V>+f2 z-G?Oq4Z+imwS`uzxp=m{{_^rlquaIMXv}=dlX>t=pU|SEK3$glnxL-HJLxyy@Pobo zAhB_e=m!L6RxZsnFI-sfHik}_PmhvZu}!EqJ;tL?eVUMbO~9J>=rw0FW@~FD`j3b| zDLB_Th3;cEbc?IP%C?l6Zq6!{t_S(qN?u*a6#Vf^GXK{xzfl*7b+>xe4;XNMoN&6k(g z=GxunnhHyIsB8NG^bw8f8yxnJ;jaTP7 z?N=I$?6j}roUhRsQn$#9Q9dD=Tj+LA#IdB&XhvI3c?lal-K%jH~s;`^qGbO_Qi^=CXw<*&;taP&3|RBw=MRxIK8)oj!l^6!*YCGAJHPiTA?#TjFhsF6)$* zRCTWie@j3PVW*^#_tew21!XrO-uK-*z?WIx65ER2C=G(|S4bE~~GI zQxflraGL6FA8yJ21>WfYeeae1en0bmFf+8Yu9dt_^oEw!N*hbkB}#q1ZluolNA=q? ztavWPC$l|4N7u31eenk`9(PYS7d!24`@&j%>g;#xPtKm3t)E+7SZZ|Yr`s1-o4Q=r zPaOZ=3D^ILb4rWJ+_~Og1V8%ML$c*vm7aAX2q_VQX^9@Y@- zo4ol(3~is;W9$7xV|bEPOuVneeUXdsXw96ZQrj@<-$FwsO`tCOzW$ z_356H)g%-0i84RoZkk=j+=Zp1) zT-idu-}@-z`9qz=-p8AH9DHD%A&1Qe z_Lf-2bENS>4v)3LBcIu0WXNG~bf;4&gi`Q+NGl-d(H#r2%0){Q1#f!9<{;AhSg(u(9{#dkujP) z9v#Og>Y^S$8XMN*NQ;-=3p1mmPH5`2-SN=j>vxZOOw4V*)nncboctiJ*p2&A)MIG* z>&NjMnmYyZ(A>?T74E&^E`iP6HCbzxnee{BJr0~_TDW_LybeCW+v%}U(80e! zK71Dm^*NORxB6`Jc)shM-p^xw;XP$Xy61CzAx}zLU%<=4!?RTH&cZE@#3-zp`(SuS za{g|pcXM<_JQF^g!*k+@>~J^Ki@Csvv@OOmNZ zyxdb>Z|mES^1ZaJz26Y%ehXdpwDvaAnWvSXIdw>1JhnBq!TmPSWl!_|9q7!{+#ArR zy5Q&QZV~CApZDl69`y744|L7TQ%A`e{Fm(wvV>ewein^=yVGwH$lA9qCLqh)-M@JR zow^$r4LQ}4y}#3lhfeueG-N;PcP!>qiy6U>`$dobUWN#=+Owje|31O!Z->Y!uth^o VXKnZIlA@7g%$mvV`rf6%{{kwpxr+b* diff --git a/Importer.cs b/Importer.cs index 97f8a03..adc5dfb 100644 --- a/Importer.cs +++ b/Importer.cs @@ -141,19 +141,17 @@ namespace Smuggler if (primitive.Material != null) { - //var normalChannel = primitive.Material.FindChannel("Normal"); - //if (normalChannel.HasValue) - //{ - // if (normalChannel.Value.Texture != null) - // { - // effect.NormalTexture = Texture2D.FromStream( - // graphicsDevice, - // normalChannel.Value.Texture.PrimaryImage.Content.Open() - // ); - // } - - // effect.NormalScale = normalChannel.Value.Parameter.X; - //} + var normalChannel = primitive.Material.FindChannel("Normal"); + if (normalChannel.HasValue) + { + if (normalChannel.Value.Texture != null) + { + effect.NormalTexture = Texture2D.FromStream( + graphicsDevice, + normalChannel.Value.Texture.PrimaryImage.Content.Open() + ); + } + } //var occlusionChannel = primitive.Material.FindChannel("Occlusion"); //if (occlusionChannel.HasValue) @@ -218,7 +216,6 @@ namespace Smuggler graphicsDevice, metallicRoughnessChannel.Value.Texture.PrimaryImage.Content.Open() ); - System.Console.WriteLine(effect.MetallicRoughnessTexture.Width); } var parameter = metallicRoughnessChannel.Value.Parameter; @@ -416,7 +413,6 @@ namespace Smuggler uint[] indices, Vector3[] positions ) { - System.Console.WriteLine("normals"); var normals = Normals(primitive); var texcoords = TexCoords(primitive);