內(nèi)置管線Shader升級到URP詳細(xì)手冊

本文基于Unity2020.2稳摄,URP10赦役,更新于20210303

本文初版內(nèi)容翻譯自:https://teodutra.com/unity/shaders/urp/graphics/2020/05/18/From-Built-in-to-URP/

譯者:大智
后續(xù)補(bǔ)充:大智

內(nèi)置管線Shader升級到URP詳細(xì)手冊

總體結(jié)構(gòu)

1、在SubShader的Tags中添加"RenderPipeline" = "UniversalPipeline"
2、所有URP著色器都是HLSL編寫的,使用宏HLSL包含的shader代碼
3、使用HLSLINCLUDE替代CGINCLUDE

內(nèi)置管線 URP
CGPROGRAM HLSLPROGRAM HLSL程序
ENDCG ENDHLSL ENDHLSL
CGINCLUDE HLSLINCLUDE HLSLINCLUDE

Include文件

內(nèi)容 內(nèi)置管線 URP
Core UnityCG.cginc Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl
Light AutoLight.cginc Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl
Shadow AutoLight.cginc Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl
表面著色器 Lighting.cginc URP內(nèi)沒有翘鸭,可以參考項目:在此處

其他有用的包括:

燈光模式LightMode

內(nèi)置管線 URP
ForwardBase UniversalForward
ForwardAdd 移除
Deferred以及相關(guān) 尚未支持
Vertex及相關(guān) 移除
ShadowCaster ShadowCaster
MotionVectors 尚未支持

支持的其他照明模式包括:

  • DepthOnly
  • Meta (for lightmap baking)
  • Universal2D

變體Variants

URP支持某些變體,因此戳葵,根據(jù)你使用的功能就乓,可能需要使用#pragma multi_compile添加一些關(guān)鍵字:

  • _MAIN_LIGHT_SHADOWS
  • _MAIN_LIGHT_SHADOWS_CASCADE
  • _ADDITIONAL_LIGHTS_VERTEX
  • _ADDITIONAL_LIGHTS
  • _ADDITIONAL_LIGHT_SHADOWS
  • _SHADOWS_SOFT
  • _MIXED_LIGHTING_SUBTRACTIVE

預(yù)定義的著色器宏

輔助宏

內(nèi)置管線 URP
UNITY_PROJ_COORD(a) 移除了,使用a.xy / a.w代替
UNITY_INITIALIZE_OUTPUT(type拱烁,name) ZERO_INITIALIZE(type生蚁,name)

陰影貼圖

必須include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl”

內(nèi)置管線 URP
UNITY_DECLARE_SHADOWMAPtex TEXTURE2D_SHADOW_PARAMtextureNamesamplerName
UNITY_SAMPLE_SHADOWtex戏自,uv SAMPLE_TEXTURE2D_SHADOWtextureName邦投,samplerNamecoord3
UNITY_SAMPLE_SHADOW_PROJtex擅笔,uv SAMPLE_TEXTURE2D_SHADOWtextureName志衣,samplerNamecoord4.xyz/coord4.w

紋理/采樣器聲明宏

Unity有很多紋理/采樣器宏來改善API之間的交叉兼容性猛们,但是人們并不習(xí)慣使用它們念脯。URP中這些宏的名稱有所變化。由于數(shù)量很多弯淘,全部的宏可以在API includes中查看绿店,下面主要列舉一些常用的:

