{"id":2916,"date":"2023-02-13T14:21:00","date_gmt":"2023-02-13T06:21:00","guid":{"rendered":"https:\/\/www.caiqinyi.cn\/?p=2916"},"modified":"2023-03-03T10:08:40","modified_gmt":"2023-03-03T02:08:40","slug":"pcf_pcss_implementation_piccolo_engine","status":"publish","type":"post","link":"https:\/\/www.caiqinyi.cn\/index.php\/2023\/02\/13\/pcf_pcss_implementation_piccolo_engine\/","title":{"rendered":"\u5728Piccolo\u5f15\u64ce\u4e0a\u5b9e\u73b0PCF\u4e0ePCSS"},"content":{"rendered":"<p><script type=\"text\/javascript\" async src=\"https:\/\/www.caiqinyi.cn\/wp-content\/MathJax\/MathJax.js?config=TeX-AMS_CHTML\">\n<\/script><br \/>\n<script type=\"text\/x-mathjax-config\">\n    MathJax.Hub.Config({\n        tex2jax: {inlineMath: [['$','$']]},\n        TeX: {equationNumbers: {autoNumber: [\"AMS\"], useLabelIds: true}},\n        \"HTML-CSS\": {linebreaks: {automatic: true}},\n        SVG: {linebreaks: {automatic: true}}\n    });\n<\/script><\/p>\n<p>\u6700\u8fd1\u5728Piccolo\u5f15\u64ce\u4e0a\u5b9e\u73b0\u4e86PCF\u4e0ePCSS, \u867d\u7136\u7ed8\u5236\u7ed3\u679c\u4e2d\u5b58\u5728\u7740\u5927\u91cf\u7684\u566a\u70b9, \u4f46\u8fd8\u662f\u60f3\u7740\u8bb0\u5f55\u4e00\u4e0b\u5b9e\u73b0\u7684\u6d41\u7a0b~<\/p>\n<p><!--more--><\/p>\n<p>Piccolo\u5f15\u64ce\u5b9e\u73b0\u9634\u5f71\u7ed8\u5236\u7684\u4ee3\u7801\u4e3b\u8981\u5728deferred_lighting.frag\u4e2d, \u5176\u5f15\u7528\u4e86mesh_lighting.inl. \u81ea\u5df1\u662f\u628aPCF\u4e0ePCSS\u76f8\u5173\u7684\u63a5\u53e3\u90fd\u653e\u5728\u4e86\u4e00\u4e2a\u65b0\u589e\u7684\u5934\u6587\u4ef6utilities.h\u4e2d, \u7531mesh_lighting.inl\u8c03\u7528\u7ed8\u5236\u9634\u5f71. \u8c03\u7528\u4ee3\u7801\u5982\u4e0b\u6240\u793a:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\nshadow = (closest_depth < current_depth) ? 1.0f : -1.0f;\r\n\r\nif (shadow <= 0.0f)\r\n{\r\n    highp vec3 En = scene_directional_light.color * NoL;\r\n    Lo += BRDF(L, V, N, F0, basecolor, metallic, roughness) * En;\r\n}\r\n else\r\n{\r\n    highp vec4  coords     = vec4(uv.x, uv.y, position_clip.z, 1.0f);\r\n    highp float visibility = PCSS(directional_light_shadow, coords);\r\n    La *= visibility;\r\n    Libl *= visibility;\r\n}\r\n\r\n<\/pre>\n<p><strong>1. PCF<\/strong><\/p>\n<p>\u5165\u53e3\u51fd\u6570\u4e3a<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\nhighp float PCF(in sampler2D shadowMap, in highp vec4 coords) \r\n{\r\n    highp vec2  uv        = coords.xy;\r\n    highp float zReceiver = coords.z; \/\/ Assumed to be eye-space z in this code\r\n\r\n    poissonDiskSamples(uv);\r\n    return PCF_Filter(shadowMap, uv, zReceiver, 0.002);\r\n}\r\n<\/pre>\n<p>$\\cdot$ <strong>Step 1: Poisson\u5706\u76d8\u91c7\u6837<\/strong><\/p>\n<p>\u6839\u636eUV\u503c\u8fdb\u884cPoisson\u5706\u76d8\u91c7\u6837, \u5f97\u5230\u4e00\u7ec4\u7528\u4e8eShadowMap\u91c7\u6837\u7684UV\u504f\u79fb\u91cf<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\nvoid poissonDiskSamples(const in highp vec2 randomSeed)\r\n{\r\n    highp float ANGLES_STEP = PI2 * float(NUM_RINGS) \/ float(NUM_SAMPLES);\r\n    highp float INV_NUM_SAMPLES = 1.0 \/ float(NUM_SAMPLES);\r\n\r\n    highp float angle      = rand_2to1(randomSeed) * PI2;\r\n    highp float radius     = INV_NUM_SAMPLES;\r\n    highp float radiusStep = radius;\r\n\r\n    for (int i = 0; i < NUM_SAMPLES; ++i)\r\n    {\r\n        poissonDisk[i] = vec2(cos(angle), sin(angle)) * pow(radius, 0.75);\r\n        radius += radiusStep;\r\n\tangle += ANGLES_STEP;\r\n    }\r\n}\r\n<\/pre>\n<p>\u671f\u95f4, \u4f1a\u5c06UV\u503c\u4f5c\u4e3a\u968f\u673a\u6570\u79cd\u5b50, \u4e0e\u4e00\u4e9bMagic Number\u8fdb\u884c\u8fd0\u7b97\u540e\u5f97\u5230\u4e00\u4e2a\u7279\u5b9a\u7684\u91c7\u6837\u89d2\u5ea6.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\nhighp float rand_2to1(highp vec2 uv) \r\n{\r\n    \/\/ 0 -1\r\n    const highp float a = 12.9898, b = 78.233, c= 43758.5453;\r\n    highp float       dt = dot(uv.xy, vec2(a, b));\r\n    highp float sn = mod(dt, PI);\r\n    return fract(sin(sn) * c);\r\n}\r\n\r\n<\/pre>\n<p>$\\cdot$ <strong>Step 2: PCF<\/strong><\/p>\n<p>\u5229\u7528Poisson\u5706\u76d8\u91c7\u6837\u5f97\u5230\u7684\u4e00\u7ec4UV\u504f\u79fb\u91cf, \u8fdb\u884cPCF.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\nhighp float PCF_Filter(in sampler2D shadowMap, highp vec2 uv, highp float zReceiver, highp float filterRadius)\r\n{ \r\n    highp float sum = 0.0;\r\n\r\n    for (int i = 0; i < PCF_NUM_SAMPLES; ++i)\r\n    {\r\n        highp float depth = unpack(texture(shadowMap, uv + poissonDisk[i] * filterRadius));\r\n\r\n        if (zReceiver <= depth)\r\n\t    {\r\n\t\tsum += 1.0;\r\n\t    }\r\n\t}\r\n\r\n\tfor (int i = 0; i < PCF_NUM_SAMPLES; ++i)\r\n\t{\r\n            highp float depth = unpack(texture(shadowMap, uv + -poissonDisk[i].yx * filterRadius));\r\n\r\n\t    if (zReceiver <= depth)\r\n\t    {\r\n\t        sum += 1.0;\r\n\t    }\r\n\t}\r\n\r\n\treturn sum \/ (2.0 * float(PCF_NUM_SAMPLES));\r\n}\r\n\r\n<\/pre>\n<p><strong>2. PCSS<\/strong><\/p>\n<p>\u5165\u53e3\u51fd\u6570\u4e3a<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\nhighp float PCSS(in sampler2D shadowMap, in highp vec4 coords)\r\n{\r\n    highp vec2 uv = coords.xy;\r\n    highp float zReceiver = coords.z; \/\/ Assumed to be eye-space z in this code\r\n    \/\/ STEP 1: blocker search\r\n    poissonDiskSamples(uv);\r\n    highp float avgBlockerDepth = findBlocker(shadowMap, uv, zReceiver);\r\n\r\n    \/\/ There are no occluders so early out(this saves filtering)\r\n    if (avgBlockerDepth == -1.0)\r\n    {\r\n\treturn 1.0;\r\n    }\r\n\r\n    \/\/ STEP 2: penumbra size\r\n    highp float penumbraRatio = penumbraSize(zReceiver, avgBlockerDepth);\r\n    highp float filterSize    = penumbraRatio * LIGHT_SIZE_UV * NEAR_PLANE \/ zReceiver;\r\n\r\n    \/\/ STEP 3: filtering\r\n    \/\/ return avgBlockerDepth;\r\n    return PCF_Filter(shadowMap, coords.xy, zReceiver, filterSize);\r\n}\r\n\r\n<\/pre>\n<p>$\\cdot$ <strong>Step 1: \u5bfb\u627e\u906e\u6321\u7269<\/strong><\/p>\n<p>\u901a\u8fc7findBlocker\u51fd\u6570\u5f97\u5230\u5f53\u524dShading Point\u7684\u6240\u6709\u906e\u6321\u7269\u7684\u5e73\u5747\u6df1\u5ea6.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\nhighp float findBlocker(in sampler2D shadowMap, highp vec2 uv, highp float zReceiver) \r\n{\r\n    \/\/ This uses similar triangles to compute what\r\n    \/\/ area of the shadow map we should search\r\n    highp float searchRadius = LIGHT_SIZE_UV * (zReceiver - NEAR_PLANE) \/ zReceiver;\r\n    highp float blockerDepthSum = 0.0;\r\n    highp int numBlockers = 0;\r\n    for (int i = 0; i < BLOCKER_SEARCH_NUM_SAMPLES; ++i)\r\n    {\r\n        highp float shadowMapDepth = unpack(texture(shadowMap, uv + poissonDisk[i] * searchRadius));\r\n\r\n\tif (shadowMapDepth < zReceiver)\r\n\t{\r\n\t    blockerDepthSum += shadowMapDepth;\r\n\t    ++numBlockers;\r\n\t}\r\n    }\r\n\r\n    if (numBlockers == 0)\r\n    {\r\n\treturn -1.0;\r\n    }\r\n\r\n    return blockerDepthSum \/ float(numBlockers);\r\n}\r\n\r\n<\/pre>\n<p>$\\cdot$ <strong>Step 2: \u8ba1\u7b97\u534a\u5f71\u5927\u5c0f<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\nhighp float penumbraSize(highp float zReceiver, highp float zBlocker) \r\n{\r\n    \/\/ Parallel plane estimation\r\n    return (zReceiver - zBlocker) \/ zBlocker;\r\n}\r\n\r\nhighp float penumbraRatio = penumbraSize(zReceiver, avgBlockerDepth);\r\nhighp float filterSize    = penumbraRatio * LIGHT_SIZE_UV * NEAR_PLANE \/ zReceiver;\r\n\r\n<\/pre>\n<p>\u539f\u7406\u53ef\u53c2\u8003\u4e0b\u56fe.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.caiqinyi.cn\/wp-content\/uploads\/2023\/02\/penumbra_size.png\" alt=\"\" width=\"264\" height=\"349\" class=\"aligncenter size-full wp-image-2963\" srcset=\"https:\/\/www.caiqinyi.cn\/wp-content\/uploads\/2023\/02\/penumbra_size.png 528w, https:\/\/www.caiqinyi.cn\/wp-content\/uploads\/2023\/02\/penumbra_size-227x300.png 227w\" sizes=\"(max-width: 264px) 100vw, 264px\" \/><\/p>\n<p>$\\cdot$ <strong>Step 3: Filtering<\/strong><\/p>\n<p>\u5c06\u4e0a\u8ff0\u6b65\u9aa4\u5f97\u5230\u7684filterSize\u4f20\u9012\u7ed9PCF_Filter\u51fd\u6570.<\/p>\n<p>\u6700\u7ec8, \u5e94\u7528\u4e86PCSS\u7684\u9634\u5f71\u7ed8\u5236\u7ed3\u679c\u5982\u4e0b\u56fe\u6240\u793a. \u53ef\u4ee5\u770b\u51fa, \u9634\u5f71\u8fb9\u7f18\u5904\u5b58\u5728\u7740\u5927\u91cf\u7684\u566a\u70b9, \u540e\u9762\u5982\u679c\u6709\u673a\u4f1a, \u518d\u52a0\u4e2a\u964d\u566a\u7684Pass\u53ed~<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.caiqinyi.cn\/wp-content\/uploads\/2023\/02\/PCSS_result.png\" alt=\"\" width=\"627\" height=\"445\" class=\"aligncenter size-full wp-image-2967\" srcset=\"https:\/\/www.caiqinyi.cn\/wp-content\/uploads\/2023\/02\/PCSS_result.png 627w, https:\/\/www.caiqinyi.cn\/wp-content\/uploads\/2023\/02\/PCSS_result-300x213.png 300w\" sizes=\"(max-width: 627px) 100vw, 627px\" \/><\/p>\n<p>\u5b8c\u6574\u4ee3\u7801\u53ef\u53c2\u8003: <a href=\"https:\/\/github.com\/HlG4399\/Piccolo\/commit\/e152ee2fd58f183fdfa1332efd7502a5cd610f4c\">Piccolo with PCF and PCSS<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u6700\u8fd1\u5728Piccolo\u5f15\u64ce\u4e0a\u5b9e\u73b0\u4e86PCF\u4e0ePCSS, \u867d\u7136\u7ed8\u5236\u7ed3\u679c\u4e2d\u5b58\u5728\u7740\u5927\u91cf\u7684\u566a\u70b9, \u4f46\u8fd8\u662f\u60f3\u7740\u8bb0\u5f55\u4e00\u4e0b\u5b9e\u73b0\u7684 &hellip; <a href=\"https:\/\/www.caiqinyi.cn\/index.php\/2023\/02\/13\/pcf_pcss_implementation_piccolo_engine\/\" class=\"more-link\">\u7ee7\u7eed\u9605\u8bfb<span class=\"screen-reader-text\">\u5728Piccolo\u5f15\u64ce\u4e0a\u5b9e\u73b0PCF\u4e0ePCSS<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10],"tags":[],"_links":{"self":[{"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/posts\/2916"}],"collection":[{"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/comments?post=2916"}],"version-history":[{"count":25,"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/posts\/2916\/revisions"}],"predecessor-version":[{"id":2971,"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/posts\/2916\/revisions\/2971"}],"wp:attachment":[{"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/media?parent=2916"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/categories?post=2916"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/tags?post=2916"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}