{"id":33,"date":"2020-12-25T09:56:26","date_gmt":"2020-12-25T09:56:26","guid":{"rendered":"https:\/\/noirccc.net\/blog\/?p=33"},"modified":"2023-05-18T00:30:49","modified_gmt":"2023-05-18T00:30:49","slug":"urp-genshin-face-shader-test","status":"publish","type":"post","link":"https:\/\/noirccc.net\/blog\/posts\/33","title":{"rendered":"URP Genshin Face Shader Test"},"content":{"rendered":"\n<h1>URP Genshin Face Shader Test<\/h1>\n\n\n\n<p><a href=\"https:\/\/github.com\/NoiRC256\/UnityURPToonLitShaderExample\">repo<\/a><\/p>\n\n\n\n<p>This is an extremely primitive test of how the face shader is achieved in Genshin Impact.<\/p>\n\n\n\n<p>A ramp texture \u201clightmap\u201d is used to define how shadows respond to main light directions. This \u201clightmap\u201d can be created by drawing a couple of characteristic shadow textures under some lighting angles, then combining the results of their SDF interpolations.<\/p>\n\n\n\n<p>(1). The \u201clightmap\u201d feature can be integrated into\u00a0<a href=\"https:\/\/github.com\/NoiRC256\/UnityURPToonLitShaderExample\"><\/a><a href=\"https:\/\/github.com\/ColinLeung-NiloCat\/UnityURPToonLitShaderExample\">UnityURPToonLitShaderExample<\/a>\u00a0by\u00a0<a href=\"https:\/\/github.com\/ColinLeung-NiloCat\">ColinLeung-NiloCat<\/a><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\n\/\/ Use r value from the original lightmap\uff08left part in shadow) or flipped lightmap (right part in shadow) depending on normalized light direction;\nfloat LightMap = RightLight &gt; 0 ? surfaceData._lightMapR.r : surfaceData._lightMapL.r;\n\n<\/code><\/pre>\n\n\n\n<p>(2). A dirThreshold value can be used to stretch the lightmap for small tweaking. This is set to around 0.1~0.5. <\/p>\n\n\n\n<p>(Outdated: see the Update section)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\nfloat lightAttenuation_temp = (FrontLight &gt; 0) ?\n    min((LightMap &gt; dirThreshold * RightLight), (LightMap &gt; dirThreshold * -RightLight)) :\n    min((LightMap &gt; (1 - dirThreshold * 2)* FrontLight - dirThreshold), (LightMap &gt; (1 - dirThreshold * 2)* -FrontLight + dirThreshold));\n\n<\/code><\/pre>\n\n\n\n<p>(3). Implement shadow color.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>half3 shadowColor = lerp(1 * surfaceData._shadowColor, 1, faceShadowMask);\nhalf3 rawLightSum = max(indirectResult*shadowColor, mainLightResult + additionalLightSumResult); \/\/ pick the highest between indirect and direct light<\/code><\/pre>\n\n\n\n<h2>Update: Fix<\/h2>\n\n\n\n<p>For (1) and (2), we could just do this.<\/p>\n\n\n\n<pre id=\"1J9NynxLOyyMrby66GAWMLaa42flzslI\" class=\"wp-block-code\"><code>\/\/ Choose original lightmap L (light from left) or flipped lightmap R (light from right).\nfloat LightMap = lerp(surfaceData._lightMapR.r, surfaceData._lightMapL.r, step(RdotL, 0));\n \n\/\/ Calculate result.\nfloat litOrShadow = step((-FdotL + 1)) \/ 2, LightMap);<\/code><\/pre>\n\n\n\n<p>The SDF lightmap contains shadow distribution data covering 0~180 degrees on one side of the face, rather than 0~90 degrees. The tip of the nose will receive lighting even when directly facing away from the light. This means the lightmap should be appiled on all angles on the xz plane. All we need to do is modify FdotL (i.e. dot product of face forward direction and light direction), standardizing it to [0, 1], equal to the range of a color value.<\/p>\n\n\n\n<p>For more info check out this video:&nbsp;<a href=\"https:\/\/www.bilibili.com\/video\/BV15t4y1V76U\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.bilibili.com\/video\/BV15t4y1V76U<\/a><\/p>\n\n\n\n<p>References\uff1a<\/p>\n\n\n\n<p>(1) ruofeng133\uff0c<a href=\"https:\/\/blog.csdn.net\/A13155283231\/article\/details\/109705794\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/blog.csdn.net\/A13155283231\/article\/details\/109705794<\/a><br>(2) \u9ed1\u9b54\u59ec\uff0c<a href=\"https:\/\/zhuanlan.zhihu.com\/p\/279334552\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/zhuanlan.zhihu.com\/p\/279334552<\/a><br>(3) xibanya\uff0c<a href=\"https:\/\/answers.unity.com\/questions\/1686727\/is-there-a-way-to-change-the-shadows-to-blue.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/answers.unity.com\/questions\/1686727\/is-there-a-way-to-change-the-shadows-to-blue.html<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A primitive proof-of-concept test of Genshin Impact&#8217;s face shader implementation. Uses a SDF lightrmap texture to define shadow visuals at different planar light angles.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[43],"tags":[58,71,53],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/posts\/33"}],"collection":[{"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/comments?post=33"}],"version-history":[{"count":9,"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/posts\/33\/revisions"}],"predecessor-version":[{"id":481,"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/posts\/33\/revisions\/481"}],"wp:attachment":[{"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/media?parent=33"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/categories?post=33"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/tags?post=33"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}