內(nèi)置管線 URP
UNITY_DECLARE_TEX2Dname TEXTURE2DtextureName); SAMPLERsamplerName);
UNITY_DECLARE_TEX2D_NOSAMPLERname TEXTURE2DtextureName);
UNITY_DECLARE_TEX2DARRAYname TEXTURE2D_ARRAYtextureName); SAMPLERsamplerName);
UNITY_SAMPLE_TEX2Dnameuv SAMPLE_TEXTURE2DtextureName庐橙,samplerName假勿,coord2
UNITY_SAMPLE_TEX2D_SAMPLERnamesamplername态鳖,uv SAMPLE_TEXTURE2DtextureName转培,samplerNamecoord2
UNITY_SAMPLE_TEX2DARRAYname郁惜,uv SAMPLE_TEXTURE2D_ARRAYtextureName堡距,samplerName甲锡,coord2index
UNITY_SAMPLE_TEX2DARRAY_LODname羽戒,uv缤沦,lod SAMPLE_TEXTURE2D_ARRAY_LODtextureNamesamplerName易稠,coord2缸废,indexlod

需要注意SCREENSPACE_TEXTURE變成了TEXTURE2D_X驶社。如果你想要在VR中(Single Pass InstancedMulti-view 模式)制作屏幕效果企量,你必須使用TEXTURE2D_X定義紋理。這個宏會為你處理正確的紋理聲明(是否為數(shù)組)亡电。對這個紋理采樣的時候必須使用SAMPLE_TEXTURE2D_X届巩,并且對uv使用UnityStereoTransformScreenSpaceTex

Shader輔助函數(shù)

下列函數(shù)可以在此文件中找到:“Packages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl”.

頂點轉(zhuǎn)換函數(shù)

內(nèi)置管線 URP
float4 UnityObjectToClipPosfloat3 pos float4 TransformObjectToHClipfloat3 positionOS
float3 UnityObjectToViewPosfloat3 pos TransformWorldToViewTransformObjectToWorldpositionOS))

法線轉(zhuǎn)換函數(shù)

內(nèi)置管線 URP
float4 UnityObjectToWorldNormalfloat3 pos float4 TransformObjectToWorldNormalfloat3 normalOS

通用輔助函數(shù)

內(nèi)置管線 URP
float3 UnityWorldSpaceViewDirfloat4 v GetCameraPositionWS() - i.worldPos
float3 UnityObjectToWorldDirfloat4 v TransformObjectToWorldDir(real3 dirOS)
float3 ObjSpaceViewDirfloat4 v 移除了份乒,可以使用TransformWorldToObject(GetCameraPositionWS()) - objectSpacePosition ;
float2 ParallaxOffsethalf h恕汇,half heighthalf3 viewDir 移除了或辖●ⅲ可以從UnityCG.cginc復(fù)制過來
fixed Luminancefixed3 c real Luminancereal3 linearRgb Include “Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl”
fixed3 DecodeLightmapfixed4 color real3 DecodeLightmap(real4 encodedIlluminance, real4 decodeInstructions) Include “Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl” URP中的decodeInstructionshalf4(LIGHTMAP_HDR_MULTIPLIER, LIGHTMAP_HDR_EXPONENT, 0.0h, 0.0h)
float4 EncodeFloatRGBAfloat v 移除了∷滔荆可以從UnityCG.cginc復(fù)制過來
float DecodeFloatRGBAfloat4 enc 移除了缺谴。可以從UnityCG.cginc復(fù)制過來
float2 EncodeFloatRGfloat v 移除了耳鸯∈祝可以從UnityCG.cginc復(fù)制過來
float DecodeFloatRGfloat2 enc 移除了∑模可以從UnityCG.cginc復(fù)制過來
float2 EncodeViewNormalStereofloat3 n 移除了煌集〖酥可以從UnityCG.cginc復(fù)制過來
float3 DecodeViewNormalStereofloat4 enc4 移除了捌省。可以從UnityCG.cginc復(fù)制過來
TANGENT_SPACE_ROTATION

前向渲染輔助函數(shù)

內(nèi)置管線 URP
float3 UnityWorldSpaceLightDir(float4 v) _MainLightPosition.xyz - TransformObjectToWorld(objectSpacePosition) Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl”
float3 ObjSpaceLightDir(float4 v) TransformWorldToObject(_MainLightPosition.xyz)-objectSpacePosition Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl”
float3 Shade4PointLights() 可以使用half3 VertexLighting(float3 positionWS, half3 normalWS) 對于VertexLighting(...) include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl”

