{"id":3472,"date":"2021-01-04T15:50:58","date_gmt":"2021-01-04T07:50:58","guid":{"rendered":"http:\/\/blog.coolcoding.cn\/?p=3472"},"modified":"2021-01-04T16:48:32","modified_gmt":"2021-01-04T08:48:32","slug":"urp%e5%90%8e%e5%a4%84%e7%90%86%e8%87%aa%e5%ae%9a%e4%b9%89volume%e6%96%b9%e5%bc%8f","status":"publish","type":"post","link":"https:\/\/blog.coolcoding.cn\/?p=3472","title":{"rendered":"URP\u540e\u5904\u7406\u81ea\u5b9a\u4e49Volume\u65b9\u5f0f"},"content":{"rendered":"\n<p>\u539f\u6587\uff1ahttps:\/\/www.jianshu.com\/p\/a5456036ab95<\/p>\n\n\n\n<p>URP\u81ea\u5e26\u7684\u540e\u5904\u7406\u529f\u80fd\u662f\u653e\u4e00\u4e2aVolume\uff0c\u5728\u4e0a\u9762\u52a0\u6302\u5e38\u7528\u540e\u5904\u7406\uff0c\u4f8b\u5982Bloom\u3001Tonemap\u7b49\uff0c\u8c03\u8282\u76f8\u5e94\u53c2\u6570\uff1b\u5728\u4e3b\u76f8\u673a\u4e0a\uff0c\u52fe\u9009PostProcessing\uff0c\u8fd9\u6837\u5c31\u80fd\u5f97\u5230\u540e\u5904\u7406\u529f\u80fd\u3002<br> \u2003\u2003\u5982\u679c\u60f3\u8981\u81ea\u5b9a\u4e49\u540e\u5904\u7406\uff0c\u4e00\u822c\u65b9\u5f0f\u662f\u5199RenderFeature\uff0c\u8fd9\u6837\u7684\u4f18\u52bf\u662f\uff0c\u6bcf\u4e2a\u81ea\u5b9a\u4e49\u7684\u540e\u5904\u7406\u5f7c\u6b64\u72ec\u7acb\uff0c\u8c03\u8282\u6e32\u67d3\u4f4d\u7f6e\u65b9\u4fbf\uff0c\u53ea\u8981\u5728URP\u7684Renderer\u91cc\u9762\u8c03\u6574\u5373\u53ef\uff0c\u4f46\u4e5f\u6709\u76f8\u5bf9\u7684\u52a3\u52bf\uff0c\u505a\u540e\u5904\u7406\u65f6\uff0c\u57fa\u672c\u662f\u8981\u628a\u539f\u6765\u7684RT\u590d\u5236\u4e00\u4efd\u51fa\u6765\uff0c\u7136\u540e\u518d\u7528\u540e\u5904\u7406\u7b97\u6cd5\u6e32\u67d3\u5230\u989c\u8272RT\u4e0a\uff0c\u6bcf\u4e00\u4e2a\u540e\u5904\u7406\u90fd\u8981\u8fd9\u4e48\u505a\uff0c\u8fd9\u6837\u65e0\u7591\u65f6\u6d6a\u8d39\u4e86\u5f88\u591a\u8d44\u6e90\uff0c\u660e\u660e\u53cc\u7f13\u51b2\u4e92\u76f8\u4ea4\u6362\u5c31\u53ef\u4ee5\u4e86\uff0c\u5374\u8fd8\u8981\u591aBlit\u8fd9\u4e48\u591a\u6b21\uff0c\u8fd9\u5927\u6982\u662fRenderFeature\u76f8\u5bf9\u81ea\u7531\u7684\u4ee3\u4ef7\u5427\u3002<br> \u2003\u2003URP\u4e2d\u5b9e\u73b0\u7684\u540e\u5904\u7406\u529f\u80fd\u662f\u53cc\u7f13\u51b2\u4e92\u76f8Blit\uff0c\u5e76\u4e14\u518d\u79fb\u52a8\u5e73\u53f0\u7684TBR\u67b6\u6784\u4e0b\u505a\u4e86\u4e00\u4e9b\u4f18\u5316\uff0c\u4f8b\u5982\uff0c\u6839\u636e\u6211\u7684\u7406\u89e3\uff0c\u5f53RT\u88ab\u8bbe\u7f6e\u4e3a\u6e32\u67d3\u76ee\u6807\u65f6\uff0c\u989c\u8272Buffer\u548c\u6df1\u5ea6Buffer\u7684\u5185\u5bb9\u662f\u5426\u8981\u5728\u610f\uff0c\u662f\u5426\u8981\u7acb\u523b\u4ece\u5185\u5b58\u8bfb\u5230GPU\u7684SRAM\uff0c\u8fd9\u610f\u5473\u7740\u5ef6\u8fdf\u6267\u884c\u7684\u6e32\u67d3\u547d\u4ee4\u5c06\u4f1a\u7acb\u523b\u6267\u884c\uff0c\u540c\u6837\u7684\uff0c\u5f53\u5b58\u50a8\u65f6\u662f\u5426\u8981\u7acb\u523b\u5199\u56de\u5185\u5b58\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">\u6b65\u9aa41.\u5b9a\u4e49\u8bbe\u7f6e\u9762\u677f<\/h4>\n\n\n\n<p>\u2003\u2003\u5b9a\u4e49\u4e00\u4e2a\u540e\u5904\u7406\u9762\u677f\u7684\u65b9\u5f0f\u76f8\u5bf9\u7b80\u5355\uff0c\u4f8b\u5982\u6211\u60f3\u628a\u5c4f\u5e55\u4e58\u4e0a\u4e00\u4e2a\u56fa\u5b9a\u7684\u989c\u8272\uff0c\u53ef\u4ee5\u8fd9\u6837\u7f16\u5199\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>namespace UnityEngine.Rendering.Universal\n{\n    [System.Serializable, VolumeComponentMenu(\"CustomVolume\/MultiplyColor\")]\n    public sealed class MultiplyColor : VolumeComponent, IPostProcessComponent\n    {\n        public MaterialParameter material = new MaterialParameter(null, true);\n\n        public ColorParameter color = new ColorParameter(Color.white, false);\n        public bool IsActive()\n        {\n            if (material.value == null)\n                return false;\n            return true;\n        }\n\n        public bool IsTileCompatible()\n        {\n            return false;\n        }\n\n        public override void Override(VolumeComponent state, float interpFactor)\n        {\n            base.Override(state, interpFactor);\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>ColorParameter\u662f\u6211\u4eec\u5b9a\u4e49\u7684\u5c5e\u6027\u9762\u677f\uff0c\u9664\u6b64\u5916\uff0c\u8fd8\u6709FloatParameter\u3001IntParameter\u3001ClampParameter\u3002<br>\n\u2003\u2003\u5f53\u4e00\u4e9b\u6211\u4eec\u9700\u8981\u7684\u5c5e\u6027\u627e\u4e0d\u5230\u65f6\uff0c\u4f8b\u5982\u679a\u4e3e\uff0c\u6216\u8005Material\uff0c\u6211\u4eec\u9700\u8981\u81ea\u5b9a\u4e49\u5c5e\u6027\uff0c\u4e0a\u9762\u7684MaterialParameter\u5c31\u662f\u6211\u81ea\u5b9a\u4e49\u7684\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>[Serializable]\npublic sealed class MaterialParameter : VolumeParameter&lt;Material> \n{ \n    public MaterialParameter(Material value, bool overrideState = false)\n        : base(value, overrideState) { }\n}\n<\/code><\/pre>\n\n\n\n<p>\u2003\u2003VolumeParameter\u6709\u4e9b\u65b9\u6cd5\u53ef\u4ee5\u91cd\u8f7d\uff0c\u5177\u4f53\u53ef\u4ee5\u70b9\u8fdb\u53bb\u770b\u770b\u3002<br>\n\n\n\u2003\u2003\u73b0\u5728\u5c31\u53ef\u4ee5\u518dVolume\u7684\u9762\u677f\u4e0a\u52a0\u6302\u8fd9\u4e2a\u540e\u5904\u7406\u8bbe\u7f6e\u9762\u677f\u4e86\uff1a\n\n\n<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/\/upload-images.jianshu.io\/upload_images\/7875603-aadb68c1e4965c4d.png?imageMogr2\/auto-orient\/strip|imageView2\/2\/w\/348\/format\/webp\" alt=\"\"\/><\/figure>\n\n\n\n<p>\n\u2003\u2003\u5982\u679c\u9700\u8981\u81ea\u5b9a\u4e49Volume\u9762\u677f\uff0c\u53ef\u4ee5\u7ee7\u627fVolumeComponentEditor\uff0c\u5177\u4f53\u53c2\u7167ChannelMixerEditor\u7684\u7f16\u5199\uff1a\n<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>namespace UnityEditor.Rendering.Universal\n{\n    [VolumeComponentEditor(typeof(ChannelMixer))]\n    sealed class ChannelMixerEditor : VolumeComponentEditor\n    {\n        \/\/something\n    }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\u6b65\u9aa42.\u7f16\u5199\u540e\u5904\u7406\u903b\u8f91<\/h3>\n\n\n\n<p>\u2003\u2003\u53ea\u5b9a\u4e49\u9762\u677f\uff0c\u663e\u7136\u662f\u4e0d\u53ef\u80fd\u6709\u540e\u5904\u7406\u529f\u80fd\u7684\uff0c\u800c URP\u73b0\u5728\u4e5f\u6ca1\u66b4\u9732\u51fa\u81ea\u5b9a\u4e49VolumePass\u7684\u65b9\u6cd5\uff0c\u5982\u679c\u60f3\u81ea\u5df1\u5b9e\u73b0\u540e\u5904\u7406\uff0c\u9700\u8981\u6539\u5199\u90e8\u5206URP\u6e90\u7801\u3002<br>\n\u2003\u2003\u5e78\u8fd0\u7684\u662f\uff0c\u8fd9\u90e8\u5206\u4ee3\u7801\u5e76\u4e0d\u662f\u7279\u522b\u96be\u770b\u3002<br>\nURP Volume\u81ea\u5e26\u7684\u540e\u5904\u7406\u4e2d\u6709\u5982\u4e0b\u51e0\u79cd \uff1a<\/p>\n\n\n\n<table class=\"wp-block-table\"><thead><tr><th>\u540e\u5904\u7406<\/th><th>\u540d\u79f0<\/th><th>\u5f15\u7528\u6587\u4ef6<\/th><\/tr><\/thead><tbody><tr><td>Bloom<\/td><td>\u8f89\u5149<\/td><td>PostProcessPass<\/td><\/tr><tr><td>Channel Mixer<\/td><td>\u901a\u9053\u6df7\u5408<\/td><td>ColorGradingLutPass<\/td><\/tr><tr><td>Chromatic Aberration<\/td><td>\u8272\u5dee<\/td><td>PostProcessPass<\/td><\/tr><tr><td>Color Adjustments<\/td><td>\u989c\u8272\u8c03\u6574<\/td><td>ColorGradingLutPass &amp; PostProcessPass<\/td><\/tr><tr><td>Color Curves<\/td><td>\u989c\u8272\u66f2\u7ebf<\/td><td>ColorGradingLutPass<\/td><\/tr><tr><td>Color Lookup<\/td><td>LUT<\/td><td>PostProcessPass<\/td><\/tr><tr><td>Depth Of Field<\/td><td>\u666f\u6df1<\/td><td>PostProcessPass<\/td><\/tr><tr><td>FileGrain<\/td><td><\/td><td>PostProcessPass<\/td><\/tr><tr><td>Lens Distortion<\/td><td>\u955c\u5934\u626d\u66f2<\/td><td>PostProcessPass<\/td><\/tr><tr><td>Lift, Gamma, Gain<\/td><td><\/td><td>ColorGradingLutPass<\/td><\/tr><tr><td>Motion Blur<\/td><td>\u52a8\u6001\u6a21\u7cca<\/td><td>PostProcessPass<\/td><\/tr><tr><td>Panini Projection<\/td><td>\u5e15\u5c3c\u5c3c\u6295\u5f71<\/td><td>PostProcessPass<\/td><\/tr><tr><td>Shadows, Midtones, Hightlights<\/td><td><\/td><td>ColorGradingLutPass<\/td><\/tr><tr><td>Split Toning<\/td><td><\/td><td>ColorGradingLutPass<\/td><\/tr><tr><td>Tonemapping<\/td><td>\u8272\u8c03\u6620\u5c04<\/td><td>ColorGradingLutPass &amp; PostProcessPass<\/td><\/tr><tr><td>Vignette<\/td><td>\u955c\u5934\u9ed1\u8fb9<\/td><td>PostProcessPass<\/td><\/tr><tr><td>White Balance<\/td><td>\u767d\u5e73\u8861<\/td><td>ColorGradingLutPass<\/td><\/tr><\/tbody><\/table>\n\n\n\n<p>\u2003\u2003\u4e0a\u9762\u4e24\u4e2a\u6587\u4ef6\u90fd\u662f\u7ee7\u627f\u81eaSRP\u7684ScriptableRenderPass\uff0c\u6211\u4e3b\u8981\u5173\u5fc3\u7684\u662fPostProcessPass\uff0c\u56e0\u4e3a\u5927\u591a\u6570\u540e\u6548\u90fd\u88ab\u8fd9\u4e2a\u6587\u4ef6\u5f15\u7528\u3002<br>\n\u2003\u2003\u5f00\u5934\u53ef\u4ee5\u770b\u89c1\u51e0\u4e2a\u5b9a\u4e49\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class PostProcessPass : ScriptableRenderPass\n{\n    RenderTextureDescriptor m_Descriptor;\n    RenderTargetHandle m_Source;\n    RenderTargetHandle m_Destination;\n\/\/...\n<\/code><\/pre>\n\n\n\n<p>\n\n\n\u2003\u2003\u5176\u4e2dm_Source\u5c06\u4f1a\u662f\u6211\u4eec\u9700\u8981\u6e32\u67d3\u7684\u539f\u59cb\u56fe\u50cf\uff0cm_Destination\u5728FrameDebug\u4e2d\uff0c\u5c06\u662f_AfterPostProcessTexture\uff1a\n\n\n<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/\/upload-images.jianshu.io\/upload_images\/7875603-9d5db62fa274a93e.png?imageMogr2\/auto-orient\/strip|imageView2\/2\/w\/829\/format\/webp\" alt=\"\"\/><\/figure>\n\n\n\n<p>\u2003\u2003\u7136\u540e\u5b9a\u4e49\u4e86\u4e00\u7968\u540e\u5904\u7406\u7ec4\u4ef6\u6210\u5458\uff0c\u5e76\u5728Execute\u4e2d\u83b7\u53d6\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>    DepthOfField m_DepthOfField;\n    MotionBlur m_MotionBlur;\n    PaniniProjection m_PaniniProjection;\n    Bloom m_Bloom;\n    LensDistortion m_LensDistortion;\n    ChromaticAberration m_ChromaticAberration;\n    Vignette m_Vignette;\n    ColorLookup m_ColorLookup;\n    ColorAdjustments m_ColorAdjustments;\n    Tonemapping m_Tonemapping;\n    FilmGrain m_FilmGrain;\n\n\/\/Execute\n    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)\n    {\n        \/\/ Start by pre-fetching all builtin effect settings we need\n        \/\/ Some of the color-grading settings are only used in the color grading lut pass\n        var stack = VolumeManager.instance.stack;\n        m_DepthOfField        = stack.GetComponent&lt;DepthOfField>();\n        m_MotionBlur          = stack.GetComponent&lt;MotionBlur>();\n        m_PaniniProjection    = stack.GetComponent&lt;PaniniProjection>();\n        m_Bloom               = stack.GetComponent&lt;Bloom>();\n        m_LensDistortion      = stack.GetComponent&lt;LensDistortion>();\n        m_ChromaticAberration = stack.GetComponent&lt;ChromaticAberration>();\n        m_Vignette            = stack.GetComponent&lt;Vignette>();\n        m_ColorLookup         = stack.GetComponent&lt;ColorLookup>();\n        m_ColorAdjustments    = stack.GetComponent&lt;ColorAdjustments>();\n        m_Tonemapping         = stack.GetComponent&lt;Tonemapping>();\n        m_FilmGrain           = stack.GetComponent&lt;FilmGrain>();\n\n\/\/do something\n<\/code><\/pre>\n\n\n\n<p>\u2003\u2003\u4e3b\u8981\u7684\u903b\u8f91\u90fd\u7f16\u5199\u5728Execute\u4e2d\uff0c\u8fd9\u662f\u6211\u4eec\u91cd\u70b9\u5173\u6ce8\u76ee\u6807\u3002<br>\n\u2003\u2003\u5f00\u5934\u5c31\u662f\u95ee\u5f53\u524d\u662f\u5426\u662fFinalPass\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if (m_IsFinalPass)\n{\n    var cmd = CommandBufferPool.Get(k_RenderFinalPostProcessingTag);\n    RenderFinalPass(cmd, ref renderingData);\n    context.ExecuteCommandBuffer(cmd);\n    CommandBufferPool.Release(cmd);\n}\nelse if (CanRunOnTile())\n{\n    \/\/ TODO: Add a fast render path if only on-tile compatible effects are used and we're actually running on a platform that supports it\n    \/\/ Note: we can still work on-tile if FXAA is enabled, it'd be part of the final pass\n}\nelse\n{\n    var cmd = CommandBufferPool.Get(k_RenderPostProcessingTag);\n    Render(cmd, ref renderingData);\n    context.ExecuteCommandBuffer(cmd);\n    CommandBufferPool.Release(cmd);\n}\n<\/code><\/pre>\n\n\n\n<p>\n\n\n\u2003\u2003URP\u7684FXAA\u662f\u5728\u6240\u6709\u76f8\u673a\uff0c\u5305\u62ecBase\u76f8\u673a\u4ee5\u53caOverlay\u76f8\u673a\u6e32\u67d3\u4e4b\u540e\u8fdb\u884c\u7684\uff0c\u53ef\u4ee5\u53d1\u73b0\uff0c\u8bbe\u7f6e\u4e86FXAA\u540e\uff0c\u6700\u540e\u4e00\u4e2a\u8c03\u7528\u662fFinalPass\uff0c\u5982\u679c\u4e0d\u662f\uff0c\u5219\u53ea\u662f\u666e\u901a\u7684Blit\uff1a\n\n\n<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/\/upload-images.jianshu.io\/upload_images\/7875603-e5ccb46a06e3fe1b.png?imageMogr2\/auto-orient\/strip|imageView2\/2\/w\/327\/format\/webp\" alt=\"\"\/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/\/upload-images.jianshu.io\/upload_images\/7875603-0b472fd077d11931.png?imageMogr2\/auto-orient\/strip|imageView2\/2\/w\/874\/format\/webp\" alt=\"\"\/><\/figure>\n\n\n\n<p>\u2003\u2003\u8c03\u7528\u6b21\u5e8f\u662f\u5728ForwardRenderer.cs\u7684Setup\u4e2d\uff0c\u5047\u5982\u662fStack\u4e2d \u6700\u540e\u4e00\u4e2a\u76f8\u673a\uff0c\u5e76\u4e14\u5f00\u4e86FXAA\uff0c\u5219\u8c03\u7528Pass\u7684\u540e\u5904\u7406\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\nbool lastCameraInTheStack = renderingData.resolveFinalTarget;\nbool hasCaptureActions = renderingData.cameraData.captureActions != null &amp;&amp; lastCameraInTheStack;\nbool applyFinalPostProcessing = anyPostProcessing &amp;&amp; lastCameraInTheStack &amp;&amp;\n                            renderingData.cameraData.antialiasing == AntialiasingMode.FastApproximateAntialiasing;\n\n\/\/something\n\nif (applyFinalPostProcessing)\n{\n    m_FinalPostProcessPass.SetupFinalPass(sourceForFinalPass);\n    EnqueuePass(m_FinalPostProcessPass);\n}\n<\/code><\/pre>\n\n\n\n<p>\u2003\u2003\u56de\u5230PostProcessPass\u4e2d\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public void SetupFinalPass(in RenderTargetHandle source)\n{\n    m_Source = source;\n    m_Destination = RenderTargetHandle.CameraTarget;\n    m_IsFinalPass = true;\n    m_HasFinalPass = false;\n    m_EnableSRGBConversionIfNeeded = true;\n}\n<\/code><\/pre>\n\n\n\n<p>\u2003\u2003m_IsFinalPass\u88ab\u8bbe\u7f6e\u4e3atrue\uff0c\u4e8e\u662f\u8c03\u7528RenderFinalPass\u8d70\u6700\u7ec8\u6e32\u67d3\u6d41\u7a0b\uff1b\u5f53\u4e0d\u662fFinalPass\u65f6\uff0c\u8c03\u7528Render\u8d70\u666e\u901a\u540e\u5904\u7406\u6d41\u7a0b\u3002<br>\n\u2003\u2003Render\u4e2d\u58f0\u660e\u4e86\u4e24\u4e2a\u5c40\u90e8\u53cc\u7f13\u51b2\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>int source = m_Source.id;\nint destination = -1;\n<\/code><\/pre>\n\n\n\n<p>\u2003\u2003\u4e24\u4e2a\u53d6\u5f97\u7f13\u51b2\u7684\u65b9\u6cd5\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>int GetSource() => source;\n\nint GetDestination()\n{\n    if (destination == -1)\n    {\n        cmd.GetTemporaryRT(ShaderConstants._TempTarget, GetStereoCompatibleDescriptor(), FilterMode.Bilinear);\n        destination = ShaderConstants._TempTarget;\n        tempTargetUsed = true;\n    }\n    else if (destination == m_Source.id &amp;&amp; m_Descriptor.msaaSamples > 1)\n    {\n        \/\/ Avoid using m_Source.id as new destination, it may come with a depth buffer that we don't want, may have MSAA that we don't want etc\n        cmd.GetTemporaryRT(ShaderConstants._TempTarget2, GetStereoCompatibleDescriptor(), FilterMode.Bilinear);\n        destination = ShaderConstants._TempTarget2;\n        tempTarget2Used = true; \n    }\n\n    return destination;\n}\n<\/code><\/pre>\n\n\n\n<p>\u2003\u2003\u4ea4\u6362\u7f13\u51b2\u533a\u65b9\u6cd5\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void Swap() => CoreUtils.Swap(ref source, ref destination);\n<\/code><\/pre>\n\n\n\n<p>\u2003\u2003\u7136\u540e\u5c31\u662f\u4e00\u5806\u7c7b\u4f3c\u4e0b\u9762\u7684\u6d41\u7a0b\uff0c\u68c0\u67e5\u4e0b\u540e\u5904\u7406\u662f\u5426\u5f00\u542f\uff0c\u76f8\u673a\u662f\u4e0d\u662f\u573a\u666f\u76f8\u673a\uff0c\u7136\u540e\u8c03\u7528\u65b9\u6cd5\uff1b\u505a\u5b8c\u540e\u8fd8\u8981\u6362\u4e0b\u7f13\u51b2\u533a\u3002<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Motion blur\nif (m_MotionBlur.IsActive() &amp;&amp; !cameraData.isSceneViewCamera)\n{\n    using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.MotionBlur)))\n    {\n        DoMotionBlur(cameraData.camera, cmd, GetSource(), GetDestination());\n        Swap();\n    }\n}\n<\/code><\/pre>\n\n\n\n<p>\u2003\u2003\u4e0d\u8fc7\u4e00\u4e9b\u6d41\u7a0b\u662f\u7279\u6b8a\u7684\uff0cBloom\u3001LensDistortion\u3001ChromaticAberration\u3001Vignette\u3001ColorGrading\u7b49\uff0c\u8fd9\u4e9b\u88ab\u5408\u6210\u7528\u4e00\u4e2aShader\u53bb\u505a\uff0c\u65b9\u6cd5\u662f\u7528\u4e00\u4e2aUberShader\uff0c\u5f00\u5173Keyword\uff0c\u505a\u5b8c\u540e\u76f4\u63a5Blit\u5230m_Destination\uff08_AfterPostProcessTexture\uff09\u4e0a\u3002<br>\n\u2003\u2003\u8fd9\u6837\u7684\u8bdd\uff0c\u5982\u679c\u6211\u4eec\u60f3\u5728\u8fd9\u4e9b\u540e\u5904\u7406\u4e4b\u540e\u6e32\u67d3\uff0c\u5c31\u8981\u60f3\u529e\u6cd5\u628a\u8fd9\u4e00\u6b65\uff08\u76f4\u63a5Blit\u5230m_Destination\uff09\u6253\u5f00\uff0c\u6253\u5f00\u7684\u65b9\u6cd5\u540e\u9762\u518d\u63d0\u3002<br>\n\u2003\u2003\u6211\u4eec\u73b0\u5728\u77e5\u9053\u4e86\u5927\u81f4\u6846\u67b6\uff0c\u6240\u4ee5\u6309\u7167URP\u6e90\u7801\u7684\u5f62\u5f0f\u7ee7\u7eed\u7f16\u5199\u3002<br>\n\u2003\u2003\u9996\u5148\u5b9a\u4e49\u7ec4\u4ef6\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Custom effects settings\nMultiplyColor m_MultiplyColor;\n<\/code><\/pre>\n\n\n\n<p>\u2003\u2003\u7136\u540e\u518dExecute\u4e2d\u83b7\u53d6\u7ec4\u4ef6<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/Custom\nm_MultiplyColor = stack.GetComponent&lt;MultiplyColor>();\n<\/code><\/pre>\n\n\n\n<p>\u2003\u2003\u7136\u540e\u518dRender\u4e2d\u68c0\u67e5Active\u5e76\u6267\u884cPass\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>enum CustomProfileId\n{\n    MultiplyColor,\n}\n\n\/\/Render\u65b9\u6cd5\n\n\/\/\n\/\/\n\/\/  Custom Effect_______________________________________________________________________\n\/\/\nif (m_MultiplyColor.IsActive() &amp;&amp; !cameraData.isSceneViewCamera)\n{\n    using (new ProfilingScope(cmd, ProfilingSampler.Get(CustomProfileId.MultiplyColor)))\n    {\n        DoMultiplyColor(cameraData.camera, cmd, GetSource(), GetDestination());\n        Swap();\n    }\n}\n\nvoid DoMultiplyColor(Camera camera, CommandBuffer cmd, int source, int destination)\n{\n    var material = m_MultiplyColor.material.value;\n\n    cmd.SetGlobalTexture(\"_BlitTex\", source);\n    cmd.SetGlobalColor(\"_Color\", m_MultiplyColor.color.value);\n    Blit(cmd, source, BlitDstDiscardContent(cmd, destination), material, 0);\n}\n<\/code><\/pre>\n\n\n\n<p>\u2003\u2003\u8fd9\u6837\u5c31\u80fd\u4ea7\u751f\u5b9e\u9645\u7684\u6548\u679c\u4e86\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Uber\u540e\u5904\u7406\u540e\u7684\u540e\u5904\u7406<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">\u573a\u666f<\/h4>\n\n\n\n<p>\u2003\u2003\u7f8e\u672f\u53cd\u9988\uff0c\u5f53\u4e3b\u76f8\u673a\u6253\u5f00FXAA\u65f6\uff0cUI\u4e5f\u53d8\u5f97\u5f88\u7cca\u3002\u7528FrameDebug\u770b\u4e86\u4e00\u773c\uff0cFXAA\u662f\u5728FinalPass\u505a\u7684\uff0c\u662f\u6240\u6709Overlay\u76f8\u673a\u6e32\u67d3\u4e4b\u540e\u8fdb\u884c\u4e00\u6b21\u6297\u952f\u9f7f\uff0c\u800c\u6211\u4eec\u5e0c\u671b\u7684\u662f\u53ea\u6709\u573a\u666f\u88ab\u6297\u952f\u9f7f\uff0c\u56e0\u6b64\u6211\u81ea\u5b9a\u4e49\u4e86\u4e00\u4e2aFXAA\u7684Volume Component\uff0c\u4eceFinalPass\u7684Shader\u4e2d\u6458\u53d6FXAA\u90e8\u5206\u6e90\u7801\u7f16\u5199\u4e86Shader\u5e76\u521b\u5efa\u6750\u8d28\uff0c\u5e76\u6309\u7167\u4e0a\u9762\u7684\u65b9\u6cd5\u5c06\u4ee3\u7801\u6dfb\u52a0\u5230PostProcessPass\u4e2d\uff0c\u4f46\u6700\u540e\u5f97\u5230\u7684\u56fe\u50cf\u6ca1\u6709Bloom\u6548\u679c\uff0c\u68c0\u67e5\u4e86\u4e00\u4e0b\u53d1\u73b0\uff0cFXAA\u7684Shader\u4e2d\u5305\u542b\u8fd9\u79cd\u8ba1\u7b97\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/\u91c7\u68375\u6b21\nhalf3 color = Load(positionSS, 0, 0).xyz;\n\nhalf3 rgbNW = Load(positionSS, -1, -1);\nhalf3 rgbNE = Load(positionSS,  1, -1);\nhalf3 rgbSW = Load(positionSS, -1,  1);\nhalf3 rgbSE = Load(positionSS,  1,  1);\n\/\/\u5c06\u989c\u8272\u94b3\u5236\u52300-1\u4e4b\u95f4\nrgbNW = saturate(rgbNW);\nrgbNE = saturate(rgbNE);\nrgbSW = saturate(rgbSW);\nrgbSE = saturate(rgbSE);\ncolor = saturate(color);\n<\/code><\/pre>\n\n\n\n<p>\u2003\u2003Bloom\u4e00\u822c\u662f\u989c\u8272\u5927\u4e8e1\u7684\u81ea\u53d1\u5149\u6750\u8d28\uff0c\u5f53\u989c\u8272\u88ab\u9650\u5236\u57281\u4ee5\u4e0b\u65f6\uff0c\u5c31\u4ea7\u751f\u4e0d\u4e86Bloom\u5149\uff0c\u56e0\u6b64\u6211\u9700\u8981\u5c06FXAA\u653e\u5230Bloom\u4e4b\u540e\u6e32\u67d3\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">\u4ee3\u7801\u5206\u6790<\/h4>\n\n\n\n<p>\u2003\u2003URP\u7684\u540e\u5904\u7406\u7684\u987a\u5e8f\u662f\u4ee3\u7801\u51b3\u5b9a\u7684\uff0c\u5c31\u7b97Volume\u4e2d\u6302\u8f7d\u7684\u987a\u5e8f\u4e0d\u540c\uff0c\u6267\u884c\u65f6\u7684\u987a\u5e8f\u4e5f\u65f6\u4e00\u81f4\u7684\u3002<br>\n\u2003\u2003\u56e0\u6b64\u5f53\u4ee3\u7801\u51b3\u5b9a\u7531Bloom\u3001LensDistortion\u3001ChromaticAberration\u7b49\u7b49\u7ec4\u6210UberShader\u6700\u540e\u6e32\u67d3\u65f6\uff0cUberShader\u80af\u5b9a\u65f6\u6700\u540e\u6e32\u67d3\u7684\uff0cUnity\u4e3a\u6b64\u505a\u4e86\u7279\u6b8a\u7684\u4f18\u5316\uff0c\u5f53\u6700\u540e\u6e32\u67d3\u65f6\uff0c\u8bbe\u7f6e\u4e0d\u540c\u7684RT\u8bbf\u95ee\u3001\u5b58\u50a8\u5c5e\u6027\uff0c\u6e90\u7801\u662f\u8fd9\u6837\u7684\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>var colorLoadAction = RenderBufferLoadAction.DontCare;\nif (m_Destination == RenderTargetHandle.CameraTarget &amp;&amp; !cameraData.isDefaultViewport)\n    colorLoadAction = RenderBufferLoadAction.Load;\n\nRenderTargetIdentifier cameraTarget = (cameraData.targetTexture != null) ? new RenderTargetIdentifier(cameraData.targetTexture) : BuiltinRenderTextureType.CameraTarget;\ncameraTarget = (m_Destination == RenderTargetHandle.CameraTarget) ? cameraTarget : m_Destination.Identifier();\ncmd.SetRenderTarget(cameraTarget, colorLoadAction, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);\n\nbool finishPostProcessOnScreen = renderingData.resolveFinalTarget || (m_Destination == RenderTargetHandle.CameraTarget || m_HasFinalPass == true);\n\n\/\/\u5982\u679c\u662fVR\uff0c\u7528Blit\uff0c\u5426\u5219\u7528DrawMesh\u6e32\u67d3\u5168\u5c4f\u9762\u7247\nif (m_IsStereo)\n{\n    Blit(cmd, GetSource(), BuiltinRenderTextureType.CurrentActive, m_Materials.uber);\n\n    if (!finishPostProcessOnScreen)\n    {\n        cmd.SetGlobalTexture(\"_BlitTex\", cameraTarget);\n        Blit(cmd, BuiltinRenderTextureType.CurrentActive, m_Source.id, m_BlitMaterial);\n    }\n}\nelse\n{\n    cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);\n\n    if (m_Destination == RenderTargetHandle.CameraTarget)\n        cmd.SetViewport(cameraData.pixelRect);\n\n    cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_Materials.uber);\n\n    if (!finishPostProcessOnScreen)\n    {\n        cmd.SetGlobalTexture(\"_BlitTex\", cameraTarget);\n        cmd.SetRenderTarget(m_Source.id, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);\n        cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_BlitMaterial);\n    }\n\n    cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix);\n}\n<\/code><\/pre>\n\n\n\n<p>\u5224\u5b9a\u903b\u8f91\u633a\u590d\u6742\uff0c\u4f46\u5982\u679c\u7b80\u5316\u6765\u770b\uff0c\u5c31\u662f\u51e0\u70b9\uff1a<br> 1.\u8bbe\u7f6eRT\u548c\u8bbf\u95ee\u3001\u5b58\u50a8\u5c5e\u6027\uff1b<br> 2.\u662f\u5426\u6709FinalPass\uff1b<br> 3.\u5c06\u6e90\u7f13\u51b2source\u6309\u7167uber shader blit\u5230\u603b\u76ee\u6807m_Destination\u4e2d\uff1b<br> 4.\u5982\u679c\u6709FinalPass\uff0c\u5219\u518d\u5c06m_Destination\u590d\u5236\u5230\u603b\u539f\u7f13\u51b2mSource<br> <strong>\u590d\u5236\u5230\u603b\u539f\u7f13\u51b2mSource\u7684\u539f\u56e0\u662f\uff0c\u5f53\u6709FinalPass\uff08MSAA\u7684resolve\u6216FXAA\uff09\u65f6\uff0c\u5c06\u76f4\u63a5\u4ecemSource\u4e2d\u53d6\u5f97\u989c\u8272\uff0c\u56e0\u6b64\u8981\u590d\u5236\u56demSource\uff0c\u5177\u4f53\u4ee3\u7801\u53c2\u89c1RenderFinalPass-&gt;cmd.SetGlobalTexture(&#8220;_BlitTex&#8221;, m_Source.Identifier())<\/strong><br>\u5f53\u6211\u4eec\u6709\u5176\u4ed6\u9700\u6c42\uff0c\u9700\u8981\u5728Bloom\u8fd9\u4e9bUberShader\u4e4b\u540e\u505a\uff0c\u53c8\u4e0d\u60f3\u7528RenderFeature\u65f6\uff0c\u5c31\u9700\u8981\u628a\u8fd9\u4e9b\u6b65\u9aa4\u62c6\u5f00\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">\u4ee3\u7801\u6539\u5199<\/h4>\n\n\n\n<p>\u2003\u2003unity\u786e\u4fe1uber shader\u80af\u5b9a\u65f6\u6700\u540e\u4e00\u4e2a\u505a\u7684\u540e\u5904\u7406\uff0c\u800c\u6211\u8981\u505a\u7684\u662f\u628a\u5b83\u5f53\u4f5c\u4e00\u4e2a\u666e\u901a\u7684\u540e\u5904\u7406\uff0c\u56e0\u6b64\u76f4\u63a5Blit\u5373\u53ef\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cmd.SetGlobalTexture(\"_BlitTex\", GetSource());\nBlit(cmd, GetSource(), GetDestination(), m_Materials.uber, 0);\nSwap();\n<\/code><\/pre>\n\n\n\n<p>\u2003\u2003\u7136\u540e\u505a\u6211\u4eec\u7684FXAA\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/\u58f0\u660e\uff1a FXAA m_FXAA;\n\/\/\u521d\u59cb\u5316\uff1am_FXAA = stack.GetComponent&lt;FXAA>();\n\nif (m_FXAA.IsActive() &amp;&amp; !cameraData.isSceneViewCamera)\n{\n    using (new ProfilingScope(cmd, ProfilingSampler.Get(CustomProfileId.FXAA)))\n    {\n        DoFXAA(cameraData.camera, cmd, GetSource(), GetDestination());\n        Swap();\n    }\n}\n<\/code><\/pre>\n\n\n\n<p>\u2003\u2003\u7136\u540e\u5c06Source\u590d\u5236\u5230\u603b\u76ee\u6807RT\u2014\u2014m_Destination\u4e2d\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/\u8bbe\u7f6eBlit\u6e90\u4e3asource\ncmd.SetGlobalTexture(\"_BlitTex\", GetSource());\n\n\/\/\u548c\u539f\u6765\u4e00\u6837\nvar colorLoadAction = RenderBufferLoadAction.DontCare;\nif (m_Destination == RenderTargetHandle.CameraTarget &amp;&amp; !cameraData.isDefaultViewport)\n    colorLoadAction = RenderBufferLoadAction.Load;\n\nRenderTargetIdentifier cameraTarget = (cameraData.targetTexture != null) ? new RenderTargetIdentifier(cameraData.targetTexture) : BuiltinRenderTextureType.CameraTarget;\ncameraTarget = (m_Destination == RenderTargetHandle.CameraTarget) ? cameraTarget : m_Destination.Identifier();\ncmd.SetRenderTarget(cameraTarget, colorLoadAction, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);\n\nbool finishPostProcessOnScreen = renderingData.resolveFinalTarget || (m_Destination == RenderTargetHandle.CameraTarget || m_HasFinalPass == true);\n\n\/\/\u7a0d\u6709\u6539\u52a8\nif (m_IsStereo)\n{\n    Blit(cmd, GetSource(), BuiltinRenderTextureType.CurrentActive, m_BlitMaterial);\n}\nelse\n{\n    cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);\n\n    if (m_Destination == RenderTargetHandle.CameraTarget)\n        cmd.SetViewport(cameraData.pixelRect);\n\n    cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_BlitMaterial);\n\n    cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix);\n}\n\n\nif(!finishPostProcessOnScreen)\n{\n    if (m_IsStereo)\n    {\n        cmd.SetGlobalTexture(\"_BlitTex\", cameraTarget);\n        Blit(cmd, BuiltinRenderTextureType.CurrentActive, m_Source.id, m_BlitMaterial);\n    }\n    else\n    {\n        cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);\n\n        cmd.SetGlobalTexture(\"_BlitTex\", cameraTarget);\n        cmd.SetRenderTarget(m_Source.id, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);\n        cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_BlitMaterial);\n\n        cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix);\n    }\n}\n<\/code><\/pre>\n\n\n\n<p>\u2003\u2003\u8fd9\u6837\u5c31\u6210\u529f\u628auber shader\u4e0e\u590d\u5236\u5230\u76ee\u6807\u5206\u6210\u4e24\u6b65\u3002<br>\n\u2003\u2003\u6211\u7684Combined post-processing stack\u90e8\u5206\u4ee3\u7801\u603b\u4f53\u5982\u4e0b\uff1a<em><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Combined post-processing stack\nusing (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.UberPostProcess)))\n{\n    \/\/ Reset uber keywords\n    m_Materials.uber.shaderKeywords = null;\n\n    \/\/ Bloom goes first\n    bool bloomActive = m_Bloom.IsActive();\n    if (bloomActive)\n    {\n        using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.Bloom)))\n            SetupBloom(cmd, GetSource(), m_Materials.uber);\n    }\n\n    \/\/ Setup other effects constants\n    SetupLensDistortion(m_Materials.uber, cameraData.isSceneViewCamera);\n    SetupChromaticAberration(m_Materials.uber);\n    SetupVignette(m_Materials.uber);\n    SetupColorGrading(cmd, ref renderingData, m_Materials.uber);\n\n    \/\/ Only apply dithering &amp; grain if there isn't a final pass.\n    SetupGrain(cameraData, m_Materials.uber);\n    SetupDithering(cameraData, m_Materials.uber);\n\n    if (RequireSRGBConversionBlitToBackBuffer(cameraData) &amp;&amp; m_EnableSRGBConversionIfNeeded)\n        m_Materials.uber.EnableKeyword(ShaderKeywordStrings.LinearToSRGBConversion);\n\n    cmd.SetGlobalTexture(\"_BlitTex\", GetSource());\n    Blit(cmd, GetSource(), GetDestination(), m_Materials.uber, 0);\n    Swap();\n\n    if (m_FXAA.IsActive() &amp;&amp; !cameraData.isSceneViewCamera)\n    {\n        using (new ProfilingScope(cmd, ProfilingSampler.Get(CustomProfileId.FXAA)))\n        {\n            DoFXAA(cameraData.camera, cmd, GetSource(), GetDestination());\n            Swap();\n        }\n    }\n\n    cmd.SetGlobalTexture(\"_BlitTex\", GetSource());\n\n    var colorLoadAction = RenderBufferLoadAction.DontCare;\n    if (m_Destination == RenderTargetHandle.CameraTarget &amp;&amp; !cameraData.isDefaultViewport)\n        colorLoadAction = RenderBufferLoadAction.Load;\n\n    RenderTargetIdentifier cameraTarget = (cameraData.targetTexture != null) ? new RenderTargetIdentifier(cameraData.targetTexture) : BuiltinRenderTextureType.CameraTarget;\n    cameraTarget = (m_Destination == RenderTargetHandle.CameraTarget) ? cameraTarget : m_Destination.Identifier();\n    cmd.SetRenderTarget(cameraTarget, colorLoadAction, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);\n\n    bool finishPostProcessOnScreen = renderingData.resolveFinalTarget || (m_Destination == RenderTargetHandle.CameraTarget || m_HasFinalPass == true);\n\n    if (m_IsStereo)\n    {\n        Blit(cmd, GetSource(), BuiltinRenderTextureType.CurrentActive, m_BlitMaterial);\n    }\n    else\n    {\n        cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);\n\n        if (m_Destination == RenderTargetHandle.CameraTarget)\n            cmd.SetViewport(cameraData.pixelRect);\n\n        cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_BlitMaterial);\n\n        cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix);\n    }\n\n    if(!finishPostProcessOnScreen)\n    {\n        if (m_IsStereo)\n        {\n\n            cmd.SetGlobalTexture(\"_BlitTex\", cameraTarget);\n            Blit(cmd, BuiltinRenderTextureType.CurrentActive, m_Source.id, m_BlitMaterial);\n        }\n        else\n        {\n            cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);\n\n            cmd.SetGlobalTexture(\"_BlitTex\", cameraTarget);\n            cmd.SetRenderTarget(m_Source.id, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);\n            cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_BlitMaterial);\n\n            cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix);\n        }\n    }\n\n        \/\/ Cleanup\n    if (bloomActive)\n        cmd.ReleaseTemporaryRT(ShaderConstants._BloomMipUp[0]);\n\n    if (tempTargetUsed)\n        cmd.ReleaseTemporaryRT(ShaderConstants._TempTarget);\n\n    if (tempTarget2Used)\n        cmd.ReleaseTemporaryRT(ShaderConstants._TempTarget2);\n}\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\u539f\u6587\uff1ahttps:\/\/www.jianshu.com\/p\/a5456036ab95 URP\u81ea\u5e26\u7684\u540e\u5904\u7406\u529f\u80fd\u662f\u653e [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3483,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts\/3472"}],"collection":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3472"}],"version-history":[{"count":2,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts\/3472\/revisions"}],"predecessor-version":[{"id":3482,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/posts\/3472\/revisions\/3482"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=\/wp\/v2\/media\/3483"}],"wp:attachment":[{"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3472"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3472"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.coolcoding.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3472"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}