{"id":773,"date":"2024-02-24T12:31:41","date_gmt":"2024-02-24T12:31:41","guid":{"rendered":"https:\/\/noirccc.net\/blog\/?p=773"},"modified":"2024-06-21T12:04:39","modified_gmt":"2024-06-21T12:04:39","slug":"%e5%8e%9f%e7%a5%9e%e6%b2%99%e6%bc%a0%e8%84%9a%e5%8d%b0%e8%bd%ae%e5%bb%93%e5%ae%9e%e7%8e%b0","status":"publish","type":"post","link":"https:\/\/noirccc.net\/blog\/zh\/posts\/773","title":{"rendered":"\u539f\u795e\u6c99\u6f20\u811a\u5370\u8f6e\u5ed3\u5b9e\u73b0"},"content":{"rendered":"\n<p><p>\u539f\u795e3.x\u7684\u6c99\u6f20\u5730\u9762\u4ea4\u4e92\u5f88\u6709\u610f\u601d\uff0c\u5c1d\u8bd5\u590d\u73b0\u4e86\u4e00\u4e0b\u3002\u76ee\u524d\u80fd\u591f\u590d\u73b0\u57fa\u7840\u7684\u4e0b\u9677\u548c\u6062\u590d\u6548\u679c\u3002\u8fd9\u91cc\u8bb0\u5f55\u5927\u81f4\u65b9\u6848\u3002\u9009\u62e9\u8fd9\u4e2a\u65b9\u6848\u7684\u4e3b\u8981\u539f\u56e0\u662f\u7f8e\u672f\u6548\u679c\u4e0a\u9650\u9ad8\u4e14\u914d\u7f6e\u7b80\u5355\uff0c\u573a\u666f\u91cc\u653e\u4e00\u4e2a script \u5c31\u80fd\u751f\u6548\uff0c\u4e0e\u7f51\u4e0a\u4e00\u4e9b\u6559\u7a0b\u4e0d\u540c\uff0c\u65e0\u9700\u4e3a\u6bcf\u4e2a\u89d2\u8272\u914d\u7f6e\u7c92\u5b50\u53d1\u5c04\u5668\u3002<\/p>\n\u65b9\u6848\u662f\u7528\u4e24\u5f20 depth texture\uff0c\u4e00\u5f20\u4ece\u4e0a\u65b9\u6355\u6349\u5730\u5f62\uff0c\u4e00\u5f20\u4ece\u4e0b\u65b9\u6355\u6349\u7269\u4f53\uff0c\u5408\u5e76\u8ba1\u7b97\u51fa\u4e00\u5f20\u7269\u4f53\u9677\u5165\u6c99\u5730\u7684 indent map\u3002indent map \u7684 R\u901a\u9053\u4ee3\u8868\u51f9\u9677\uff0c\u901a\u8fc7\u540e\u5904\u7406\u5728G\u901a\u9053\u751f\u6210\u63cf\u8fb9\uff08\u6a21\u62df\u51f9\u9677\u5468\u56f4\u7684\u4e00\u5708\u51f8\u8d77\uff09\u5e76\u6a21\u7cca\u3002\u6c99\u5730 shader \u7528\u8fd9\u5f20 indent map \u4f5c\u4e3a\u9ad8\u5ea6\u56fe\uff0c\u914d\u5408 distance-based tessellation\u3002<\/p>\n\n\n\n<div class=\"wp-block-argon-github github-info-card card shadow-sm github-info-card-full\" data-author=\"NoiRC256\" data-project=\"GenshinSandprints\"><div class=\"github-info-card-header\"><a href=\"https:\/\/github.com\/\" target=\"_blank\" title=\"Github\" rel=\"noopener\"><span><i class=\"fa fa-github\"><\/i>\u00a0GitHub<\/span><\/a><\/div><div class=\"github-info-card-body\"><div class=\"github-info-card-name-a\"><a href=\"https:\/\/github.com\/NoiRC256\/GenshinSandprints\" target=\"_blank\" rel=\"noopener\"><span class=\"github-info-card-name\">NoiRC256\/GenshinSandprints<\/span><\/a><\/div><div class=\"github-info-card-description\"><\/div><\/div><div class=\"github-info-card-bottom\"><span class=\"github-info-card-meta github-info-card-meta-stars\"><i class=\"fa fa-star\"><\/i>\u00a0<span class=\"github-info-card-stars\"><\/span><\/span><span class=\"github-info-card-meta github-info-card-meta-forks\"><i class=\"fa fa-code-fork\"><\/i>\u00a0<span class=\"github-info-card-forks\"><\/span><\/span><\/div><\/div>\n\n\n\n<p>\u76ee\u524d\u53ea\u80fd\u5728\u56fa\u5b9a\u8303\u56f4\u5185\u751f\u6548\uff0c\u4e14\u6ca1\u6709\u4f18\u5316\u6027\u80fd\u5f00\u9500\u548c\u7f8e\u672f\u8868\u73b0\u3002\u540e\u7eed\u6709\u7a7a\u53ef\u80fd\u4f1a\u6162\u6162\u7ee7\u7eed\u5f00\u53d1\u3002<\/p>\n\n\n\n<iframe src=\"\/\/player.bilibili.com\/player.html?aid=814822795&amp;bvid=BV1mG4y1r7bY&amp;cid=813709569&amp;page=1\n&amp;high_quality=1&amp;danmaku=0\" scrolling=\"no\" border=\"0\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\" style=\"width: 100%; height: 600px; max-width: 100%\uff1balign:center; padding:20px 0;\"> <\/iframe>\n\n\n\n<iframe src=\"\/\/player.bilibili.com\/player.html?aid=389084779&amp;bvid=BV14d4y117KG&amp;cid=859879258&amp;page=1\n&amp;high_quality=1&amp;danmaku=0\" scrolling=\"no\" border=\"0\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\" style=\"width: 100%; height: 600px; max-width: 100%\uff1balign:center; padding:20px 0;\"> <\/iframe>\n\n\n\n<p>\u5927\u81f4\u9700\u6c42\uff1a<\/p>\n\n\n\n<ul>\n<li>\u4e0d\u4ec5\u9650\u4e8e\u89d2\u8272\u3002\u602a\u7269\uff0c\u7269\u4ef6\u7b49\u90fd\u80fd\u4e0e\u6c99\u5730\u4ea7\u751f\u4ea4\u4e92<\/li>\n\n\n\n<li>\u65e0\u9700\u4e3a\u6bcf\u4e2a\u53ef\u4ee5\u4ea7\u751f\u4ea4\u4e92\u7684\u5355\u4f4d\u505a\u7279\u6b8a\u914d\u7f6e<\/li>\n\n\n\n<li>\u6c99\u5b50\u4e0b\u9677\u533a\u57df\u7684\u8f6e\u5ed3\u8d34\u5408\u4e0e\u5176\u63a5\u89e6\u7684 mesh \uff08\u662f mesh \u672c\u8eab\u800c\u4e0d\u662f\u78b0\u649e\u4f53\u79ef\uff09<\/li>\n\n\n\n<li>\u4e0b\u9677\u533a\u57df\u5468\u56f4\u6709\u4e00\u5708\u51f8\u8d77\u7684\u6c99\u5b50\uff0c\u6a21\u62df\u6c99\u5b50\u88ab\u5411\u5468\u56f4\u63a8\u5f00\u7684\u6548\u679c<\/li>\n\n\n\n<li>\u4e0b\u9677\u968f\u65f6\u95f4\u6062\u590d<\/li>\n\n\n\n<li>\u6548\u679c\u751f\u6548\u8303\u56f4\u53ef\u4ee5\u5f88\u5927\uff0c\u517c\u5bb9\u5f00\u653e\u4e16\u754c<\/li>\n<\/ul>\n\n\n\n<p>Some simple interactive snow shaders found online require special per-object setups. Eg. Add particle emitters to a character&#8217;s left and right foot, use a camera to capture particles from the top, and pass the render texture to the shader. Most approaches also only work in a small pre-defined area. These methods work well for small projects and demos, but lack accuracy, flexibility, and scalabiliy. Scalability is a crucial aspect to consider, especially for games like Genshin Impact, where there&#8217;a a large expanding open world and new characters are being constantly implemented. It would be quite cumbersome to add another step to the character configuration process, just for one functionality available in certain regions of a scene. It would be better to have a system that is decoupled from the character configuration process. Furthermore, it we would need a lot of work to ensure visual quality using the particle emitter approach, since the shapes of the particles are largely fixed.<\/p>\n\n\n\n<p>Batman: Arkham Origins uses a depth capture method, described in <a href=\"https:\/\/www.youtube.com\/watch?v=87rg95XBalE\" target=\"_blank\" rel=\"noopener\" title=\"\">this GDC video<\/a>. This is a promising approach with high extendability. Camera depth texture captures object shapes with higher precision, and we don&#8217;t have to setup particle systems for every character or object we want to capture. There are some limitations though. The depth capture method used in Batman: Arkham Origins only supports flat terrain, and doesn&#8217;t work well on uneven surfaces. Objects on a higher elevation might be ignored because they&#8217;re outside the depth threshold. One way to address this problem is to use a second depth camera to capture terrain depth. Then, we can combine object depth with terrain depth to obtain a normalized depth texture that describes object depth in terrain space. Another problem is open world compatibility. Batman: Arkham Origins uses a pooling approach to manage multiple depth textures for different pre-defined areas. To allow easier open world integration, it might be possible to just use one texture, and constantly offset its contents based on the world offset of our character.<\/p>\n\n\n\n<p>The current WIP terrain deformation pipeline uses a modified approach to achieve similar results as Genshin Impact.<\/p>\n\n\n\n<h3>Features<\/h3>\n\n\n\n<p>\u221a The shape of sand deformation follows the contour of whatever mesh that intersects with the terrain.<\/p>\n\n\n\n<p>\u221a Detailed indents, including a ring of raised sand around the indent, simulating how sand is pushed away from the point of contact.<\/p>\n\n\n\n<p>\u221a Indentations slowly regenerate over time.<\/p>\n\n\n\n<p>\u221a Compatible with open world. The effect will be triggered within an area around the player character.<\/p>\n\n\n\n<p>\u221a No special configuration needed. Any mesh can leave trails on the terrain as long as they&#8217;re in the target layers.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"DynamicIndent WIP 1\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/hWOKrJXC8oQ?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<h3>How it works<\/h3>\n\n\n\n<ul>\n<li>Use a 2-camera setup: Bottom camera to capture object depths, and top camera to capture terrain depth. The depth textures are combined to generate a single normalized depth texture of object depths.<\/li>\n\n\n\n<li>Apply Kawase blur to the depth texture to smooth the result. Apply an extra pass to generate outlines on a different color channel.<\/li>\n\n\n\n<li>Areas where sand should be lowered are now marked by R pixels, while areas where sand should be raised are marked by G pixels.<\/li>\n\n\n\n<li>Add the new pixels to the current heightmap texture. A compute shader updates the texture to fade pixels over time, which regenerates the indentations.<\/li>\n\n\n\n<li>An external script passes required information to the sand shader and controls the worldspace position of the depth cameras. This script can be configured to follow the current active character and provide its wordspace position change per frame. The heigthmap is shifted based on target position change. This way, the effect will always be available around the player.<\/li>\n\n\n\n<li>The sand shader uses the heightmap texture to perform distance-based tessellation. The shader also maps worldspace position change to texture uv, so that deformation is applied at the correct position.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='https:\/\/noirccc.net\/blog\/wp-content\/uploads\/2023\/01\/dynamicindent-ex1_2.webp'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  decoding=\"async\" loading=\"lazy\" data-original=\"https:\/\/noirccc.net\/blog\/wp-content\/uploads\/2023\/01\/dynamicindent-ex1_2.webp\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" alt=\"\" class=\"wp-image-487\" width=\"470\" height=\"576\"  sizes=\"(max-width: 470px) 100vw, 470px\" \/><\/div><\/figure>\n\n\n\n<h3>Note<\/h3>\n\n\n\n<ul>\n<li>No Unity terrain system integration at the moment.<\/li>\n<\/ul>\n\n\n\n<ul>\n<li>Due to precision limitations, the heigtmap under bilinear\/trilinear filtering will be come a bit more blurry every time it&#8217;s shifted. A potential solution is to accumulate character position change and only offset the texture when we reach whole values.<\/li>\n\n\n\n<li>Genshin Impact has special self-shadows in the indented area. This is not implemented here.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>\u539f\u795e3.x\u7684\u6c99\u6f20\u5730\u9762\u4ea4\u4e92\u5f88\u6709\u610f\u601d\uff0c\u5c1d\u8bd5\u590d\u73b0\u4e86\u4e00\u4e0b\u3002\u76ee\u524d\u80fd\u591f\u590d\u73b0\u57fa\u7840\u7684\u4e0b\u9677\u548c\u6062\u590d\u6548\u679c\u3002\u8fd9\u91cc\u8bb0\u5f55\u5927\u81f4\u65b9\u6848\u3002\u9009\u62e9\u8fd9\u4e2a\u65b9\u6848\u7684\u4e3b\u8981\u539f\u56e0\u662f\u7f8e\u672f\u6548\u679c\u4e0a\u9650\u9ad8\u4e14\u914d\u7f6e\u7b80\u5355\uff0c\u573a\u666f\u91cc\u653e\u4e00\u4e2a script \u5c31\u80fd\u751f\u6548\uff0c\u4e0e\u7f51\u4e0a\u4e00\u4e9b\u6559\u7a0b\u4e0d\u540c\uff0c\u65e0\u9700\u4e3a\u6bcf\u4e2a\u89d2\u8272\u914d\u7f6e\u7c92\u5b50\u53d1\u5c04\u5668\u3002 \u65b9\u6848\u662f\u7528\u4e24\u5f20 depth texture\uff0c\u4e00\u5f20\u4ece\u4e0a\u65b9\u6355\u6349\u5730\u5f62\uff0c\u4e00\u5f20\u4ece\u4e0b\u65b9\u6355\u6349\u7269\u4f53\uff0c\u5408\u5e76\u8ba1\u7b97\u51fa\u4e00\u5f20\u7269\u4f53\u9677\u5165\u6c99\u5730\u7684 indent map\u3002indent map \u7684 R\u901a\u9053\u4ee3\u8868\u51f9\u9677\uff0c\u901a\u8fc7\u540e\u5904\u7406\u5728G\u901a\u9053\u751f\u6210\u63cf\u8fb9\uff08\u6a21\u62df\u51f9\u9677\u5468\u56f4\u7684\u4e00\u5708\u51f8\u8d77\uff09\u5e76\u6a21\u7cca\u3002\u6c99\u5730 shader \u7528\u8fd9\u5f20 indent map \u4f5c\u4e3a\u9ad8\u5ea6\u56fe\uff0c\u914d\u5408 distance-based tessellation\u3002 \u76ee\u524d\u53ea\u80fd\u5728\u56fa\u5b9a\u8303\u56f4\u5185\u751f\u6548\uff0c\u4e14\u6ca1\u6709\u4f18\u5316\u6027\u80fd\u5f00\u9500\u548c\u7f8e\u672f\u8868\u73b0\u3002\u540e\u7eed\u6709\u7a7a\u53ef\u80fd\u4f1a\u6162\u6162\u7ee7\u7eed\u5f00\u53d1\u3002 \u5927\u81f4\u9700\u6c42\uff1a Some simple interactive snow shaders found online require special per-object setups. Eg. Add particle emitters to a character&#8217;s left and right foot, use a camera to capture particles from the top, and pass the render [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":523,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[47,56],"tags":[60,63,69],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/posts\/773"}],"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=773"}],"version-history":[{"count":10,"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/posts\/773\/revisions"}],"predecessor-version":[{"id":1215,"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/posts\/773\/revisions\/1215"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/media\/523"}],"wp:attachment":[{"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/media?parent=773"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/categories?post=773"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/noirccc.net\/blog\/wp-json\/wp\/v2\/tags?post=773"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}