屏幕空間輔助函數(shù)

內(nèi)置管線 URP
float4 ComputeScreenPos(float4 clipPos) float4 ComputeScreenPosfloat4 positionCS Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl”
float4 ComputeGrabScreenPos(float4 clipPos) 移除了

頂點照明輔助函數(shù)

內(nèi)置管線 URP
float3 ShadeVertexLights (float4 vertex, float3 normal) 移除了碉钠,可以嘗試使用UNITY_LIGHTMODEL_AMBIENT.xyz + VertexLighting(...) 對于VertexLighting(...) include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl”

可以在“Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl”中找到很多工具函數(shù)纲缓。

內(nèi)置著色器變量

除了光照相關(guān)的變量外,其他的變量名都基本沒變

照明

內(nèi)置管線 URP
_LightColor0 _MainLightColor Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl”
_WorldSpaceLightPos0 _MainLightPosition Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl”
_LightMatrix0 移除了喊废。目前尚不支持Cookie
unity_4LightPosX0祝高,unity_4LightPosY0unity_4LightPosZ0 在URP中污筷,其他光源存儲在數(shù)組/緩沖區(qū)中(取決于平臺)工闺。使用Light GetAdditionalLight(uint i, float3 positionWS)獲取額外光源信息 Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl”
unity_4LightAtten0 在URP中,其他光源存儲在數(shù)組/緩沖區(qū)中(取決于平臺)。使用Light GetAdditionalLight(uint i, float3 positionWS)獲取額外光源信息 Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl”
unity_LightColor 在URP中陆蟆,其他光源存儲在數(shù)組/緩沖區(qū)中(取決于平臺)雷厂。使用Light GetAdditionalLight(uint i, float3 positionWS)獲取額外光源信息 Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl”
unity_WorldToShadow float4x4 _MainLightWorldToShadow[MAX_SHADOW_CASCADES + 1] 或者_AdditionalLightsWorldToShadow[MAX_VISIBLE_LIGHTS] Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl”

如果要使用循環(huán)所有其他燈光GetAdditionalLight(...)GetAdditionalLightsCount()可以使用來查詢其他燈光計數(shù)叠殷。

其他

陰影

有關(guān)陰影的更多信息改鲫,“Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl”

內(nèi)置管線 URP
UNITY_SHADOW_COORDSx 移除了。DIY林束,例如float4 shadowCoord : TEXCOORD0;
TRANSFER_SHADOWa a.shadowCoord = TransformWorldToShadowCoordworldSpacePosition 啟用cascades時像棘,對片段執(zhí)行此操作以避免視覺鬼影
SHADOWS_SCREEN 移除了。不支持壶冒。

有關(guān)霧的更多信息缕题,“Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl”.

內(nèi)置管線 URP
UNITY_FOG_COORDS(x) 移除了。DIY胖腾,例如float fogCoord : TEXCOORD0;
UNITY_TRANSFER_FOG(o*避除,outpos) o.fogCoord = ComputeFogFactor(clipSpacePosition.z);
UNITY_APPLY_FOG(coordcol) color = MixFog(color胸嘁,i.fogCoord);

深度

要使用相機(jī)深度紋理瓶摆,需要include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl” ,然后會自動聲明_CameraDepthTexture性宏,也會包含輔助函數(shù)SampleSceneDepth(...)LoadSceneDepth(...)群井。

內(nèi)置管線 URP
LinearEyeDepthsceneZ LinearEyeDepthsceneZ_ZBufferParams Include “Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl”
Linear01DepthsceneZ Linear01DepthsceneZ毫胜,_ZBufferParams Include “Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl”

其他中的其他

內(nèi)置管線 URP
ShadeSH9normal SampleSHnormal Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl”
unity_ColorSpaceLuminance 移除了书斜。使用Luminance() Include “Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl”

