{"id":1441,"date":"2024-05-28T23:21:27","date_gmt":"2024-05-28T14:21:27","guid":{"rendered":"https:\/\/xn--k10aa.com\/?p=1441"},"modified":"2024-10-20T21:16:39","modified_gmt":"2024-10-20T12:16:39","slug":"cs3","status":"publish","type":"post","link":"https:\/\/remoooo.com\/en\/cs3\/","title":{"rendered":"Compute Shader Learning Notes (Part 3) Particle Effects and Cluster Behavior Simulation"},"content":{"rendered":"\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-316.png\" alt=\"img\" class=\"wp-image-1455 lazyload\"\/><noscript><img decoding=\"async\" width=\"1436\" height=\"768\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-316.png\" alt=\"img\" class=\"wp-image-1455 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-316.png 1436w, https:\/\/remoooo.com\/wp-content\/uploads\/image-316-300x160.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-316-1024x548.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-316-768x411.png 768w\" sizes=\"(max-width: 1436px) 100vw, 1436px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u7d27\u63a5\u7740\u4e0a\u4e00\u7bc7\u6587\u7ae0<\/p>\n\n\n\n<p><a href=\"https:\/\/xn--k10aa.com\/compute-shader%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%ef%bc%88%e4%b8%80%ef%bc%89-2\/\" data-type=\"post\" data-id=\"1403\">remoooo\uff1aCompute Shader\u5b66\u4e60\u7b14\u8bb0\uff08\u4e8c\uff09\u4e4b \u540e\u5904\u7406\u6548\u679c<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">L4 \u7c92\u5b50\u6548\u679c\u4e0e\u7fa4\u96c6\u884c\u4e3a\u6a21\u62df<\/h2>\n\n\n\n<p>\u672c\u7ae0\u8282\u4f7f\u7528Compute Shader\u751f\u6210\u7c92\u5b50\u3002\u5b66\u4e60\u5982\u4f55\u4f7f\u7528DrawProcedural\u548cDrawMeshInstancedIndirect\uff0c\u4e5f\u5c31\u662fGPU Instancing\u3002<\/p>\n\n\n\n<p>\u77e5\u8bc6\u70b9\u603b\u7ed3\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Compute Shader\u3001Material\u3001C#\u811a\u672c\u548cShader\u5171\u540c\u534f\u4f5c<\/li>\n\n\n\n<li>Graphics.DrawProcedural<\/li>\n\n\n\n<li>material.SetBuffer()<\/li>\n\n\n\n<li>xorshift \u968f\u673a\u7b97\u6cd5<\/li>\n\n\n\n<li>\u96c6\u7fa4\u884c\u4e3a\u6a21\u62df<\/li>\n\n\n\n<li>Graphics.DrawMeshInstancedIndirect<\/li>\n\n\n\n<li>\u65cb\u8f6c\u5e73\u79fb\u7f29\u653e\u77e9\u9635\uff0c\u9f50\u6b21\u5750\u6807<\/li>\n\n\n\n<li>Surface Shader<\/li>\n\n\n\n<li>ComputeBufferType.Default<\/li>\n\n\n\n<li>#pragma instancing_options procedural:setup<\/li>\n\n\n\n<li>unity_InstanceID<\/li>\n\n\n\n<li>Skinned Mesh Renderer<\/li>\n\n\n\n<li>\u6570\u636e\u5bf9\u9f50<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">1. \u4ecb\u7ecd\u4e0e\u51c6\u5907\u5de5\u4f5c<\/h3>\n\n\n\n<p>Compute Shader\u9664\u4e86\u53ef\u4ee5\u540c\u65f6\u5904\u7406\u5927\u91cf\u7684\u6570\u636e\uff0c\u8fd8\u6709\u4e00\u4e2a\u5173\u952e\u7684\u4f18\u52bf\uff0c\u5c31\u662fBuffer\u5b58\u50a8\u5728GPU\u4e2d\u3002\u56e0\u6b64\u53ef\u4ee5\u5c06Compute Shader\u5904\u7406\u597d\u7684\u6570\u636e\u76f4\u63a5\u4f20\u9012\u7ed9\u4e0eMaterial\u5173\u8054\u7684Shader\u4e2d\uff0c\u5373Vertex\/Fragment Shader\u3002\u8fd9\u91cc\u7684\u5173\u952e\u5c31\u662f\uff0cmaterial\u4e5f\u53ef\u4ee5\u50cfCompute Shader\u4e00\u6837SetBuffer()\uff0c\u76f4\u63a5\u4eceGPU\u7684Buffer\u4e2d\u8bbf\u95ee\u6570\u636e\uff01<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-303.png\" alt=\"img\" class=\"wp-image-1442 lazyload\"\/><noscript><img decoding=\"async\" width=\"1440\" height=\"359\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-303.png\" alt=\"img\" class=\"wp-image-1442 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-303.png 1440w, https:\/\/remoooo.com\/wp-content\/uploads\/image-303-300x75.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-303-1024x255.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-303-768x191.png 768w\" sizes=\"(max-width: 1440px) 100vw, 1440px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u4f7f\u7528Compute Shader\u6765\u5236\u4f5c\u7c92\u5b50\u7cfb\u7edf\u53ef\u4ee5\u5145\u5206\u4f53\u73b0Compute Shader\u7684\u5f3a\u5927\u5e76\u884c\u80fd\u529b\u3002<\/p>\n\n\n\n<p>\u5728\u6e32\u67d3\u8fc7\u7a0b\u4e2d\uff0cVertex Shader\u4f1a\u4eceCompute Buffer\u4e2d\u8bfb\u53d6\u6bcf\u4e2a\u7c92\u5b50\u7684\u4f4d\u7f6e\u548c\u5176\u4ed6\u5c5e\u6027\uff0c\u5e76\u5c06\u5b83\u4eec\u8f6c\u6362\u4e3a\u5c4f\u5e55\u4e0a\u7684\u9876\u70b9\u3002Fragment Shader\u5219\u8d1f\u8d23\u6839\u636e\u8fd9\u4e9b\u9876\u70b9\u7684\u4fe1\u606f\uff08\u5982\u4f4d\u7f6e\u548c\u989c\u8272\uff09\u6765\u751f\u6210\u50cf\u7d20\u3002\u901a\u8fc7Graphics.DrawProcedural\u65b9\u6cd5\uff0cUnity\u53ef\u4ee5<strong>\u76f4\u63a5\u6e32\u67d3<\/strong>\u8fd9\u4e9b\u7531Shader\u5904\u7406\u7684\u9876\u70b9\uff0c\u65e0\u9700\u9884\u5148\u5b9a\u4e49\u7684\u7f51\u683c\u7ed3\u6784\uff0c\u4e5f\u4e0d\u4f9d\u8d56Mesh Renderer\uff0c\u8fd9\u5bf9\u4e8e\u6e32\u67d3\u5927\u91cf\u7c92\u5b50\u7279\u522b\u6709\u6548\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2. \u7c92\u5b50\u4f60\u597d<\/h3>\n\n\n\n<p>\u6b65\u9aa4\u4e5f\u662f\u975e\u5e38\u7b80\u5355\uff0c\u5728 C# \u4e2d\u5b9a\u4e49\u597d\u7c92\u5b50\u7684\u4fe1\u606f\uff08\u4f4d\u7f6e\u3001\u901f\u5ea6\u4e0e\u751f\u547d\u5468\u671f\uff09\uff0c\u521d\u59cb\u5316\u5c06\u6570\u636e\u4f20\u7ed9Buffer\uff0c\u7ed1\u5b9aBuffer\u5230Compute Shader\u548cMaterial\u3002\u6e32\u67d3\u9636\u6bb5\u5728OnRenderObject()\u91cc\u8c03\u7528Graphics.DrawProceduralNow\u5b9e\u73b0\u9ad8\u6548\u5730\u6e32\u67d3\u7c92\u5b50\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-306.png\" alt=\"img\" class=\"wp-image-1445 lazyload\"\/><noscript><img decoding=\"async\" width=\"1366\" height=\"216\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-306.png\" alt=\"img\" class=\"wp-image-1445 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-306.png 1366w, https:\/\/remoooo.com\/wp-content\/uploads\/image-306-300x47.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-306-1024x162.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-306-768x121.png 768w\" sizes=\"(max-width: 1366px) 100vw, 1366px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u65b0\u5efa\u4e00\u4e2a\u573a\u666f\uff0c\u5236\u4f5c\u4e00\u4e2a\u6548\u679c\uff1a\u767e\u4e07\u7c92\u5b50\u8ddf\u968f\u9f20\u6807\u7efd\u653e\u751f\u547d\u7684\u7c92\u5b50\uff0c\u5982\u4e0b\uff1a<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-311.png\" alt=\"img\" class=\"wp-image-1450 lazyload\"\/><noscript><img decoding=\"async\" width=\"956\" height=\"374\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-311.png\" alt=\"img\" class=\"wp-image-1450 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-311.png 956w, https:\/\/remoooo.com\/wp-content\/uploads\/image-311-300x117.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-311-768x300.png 768w\" sizes=\"(max-width: 956px) 100vw, 956px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u5199\u5230\u8fd9\u91cc\uff0c\u4e0d\u7981\u8ba9\u6211\u601d\u7eea\u4e07\u5343\u3002\u7c92\u5b50\u7684\u751f\u547d\u5468\u671f\u5f88\u77ed\u6682\uff0c\u5982\u540c\u661f\u706b\u4e00\u822c\u77ac\u95f4\u70b9\u71c3\uff0c\u53c8\u5982\u540c\u6d41\u661f\u4e00\u95ea\u5373\u901d\u3002\u7eb5\u6709\u5343\u767e\u78e8\u96be\uff0c\u6211\u4ea6\u4e0d\u8fc7\u662f\u4ebf\u4e07\u5c18\u57c3\u4e2d\u7684\u4e00\u7c92\uff0c\u5e73\u51e1\u4e14\u6e3a\u5c0f\u3002\u8fd9\u4e9b\u7c92\u5b50\uff0c\u867d\u6216\u8bb8\u4f1a\u5728\u7a7a\u95f4\u4e2d\u968f\u673a\u6f02\u6d6e\uff08<strong>\u4f7f\u7528&#8221;Xorshift&#8221;\u7b97\u6cd5\u8ba1\u7b97\u7c92\u5b50\u751f\u6210\u7684\u4f4d\u7f6e<\/strong>\uff09\uff0c\u6216\u8bb8\u4f1a\u62e5\u6709\u72ec\u4e00\u65e0\u4e8c\u7684\u8272\u5f69\uff0c\u4f46\u5b83\u4eec\u7ec8\u7a76\u9003\u4e0d\u51fa\u88ab\u7a0b\u5f0f\u9884\u8bbe\u7684\u547d\u8fd0\u3002\u8fd9\u96be\u9053\u4e0d\u6b63\u662f\u6211\u7684\u4eba\u751f\u5199\u7167\u5417\uff1f\u6309\u90e8\u5c31\u73ed\u5730\u4e0a\u6f14\u7740\u81ea\u5df1\u7684\u89d2\u8272\uff0c\u65e0\u6cd5\u9003\u8131\u90a3\u65e0\u5f62\u7684\u675f\u7f1a\u3002<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\u201c\u4e0a\u5e1d\u5df2\u6b7b\uff01\u800c\u6211\u4eec\u8fd9\u4e9b\u6740\u6b7b\u4ed6\u7684\u4eba\uff0c\u53c8\u600e\u80fd\u4e0d\u611f\u5230\u6700\u5927\u7684\u75db\u82e6\u5462\uff1f\u201d &#8211; \u5f17\u91cc\u5fb7\u91cc\u5e0c\u00b7\u5c3c\u91c7<\/p>\n<\/blockquote>\n\n\n\n<p>\u5c3c\u91c7\u4e0d\u4ec5\u5ba3\u544a\u4e86\u5b97\u6559\u4fe1\u4ef0\u7684\u6d88\u901d\uff0c\u66f4\u6307\u51fa\u4e86\u73b0\u4ee3\u4eba\u9762\u4e34\u7684\u865a\u65e0\u611f\uff0c\u5373\u6ca1\u6709\u4e86\u4f20\u7edf\u7684\u9053\u5fb7\u548c\u5b97\u6559\u652f\u67f1\uff0c\u4eba\u4eec\u611f\u5230\u4e86\u524d\u6240\u672a\u6709\u7684\u5b64\u72ec\u548c\u65b9\u5411\u611f\u7684\u7f3a\u5931\u3002\u7c92\u5b50\u5728C#\u811a\u672c\u4e2d\u88ab\u5b9a\u4e49\u3001\u521b\u9020\uff0c\u6309\u7167\u7279\u5b9a\u89c4\u5219\u8fd0\u52a8\u548c\u6d88\u4ea1\uff0c\u8fd9\u4e0e\u5c3c\u91c7\u6240\u63cf\u8ff0\u7684\u73b0\u4ee3\u4eba\u5728\u5b87\u5b99\u4e2d\u7684\u72b6\u6001\u9887\u6709\u76f8\u4f3c\u4e4b\u5904\u3002\u867d\u7136\u6bcf\u4e2a\u4eba\u90fd\u8bd5\u56fe\u5bfb\u627e\u81ea\u5df1\u7684\u610f\u4e49\uff0c\u4f46\u6700\u7ec8\u4ecd\u53d7\u9650\u4e8e\u66f4\u5e7f\u6cdb\u7684\u793e\u4f1a\u548c\u5b87\u5b99\u89c4\u5219\u3002<\/p>\n\n\n\n<p>\u751f\u6d3b\u4e2d\u5145\u6ee1\u4e86\u5404\u79cd\u4e0d\u53ef\u907f\u514d\u7684\u75db\u82e6\uff0c\u53cd\u6620\u4e86\u4eba\u7c7b\u5b58\u5728\u7684\u56fa\u6709\u865a\u65e0\u548c\u5b64\u72ec\u611f\u3002\u5931\u604b\u3001\u751f\u79bb\u6b7b\u522b\u3001\u5de5\u4f5c\u5931\u610f\u4ee5\u53ca<strong>\u5373\u5c06\u7f16\u5199\u7684\u7c92\u5b50\u6b7b\u4ea1\u903b\u8f91<\/strong>\u7b49\u7b49\uff0c\u90fd\u5370\u8bc1\u4e86\u5c3c\u91c7\u6240\u8868\u8fbe\u7684\uff0c\u751f\u6d3b\u4e2d\u6ca1\u6709\u4ec0\u4e48\u662f\u6c38\u6052\u4e0d\u53d8\u7684\u3002\u540c\u4e00\u4e2aBuffer\u4e2d\u7684\u7c92\u5b50\u5fc5\u7136\u5728\u672a\u6765\u67d0\u4e2a\u65f6\u523b\u6d88\u5931\uff0c\u8fd9\u4f53\u73b0\u4e86\u5c3c\u91c7\u6240\u63cf\u8ff0\u7684\u73b0\u4ee3\u4eba\u7684\u5b64\u72ec\u611f\uff0c\u4e2a\u4f53\u53ef\u80fd\u4f1a\u611f\u53d7\u5230\u524d\u6240\u672a\u6709\u7684\u5b64\u7acb\u65e0\u63f4\uff0c\u56e0\u6b64\u6bcf\u4e2a\u4eba\u90fd\u662f\u5b64\u72ec\u7684\u6218\u58eb\uff0c\u5fc5\u987b\u5b66\u4f1a\u72ec\u81ea\u9762\u5bf9\u5185\u5fc3\u7684\u9f99\u5377\u98ce\u548c\u5916\u90e8\u4e16\u754c\u7684\u51b7\u6f20\u3002<\/p>\n\n\n\n<p>\u4f46\u662f\u6ca1\u5173\u7cfb\uff0c\u300c\u590f\u5929\u4f1a\u5468\u800c\u590d\u59cb\uff0c\u8be5\u76f8\u9022\u7684\u4eba\u4f1a\u518d\u6b21\u76f8\u9022\u300d\u3002\u672c\u6587\u7684\u7c92\u5b50\u4e5f\u4f1a\u5728\u7ed3\u675f\u540e\u518d\u6b21\u751f\u6210\uff0c\u4ee5\u6700\u597d\u7684\u72b6\u6001\u62e5\u62b1\u5c5e\u4e8e\u5b83\u7684Buffer\u3002<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Summer will come around again. People who meet will meet again.<\/p>\n<\/blockquote>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-305.png\" alt=\"img\" class=\"wp-image-1444 lazyload\"\/><noscript><img decoding=\"async\" width=\"280\" height=\"272\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-305.png\" alt=\"img\" class=\"wp-image-1444 lazyload\"\/><\/noscript><\/figure>\n\n\n\n<p>\u5f53\u524d\u7248\u672c\u4ee3\u7801\uff0c\u53ef\u4ee5\u81ea\u5df1\u62f7\u4e0b\u6765\u8dd1\u8dd1\uff08\u90fd\u6709\u6ce8\u91ca\uff09\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Compute Shader\uff1ahttps:\/\/github.com\/Remyuu\/Unity-Compute-Shader-Learn\/blob\/L4_First_Particle\/Assets\/Shaders\/ParticleFun.compute<\/li>\n\n\n\n<li>CPU\uff1ahttps:\/\/github.com\/Remyuu\/Unity-Compute-Shader-Learn\/blob\/L4_First_Particle\/Assets\/Scripts\/ParticleFun.cs<\/li>\n\n\n\n<li>Shader\uff1ahttps:\/\/github.com\/Remyuu\/Unity-Compute-Shader-Learn\/blob\/L4_First_Particle\/Assets\/Shaders\/Particle.shader<\/li>\n<\/ul>\n\n\n\n<p>\u5e9f\u8bdd\u5c31\u8bf4\u5230\u8fd9\uff0c\u5148\u770b\u770b C# \u811a\u672c\u662f\u548b\u5199\u7684\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-304.png\" alt=\"img\" class=\"wp-image-1443 lazyload\"\/><noscript><img decoding=\"async\" width=\"962\" height=\"250\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-304.png\" alt=\"img\" class=\"wp-image-1443 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-304.png 962w, https:\/\/remoooo.com\/wp-content\/uploads\/image-304-300x78.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-304-768x200.png 768w\" sizes=\"(max-width: 962px) 100vw, 962px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u8001\u6837\u5b50\uff0c\u5148\u5b9a\u4e49\u7c92\u5b50\u7684Buffer\uff08\u7ed3\u6784\u4f53\uff09\uff0c\u5e76\u4e14\u521d\u59cb\u5316\u4e00\u4e0b\u5b50\uff0c\u7136\u540e\u4f20\u7ed9GPU\uff0c<strong>\u5173\u952e\u5728\u4e8e\u6700\u540e\u4e09\u884c\u5c06Buffer\u7ed1\u5b9a\u7ed9shader\u7684\u64cd\u4f5c<\/strong>\u3002\u4e0b\u9762\u7701\u7565\u53f7\u7684\u4ee3\u7801\u6ca1\u4ec0\u4e48\u597d\u8bb2\u7684\uff0c\u90fd\u662f\u5e38\u89c4\u64cd\u4f5c\uff0c\u7528\u6ce8\u91ca\u4e00\u7b14\u5e26\u8fc7\u4e86\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>struct Particle{\n    public Vector3 position; \/\/ \u7c92\u5b50\u4f4d\u7f6e\n    public Vector3 velocity; \/\/ \u7c92\u5b50\u901f\u5ea6\n    public float life;       \/\/ \u7c92\u5b50\u751f\u547d\u5468\u671f\n}\nComputeBuffer particleBuffer; \/\/ GPU \u7684 Buffer\n...\n\/\/ Init() \u4e2d\n    \/\/ \u521d\u59cb\u5316\u7c92\u5b50\u6570\u7ec4\n    Particle&#91;] particleArray = new Particle&#91;particleCount];\n\n    for (int i = 0; i &lt; particleCount; i++){\n        \/\/ \u751f\u6210\u968f\u673a\u4f4d\u7f6e\u548c\u5f52\u4e00\u5316\n        ...\n        \/\/ \u8bbe\u7f6e\u7c92\u5b50\u7684\u521d\u59cb\u4f4d\u7f6e\u548c\u901f\u5ea6\n        ... \n        \/\/ \u8bbe\u7f6e\u7c92\u5b50\u7684\u751f\u547d\u5468\u671f\n        particleArray&#91;i].life = Random.value * 5.0f + 1.0f;\n    }\n    \/\/ \u521b\u5efa\u5e76\u8bbe\u7f6eCompute Buffer\n    ...\n    \/\/ \u67e5\u627eCompute Shader\u4e2d\u7684kernel ID\n    ...\n    \/\/ \u7ed1\u5b9aCompute Buffer\u5230shader\n    shader.SetBuffer(kernelID, \"particleBuffer\", particleBuffer);\n    material.SetBuffer(\"particleBuffer\", particleBuffer);\n    material.SetInt(\"_PointSize\", pointSize);<\/code><\/pre>\n\n\n\n<p>\u5173\u952e\u7684\u6e32\u67d3\u9636\u6bb5\u6765\u4e86 OnRenderObject() \u3002material.SetPass \u7528\u4e8e\u8bbe\u7f6e\u6e32\u67d3\u6750\u8d28\u901a\u9053\u3002DrawProceduralNow \u65b9\u6cd5\u5728\u4e0d\u4f7f\u7528\u4f20\u7edf\u7f51\u683c\u7684\u60c5\u51b5\u4e0b\u7ed8\u5236\u51e0\u4f55\u4f53\u3002MeshTopology.Points \u6307\u5b9a\u4e86\u6e32\u67d3\u7684\u62d3\u6251\u7c7b\u578b\u4e3a\u70b9\uff0cGPU\u4f1a\u628a\u6bcf\u4e2a\u9876\u70b9\u4f5c\u4e3a\u4e00\u4e2a\u70b9\u6765\u5904\u7406\uff0c\u4e0d\u4f1a\u8fdb\u884c\u9876\u70b9\u4e4b\u95f4\u7684\u8fde\u7ebf\u6216\u9762\u7684\u5f62\u6210\u3002\u7b2c\u4e8c\u4e2a\u53c2\u6570 1 \u8868\u793a\u4ece\u7b2c\u4e00\u4e2a\u9876\u70b9\u5f00\u59cb\u7ed8\u5236\u3002particleCount \u6307\u5b9a\u4e86\u8981\u6e32\u67d3\u7684\u9876\u70b9\u6570\uff0c\u8fd9\u91cc\u662f\u7c92\u5b50\u7684\u6570\u91cf\uff0c\u5373\u544a\u8bc9GPU\u603b\u5171\u9700\u8981\u6e32\u67d3\u591a\u5c11\u4e2a\u70b9\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void OnRenderObject()\n{\n    material.SetPass(0);\n    Graphics.DrawProceduralNow(MeshTopology.Points, 1, particleCount);\n}<\/code><\/pre>\n\n\n\n<p>\u83b7\u53d6\u5f53\u524d\u9f20\u6807\u4f4d\u7f6e\u65b9\u6cd5\u3002OnGUI()\u8fd9\u4e2a\u65b9\u6cd5\u6bcf\u4e00\u5e27\u53ef\u80fd\u8c03\u7528\u591a\u6b21\u3002z\u503c\u8bbe\u4e3a\u6444\u50cf\u673a\u7684\u8fd1\u88c1\u526a\u9762\u52a0\u4e0a\u4e00\u4e2a\u504f\u79fb\u91cf\uff0c\u8fd9\u91cc\u52a014\u662f\u4e3a\u4e86\u5f97\u5230\u4e00\u4e2a\u66f4\u5408\u9002\u89c6\u89c9\u6df1\u5ea6\u7684\u4e16\u754c\u5750\u6807\uff08\u4e5f\u53ef\u4ee5\u81ea\u884c\u8c03\u6574\uff09\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void OnGUI()\n{\n    Vector3 p = new Vector3();\n    Camera c = Camera.main;\n    Event e = Event.current;\n    Vector2 mousePos = new Vector2();\n\n    \/\/ Get the mouse position from Event.\n    \/\/ Note that the y position from Event is inverted.\n    mousePos.x = e.mousePosition.x;\n    mousePos.y = c.pixelHeight - e.mousePosition.y;\n\n    p = c.ScreenToWorldPoint(new Vector3(mousePos.x, mousePos.y, c.nearClipPlane + 14));\n\n    cursorPos.x = p.x;\n    cursorPos.y = p.y;\n}<\/code><\/pre>\n\n\n\n<p>\u4e0a\u9762\u5df2\u7ecf\u5c06 ComputeBuffer particleBuffer; \u4f20\u5230\u4e86Compute Shader\u548cShader\u4e2d\u3002<\/p>\n\n\n\n<p>\u5148\u770b\u770bCompute Shader\u7684\u6570\u636e\u7ed3\u6784\u3002\u6ca1\u4ec0\u4e48\u7279\u522b\u7684\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u5b9a\u4e49\u7c92\u5b50\u6570\u636e\u7ed3\u6784\nstruct Particle\n{\n    float3 position;  \/\/ \u7c92\u5b50\u7684\u4f4d\u7f6e\n    float3 velocity;  \/\/ \u7c92\u5b50\u7684\u901f\u5ea6\n    float life;       \/\/ \u7c92\u5b50\u7684\u5269\u4f59\u751f\u547d\u65f6\u95f4\n};\n\n\/\/ \u7528\u4e8e\u5b58\u50a8\u548c\u66f4\u65b0\u7c92\u5b50\u6570\u636e\u7684\u7ed3\u6784\u5316\u7f13\u51b2\u533a\uff0c\u53ef\u4eceGPU\u8bfb\u5199\nRWStructuredBuffer&lt;Particle&gt; particleBuffer;\n\n\/\/ \u4eceCPU\u8bbe\u7f6e\u7684\u53d8\u91cf\nfloat deltaTime;       \/\/ \u4ece\u4e0a\u4e00\u5e27\u5230\u5f53\u524d\u5e27\u7684\u65f6\u95f4\u5dee\nfloat2 mousePosition;  \/\/ \u5f53\u524d\u9f20\u6807\u4f4d\u7f6e<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-307.png\" alt=\"img\" class=\"wp-image-1446 lazyload\"\/><noscript><img decoding=\"async\" width=\"1440\" height=\"944\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-307.png\" alt=\"img\" class=\"wp-image-1446 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-307.png 1440w, https:\/\/remoooo.com\/wp-content\/uploads\/image-307-300x197.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-307-1024x671.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-307-768x503.png 768w\" sizes=\"(max-width: 1440px) 100vw, 1440px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u8fd9\u91cc\u7b80\u5355\u8bb2\u8bb2\u4e00\u4e2a\u7279\u522b\u597d\u7528\u7684\u968f\u673a\u6570\u5e8f\u5217\u751f\u6210\u65b9\u6cd5 xorshift \u7b97\u6cd5\u3002\u4e00\u4f1a\u5c06\u7528\u6765\u968f\u673a\u7c92\u5b50\u7684\u8fd0\u52a8\u65b9\u5411\u5982\u4e0a\u56fe\uff0c\u7c92\u5b50\u4f1a\u968f\u673a\u671d\u7740\u4e09\u7ef4\u7684\u65b9\u5411\u8fd0\u52a8\u3002<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u8be6\u7ec6\u53c2\u8003\uff1ahttps:\/\/en.wikipedia.org\/wiki\/Xorshift<\/li>\n\n\n\n<li>\u539f\u8bba\u6587\u94fe\u63a5\uff1ahttps:\/\/www.jstatsoft.org\/article\/view\/v008i14<\/li>\n<\/ul>\n\n\n\n<p>\u8fd9\u4e2a\u7b97\u6cd503\u5e74\u7531George Marsaglia\u63d0\u51fa\uff0c\u4f18\u70b9\u5728\u4e8e\u8fd0\u7b97\u901f\u5ea6\u6781\u5feb\uff0c\u5e76\u4e14\u975e\u5e38\u8282\u7ea6\u7a7a\u95f4\u3002\u5373\u4f7f\u662f\u6700\u7b80\u5355\u7684Xorshift\u5b9e\u73b0\uff0c\u5176\u4f2a\u968f\u673a\u6570\u5468\u671f\u4e5f\u662f\u76f8\u5f53\u957f\u7684\u3002<\/p>\n\n\n\n<p>\u57fa\u672c\u64cd\u4f5c\u662f\u4f4d\u79fb\uff08shift\uff09\u548c\u5f02\u6216\uff08xor\uff09\u3002\u7b97\u6cd5\u7684\u540d\u5b57\u4e5f\u7531\u6b64\u800c\u6765\u3002\u5b83\u7684\u6838\u5fc3\u662f\u7ef4\u62a4\u4e00\u4e2a\u975e\u96f6\u7684\u72b6\u6001\u53d8\u91cf\uff0c\u901a\u8fc7\u5bf9\u8fd9\u4e2a\u72b6\u6001\u53d8\u91cf\u8fdb\u884c\u4e00\u7cfb\u5217\u7684\u4f4d\u79fb\u548c\u5f02\u6216\u64cd\u4f5c\u6765\u751f\u6210\u968f\u673a\u6570\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u7528\u4e8e\u751f\u6210\u968f\u673a\u6570\u7684\u72b6\u6001\u53d8\u91cf\nuint rng_state;\n\nuint rand_xorshift() {\n    \/\/ Xorshift algorithm from George Marsaglia's paper\n    rng_state ^= (rng_state &lt;&lt; 13);  \/\/ \u5c06\u72b6\u6001\u53d8\u91cf\u5de6\u79fb13\u4f4d\uff0c\u7136\u540e\u4e0e\u539f\u72b6\u6001\u8fdb\u884c\u5f02\u6216\n    rng_state ^= (rng_state &gt;&gt; 17);  \/\/ \u5c06\u66f4\u65b0\u540e\u7684\u72b6\u6001\u53d8\u91cf\u53f3\u79fb17\u4f4d\uff0c\u518d\u6b21\u8fdb\u884c\u5f02\u6216\n    rng_state ^= (rng_state &lt;&lt; 5);   \/\/ \u6700\u540e\uff0c\u5c06\u72b6\u6001\u53d8\u91cf\u5de6\u79fb5\u4f4d\uff0c\u8fdb\u884c\u6700\u540e\u4e00\u6b21\u5f02\u6216\n    return rng_state;                \/\/ \u8fd4\u56de\u66f4\u65b0\u540e\u7684\u72b6\u6001\u53d8\u91cf\u4f5c\u4e3a\u751f\u6210\u7684\u968f\u673a\u6570\n}<\/code><\/pre>\n\n\n\n<p><strong>\u57fa\u672cXorshift<\/strong> \u7b97\u6cd5\u7684\u6838\u5fc3\u5df2\u5728\u524d\u9762\u7684\u89e3\u91ca\u4e2d\u63d0\u5230\uff0c\u4e0d\u8fc7\u4e0d\u540c\u7684\u4f4d\u79fb\u7ec4\u5408\u53ef\u4ee5\u521b\u5efa\u591a\u79cd\u53d8\u4f53\u3002\u539f\u8bba\u6587\u8fd8\u63d0\u5230\u4e86Xorshift128\u53d8\u4f53\u3002\u4f7f\u7528128\u4f4d\u7684\u72b6\u6001\u53d8\u91cf\uff0c\u901a\u8fc7\u56db\u6b21\u4e0d\u540c\u7684\u4f4d\u79fb\u548c\u5f02\u6216\u64cd\u4f5c\u66f4\u65b0\u72b6\u6001\u3002\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-310.png\" alt=\"img\" class=\"wp-image-1449 lazyload\"\/><noscript><img decoding=\"async\" width=\"1440\" height=\"289\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-310.png\" alt=\"img\" class=\"wp-image-1449 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-310.png 1440w, https:\/\/remoooo.com\/wp-content\/uploads\/image-310-300x60.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-310-1024x206.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-310-768x154.png 768w\" sizes=\"(max-width: 1440px) 100vw, 1440px\" \/><\/noscript><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ c language Ver\nuint32_t xorshift128(void) {\n    static uint32_t x = 123456789;\n    static uint32_t y = 362436069;\n    static uint32_t z = 521288629;\n    static uint32_t w = 88675123; \n    uint32_t t = x ^ (x &lt;&lt; 11);\n    x = y; y = z; z = w;\n    w = w ^ (w &gt;&gt; 19) ^ (t ^ (t &gt;&gt; 8));\n    return w;\n}<\/code><\/pre>\n\n\n\n<p>\u53ef\u4ee5\u4ea7\u751f\u66f4\u957f\u7684\u5468\u671f\u548c\u66f4\u597d\u7684\u7edf\u8ba1\u6027\u80fd\u3002\u8fd9\u4e2a\u53d8\u4f53\u7684\u5468\u671f\u63a5\u8fd1 \uff0c\u975e\u5e38\u5389\u5bb3\u3002<\/p>\n\n\n\n<p>\u603b\u7684\u6765\u8bf4\uff0c\u8fd9\u4e2a\u7b97\u6cd5\u7528\u5728\u6e38\u620f\u5f00\u53d1\u5b8c\u5168\u8db3\u591f\u4e86\uff0c\u53ea\u662f\u4e0d\u9002\u5408\u7528\u5728\u5bc6\u7801\u5b66\u7b49\u9886\u57df\u3002<\/p>\n\n\n\n<p>\u5728Compute Shader\u4e2d\u4f7f\u7528\u8fd9\u4e2a\u7b97\u6cd5\u65f6\uff0c\u9700\u8981\u6ce8\u610fXorshift\u7b97\u6cd5\u751f\u6210\u7684\u968f\u673a\u6570\u8303\u56f4\u65f6uint32\u7684\u7684\u8303\u56f4\uff0c\u9700\u8981\u518d\u505a\u4e00\u4e2a\u6620\u5c04( [0, 2^32-1] \u6620\u5c04\u5230 [0, 1])\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>float tmp = (1.0 \/ 4294967296.0);  \/\/ \u8f6c\u6362\u56e0\u5b50\nrand_xorshift()) * tmp<\/code><\/pre>\n\n\n\n<p>\u800c\u7c92\u5b50\u8fd0\u52a8\u65b9\u5411\u662f\u6709\u7b26\u53f7\u7684\uff0c\u56e0\u6b64\u53ea\u8981\u5728\u8fd9\u4e2a\u57fa\u7840\u4e0a\u51cf\u53bb0.5\u5c31\u597d\u4e86\u3002\u4e09\u4e2a\u65b9\u5411\u7684\u968f\u673a\u8fd0\u52a8\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>float f0 = float(rand_xorshift()) * tmp - 0.5;\nfloat f1 = float(rand_xorshift()) * tmp - 0.5;\nfloat f2 = float(rand_xorshift()) * tmp - 0.5;\nfloat3 normalF3 = normalize(float3(f0, f1, f2)) * 0.8f; \/\/ \u7f29\u653e\u4e86\u8fd0\u52a8\u65b9\u5411<\/code><\/pre>\n\n\n\n<p>\u6bcf\u4e00\u4e2aKernel\u9700\u8981\u5b8c\u6210\u7684\u5185\u5bb9\u5982\u4e0b\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u5148\u5f97\u5230Buffer\u4e2d\u4e0a\u4e00\u5e27\u7684\u7c92\u5b50\u4fe1\u606f<\/li>\n\n\n\n<li>\u7ef4\u62a4\u7c92\u5b50Buffer\uff08\u8ba1\u7b97\u7c92\u5b50\u901f\u5ea6\uff0c\u66f4\u65b0\u4f4d\u7f6e\u3001\u751f\u547d\u503c\uff09\uff0c\u5199\u56deBuffer<\/li>\n\n\n\n<li>\u82e5\u751f\u547d\u503c\u5c0f\u4e8e0\uff0c\u91cd\u65b0\u751f\u6210\u4e00\u4e2a\u7c92\u5b50<\/li>\n<\/ul>\n\n\n\n<p>\u751f\u6210\u7c92\u5b50\uff0c\u521d\u59cb\u4f4d\u7f6e\u5229\u7528\u521a\u521aXorshift\u5f97\u5230\u7684\u968f\u673a\u6570\uff0c\u5b9a\u4e49\u7c92\u5b50\u7684\u751f\u547d\u503c\uff0c\u91cd\u7f6e\u901f\u5ea6\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u8bbe\u7f6e\u7c92\u5b50\u7684\u65b0\u4f4d\u7f6e\u548c\u751f\u547d\u503c\nparticleBuffer&#91;id].position = float3(normalF3.x + mousePosition.x, normalF3.y + mousePosition.y, normalF3.z + 3.0);\nparticleBuffer&#91;id].life = 4;  \/\/ \u91cd\u7f6e\u751f\u547d\u503c\nparticleBuffer&#91;id].velocity = float3(0,0,0);  \/\/ \u91cd\u7f6e\u901f\u5ea6<\/code><\/pre>\n\n\n\n<p>\u6700\u540e\u662fShader\u7684\u57fa\u672c\u6570\u636e\u7ed3\u6784\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>struct Particle{\n    float3 position;\n    float3 velocity;\n    float life;\n};\n\nstruct v2f{\n    float4 position : SV_POSITION;\n    float4 color : COLOR;\n    float life : LIFE;\n    float size: PSIZE;\n};\n\/\/ particles' data\nStructuredBuffer&lt;Particle&gt; particleBuffer;<\/code><\/pre>\n\n\n\n<p>\u7136\u540e\u5728\u9876\u70b9\u7740\u8272\u5668\u8ba1\u7b97\u7c92\u5b50\u7684\u9876\u70b9\u8272\u3001\u9876\u70b9\u7684Clip\u4f4d\u7f6e\u4ee5\u53ca\u4f20\u8f93\u4e00\u4e2a\u9876\u70b9\u5927\u5c0f\u7684\u4fe1\u606f\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>v2f vert(uint vertex_id : SV_VertexID, uint instance_id : SV_InstanceID){\n    v2f o = (v2f)0;\n\n    \/\/ Color\n    float life = particleBuffer&#91;instance_id].life;\n    float lerpVal = life * 0.25f;\n    o.color = fixed4(1.0f - lerpVal+0.1, lerpVal+0.1, 1.0f, lerpVal);\n\n    \/\/ Position\n    o.position = UnityObjectToClipPos(float4(particleBuffer&#91;instance_id].position, 1.0f));\n    o.size = _PointSize;\n\n    return o;\n}<\/code><\/pre>\n\n\n\n<p>\u7247\u5143\u7740\u8272\u5668\u8ba1\u7b97\u63d2\u503c\u989c\u8272\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>float4 frag(v2f i) : COLOR{\n    return i.color;\n}<\/code><\/pre>\n\n\n\n<p>\u81f3\u6b64\uff0c\u5c31\u53ef\u4ee5\u5f97\u5230\u4e0a\u9762\u7684\u6548\u679c\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-312.png\" alt=\"img\" class=\"wp-image-1451 lazyload\"\/><noscript><img decoding=\"async\" width=\"1110\" height=\"424\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-312.png\" alt=\"img\" class=\"wp-image-1451 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-312.png 1110w, https:\/\/remoooo.com\/wp-content\/uploads\/image-312-300x115.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-312-1024x391.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-312-768x293.png 768w\" sizes=\"(max-width: 1110px) 100vw, 1110px\" \/><\/noscript><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">3. Quad\u7c92\u5b50<\/h3>\n\n\n\n<p>\u4e0a\u4e00\u8282\u6bcf\u4e00\u4e2a\u7c92\u5b50\u90fd\u53ea\u6709\u4e00\u4e2a\u70b9\uff0c\u6ca1\u4ec0\u4e48\u610f\u601d\u3002\u73b0\u5728\u628a\u4e00\u4e2a\u70b9\u53d8\u6210\u4e00\u4e2aQuad\u3002\u5728Unity\u4e2d\uff0c\u6ca1\u6709Quad\uff0c\u53ea\u6709\u4e24\u4e2a\u4e09\u89d2\u5f62\u7ec4\u6210\u7684\u5047Quad\u3002<\/p>\n\n\n\n<p>\u5f00\u5e72\uff0c\u57fa\u4e8e\u4e0a\u9762\u7684\u4ee3\u7801\u3002\u5728 C# \u4e2d\u5b9a\u4e49\u9876\u70b9\uff0c\u4e00\u4e2aQuad\u7684\u5c3a\u5bf8\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ struct\nstruct Vertex\n{\n    public Vector3 position;\n    public Vector2 uv;\n    public float life;\n}\nconst int SIZE_VERTEX = 6 * sizeof(float);\npublic float quadSize = 0.1f; \/\/ Quad\u7684\u5c3a\u5bf8<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-313.png\" alt=\"img\" class=\"wp-image-1452 lazyload\"\/><noscript><img decoding=\"async\" width=\"1440\" height=\"636\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-313.png\" alt=\"img\" class=\"wp-image-1452 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-313.png 1440w, https:\/\/remoooo.com\/wp-content\/uploads\/image-313-300x133.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-313-1024x452.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-313-768x339.png 768w\" sizes=\"(max-width: 1440px) 100vw, 1440px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u6bcf\u4e00\u4e2a\u7c92\u5b50\u7684\u7684\u57fa\u7840\u4e0a\uff0c\u8bbe\u7f6e\u516d\u4e2a\u9876\u70b9\u7684uv\u5750\u6807\uff0c\u7ed9\u9876\u70b9\u7740\u8272\u5668\u7528\u3002\u5e76\u4e14\u6309\u7167Unity\u89c4\u5b9a\u7684\u987a\u5e8f\u7ed8\u5236\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>index = i*6;\n    \/\/Triangle 1 - bottom-left, top-left, top-right\n    vertexArray&#91;index].uv.Set(0,0);\n    vertexArray&#91;index+1].uv.Set(0,1);\n    vertexArray&#91;index+2].uv.Set(1,1);\n    \/\/Triangle 2 - bottom-left, top-right, bottom-right\n    vertexArray&#91;index+3].uv.Set(0,0);\n    vertexArray&#91;index+4].uv.Set(1,1);\n    vertexArray&#91;index+5].uv.Set(1,0);<\/code><\/pre>\n\n\n\n<p>\u6700\u540e\u4f20\u9012\u7ed9Buffer\u3002\u8fd9\u91cc\u7684 halfSize \u76ee\u7684\u662f\u4f20\u7ed9Compute Shader\u8ba1\u7b97Quad\u7684\u5404\u4e2a\u9876\u70b9\u4f4d\u7f6e\u7528\u7684\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vertexBuffer = new ComputeBuffer(numVertices, SIZE_VERTEX);\nvertexBuffer.SetData(vertexArray);\nshader.SetBuffer(kernelID, \"vertexBuffer\", vertexBuffer);\nshader.SetFloat(\"halfSize\", quadSize*0.5f);\n\nmaterial.SetBuffer(\"vertexBuffer\", vertexBuffer);<\/code><\/pre>\n\n\n\n<p>\u6e32\u67d3\u9636\u6bb5\u628a\u70b9\u6539\u4e3a\u4e09\u89d2\u5f62\uff0c\u6709\u516d\u4e2a\u70b9\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void OnRenderObject()\n{\n    material.SetPass(0);\n    Graphics.DrawProceduralNow(MeshTopology.Triangles, 6, numParticles);\n}<\/code><\/pre>\n\n\n\n<p>\u5728Shader\u4e2d\u6539\u4e00\u4e0b\u8bbe\u7f6e\uff0c\u63a5\u6536\u9876\u70b9\u6570\u636e\u3002\u5e76\u4e14\u63a5\u6536\u4e00\u5f20\u8d34\u56fe\u7528\u4e8e\u663e\u793a\u3002\u9700\u8981\u505aalpha\u5254\u9664\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>_MainTex(\"Texture\", 2D) = \"white\" {}     \n...\nTags{ \"Queue\"=\"Transparent\" \"RenderType\"=\"Transparent\" \"IgnoreProjector\"=\"True\" }\nLOD 200\nBlend SrcAlpha OneMinusSrcAlpha\nZWrite Off\n...\n    struct Vertex{\n        float3 position;\n        float2 uv;\n        float life;\n    };\n    StructuredBuffer&lt;Vertex&gt; vertexBuffer;\n    sampler2D _MainTex;\n    v2f vert(uint vertex_id : SV_VertexID, uint instance_id : SV_InstanceID)\n    {\n        v2f o = (v2f)0;\n\n        int index = instance_id*6 + vertex_id;\n        float lerpVal = vertexBuffer&#91;index].life * 0.25f;\n        o.color = fixed4(1.0f - lerpVal+0.1, lerpVal+0.1, 1.0f, lerpVal);\n        o.position = UnityWorldToClipPos(float4(vertexBuffer&#91;index].position, 1.0f));\n        o.uv = vertexBuffer&#91;index].uv;\n\n        return o;\n    }\n\n    float4 frag(v2f i) : COLOR\n    {\n        fixed4 color = tex2D( _MainTex, i.uv ) * i.color;\n        return color;\n    }<\/code><\/pre>\n\n\n\n<p>\u5728Compute Shader\u4e2d\uff0c\u589e\u52a0\u63a5\u6536\u9876\u70b9\u6570\u636e\uff0c\u8fd8\u6709halfSize\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>struct Vertex\n{\n    float3 position;\n    float2 uv;\n    float life;\n};\nRWStructuredBuffer&lt;Vertex&gt; vertexBuffer;\nfloat halfSize;<\/code><\/pre>\n\n\n\n<p>\u8ba1\u7b97\u6bcf\u4e2aQuad\u516d\u4e2a\u9876\u70b9\u7684\u4f4d\u7f6e\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-308.png\" alt=\"img\" class=\"wp-image-1447 lazyload\"\/><noscript><img decoding=\"async\" width=\"1440\" height=\"568\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-308.png\" alt=\"img\" class=\"wp-image-1447 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-308.png 1440w, https:\/\/remoooo.com\/wp-content\/uploads\/image-308-300x118.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-308-1024x404.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-308-768x303.png 768w\" sizes=\"(max-width: 1440px) 100vw, 1440px\" \/><\/noscript><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/Set the vertex buffer \/\/\n    int index = id.x * 6;\n    \/\/Triangle 1 - bottom-left, top-left, top-right   \n    vertexBuffer&#91;index].position.x = p.position.x-halfSize;\n    vertexBuffer&#91;index].position.y = p.position.y-halfSize;\n    vertexBuffer&#91;index].position.z = p.position.z;\n    vertexBuffer&#91;index].life = p.life;\n    vertexBuffer&#91;index+1].position.x = p.position.x-halfSize;\n    vertexBuffer&#91;index+1].position.y = p.position.y+halfSize;\n    vertexBuffer&#91;index+1].position.z = p.position.z;\n    vertexBuffer&#91;index+1].life = p.life;\n    vertexBuffer&#91;index+2].position.x = p.position.x+halfSize;\n    vertexBuffer&#91;index+2].position.y = p.position.y+halfSize;\n    vertexBuffer&#91;index+2].position.z = p.position.z;\n    vertexBuffer&#91;index+2].life = p.life;\n    \/\/Triangle 2 - bottom-left, top-right, bottom-right  \/\/ \/\/ \n    vertexBuffer&#91;index+3].position.x = p.position.x-halfSize;\n    vertexBuffer&#91;index+3].position.y = p.position.y-halfSize;\n    vertexBuffer&#91;index+3].position.z = p.position.z;\n    vertexBuffer&#91;index+3].life = p.life;\n    vertexBuffer&#91;index+4].position.x = p.position.x+halfSize;\n    vertexBuffer&#91;index+4].position.y = p.position.y+halfSize;\n    vertexBuffer&#91;index+4].position.z = p.position.z;\n    vertexBuffer&#91;index+4].life = p.life;\n    vertexBuffer&#91;index+5].position.x = p.position.x+halfSize;\n    vertexBuffer&#91;index+5].position.y = p.position.y-halfSize;\n    vertexBuffer&#91;index+5].position.z = p.position.z;\n    vertexBuffer&#91;index+5].life = p.life;<\/code><\/pre>\n\n\n\n<p>\u5927\u529f\u544a\u6210\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-309.png\" alt=\"img\" class=\"wp-image-1448 lazyload\"\/><noscript><img decoding=\"async\" width=\"1070\" height=\"616\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-309.png\" alt=\"img\" class=\"wp-image-1448 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-309.png 1070w, https:\/\/remoooo.com\/wp-content\/uploads\/image-309-300x173.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-309-1024x590.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-309-768x442.png 768w\" sizes=\"(max-width: 1070px) 100vw, 1070px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u5f53\u524d\u7248\u672c\u4ee3\u7801\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Compute Shader\uff1ahttps:\/\/github.com\/Remyuu\/Unity-Compute-Shader-Learn\/blob\/L4_Quad\/Assets\/Shaders\/QuadParticles.compute<\/li>\n\n\n\n<li>CPU\uff1ahttps:\/\/github.com\/Remyuu\/Unity-Compute-Shader-Learn\/blob\/L4_Quad\/Assets\/Scripts\/QuadParticles.cs<\/li>\n\n\n\n<li>Shader\uff1ahttps:\/\/github.com\/Remyuu\/Unity-Compute-Shader-Learn\/blob\/L4_Quad\/Assets\/Shaders\/QuadParticle.shader<\/li>\n<\/ul>\n\n\n\n<p>\u4e0b\u4e00\u8282\uff0c\u5c06Mesh\u5347\u7ea7\u4e3a\u9884\u5236\u4f53\uff0c\u5e76\u4e14\u5c1d\u8bd5\u6a21\u62df\u9e1f\u7c7b\u98de\u884c\u65f6\u7684\u96c6\u7fa4\u884c\u4e3a\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4. Flocking\uff08\u96c6\u7fa4\u884c\u4e3a\uff09\u6a21\u62df<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-317.png\" alt=\"img\" class=\"wp-image-1457 lazyload\"\/><noscript><img decoding=\"async\" width=\"1158\" height=\"604\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-317.png\" alt=\"img\" class=\"wp-image-1457 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-317.png 1158w, https:\/\/remoooo.com\/wp-content\/uploads\/image-317-300x156.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-317-1024x534.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-317-768x401.png 768w\" sizes=\"(max-width: 1158px) 100vw, 1158px\" \/><\/noscript><\/figure>\n\n\n\n<p>Flocking \u662f\u4e00\u79cd\u6a21\u62df\u81ea\u7136\u754c\u4e2d\u9e1f\u7fa4\u3001\u9c7c\u7fa4\u7b49\u52a8\u7269\u96c6\u4f53\u8fd0\u52a8\u884c\u4e3a\u7684\u7b97\u6cd5\u3002\u6838\u5fc3\u662f\u57fa\u4e8e\u4e09\u4e2a\u57fa\u672c\u7684\u884c\u4e3a\u89c4\u5219\uff0c\u7531Craig Reynolds\u5728Sig 87\u63d0\u51fa\uff0c\u901a\u5e38\u88ab\u79f0\u4e3a\u201cBoids\u201d\u7b97\u6cd5\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u5206\u79bb\uff08Separation\uff09<\/strong> \u7c92\u5b50\u4e0e\u7c92\u5b50\u4e4b\u95f4\u4e0d\u80fd\u592a\u9760\u8fd1\uff0c\u8981\u6709\u8fb9\u754c\u611f\u3002\u5177\u4f53\u662f\u8ba1\u7b97\u5468\u8fb9\u4e00\u5b9a\u534a\u5f84\u7684\u7c92\u5b50\u7136\u540e\u8ba1\u7b97\u4e00\u4e2a\u907f\u514d\u78b0\u649e\u7684\u65b9\u5411\u3002<\/li>\n\n\n\n<li><strong>\u5bf9\u9f50\uff08Alignment\uff09<\/strong> \u4e2a\u4f53\u7684\u901f\u5ea6\u8d8b\u4e8e\u7fa4\u4f53\u7684\u5e73\u5747\u901f\u5ea6\uff0c\u8981\u6709\u5f52\u5c5e\u611f\u3002\u5177\u4f53\u662f\u8ba1\u7b97\u89c6\u89c9\u8303\u56f4\u5185\u7c92\u5b50\u7684\u5e73\u5747\u901f\u5ea6\uff08\u901f\u5ea6\u5927\u5c0f <strong>\u65b9\u5411<\/strong>\uff09\u3002\u8fd9\u4e2a\u89c6\u89c9\u8303\u56f4\u8981\u6839\u636e\u9e1f\u7c7b\u5b9e\u9645\u7684\u751f\u7269\u7279\u6027\u51b3\u5b9a\uff0c\u4e0b\u4e00\u8282\u4f1a\u63d0\u53ca\u3002<\/li>\n\n\n\n<li><strong>\u805a\u5408\uff08Cohesion\uff09<\/strong> \u4e2a\u4f53\u7684\u4f4d\u7f6e\u8d8b\u4e8e\u5e73\u5747\u4f4d\u7f6e\uff08\u7fa4\u4f53\u7684\u4e2d\u5fc3\uff09\uff0c\u8981\u6709\u5b89\u5168\u611f\u3002\u5177\u4f53\u662f\uff0c\u6bcf\u4e2a\u7c92\u5b50\u627e\u51fa\u5468\u56f4\u90bb\u5c45\u7684\u51e0\u4f55\u4e2d\u5fc3\uff0c\u8ba1\u7b97\u4e00\u4e2a\u79fb\u52a8\u5411\u91cf\uff08\u6700\u7ec8\u7ed3\u679c\u662f\u5e73\u5747<strong>\u4f4d\u7f6e<\/strong>\uff09\u3002<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-314.png\" alt=\"img\" class=\"wp-image-1453 lazyload\"\/><noscript><img decoding=\"async\" width=\"1176\" height=\"250\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-314.png\" alt=\"img\" class=\"wp-image-1453 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-314.png 1176w, https:\/\/remoooo.com\/wp-content\/uploads\/image-314-300x64.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-314-1024x218.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-314-768x163.png 768w\" sizes=\"(max-width: 1176px) 100vw, 1176px\" \/><\/noscript><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-318.png\" alt=\"img\" class=\"wp-image-1456 lazyload\"\/><noscript><img decoding=\"async\" width=\"1094\" height=\"350\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-318.png\" alt=\"img\" class=\"wp-image-1456 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-318.png 1094w, https:\/\/remoooo.com\/wp-content\/uploads\/image-318-300x96.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-318-1024x328.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-318-768x246.png 768w\" sizes=\"(max-width: 1094px) 100vw, 1094px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u601d\u8003\u4e00\u4e0b\uff0c\u4e0a\u9762\u4e09\u4e2a\u89c4\u5219\uff0c\u54ea\u4e00\u4e2a\u6700\u96be\u5b9e\u73b0\uff1f<\/p>\n\n\n\n<p>\u7b54\uff1aSeparation\u3002\u4f17\u6240\u5468\u77e5\uff0c\u8ba1\u7b97\u7269\u4f53\u95f4\u7684\u78b0\u649e\u662f\u975e\u5e38\u96be\u4ee5\u5b9e\u73b0\u7684\u3002\u56e0\u4e3a\u6bcf\u4e2a\u4e2a\u4f53\u90fd\u9700\u8981\u4e0e\u5176\u4ed6\u6240\u6709\u4e2a\u4f53\u8fdb\u884c\u8ddd\u79bb\u6bd4\u8f83\uff0c\u8fd9\u4f1a\u5bfc\u81f4\u7b97\u6cd5\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u63a5\u8fd1O(n^2)\uff0c\u5176\u4e2dn\u662f\u7c92\u5b50\u7684\u6570\u91cf\u3002\u4f8b\u5982\uff0c\u5982\u679c\u67091000\u4e2a\u7c92\u5b50\uff0c\u90a3\u4e48\u5728\u6bcf\u6b21\u8fed\u4ee3\u4e2d\u53ef\u80fd\u9700\u8981\u8fdb\u884c\u5c06\u8fd1500,000\u6b21\u7684\u8ddd\u79bb\u8ba1\u7b97\u3002\u5728\u5f53\u5e74\u539f\u8bba\u6587\u4f5c\u8005\u5728\u6ca1\u6709\u7ecf\u8fc7\u4f18\u5316\u7684\u539f\u59cb\u7b97\u6cd5\uff08\u65f6\u95f4\u590d\u6742\u5ea6O(N^2)\uff09\u4e2d\u6e32\u67d3\u4e00\u5e27\uff0880\u53ea\u9e1f\uff09\u6240\u9700\u65f6\u95f4\u662f95\u79d2\uff0c\u6e32\u67d3\u4e00\u4e2a300\u5e27\u7684\u52a8\u753b\u4f7f\u7528\u4e86\u5c06\u8fd19\u4e2a\u5c0f\u65f6\u3002<\/p>\n\n\n\n<p>\u4e00\u822c\u6765\u8bf4\uff0c\u4f7f\u7528\u56db\u53c9\u6811\u6216\u8005\u662f\u683c\u70b9\u54c8\u5e0c\uff08Spatial Hashing\uff09\u7b49\u7a7a\u95f4\u5212\u5206\u65b9\u6cd5\u53ef\u4ee5\u4f18\u5316\u8ba1\u7b97\u3002\u4e5f\u53ef\u4ee5\u7ef4\u62a4\u4e00\u4e2a\u8fd1\u90bb\u5217\u8868\u5b58\u50a8\u6bcf\u4e2a\u4e2a\u4f53\u5468\u8fb9\u4e00\u5b9a\u8ddd\u79bb\u7684\u4e2a\u4f53\u3002\u5f53\u7136\u4e86\uff0c\u8fd8\u53ef\u4ee5\u4f7f\u7528Compute Shader\u786c\u7b97\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-315.png\" alt=\"img\" class=\"wp-image-1454 lazyload\"\/><noscript><img decoding=\"async\" width=\"274\" height=\"264\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-315.png\" alt=\"img\" class=\"wp-image-1454 lazyload\"\/><\/noscript><\/figure>\n\n\n\n<p>\u5e9f\u8bdd\u4e0d\u591a\u8bf4\uff0c\u5f00\u5e72\u3002<\/p>\n\n\n\n<p>\u9996\u5148\u4e0b\u8f7d\u597d\u9884\u5907\u7684\u5de5\u7a0b\u6587\u4ef6\uff08\u5982\u679c\u6ca1\u6709\u4e8b\u5148\u51c6\u5907\uff09\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u9e1f\u7684Prefab\uff1ahttps:\/\/github.com\/Remyuu\/Unity-Compute-Shader-Learn\/blob\/main\/Assets\/Prefabs\/Boid.prefab<\/li>\n\n\n\n<li>\u811a\u672c\uff1ahttps:\/\/github.com\/Remyuu\/Unity-Compute-Shader-Learn\/blob\/main\/Assets\/Scripts\/SimpleFlocking.cs<\/li>\n\n\n\n<li>Compute Shader\uff1ahttps:\/\/github.com\/Remyuu\/Unity-Compute-Shader-Learn\/blob\/main\/Assets\/Shaders\/SimpleFlocking.compute<\/li>\n<\/ul>\n\n\n\n<p>\u7136\u540e\u6dfb\u52a0\u5230\u4e00\u4e2a\u7a7aGO\u4e2d\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-321.png\" alt=\"img\" class=\"wp-image-1460 lazyload\"\/><noscript><img decoding=\"async\" width=\"1124\" height=\"458\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-321.png\" alt=\"img\" class=\"wp-image-1460 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-321.png 1124w, https:\/\/remoooo.com\/wp-content\/uploads\/image-321-300x122.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-321-1024x417.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-321-768x313.png 768w\" sizes=\"(max-width: 1124px) 100vw, 1124px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u542f\u52a8\u9879\u76ee\u5c31\u53ef\u4ee5\u770b\u5230\u4e00\u5806\u9e1f\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-319.png\" alt=\"img\" class=\"wp-image-1458 lazyload\"\/><noscript><img decoding=\"async\" width=\"1062\" height=\"504\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-319.png\" alt=\"img\" class=\"wp-image-1458 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-319.png 1062w, https:\/\/remoooo.com\/wp-content\/uploads\/image-319-300x142.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-319-1024x486.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-319-768x364.png 768w\" sizes=\"(max-width: 1062px) 100vw, 1062px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u4e0b\u9762\u662f\u5173\u4e8e\u7fa4\u4f53\u884c\u4e3a\u6a21\u62df\u7684\u4e00\u4e9b\u53c2\u6570\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u5b9a\u4e49\u7fa4\u4f53\u884c\u4e3a\u6a21\u62df\u7684\u53c2\u6570\u3002\n    public float rotationSpeed = 1f; \/\/ \u65cb\u8f6c\u901f\u5ea6\u3002\n    public float boidSpeed = 1f; \/\/ Boid\u901f\u5ea6\u3002\n    public float neighbourDistance = 1f; \/\/ \u90bb\u8fd1\u8ddd\u79bb\u3002\n    public float boidSpeedVariation = 1f; \/\/ \u901f\u5ea6\u53d8\u5316\u3002\n    public GameObject boidPrefab; \/\/ Boid\u5bf9\u8c61\u7684\u9884\u5236\u4f53\u3002\n    public int boidsCount; \/\/ Boid\u7684\u6570\u91cf\u3002\n    public float spawnRadius; \/\/ Boid\u751f\u6210\u7684\u534a\u5f84\u3002\n    public Transform target; \/\/ \u7fa4\u4f53\u7684\u79fb\u52a8\u76ee\u6807\u3002<\/code><\/pre>\n\n\n\n<p>\u9664\u4e86Boid\u9884\u5236\u4f53boidPrefab\u548c\u751f\u6210\u534a\u5f84spawnRadius\u4e4b\u5916\uff0c\u5176\u4ed6\u90fd\u9700\u8981\u4f20\u7ed9GPU\u3002<\/p>\n\n\n\n<p>\u4e3a\u4e86\u65b9\u4fbf\uff0c\u8fd9\u4e00\u8282\u5148\u72af\u4e2a\u8822\uff0c\u53ea\u5728GPU\u8ba1\u7b97\u9e1f\u7684\u4f4d\u7f6e\u548c\u65b9\u5411\uff0c\u7136\u540e\u4f20\u56de\u7ed9CPU\uff0c\u505a\u5982\u4e0b\u5904\u7406\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>...\nboidsBuffer.GetData(boidsArray);\n\/\/ \u66f4\u65b0\u6bcf\u4e2a\u9e1f\u7684\u4f4d\u7f6e\u4e0e\u671d\u5411\nfor (int i = 0; i &lt; boidsArray.Length; i++){\n    boids&#91;i].transform.localPosition = boidsArray&#91;i].position;\n    if (!boidsArray&#91;i].direction.Equals(Vector3.zero)){\n        boids&#91;i].transform.rotation = Quaternion.LookRotation(boidsArray&#91;i].direction);\n    }\n}<\/code><\/pre>\n\n\n\n<p>Quaternion.LookRotation() \u65b9\u6cd5\u7528\u4e8e\u521b\u5efa\u4e00\u4e2a\u65cb\u8f6c\uff0c\u4f7f\u5bf9\u8c61\u9762\u5411\u6307\u5b9a\u7684\u65b9\u5411\u3002<\/p>\n\n\n\n<p>\u5728Compute Shader\u4e2d\u8ba1\u7b97\u6bcf\u4e2a\u9e1f\u7684\u4f4d\u7f6e\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#pragma kernel CSMain\n#define GROUP_SIZE 256    \nstruct Boid{\n    float3 position;\n    float3 direction;\n};\nRWStructuredBuffer&lt;Boid&gt; boidsBuffer;\nfloat time;\nfloat deltaTime;\nfloat rotationSpeed;\nfloat boidSpeed;\nfloat boidSpeedVariation;\nfloat3 flockPosition;\nfloat neighbourDistance;\nint boidsCount;\n<\/code><\/pre>\n\n\n<p>[numthreads(GROUP_SIZE,1,1)]<\/p>\n\n\n\n<p>void CSMain (uint3 id : SV_DispatchThreadID){ &#8230;\/\/ \u63a5\u4e0b\u6587 }<\/p>\n\n\n\n<p>\u5148\u5199\u5bf9\u9f50\u548c\u805a\u5408\u7684\u903b\u8f91\uff0c\u6700\u7ec8\u8f93\u51fa\u5b9e\u9645\u4f4d\u7f6e\u3001\u65b9\u5411\u7ed9Buffer\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Boid boid = boidsBuffer&#91;id.x];\n\n    float3 separation = 0; \/\/ \u5206\u79bb\n    float3 alignment = 0; \/\/ \u5bf9\u9f50 - \u65b9\u5411\n    float3 cohesion = flockPosition; \/\/ \u805a\u5408 - \u4f4d\u7f6e\n\n    uint nearbyCount = 1; \/\/ \u81ea\u8eab\u7b97\u4f5c\u5468\u8fb9\u7684\u4e2a\u4f53\u3002\n\n    for (int i=0; i&lt;boidsCount; i++)\n    {\n        if(i!=(int)id.x) \/\/ \u628a\u81ea\u5df1\u6392\u9664 \n        {\n            Boid temp = boidsBuffer&#91;i];\n            \/\/ \u8ba1\u7b97\u5468\u56f4\u8303\u56f4\u5185\u7684\u4e2a\u4f53\n            if(distance(boid.position, temp.position)&lt; neighbourDistance){\n                alignment += temp.direction;\n                cohesion += temp.position;\n                nearbyCount++;\n            }\n        }\n    }\n    float avg = 1.0 \/ nearbyCount;\n    alignment *= avg;\n    cohesion *= avg;\n    cohesion = normalize(cohesion-boid.position);\n\n    \/\/ \u7efc\u5408\u4e00\u4e2a\u79fb\u52a8\u65b9\u5411\n    float3 direction = alignment + separation + cohesion;\n    \/\/ \u5e73\u6ed1\u8f6c\u5411\u548c\u4f4d\u7f6e\u66f4\u65b0\n    boid.direction = lerp(direction, normalize(boid.direction), 0.94);\n    \/\/ deltaTime\u786e\u4fdd\u79fb\u52a8\u901f\u5ea6\u4e0d\u4f1a\u56e0\u5e27\u7387\u53d8\u5316\u800c\u6539\u53d8\u3002\n    boid.position += boid.direction * boidSpeed * deltaTime;\n\n    boidsBuffer&#91;id.x] = boid;<\/code><\/pre>\n\n\n\n<p>\u8fd9\u5c31\u662f\u6ca1\u6709\u8fb9\u754c\u611f\uff08\u5206\u79bb\u9879\uff09\u7684\u4e0b\u573a\uff0c\u6240\u6709\u7684\u4e2a\u4f53\u90fd\u8868\u73b0\u51fa\u76f8\u5f53\u4eb2\u5bc6\u7684\u5173\u7cfb\uff0c\u90fd\u91cd\u53e0\u5728\u4e00\u8d77\u4e86\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-320.png\" alt=\"img\" class=\"wp-image-1459 lazyload\"\/><noscript><img decoding=\"async\" width=\"922\" height=\"418\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-320.png\" alt=\"img\" class=\"wp-image-1459 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-320.png 922w, https:\/\/remoooo.com\/wp-content\/uploads\/image-320-300x136.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-320-768x348.png 768w\" sizes=\"(max-width: 922px) 100vw, 922px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u6dfb\u52a0\u4e0b\u9762\u7684\u4ee3\u7801\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if(distance(boid.position, temp.position)&lt; neighbourDistance)\n{\n    float3 offset = boid.position - temp.position;\n    float dist = length(offset);\n    if(dist &lt; neighbourDistance)\n    {\n        dist = max(dist, 0.000001);\n        separation += offset * (1.0\/dist - 1.0\/neighbourDistance);\n    }\n    ...<\/code><\/pre>\n\n\n\n<p>1.0\/dist \u5f53Boid\u8d8a\u9760\u8fd1\u65f6\uff0c\u8fd9\u4e2a\u503c\u8d8a\u5927\uff0c\u8868\u793a\u5206\u79bb\u529b\u5ea6\u5e94\u5f53\u8d8a\u5927\u30021.0\/neighbourDistance \u662f\u4e00\u4e2a\u5e38\u6570\uff0c\u57fa\u4e8e\u5b9a\u4e49\u7684\u90bb\u8fd1\u8ddd\u79bb\u3002\u4e24\u8005\u7684\u5dee\u503c\u8868\u793a\u5b9e\u9645\u7684\u5206\u79bb\u529b\u5e94\u5bf9\u8ddd\u79bb\u7684\u53cd\u5e94\u7a0b\u5ea6\u3002\u5982\u679c\u4e24\u4e2aBoid\u7684\u8ddd\u79bb\u6b63\u597d\u662f neighbourDistance\uff0c\u8fd9\u4e2a\u503c\u4e3a\u96f6\uff08\u6ca1\u6709\u5206\u79bb\u529b\uff09\u3002\u5982\u679c\u4e24\u4e2aBoid\u8ddd\u79bb\u5c0f\u4e8e neighbourDistance\uff0c\u8fd9\u4e2a\u503c\u4e3a\u6b63\uff0c\u4e14\u8ddd\u79bb\u8d8a\u5c0f\uff0c\u503c\u8d8a\u5927\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-324.png\" alt=\"img\" class=\"wp-image-1463 lazyload\"\/><noscript><img decoding=\"async\" width=\"1440\" height=\"729\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-324.png\" alt=\"img\" class=\"wp-image-1463 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-324.png 1440w, https:\/\/remoooo.com\/wp-content\/uploads\/image-324-300x152.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-324-1024x518.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-324-768x389.png 768w\" sizes=\"(max-width: 1440px) 100vw, 1440px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u5f53\u524d\u4ee3\u7801\uff1ahttps:\/\/github.com\/Remyuu\/Unity-Compute-Shader-Learn\/blob\/L4_Flocking\/Assets\/Shaders\/SimpleFlocking.compute<\/p>\n\n\n\n<p>\u4e0b\u4e00\u8282\u5c06\u91c7\u7528Instanced Mesh\uff0c\u63d0\u9ad8\u6027\u80fd\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5. GPU Instancing\u4f18\u5316<\/h3>\n\n\n\n<p>\u9996\u5148\u56de\u987e\u4e00\u4e0b\u672c\u7ae0\u8282\u7684\u5185\u5bb9\u3002\u300c\u7c92\u5b50\u4f60\u597d\u300d\u4e0e\u300cQuad\u7c92\u5b50\u300d\u7684\u4e24\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u90fd\u8fd0\u7528\u4e86Instanced\u6280\u672f\uff08Graphics.DrawProceduralNow()\uff09\uff0c\u5c06Compute Shader\u7684\u8ba1\u7b97\u597d\u7684\u7c92\u5b50\u4f4d\u7f6e\u76f4\u63a5\u4f20\u9012\u7ed9VertexFrag\u7740\u8272\u5668\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-322.png\" alt=\"img\" class=\"wp-image-1461 lazyload\"\/><noscript><img decoding=\"async\" width=\"1440\" height=\"359\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-322.png\" alt=\"img\" class=\"wp-image-1461 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-322.png 1440w, https:\/\/remoooo.com\/wp-content\/uploads\/image-322-300x75.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-322-1024x255.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-322-768x191.png 768w\" sizes=\"(max-width: 1440px) 100vw, 1440px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u672c\u8282\u4f7f\u7528\u7684DrawMeshInstancedIndirect \u7528\u4e8e\u7ed8\u5236\u5927\u91cf\u51e0\u4f55\u4f53\u5b9e\u4f8b\uff0c\u5b9e\u4f8b\u90fd\u662f\u76f8\u4f3c\u7684\uff0c\u53ea\u662f\u4f4d\u7f6e\u3001\u65cb\u8f6c\u6216\u5176\u4ed6\u53c2\u6570\u7565\u6709\u4e0d\u540c\u3002\u76f8\u5bf9\u4e8e\u6bcf\u5e27\u90fd\u91cd\u65b0\u751f\u6210\u51e0\u4f55\u4f53\u5e76\u6e32\u67d3\u7684 DrawProceduralNow\uff0cDrawMeshInstancedIndirect \u53ea\u9700\u8981\u4e00\u6b21\u6027\u8bbe\u7f6e\u597d\u5b9e\u4f8b\u7684\u4fe1\u606f\uff0c\u7136\u540e GPU \u5c31\u53ef\u4ee5\u6839\u636e\u8fd9\u4e9b\u4fe1\u606f\u4e00\u6b21\u6027\u6e32\u67d3\u6240\u6709\u5b9e\u4f8b\u3002\u6e32\u67d3\u8349\u5730\u3001\u7fa4\u4f53\u52a8\u7269\u5c31\u7528\u8fd9\u4e2a\u51fd\u6570\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-326.png\" alt=\"img\" class=\"wp-image-1465 lazyload\"\/><noscript><img decoding=\"async\" width=\"1440\" height=\"197\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-326.png\" alt=\"img\" class=\"wp-image-1465 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-326.png 1440w, https:\/\/remoooo.com\/wp-content\/uploads\/image-326-300x41.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-326-1024x140.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-326-768x105.png 768w\" sizes=\"(max-width: 1440px) 100vw, 1440px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u8fd9\u4e2a\u51fd\u6570\u6709\u5f88\u591a\u53c2\u6570\uff0c\u53ea\u7528\u5176\u4e2d\u7684\u4e00\u90e8\u5206\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-323.png\" alt=\"img\" class=\"wp-image-1462 lazyload\"\/><noscript><img decoding=\"async\" width=\"1386\" height=\"670\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-323.png\" alt=\"img\" class=\"wp-image-1462 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-323.png 1386w, https:\/\/remoooo.com\/wp-content\/uploads\/image-323-300x145.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-323-1024x495.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-323-768x371.png 768w\" sizes=\"(max-width: 1386px) 100vw, 1386px\" \/><\/noscript><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>Graphics.DrawMeshInstancedIndirect(boidMesh, 0, boidMaterial, bounds, argsBuffer);<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li>boidMesh\uff1a\u628a\u9e1fMesh\u4e22\u8fdb\u53bb\u3002<\/li>\n\n\n\n<li>subMeshIndex\uff1a\u7ed8\u5236\u7684\u5b50\u7f51\u683c\u7d22\u5f15\u3002\u5982\u679c\u7f51\u683c\u53ea\u6709\u4e00\u4e2a\u5b50\u7f51\u683c\uff0c\u901a\u5e38\u4e3a0\u3002<\/li>\n\n\n\n<li>boidMaterial\uff1a\u5e94\u7528\u5230\u5b9e\u4f8b\u5316\u5bf9\u8c61\u7684\u6750\u8d28\u3002<\/li>\n\n\n\n<li>bounds\uff1a\u5305\u56f4\u76d2\u6307\u5b9a\u4e86\u7ed8\u5236\u7684\u8303\u56f4\u3002\u5b9e\u4f8b\u5316\u5bf9\u8c61\u53ea\u6709\u5728\u8fd9\u4e2a\u5305\u56f4\u76d2\u5185\u7684\u533a\u57df\u624d\u4f1a\u88ab\u6e32\u67d3\u3002\u4f18\u5316\u6027\u80fd\u4e4b\u7528\u3002<\/li>\n\n\n\n<li>argsBuffer\uff1a\u53c2\u6570\u7684 ComputeBuffer\uff0c\u53c2\u6570\u5305\u62ec\u6bcf\u4e2a\u5b9e\u4f8b\u7684\u51e0\u4f55\u4f53\u7684\u7d22\u5f15\u6570\u91cf\u548c\u5b9e\u4f8b\u5316\u7684\u6570\u91cf\u3002<\/li>\n<\/ol>\n\n\n\n<p>\u8fd9\u4e2a argsBuffer \u662f\u5565\uff1f\u8fd9\u4e2a\u53c2\u6570\u7528\u6765\u544a\u8bc9Unity\uff0c\u6211\u4eec\u73b0\u5728\u8981\u6e32\u67d3\u54ea\u4e2aMesh\u3001\u8981\u6e32\u67d3\u591a\u5c11\u4e2a\uff01\u53ef\u4ee5\u7528\u4e00\u79cd\u7279\u6b8a\u7684Buffer\u4f5c\u4e3a\u53c2\u6570\u7ed9\u8fdb\u53bb\u3002<\/p>\n\n\n\n<p>\u5728\u521d\u59cb\u5316shader\u65f6\u5019\uff0c\u521b\u5efa\u4e00\u79cd\u7279\u6b8aBuffer\uff0c\u5176\u6807\u6ce8\u4e3a ComputeBufferType.IndirectArguments \u3002\u8fd9\u79cd\u7c7b\u578b\u7684\u7f13\u51b2\u533a\u4e13\u95e8\u7528\u4e8e\u4f20\u9012\u7ed9 GPU\uff0c\u4ee5\u4fbf\u5728 GPU \u4e0a\u6267\u884c\u95f4\u63a5\u7ed8\u5236\u547d\u4ee4\u3002\u8fd9\u91cc\u7684new ComputeBuffer \u7b2c\u4e00\u4e2a\u53c2\u6570\u662f 1 \uff0c\u8868\u793a\u4e00\u4e2aargs\u6570\u7ec4\uff08\u4e00\u4e2a\u6570\u7ec4\u67095\u4e2auint\uff09\uff0c\u4e0d\u8981\u7406\u89e3\u9519\u4e86\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ComputeBuffer argsBuffer;\n...\nargsBuffer = new ComputeBuffer(1, 5 * sizeof(uint), ComputeBufferType.IndirectArguments);\nif (boidMesh != null)\n{\n    args&#91;0] = (uint)boidMesh.GetIndexCount(0);\n    args&#91;1] = (uint)numOfBoids;\n}\nargsBuffer.SetData(args);\n...\nGraphics.DrawMeshInstancedIndirect(boidMesh, 0, boidMaterial, bounds, argsBuffer);<\/code><\/pre>\n\n\n\n<p>\u5728\u4e0a\u4e00\u7ae0\u7684\u57fa\u7840\u4e0a\uff0c\u4e2a\u4f53\u7684\u6570\u636e\u7ed3\u6784\u589e\u52a0\u4e00\u4e2aoffset\uff0c\u5728Compute Shader\u7528\u4e8e\u65b9\u5411\u4e0a\u7684\u504f\u79fb\u3002\u53e6\u5916\u521d\u59cb\u72b6\u6001\u7684\u65b9\u5411\u7528Slerp\u63d2\u503c\uff0c70%\u4fdd\u6301\u539f\u6765\u7684\u65b9\u5411\uff0c30%\u968f\u673a\u3002Slerp\u63d2\u503c\u7684\u7ed3\u679c\u662f\u56db\u5143\u6570\uff0c\u9700\u8981\u7528\u56db\u5143\u6570\u65b9\u6cd5\u8f6c\u6362\u5230\u6b27\u62c9\u89d2\u518d\u4f20\u5165\u6784\u9020\u51fd\u6570\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public float noise_offset;\n...\nQuaternion rot = Quaternion.Slerp(transform.rotation, Random.rotation, 0.3f);\nboidsArray&#91;i] = new Boid(pos, rot.eulerAngles, offset);<\/code><\/pre>\n\n\n\n<p>\u5c06\u8fd9\u4e2a\u65b0\u7684\u5c5e\u6027noise_offset\u4f20\u5230Compute Shader\u540e\uff0c\u8ba1\u7b97\u8303\u56f4\u662f [-1, 1] \u7684\u566a\u58f0\u503c\uff0c\u5e94\u7528\u5230\u9e1f\u7684\u901f\u5ea6\u4e0a\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>float noise = clamp(noise1(time \/ 100.0 + boid.noise_offset), -1, 1) * 2.0 - 1.0;\nfloat velocity = boidSpeed * (1.0 + noise * boidSpeedVariation);<\/code><\/pre>\n\n\n\n<p>\u7136\u540e\u7a0d\u5fae\u4f18\u5316\u4e86\u4e00\u4e0b\u7b97\u6cd5\u3002Compute Shader\u5927\u4f53\u662f\u6ca1\u6709\u533a\u522b\u7684\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if (distance(boid_pos, boidsBuffer&#91;i].position) &lt; neighbourDistance)\n{\n    float3 tempBoid_position = boidsBuffer&#91;i].position;\n\n    float3 offset = boid.position - tempBoid_position;\n    float dist = length(offset);\n    if (dist&lt;neighbourDistance){\n        dist = max(dist, 0.000001);\/\/Avoid division by zero\n        separation += offset * (1.0\/dist - 1.0\/neighbourDistance);\n    }\n    alignment += boidsBuffer&#91;i].direction;\n    cohesion += tempBoid_position;\n\n    nearbyCount += 1;\n}<\/code><\/pre>\n\n\n\n<p>\u6700\u5927\u7684\u4e0d\u540c\u5728\u4e8eShader\u4e0a\u3002\u672c\u8282\u4f7f\u7528Surface Shader\u53d6\u4ee3Frag\u3002\u8fd9\u4e2a\u4e1c\u897f\u5176\u5b9e\u5c31\u662f\u4e00\u4e2a\u5305\u88c5\u597d\u7684vertex and fragment shader\u3002Unity\u5df2\u7ecf\u5b8c\u6210\u4e86\u5149\u7167\u3001\u9634\u5f71\u7b49\u4e00\u7cfb\u5217\u7e41\u7410\u7684\u5de5\u4f5c\u3002\u4f60\u4f9d\u65e7\u53ef\u4ee5\u6307\u5b9a\u4e00\u4e2aVert\u3002<\/p>\n\n\n\n<p>\u5199Shader\u5236\u4f5c\u6750\u8d28\u7684\u65f6\u5019\uff0c\u9700\u8981\u5bf9Instanced\u7684\u7269\u4f53\u505a\u7279\u522b\u5904\u7406\u3002\u56e0\u4e3a\u666e\u901a\u7684\u6e32\u67d3\u5bf9\u8c61\uff0c\u4ed6\u4eec\u7684\u4f4d\u7f6e\u3001\u65cb\u8f6c\u548c\u5176\u4ed6\u5c5e\u6027\u5728Unity\u4e2d\u662f\u9759\u6001\u7684\u3002\u800c\u5bf9\u4e8e\u5f53\u524d\u8981\u6784\u5efa\u7684\u5b9e\u4f8b\u5316\u5bf9\u8c61\uff0c\u5176\u4f4d\u7f6e\u3001\u65cb\u8f6c\u7b49\u53c2\u6570\u65f6\u523b\u5728\u53d8\u5316\uff0c\u56e0\u6b64\uff0c\u5728\u6e32\u67d3\u7ba1\u7ebf\u4e2d\u9700\u8981\u901a\u8fc7\u7279\u6b8a\u7684\u673a\u5236\u6765\u52a8\u6001\u8bbe\u7f6e\u6bcf\u4e2a\u5b9e\u4f8b\u5316\u5bf9\u8c61\u7684\u4f4d\u7f6e\u548c\u53c2\u6570\u3002\u5f53\u524d\u7684\u65b9\u6cd5\u57fa\u4e8e\u7a0b\u5e8f\u7684\u5b9e\u4f8b\u5316\u6280\u672f\uff0c\u53ef\u4ee5\u4e00\u6b21\u6027\u6e32\u67d3\u6240\u6709\u7684\u5b9e\u4f8b\u5316\u5bf9\u8c61\uff0c\u800c\u4e0d\u9700\u8981\u9010\u4e2a\u7ed8\u5236\u3002\u4e5f\u5c31\u662f\u4e00\u6b21\u6027\u6279\u91cf\u6e32\u67d3\u3002<\/p>\n\n\n\n<p>\u7740\u8272\u5668\u5e94\u7528instanced\u6280\u672f\u65b9\u6cd5\u3002\u5b9e\u4f8b\u5316\u9636\u6bb5\u662f\u5728vert\u4e4b\u524d\u6267\u884c\u3002\u8fd9\u6837\u6bcf\u4e2a\u5b9e\u4f8b\u5316\u7684\u5bf9\u8c61\u90fd\u6709\u5355\u72ec\u7684\u65cb\u8f6c\u3001\u4f4d\u79fb\u548c\u7f29\u653e\u7b49\u77e9\u9635\u3002<\/p>\n\n\n\n<p>\u73b0\u5728\u9700\u8981\u4e3a\u6bcf\u4e2a\u5b9e\u4f8b\u5316\u5bf9\u8c61\u521b\u5efa\u5c5e\u4e8e\u4ed6\u4eec\u7684\u65cb\u8f6c\u77e9\u9635\u3002\u4eceBuffer\u4e2d\u6211\u4eec\u62ff\u5230\u4e86Compute Shader\u8ba1\u7b97\u540e\u7684\u9e1f\u7684\u57fa\u672c\u4fe1\u606f\uff08\u4e0a\u4e00\u8282\u4e2d\uff0c\u8be5\u6570\u636e\u4f20\u56de\u4e86CPU\uff0c\u8fd9\u91cc\u76f4\u63a5\u4f20\u7ed9Shader\u505a\u5b9e\u4f8b\u5316\uff09\uff1a<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-325.png\" alt=\"img\" class=\"wp-image-1464 lazyload\"\/><noscript><img decoding=\"async\" width=\"1020\" height=\"244\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-325.png\" alt=\"img\" class=\"wp-image-1464 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-325.png 1020w, https:\/\/remoooo.com\/wp-content\/uploads\/image-325-300x72.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-325-768x184.png 768w\" sizes=\"(max-width: 1020px) 100vw, 1020px\" \/><\/noscript><\/figure>\n\n\n\n<p>Shader\u91cc\u5c06Buffer\u4f20\u6765\u7684\u6570\u636e\u7ed3\u6784\u3001\u76f8\u5173\u64cd\u4f5c\u7528\u4e0b\u9762\u7684\u5b8f\u5305\u88f9\u8d77\u6765\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ .shader\n#ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED\nstruct Boid\n{\n    float3 position;\n    float3 direction;\n    float noise_offset;\n};\n\nStructuredBuffer&lt;Boid&gt; boidsBuffer; \n#endif<\/code><\/pre>\n\n\n\n<p>\u7531\u4e8e\u6211\u53ea\u5728 C# \u7684 DrawMeshInstancedIndirect \u7684args[1]\u6307\u5b9a\u4e86\u9700\u8981\u5b9e\u4f8b\u5316\u7684\u6570\u91cf\uff08\u9e1f\u7684\u6570\u91cf\uff0c\u4e5f\u662fBuffer\u7684\u5927\u5c0f\uff09\uff0c\u56e0\u6b64\u76f4\u63a5\u4f7f\u7528unity_InstanceID\u7d22\u5f15\u8bbf\u95eeBuffer\u5c31\u597d\u4e86\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#pragma instancing_options procedural:setup\n\nvoid setup()\n{\n    #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED\n        _BoidPosition = boidsBuffer&#91;unity_InstanceID].position;\n        _Matrix = create_matrix(boidsBuffer&#91;unity_InstanceID].position, boidsBuffer&#91;unity_InstanceID].direction, float3(0.0, 1.0, 0.0));\n    #endif\n}<\/code><\/pre>\n\n\n\n<p>\u8fd9\u91cc\u7684\u7a7a\u95f4\u53d8\u6362\u77e9\u9635\u7684\u8ba1\u7b97\u6d89\u53ca\u5230<strong>Homogeneous Coordinates<\/strong>\uff0c\u53ef\u4ee5\u53bb\u590d\u4e60\u4e00\u4e0bGAMES101\u7684\u8bfe\u7a0b\u3002\u70b9\u662f(x,y,z,1)\uff0c\u5750\u6807\u662f(x,y,z,0)\u3002<\/p>\n\n\n\n<p>\u5982\u679c\u4f7f\u7528\u4eff\u5c04\u53d8\u6362\uff08Affine Transformations\uff09\uff0c\u4ee3\u7801\u662f\u8fd9\u6837\u7684\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void setup()\n{\n    #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED\n    _BoidPosition = boidsBuffer&#91;unity_InstanceID].position;\n    _LookAtMatrix = look_at_matrix(boidsBuffer&#91;unity_InstanceID].direction, float3(0.0, 1.0, 0.0));\n    #endif\n}\n void vert(inout appdata_full v, out Input data)\n{\n    UNITY_INITIALIZE_OUTPUT(Input, data);\n    #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED\n    v.vertex = mul(_LookAtMatrix, v.vertex);\n    v.vertex.xyz += _BoidPosition;\n    #endif\n}<\/code><\/pre>\n\n\n\n<p>\u4e0d\u591f\u4f18\u96c5\uff0c\u6211\u4eec\u76f4\u63a5\u4f7f\u7528\u4e00\u4e2a\u9f50\u6b21\u5750\u6807\uff08Homogeneous Coordinates\uff09\u3002\u4e00\u4e2a\u77e9\u9635\u641e\u6382\u65cb\u8f6c\u5e73\u79fb\u7f29\u653e\uff01<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void setup()\n{\n    #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED\n    _BoidPosition = boidsBuffer&#91;unity_InstanceID].position;\n    _Matrix = create_matrix(boidsBuffer&#91;unity_InstanceID].position, boidsBuffer&#91;unity_InstanceID].direction, float3(0.0, 1.0, 0.0));\n    #endif\n}\n void vert(inout appdata_full v, out Input data)\n{\n    UNITY_INITIALIZE_OUTPUT(Input, data);\n\n    #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED\n    v.vertex = mul(_Matrix, v.vertex);\n    #endif\n}<\/code><\/pre>\n\n\n\n<p>\u81f3\u6b64\uff0c\u5c31\u5927\u529f\u544a\u6210\u4e86\uff01\u5f53\u524d\u7684\u5e27\u7387\u6bd4\u4e0a\u4e00\u8282\u63d0\u5347\u4e86\u5c06\u8fd1\u4e00\u500d\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-329.png\" alt=\"img\" class=\"wp-image-1469 lazyload\"\/><noscript><img decoding=\"async\" width=\"1440\" height=\"872\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-329.png\" alt=\"img\" class=\"wp-image-1469 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-329.png 1440w, https:\/\/remoooo.com\/wp-content\/uploads\/image-329-300x182.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-329-1024x620.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-329-768x465.png 768w\" sizes=\"(max-width: 1440px) 100vw, 1440px\" \/><\/noscript><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-327.png\" alt=\"img\" class=\"wp-image-1466 lazyload\"\/><noscript><img decoding=\"async\" width=\"898\" height=\"454\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-327.png\" alt=\"img\" class=\"wp-image-1466 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-327.png 898w, https:\/\/remoooo.com\/wp-content\/uploads\/image-327-300x152.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-327-768x388.png 768w\" sizes=\"(max-width: 898px) 100vw, 898px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u5f53\u524d\u7248\u672c\u4ee3\u7801\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Compute Shader\uff1ahttps:\/\/github.com\/Remyuu\/Unity-Compute-Shader-Learn\/blob\/L4_Instanced\/Assets\/Shaders\/InstancedFlocking.compute<\/li>\n\n\n\n<li>CPU\uff1ahttps:\/\/github.com\/Remyuu\/Unity-Compute-Shader-Learn\/blob\/L4_Instanced\/Assets\/Scripts\/InstancedFlocking.cs<\/li>\n\n\n\n<li>Shader\uff1ahttps:\/\/github.com\/Remyuu\/Unity-Compute-Shader-Learn\/blob\/L4_Instanced\/Assets\/Shaders\/InstancedFlocking.shader<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">6. \u5e94\u7528\u8499\u76ae\u52a8\u753b<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-328.png\" alt=\"img\" class=\"wp-image-1467 lazyload\"\/><noscript><img decoding=\"async\" width=\"1212\" height=\"336\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-328.png\" alt=\"img\" class=\"wp-image-1467 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-328.png 1212w, https:\/\/remoooo.com\/wp-content\/uploads\/image-328-300x83.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-328-1024x284.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-328-768x213.png 768w\" sizes=\"(max-width: 1212px) 100vw, 1212px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u672c\u8282\u8981\u505a\u7684\u662f\uff0c\u4f7f\u7528Animator\u7ec4\u4ef6\uff0c\u5728\u5b9e\u4f8b\u5316\u7269\u4f53\u4e4b\u524d\uff0c\u5c06\u5404\u4e2a\u5173\u952e\u5e27\u7684Mesh\u6293\u53d6\u5230Buffer\u5f53\u4e2d\u3002\u901a\u8fc7\u9009\u53d6\u4e0d\u540c\u7d22\u5f15\uff0c\u5f97\u5230\u4e0d\u540c\u59ff\u52bf\u7684Mesh\u3002\u5177\u4f53\u7684\u9aa8\u9abc\u52a8\u753b\u5236\u4f5c\u4e0d\u5728\u672c\u6587\u8ba8\u8bba\u8303\u56f4\u3002<\/p>\n\n\n\n<p>\u53ea\u9700\u8981\u5728\u4e0a\u4e00\u7ae0\u7684\u57fa\u7840\u4e0a\u4fee\u6539\u4ee3\u7801\uff0c\u6dfb\u52a0Animator\u7b49\u903b\u8f91\u3002\u6211\u5df2\u7ecf\u5728\u4e0b\u9762\u5199\u4e86\u6ce8\u91ca\uff0c\u53ef\u4ee5\u770b\u770b\u3002<\/p>\n\n\n\n<p>\u5e76\u4e14\u4e2a\u4f53\u7684\u6570\u636e\u7ed3\u6784\u6709\u6240\u66f4\u65b0\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>struct Boid{\n    float3 position;\n    float3 direction;\n    float noise_offset;\n    float speed; \/\/ \u6682\u65f6\u6ca1\u5565\u7528\n    float frame; \/\/ \u8868\u793a\u52a8\u753b\u4e2d\u7684\u5f53\u524d\u5e27\u7d22\u5f15\n    float3 padding; \/\/ \u786e\u4fdd\u6570\u636e\u5bf9\u9f50\n};<\/code><\/pre>\n\n\n\n<p>\u8be6\u7ec6\u8bf4\u8bf4\u8fd9\u91cc\u7684\u5bf9\u9f50\u3002\u4e00\u4e2a\u6570\u636e\u7ed3\u6784\u4e2d\uff0c\u6570\u636e\u7684\u5927\u5c0f\u6700\u597d\u662f16\u5b57\u8282\u7684\u6574\u6570\u500d\u3002<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>float3 position; (12\u5b57\u8282)<\/li>\n\n\n\n<li>float3 direction; (12\u5b57\u8282)<\/li>\n\n\n\n<li>float noise_offset; (4\u5b57\u8282)<\/li>\n\n\n\n<li>float speed; (4\u5b57\u8282)<\/li>\n\n\n\n<li>float frame; (4\u5b57\u8282)<\/li>\n\n\n\n<li>float3 padding; (12\u5b57\u8282)<\/li>\n<\/ul>\n\n\n\n<p>\u5982\u679c\u6ca1\u6709Padding\uff0c\u5927\u5c0f\u662f36\u5b57\u8282\uff0c\u4e0d\u662f\u5e38\u89c1\u7684\u5bf9\u9f50\u5927\u5c0f\u3002\u52a0\u4e0aPadding\uff0c\u5bf9\u9f50\u523048\u5b57\u8282\uff0c\u5b8c\u7f8e\uff01<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>private SkinnedMeshRenderer boidSMR; \/\/ \u7528\u4e8e\u5f15\u7528\u5305\u542b\u8499\u76ae\u7f51\u683c\u7684SkinnedMeshRenderer\u7ec4\u4ef6\u3002\nprivate Animator animator;\npublic AnimationClip animationClip; \/\/ \u5177\u4f53\u7684\u52a8\u753b\u526a\u8f91\uff0c\u901a\u5e38\u7528\u4e8e\u8ba1\u7b97\u52a8\u753b\u76f8\u5173\u7684\u53c2\u6570\u3002\n\nprivate int numOfFrames; \/\/ \u52a8\u753b\u4e2d\u7684\u5e27\u6570\uff0c\u7528\u4e8e\u786e\u5b9a\u5728GPU\u7f13\u51b2\u533a\u4e2d\u5b58\u50a8\u591a\u5c11\u5e27\u6570\u636e\u3002\npublic float boidFrameSpeed = 10f; \/\/ \u63a7\u5236\u52a8\u753b\u64ad\u653e\u7684\u901f\u5ea6\u3002\nMaterialPropertyBlock props; \/\/ \u5728\u4e0d\u521b\u5efa\u65b0\u6750\u6599\u5b9e\u4f8b\u7684\u60c5\u51b5\u4e0b\u4f20\u9012\u53c2\u6570\u7ed9\u7740\u8272\u5668\u3002\u8fd9\u610f\u5473\u7740\u53ef\u4ee5\u6539\u53d8\u5b9e\u4f8b\u7684\u6750\u8d28\u5c5e\u6027\uff08\u5982\u989c\u8272\u3001\u5149\u7167\u7cfb\u6570\u7b49\uff09\uff0c\u800c\u4e0d\u4f1a\u5f71\u54cd\u5230\u4f7f\u7528\u76f8\u540c\u6750\u6599\u7684\u5176\u4ed6\u5bf9\u8c61\u3002\nMesh boidMesh; \/\/ \u5b58\u50a8\u4eceSkinnedMeshRenderer\u70d8\u7119\u51fa\u7684\u7f51\u683c\u6570\u636e\u3002\n...\nvoid Start(){ \/\/ \u8fd9\u91cc\u9996\u5148\u521d\u59cb\u5316Boid\u6570\u636e\uff0c\u7136\u540e\u8c03\u7528GenerateSkinnedAnimationForGPUBuffer\u6765\u51c6\u5907\u52a8\u753b\u6570\u636e\uff0c\u6700\u540e\u8c03\u7528InitShader\u6765\u8bbe\u7f6e\u6e32\u67d3\u6240\u9700\u7684Shader\u53c2\u6570\u3002\n    ...\n    \/\/ This property block is used only for avoiding an instancing bug.\n    props = new MaterialPropertyBlock();\n    props.SetFloat(\"_UniqueID\", Random.value);\n    ...\n    InitBoids();\n    GenerateSkinnedAnimationForGPUBuffer();\n    InitShader();\n}\nvoid InitShader(){ \/\/ \u6b64\u65b9\u6cd5\u914d\u7f6eShader\u548c\u6750\u6599\u5c5e\u6027\uff0c\u786e\u4fdd\u52a8\u753b\u64ad\u653e\u53ef\u4ee5\u6839\u636e\u5b9e\u4f8b\u7684\u4e0d\u540c\u9636\u6bb5\u6b63\u786e\u663e\u793a\u3002frameInterpolation\u7684\u542f\u7528\u6216\u7981\u7528\u51b3\u5b9a\u4e86\u662f\u5426\u5728\u52a8\u753b\u5e27\u4e4b\u95f4\u8fdb\u884c\u63d2\u503c\uff0c\u4ee5\u83b7\u5f97\u66f4\u5e73\u6ed1\u7684\u52a8\u753b\u6548\u679c\u3002\n    ...\n    if (boidMesh)\/\/Set by the GenerateSkinnedAnimationForGPUBuffer\n    ...\n    shader.SetFloat(\"boidFrameSpeed\", boidFrameSpeed);\n    shader.SetInt(\"numOfFrames\", numOfFrames);\n    boidMaterial.SetInt(\"numOfFrames\", numOfFrames);\n    if (frameInterpolation &amp;&amp; !boidMaterial.IsKeywordEnabled(\"FRAME_INTERPOLATION\"))\n    boidMaterial.EnableKeyword(\"FRAME_INTERPOLATION\");\n    if (!frameInterpolation &amp;&amp; boidMaterial.IsKeywordEnabled(\"FRAME_INTERPOLATION\"))\n    boidMaterial.DisableKeyword(\"FRAME_INTERPOLATION\");\n}\nvoid Update(){\n    ...\n    \/\/ \u540e\u9762\u4e24\u4e2a\u53c2\u6570\uff1a\n        \/\/ 1. 0: \u53c2\u6570\u7f13\u51b2\u533a\u7684\u504f\u79fb\u91cf\uff0c\u7528\u4e8e\u6307\u5b9a\u4ece\u54ea\u91cc\u5f00\u59cb\u8bfb\u53d6\u53c2\u6570\u3002\n        \/\/ 2. props: \u524d\u9762\u521b\u5efa\u7684 MaterialPropertyBlock\uff0c\u5305\u542b\u6240\u6709\u5b9e\u4f8b\u5171\u4eab\u7684\u5c5e\u6027\u3002\n    Graphics.DrawMeshInstancedIndirect( boidMesh, 0, boidMaterial, bounds, argsBuffer, 0, props);\n}\nvoid OnDestroy(){ \n    ...\n    if (vertexAnimationBuffer != null) vertexAnimationBuffer.Release();\n}\nprivate void GenerateSkinnedAnimationForGPUBuffer()\n{\n    ... \/\/ \u63a5\u4e0b\u6587\n}<\/code><\/pre>\n\n\n\n<p>\u4e3a\u4e86\u7ed9Shader\u5728\u4e0d\u540c\u7684\u65f6\u95f4\u63d0\u4f9b\u4e0d\u540c\u59ff\u52bf\u7684Mesh\uff0c\u56e0\u6b64\u5728 GenerateSkinnedAnimationForGPUBuffer() \u51fd\u6570\u4e2d\uff0c\u4ece Animator \u548c SkinnedMeshRenderer \u4e2d\u63d0\u53d6\u6bcf\u4e00\u5e27\u7684\u7f51\u683c\u9876\u70b9\u6570\u636e\uff0c\u7136\u540e\u5c06\u8fd9\u4e9b\u6570\u636e\u5b58\u50a8\u5230GPU\u7684 ComputeBuffer \u4e2d\uff0c\u4ee5\u4fbf\u5728\u5b9e\u4f8b\u5316\u6e32\u67d3\u65f6\u4f7f\u7528\u3002<\/p>\n\n\n\n<p>\u901a\u8fc7GetCurrentAnimatorStateInfo\u83b7\u53d6\u5f53\u524d\u52a8\u753b\u5c42\u7684\u72b6\u6001\u4fe1\u606f\uff0c\u7528\u4e8e\u540e\u7eed\u63a7\u5236\u52a8\u753b\u7684\u7cbe\u786e\u64ad\u653e\u3002<\/p>\n\n\n\n<p>numOfFrames \u4f7f\u7528\u6700\u63a5\u8fd1\u52a8\u753b\u957f\u5ea6\u548c\u5e27\u7387\u4e58\u79ef\u7684\u4e8c\u6b21\u5e42\u6765\u786e\u5b9a\uff0c\u53ef\u4ee5\u4f18\u5316GPU\u7684\u5185\u5b58\u8bbf\u95ee\u3002<\/p>\n\n\n\n<p>\u7136\u540e\u521b\u5efa\u4e00\u4e2aComputeBuffer\u6765\u5b58\u50a8\u6240\u6709\u5e27\u7684\u6240\u6709\u9876\u70b9\u6570\u636e\u3002vertexAnimationBuffer<\/p>\n\n\n\n<p>\u5728for\u5faa\u73af\u4e2d\uff0c\u70d8\u7119\u6240\u6709\u52a8\u753b\u5e27\u3002\u5177\u4f53\u505a\u6cd5\u662f\uff0c\u5728\u6bcf\u4e2asampleTime\u65f6\u95f4\u70b9\u64ad\u653e\u5e76\u7acb\u5373\u66f4\u65b0\uff0c\u7136\u540e\u70d8\u7119\u5f53\u524d\u52a8\u753b\u5e27\u7684\u7f51\u683c\u5230bakedMesh\u4e2d\u3002\u5e76\u4e14\u63d0\u53d6\u521a\u521a\u70d8\u7119\u597d\u7684Mesh\u9876\u70b9\uff0c\u66f4\u65b0\u5230\u6570\u7ec4 vertexAnimationData \u4e2d\uff0c\u6700\u540e\u4e0a\u4f20\u81f3GPU\uff0c\u7ed3\u675f\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ ...\u63a5\u4e0a\u6587\nboidSMR = boidObject.GetComponentInChildren&lt;SkinnedMeshRenderer&gt;();\nboidMesh = boidSMR.sharedMesh;\nanimator = boidObject.GetComponentInChildren&lt;Animator&gt;();\nint iLayer = 0;\nAnimatorStateInfo aniStateInfo = animator.GetCurrentAnimatorStateInfo(iLayer);\n\nMesh bakedMesh = new Mesh();\nfloat sampleTime = 0;\nfloat perFrameTime = 0;\n\nnumOfFrames = Mathf.ClosestPowerOfTwo((int)(animationClip.frameRate * animationClip.length));\nperFrameTime = animationClip.length \/ numOfFrames;\n\nvar vertexCount = boidSMR.sharedMesh.vertexCount;\nvertexAnimationBuffer = new ComputeBuffer(vertexCount * numOfFrames, 16);\nVector4&#91;] vertexAnimationData = new Vector4&#91;vertexCount * numOfFrames];\nfor (int i = 0; i &lt; numOfFrames; i++)\n{\n    animator.Play(aniStateInfo.shortNameHash, iLayer, sampleTime);\n    animator.Update(0f);\n\n    boidSMR.BakeMesh(bakedMesh);\n\n    for(int j = 0; j &lt; vertexCount; j++)\n    {\n        Vector4 vertex = bakedMesh.vertices&#91;j];\n        vertex.w = 1;\n        vertexAnimationData&#91;(j * numOfFrames) +  i] = vertex;\n    }\n\n    sampleTime += perFrameTime;\n}\n\nvertexAnimationBuffer.SetData(vertexAnimationData);\nboidMaterial.SetBuffer(\"vertexAnimation\", vertexAnimationBuffer);\n\nboidObject.SetActive(false);<\/code><\/pre>\n\n\n\n<p>\u5728Compute Shader\u4e2d\uff0c\u7ef4\u62a4\u6bcf\u4e00\u4e2a\u4e2a\u4f53\u6570\u636e\u7ed3\u6784\u4e2d\u50a8\u5b58\u7684\u5e27\u53d8\u91cf\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>boid.frame = boid.frame + velocity * deltaTime * boidFrameSpeed;\nif (boid.frame &gt;= numOfFrames) boid.frame -= numOfFrames;<\/code><\/pre>\n\n\n\n<p>\u5728Shader\u4e2dlerp\u4e0d\u540c\u5e27\u7684\u52a8\u753b\u3002\u5de6\u8fb9\u662f\u6ca1\u6709\u5e27\u63d2\u503c\u7684\uff0c\u53f3\u8fb9\u662f\u63d2\u503c\u540e\u7684\uff0c\u6548\u679c\u975e\u5e38\u663e\u8457\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-96.jpeg\" alt=\"\u89c6\u9891\u5c01\u9762\" class=\"wp-image-1468 lazyload\"\/><noscript><img decoding=\"async\" width=\"1254\" height=\"746\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-96.jpeg\" alt=\"\u89c6\u9891\u5c01\u9762\" class=\"wp-image-1468 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-96.jpeg 1254w, https:\/\/remoooo.com\/wp-content\/uploads\/image-96-300x178.jpeg 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-96-1024x609.jpeg 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-96-768x457.jpeg 768w\" sizes=\"(max-width: 1254px) 100vw, 1254px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u597d\u7684\u6807\u9898\u53ef\u4ee5\u83b7\u5f97\u66f4\u591a\u7684\u63a8\u8350\u53ca\u5173\u6ce8\u8005<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void vert(inout appdata_custom v)\n{\n    #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED\n        #ifdef FRAME_INTERPOLATION\n            v.vertex = lerp(vertexAnimation&#91;v.id * numOfFrames + _CurrentFrame], vertexAnimation&#91;v.id * numOfFrames + _NextFrame], _FrameInterpolation);\n        #else\n            v.vertex = vertexAnimation&#91;v.id * numOfFrames + _CurrentFrame];\n        #endif\n        v.vertex = mul(_Matrix, v.vertex);\n    #endif\n}\nvoid setup()\n{\n    #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED\n        _Matrix = create_matrix(boidsBuffer&#91;unity_InstanceID].position, boidsBuffer&#91;unity_InstanceID].direction, float3(0.0, 1.0, 0.0));\n        _CurrentFrame = boidsBuffer&#91;unity_InstanceID].frame;\n        #ifdef FRAME_INTERPOLATION\n            _NextFrame = _CurrentFrame + 1;\n            if (_NextFrame &gt;= numOfFrames) _NextFrame = 0;\n            _FrameInterpolation = frac(boidsBuffer&#91;unity_InstanceID].frame);\n        #endif\n    #endif\n}<\/code><\/pre>\n\n\n\n<p>\u975e\u5e38\u4e0d\u5bb9\u6613\uff0c\u7ec8\u4e8e\u5b8c\u6574\u4e86\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-332.png\" alt=\"img\" class=\"wp-image-1472 lazyload\"\/><noscript><img decoding=\"async\" width=\"1440\" height=\"821\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-332.png\" alt=\"img\" class=\"wp-image-1472 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-332.png 1440w, https:\/\/remoooo.com\/wp-content\/uploads\/image-332-300x171.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-332-1024x584.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-332-768x438.png 768w\" sizes=\"(max-width: 1440px) 100vw, 1440px\" \/><\/noscript><\/figure>\n\n\n\n<p>\u5b8c\u6574\u5de5\u7a0b\u94fe\u63a5\uff1ahttps:\/\/github.com\/Remyuu\/Unity-Compute-Shader-Learn\/tree\/L4_Skinned\/Assets\/Scripts<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">8. \u603b\u7ed3\/\u5c0f\u6d4b\u8bd5<\/h3>\n\n\n\n<p>When rendering points which gives the best answer?<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-331.png\" alt=\"img\" class=\"wp-image-1471 lazyload\"\/><noscript><img decoding=\"async\" width=\"1440\" height=\"380\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-331.png\" alt=\"img\" class=\"wp-image-1471 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-331.png 1440w, https:\/\/remoooo.com\/wp-content\/uploads\/image-331-300x79.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-331-1024x270.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-331-768x203.png 768w\" sizes=\"(max-width: 1440px) 100vw, 1440px\" \/><\/noscript><\/figure>\n\n\n\n<p>What are the three key steps in flocking?<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-330.png\" alt=\"img\" class=\"wp-image-1470 lazyload\"\/><noscript><img decoding=\"async\" width=\"1440\" height=\"368\" src=\"https:\/\/\u80a5\u80a5.com\/wp-content\/uploads\/image-330.png\" alt=\"img\" class=\"wp-image-1470 lazyload\" srcset=\"https:\/\/remoooo.com\/wp-content\/uploads\/image-330.png 1440w, https:\/\/remoooo.com\/wp-content\/uploads\/image-330-300x77.png 300w, https:\/\/remoooo.com\/wp-content\/uploads\/image-330-1024x262.png 1024w, https:\/\/remoooo.com\/wp-content\/uploads\/image-330-768x196.png 768w\" sizes=\"(max-width: 1440px) 100vw, 1440px\" \/><\/noscript><\/figure>\n\n\n\n<p>When creating an arguments buffer for DrawMeshInstancedIndirect, how many uints are required?<\/p>\n\n\n\n<p><img decoding=\"async\" class=\"lazyload\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/picx.zhimg.com\/80\/v2-93d1dc1419f1246f0ccbe8b33a2d8e35_1440w.png?source=d16d100b\" alt=\"img\"><noscript><img decoding=\"async\" class=\"lazyload\" src=\"https:\/\/picx.zhimg.com\/80\/v2-93d1dc1419f1246f0ccbe8b33a2d8e35_1440w.png?source=d16d100b\" alt=\"img\"><\/noscript><\/p>\n\n\n\n<p>We created the wing flapping by using a skinned mesh shader. True or False.<\/p>\n\n\n\n<p><img decoding=\"async\" class=\"lazyload\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/picx.zhimg.com\/80\/v2-7cb3d96798ee1a490d9e0d9641a8d120_1440w.png?source=d16d100b\" alt=\"img\"><noscript><img decoding=\"async\" class=\"lazyload\" src=\"https:\/\/picx.zhimg.com\/80\/v2-7cb3d96798ee1a490d9e0d9641a8d120_1440w.png?source=d16d100b\" alt=\"img\"><\/noscript><\/p>\n\n\n\n<p>In a shader used by DrawMeshInstancedIndirect, which variable name gives the correct index for the instance?<\/p>\n\n\n\n<p><img decoding=\"async\" class=\"lazyload\" src=\"data:image\/gif;base64,R0lGODlhAQABAIAAAAAAAP\/\/\/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"https:\/\/picx.zhimg.com\/80\/v2-d4793de8e95a27312d93da12486354cf_1440w.png?source=d16d100b\" alt=\"img\"><noscript><img decoding=\"async\" class=\"lazyload\" src=\"https:\/\/picx.zhimg.com\/80\/v2-d4793de8e95a27312d93da12486354cf_1440w.png?source=d16d100b\" alt=\"img\"><\/noscript><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">References<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>https:\/\/en.wikipedia.org\/wiki\/Boids<\/li>\n\n\n\n<li><a href=\"https:\/\/dl.acm.org\/doi\/10.1145\/37401.37406\">Flocks, Herds, and Schools: A Distributed Behavioral Model<\/a><\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>\u7d27\u63a5\u7740\u4e0a\u4e00\u7bc7\u6587\u7ae0 remoooo\uff1aCompute Shader\u5b66\u4e60\u7b14\u8bb0\uff08\u4e8c\uff09\u4e4b \u540e\u5904\u7406\u6548\u679c L4 \u7c92\u5b50\u6548\u679c\u4e0e\u7fa4 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1455,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[53],"tags":[74,37],"class_list":["post-1441","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tech","tag-compute-shader","tag-unity"],"_links":{"self":[{"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/posts\/1441","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/comments?post=1441"}],"version-history":[{"count":2,"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/posts\/1441\/revisions"}],"predecessor-version":[{"id":1596,"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/posts\/1441\/revisions\/1596"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/media\/1455"}],"wp:attachment":[{"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/media?parent=1441"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/categories?post=1441"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/remoooo.com\/en\/wp-json\/wp\/v2\/tags?post=1441"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}