后處理/視覺特效

URP不支持OnPreCullOnPreRender酵使,OnPostRenderOnRenderImage這些方法荐吉。URP支持OnRenderObjectOnWillRenderObject,但是如果在URP中使用你可能會發(fā)現(xiàn)問題口渔。因此样屠,如果你曾經(jīng)在舊管線創(chuàng)建視覺效果時使用它們,那么現(xiàn)在你需要學(xué)習(xí)新方法了缺脉。URP包含以下注入點:

  • beginCameraRendering(ScriptableRenderContext context, Camera camera)
  • endCameraRendering(ScriptableRenderContext context, Camera camera)
  • beginFrameRendering(ScriptableRenderContext context,Camera[] cameras)
  • endFrameRendering(ScriptableRenderContext context,Camera[] cameras)

用法示例:

void OnEnable()
{
    RenderPipelineManager.beginCameraRendering += MyCameraRendering;
}

void OnDisable()
{
    RenderPipelineManager.beginCameraRendering -= MyCameraRendering;
}

void MyCameraRendering(ScriptableRenderContext context, Camera camera)
{
    ...
    if(camera == myEffectCamera)
    {
    ...
    }
    ...
}

就像我說的那樣痪欲,OnWillRenderObject是受支持的,但是攻礼,如果你需要在其中執(zhí)行渲染調(diào)用(例如业踢,水反射/折射),它將無法正常工作礁扮。調(diào)用Camera.Render()知举,你將看到以下消息:

Recursive rendering is not supported in SRP (are you calling Camera.Render from within a render pipeline?)

翻譯過來就是:

SRP不支持遞歸渲染(你是從渲染管道中調(diào)用Camera.Render嗎瞬沦?)

在這種情況下,URP中應(yīng)該將OnWillRenderObject替換為begin/endCameraRendering(如上面的例子)雇锡,并調(diào)用RenderSingleCamera()蛙埂,而不是 Camera.Render()。更改上面的示例遮糖,你將獲得以下內(nèi)容

void MyCameraRendering(ScriptableRenderContext context, Camera camera)
{
    ...
    if(camera == myEffectCamera)
    {
    ...
        UniversalRenderPipeline.RenderSingleCamera(context, camera);
    }
    ...
}

使用后處理的另一種方法是使用ScriptableRendererFeature绣的。這篇文章很好地解釋了使用RenderFeature的描邊效果。ScriptableRendererFeature可以讓你將ScriptableRenderPass(es)注入到渲染管線的不同階段欲账,因此是創(chuàng)建后處理效果的強(qiáng)大工具屡江。注入位置可以包含以下:

  • BeforeRendering
  • BeforeRenderingShadows
  • AfterRenderingShadows
  • BeforeRenderingPrepasses
  • AfterRenderingPrePasses
  • BeforeRenderingOpaques
  • AfterRenderingOpaques
  • BeforeRenderingSkybox
  • AfterRenderingSkybox
  • BeforeRenderingTransparents
  • AfterRenderingTransparents
  • BeforeRenderingPostProcessing
  • AfterRenderingPostProcessing
  • AfterRendering

這是ScriptableRendererFeature使用自定義材質(zhì)執(zhí)行blit的簡單示例:

public class CustomRenderPassFeature : ScriptableRendererFeature
{
    class CustomRenderPass : ScriptableRenderPass
    {
        CustomRPSettings _CustomRPSettings;
        RenderTargetHandle _TemporaryColorTexture;

        private RenderTargetIdentifier _Source;
        private RenderTargetHandle _Destination;

        public CustomRenderPass(CustomRPSettings settings)
        {
            _CustomRPSettings = settings;
        }

        public void Setup(RenderTargetIdentifier source, RenderTargetHandle destination)
        {
            _Source = source;
            _Destination = destination;
        }

        public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
        {
            _TemporaryColorTexture.Init("_TemporaryColorTexture");
        }

        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
        {
            CommandBuffer cmd = CommandBufferPool.Get("My Pass");

            if (_Destination == RenderTargetHandle.CameraTarget)
            {
                cmd.GetTemporaryRT(_TemporaryColorTexture.id, renderingData.cameraData.cameraTargetDescriptor, FilterMode.Point);
                cmd.Blit(_Source, _TemporaryColorTexture.Identifier());
                cmd.Blit(_TemporaryColorTexture.Identifier(), _Source, _CustomRPSettings.m_Material);
            }
            else
            {
                cmd.Blit(_Source, _Destination.Identifier(), _CustomRPSettings.m_Material, 0);
            }

            context.ExecuteCommandBuffer(cmd);
            CommandBufferPool.Release(cmd);
        }

        public override void FrameCleanup(CommandBuffer cmd)
        {
            if (_Destination == RenderTargetHandle.CameraTarget)
            {
                cmd.ReleaseTemporaryRT(_TemporaryColorTexture.id);
            }
        }
    }

    [System.Serializable]
    public class CustomRPSettings
    {
        public Material m_Material;
    }

    public CustomRPSettings m_CustomRPSettings = new CustomRPSettings();
    CustomRenderPass _ScriptablePass;

    public override void Create()
    {
        _ScriptablePass = new CustomRenderPass(m_CustomRPSettings);

        _ScriptablePass.renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
    }

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        _ScriptablePass.Setup(renderer.cameraColorTarget, RenderTargetHandle.CameraTarget);
        renderer.EnqueuePass(_ScriptablePass);
    }
}

你可以通過單擊“Create > Rendering > Universal Render Pipeline > Renderer Feature”來創(chuàng)建一個ScriptableRendererFeature。你創(chuàng)建的功能必須添加到你的中ForwardRenderer赛不。為此惩嘉,選擇ForwardRenderer,單擊Add Renderer Feature踢故,然后選擇要添加的功能文黎。你可以在Inspector中公開屬性,例如上面的例子中包含了一個材質(zhì)球?qū)傩浴?/p>

結(jié)語

由于Unity和URP殿较、SRP都在快速迭代更新耸峭,本文也會不定時更新。如果有問題淋纲,你可以在本文原文中評論劳闹,也可以通過微信:zhz11235或者QQ:329541945找到我。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末洽瞬,一起剝皮案震驚了整個濱河市本涕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌伙窃,老刑警劉巖菩颖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異为障,居然都是意外死亡晦闰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門产场,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鹅髓,“玉大人,你說我怎么就攤上這事京景。” “怎么了骗奖?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵确徙,是天一觀的道長醒串。 經(jīng)常有香客問我,道長鄙皇,這世上最難降的妖魔是什么芜赌? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮伴逸,結(jié)果婚禮上缠沈,老公的妹妹穿的比我還像新娘。我一直安慰自己错蝴,他們只是感情好洲愤,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著顷锰,像睡著了一般柬赐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上官紫,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天肛宋,我揣著相機(jī)與錄音,去河邊找鬼束世。 笑死酝陈,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的毁涉。 我是一名探鬼主播后添,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼薪丁!你這毒婦竟也來了遇西?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤严嗜,失蹤者是張志新(化名)和其女友劉穎粱檀,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漫玄,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡茄蚯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了睦优。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片渗常。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖汗盘,靈堂內(nèi)的尸體忽然破棺而出皱碘,到底是詐尸還是另有隱情,我是刑警寧澤隐孽,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布癌椿,位于F島的核電站健蕊,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏踢俄。R本人自食惡果不足惜缩功,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望都办。 院中可真熱鬧嫡锌,春花似錦、人聲如沸琳钉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽槽卫。三九已至跟压,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間歼培,已是汗流浹背震蒋。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留躲庄,地道東北人查剖。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像噪窘,于是被迫代替她去往敵國和親笋庄。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容