204 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			204 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 
								 | 
							
								## 描边相关属性
							 | 
						|||
| 
								 | 
							
								| Property                  | Function                                                     |
							 | 
						|||
| 
								 | 
							
								| ------------------------- | ------------------------------------------------------------ |
							 | 
						|||
| 
								 | 
							
								| `OUTLINE MODE`            | 指定背面挤出描边的方式。 你可以选择`NML`(正常倒置法)/`POS`(位置缩放法)。/ `POS`(位置缩放法)。在大多数情况下,使用NML,但如果是只由硬边组成的网格(如立方体),POS将防止轮廓被断开。
							 | 
						|||
| 
								 | 
							
								对简单的形状使用POS,对人物和有复杂轮廓的东西使用NML会比较好。 |
							 | 
						|||
| 
								 | 
							
								| `Outline_Width`           | 定义描边宽度 **注意: 这个值依赖于模型被导入Unity时的比例。** which means that you have to be careful if the scale is not 1. |
							 | 
						|||
| 
								 | 
							
								| `Farthest_Distance`       | 轮廓的宽度将根据摄像机和物体之间的距离而改变。摄像机大于这个距离时轮廓宽度将为0。 |
							 | 
						|||
| 
								 | 
							
								| `Nearest_Distance`        | 轮廓的宽度将根据摄像机和物体之间的距离而改变。摄像机小于这个距离时宽度将为`Outline_Width`。 |
							 | 
						|||
| 
								 | 
							
								| `Outline_Sampler`         | 用于美术手动隐藏指定区域的轮廓? |
							 | 
						|||
| 
								 | 
							
								| `Outline_Color`           | 轮廓颜色。 |
							 | 
						|||
| 
								 | 
							
								| `Is_BlendBaseColor`       | 是否与BaseColor颜色融合。 |
							 | 
						|||
| 
								 | 
							
								| `Is_LightColor_Outline`   | 是否受灯光颜色影响。 |
							 | 
						|||
| 
								 | 
							
								| `Is_OutlineTex`           | 是否存在轮廓贴图。 |
							 | 
						|||
| 
								 | 
							
								| `OutlineTex`              | 轮廓贴图,用于控制颜色。 |
							 | 
						|||
| 
								 | 
							
								| `Offset_Camera_Z`         | 在摄像机空间Z坐标轴上偏移。可以用于调整模型尖端与模型交界处处效果。 大多数情况设置为0。 |
							 | 
						|||
| 
								 | 
							
								| `Is_BakedNormal`          | 是否使用烘焙的法线贴图的法线值。 |
							 | 
						|||
| 
								 | 
							
								| `BakedNormal for Outline` | 指定的烘焙法线贴图。 |
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## 调整轮廓强度
							 | 
						|||
| 
								 | 
							
								>`_OutlineMode`有两种模式:NormalDirection与PositionScaling,除了一些简单基础几何体,其他一般使用法线方向偏移。
							 | 
						|||
| 
								 | 
							
								### Outline Sampler
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								黑色表示“无线条”,白色表示宽度为 100%。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### BakedNormal
							 | 
						|||
| 
								 | 
							
								采样烘焙的法线贴图,并将值赋予顶点法线。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### Offset_Camera_Z
							 | 
						|||
| 
								 | 
							
								>`Offset_Camera_Z`就是单纯的深度偏移,可以用于调整模型尖端与模型交界处处效果。但本人认为这个没有必要。
							 | 
						|||
| 
								 | 
							
								效果如图:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## 顶点着色器
							 | 
						|||
| 
								 | 
							
								主要用于偏移顶点坐标、采样法线贴图值并传递给顶点以及传递顶点数据。计算物体与摄像机距离,对设定的最近距离与最远距离插值得到距离因子。之后乘以`_Outline_Width*0.001`。
							 | 
						|||
| 
								 | 
							
								>个人认为这里的比例存在问题,应该使用到摄像机矩阵参数作为比值会比较好。
							 | 
						|||
| 
								 | 
							
								```c#
							 | 
						|||
| 
								 | 
							
								float Set_Outline_Width = (_Outline_Width*0.001*smoothstep( _Farthest_Distance, _Nearest_Distance, distance(objPos.rgb,_WorldSpaceCameraPos) )*_Outline_Sampler_var.rgb).r;
							 | 
						|||
| 
								 | 
							
								//Transparent开启时`_ZOverDrawMode`为1,否则为0。
							 | 
						|||
| 
								 | 
							
								Set_Outline_Width *= (1.0f - _ZOverDrawMode);
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								```c#
							 | 
						|||
| 
								 | 
							
								#ifdef _OUTLINE_NML
							 | 
						|||
| 
								 | 
							
								    //v.2.0.4.3 baked Normal Texture for Outline
							 | 
						|||
| 
								 | 
							
								    o.pos = UnityObjectToClipPos(lerp(float4(v.vertex.xyz + v.normal*Set_Outline_Width,1), float4(v.vertex.xyz + _BakedNormalDir*Set_Outline_Width,1),_Is_BakedNormal));
							 | 
						|||
| 
								 | 
							
								#elif _OUTLINE_POS
							 | 
						|||
| 
								 | 
							
								    Set_Outline_Width = Set_Outline_Width*2;
							 | 
						|||
| 
								 | 
							
								    float signVar = dot(normalize(v.vertex),normalize(v.normal))<0 ? -1 : 1;
							 | 
						|||
| 
								 | 
							
								    o.pos = UnityObjectToClipPos(float4(v.vertex.xyz + signVar*normalize(v.vertex)*Set_Outline_Width, 1));
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								    //v.2.0.7.5
							 | 
						|||
| 
								 | 
							
								    o.pos.z = o.pos.z + _Offset_Z * _ClipCameraPos.z;
							 | 
						|||
| 
								 | 
							
								    return o;
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## 像素着色器
							 | 
						|||
| 
								 | 
							
								主要用来设置轮廓颜色,`轮廓颜色=灯光颜色 * BaseMap * BaseColor * (OutlineTex)`。同时提供了裁剪功能,可以根据ClippingMask、BaseMap的Alpha通道进行裁剪。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								>`_Is_LightColor_Outline`根据`ShaderGUI`的选项进行设置,但这里感觉可以增加CaptureMat、World映射Ramp、环境探针以增加更多效果。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								```c#
							 | 
						|||
| 
								 | 
							
								    //计算灯光色(小于0.05则使用环境色)、灯光亮度
							 | 
						|||
| 
								 | 
							
								    half3 ambientSkyColor = unity_AmbientSky.rgb>0.05 ? unity_AmbientSky.rgb*_Unlit_Intensity : half3(0.05,0.05,0.05)*_Unlit_Intensity;
							 | 
						|||
| 
								 | 
							
								    float3 lightColor = _LightColor0.rgb >0.05 ? _LightColor0.rgb : ambientSkyColor.rgb;
							 | 
						|||
| 
								 | 
							
								    float lightColorIntensity = (0.299*lightColor.r + 0.587*lightColor.g + 0.114*lightColor.b);
							 | 
						|||
| 
								 | 
							
								    lightColor = lightColorIntensity<1 ? lightColor : lightColor/lightColorIntensity;//灯光亮度小于1时,对颜色亮度进行缩放。
							 | 
						|||
| 
								 | 
							
								    lightColor = lerp(half3(1.0,1.0,1.0), lightColor, _Is_LightColor_Outline);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    //计算BaseMap*BaseColor值、采样OutlineMap值。
							 | 
						|||
| 
								 | 
							
								    float2 Set_UV0 = i.uv0;
							 | 
						|||
| 
								 | 
							
								    float4 _MainTex_var = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, TRANSFORM_TEX(Set_UV0, _MainTex));
							 | 
						|||
| 
								 | 
							
								    float3 Set_BaseColor = _BaseColor.rgb*_MainTex_var.rgb;
							 | 
						|||
| 
								 | 
							
								    float3 _Is_BlendBaseColor_var = lerp( _Outline_Color.rgb*lightColor, (_Outline_Color.rgb*Set_BaseColor*Set_BaseColor*lightColor), _Is_BlendBaseColor );
							 | 
						|||
| 
								 | 
							
								    float3 _OutlineTex_var = tex2D(_OutlineTex,TRANSFORM_TEX(Set_UV0, _OutlineTex)).rgb;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#ifdef _IS_OUTLINE_CLIPPING_NO
							 | 
						|||
| 
								 | 
							
								    float3 Set_Outline_Color = lerp(_Is_BlendBaseColor_var, _OutlineTex_var.rgb*_Outline_Color.rgb*lightColor, _Is_OutlineTex );
							 | 
						|||
| 
								 | 
							
								    return float4(Set_Outline_Color,1.0);
							 | 
						|||
| 
								 | 
							
								#elif _IS_OUTLINE_CLIPPING_YES
							 | 
						|||
| 
								 | 
							
								    //开启裁剪模式的状态下,可以根据ClippingMask、BaseMap的Alpha通道进行裁剪。
							 | 
						|||
| 
								 | 
							
								    float4 _ClippingMask_var = SAMPLE_TEXTURE2D(_ClippingMask, sampler_MainTex, TRANSFORM_TEX(Set_UV0, _ClippingMask));
							 | 
						|||
| 
								 | 
							
								    float Set_MainTexAlpha = _MainTex_var.a;
							 | 
						|||
| 
								 | 
							
								    float _IsBaseMapAlphaAsClippingMask_var = lerp( _ClippingMask_var.r, Set_MainTexAlpha, _IsBaseMapAlphaAsClippingMask );
							 | 
						|||
| 
								 | 
							
								    float _Inverse_Clipping_var = lerp( _IsBaseMapAlphaAsClippingMask_var, (1.0 - _IsBaseMapAlphaAsClippingMask_var), _Inverse_Clipping );
							 | 
						|||
| 
								 | 
							
								    float Set_Clipping = saturate((_Inverse_Clipping_var+_Clipping_Level));
							 | 
						|||
| 
								 | 
							
								    clip(Set_Clipping - 0.5);
							 | 
						|||
| 
								 | 
							
								    float4 Set_Outline_Color = lerp( float4(_Is_BlendBaseColor_var,Set_Clipping), float4((_OutlineTex_var.rgb*_Outline_Color.rgb*lightColor),Set_Clipping), _Is_OutlineTex );
							 | 
						|||
| 
								 | 
							
								    return Set_Outline_Color;
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## 完整代码
							 | 
						|||
| 
								 | 
							
								```c#
							 | 
						|||
| 
								 | 
							
								uniform float4 _LightColor0; // this is not set in c# code ?
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								struct VertexInput {
							 | 
						|||
| 
								 | 
							
								    float4 vertex : POSITION;
							 | 
						|||
| 
								 | 
							
								    float3 normal : NORMAL;
							 | 
						|||
| 
								 | 
							
								    float4 tangent : TANGENT;
							 | 
						|||
| 
								 | 
							
								    float2 texcoord0 : TEXCOORD0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    UNITY_VERTEX_INPUT_INSTANCE_ID
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								struct VertexOutput {
							 | 
						|||
| 
								 | 
							
								    float4 pos : SV_POSITION;
							 | 
						|||
| 
								 | 
							
								    float2 uv0 : TEXCOORD0;
							 | 
						|||
| 
								 | 
							
								    float3 normalDir : TEXCOORD1;
							 | 
						|||
| 
								 | 
							
								    float3 tangentDir : TEXCOORD2;
							 | 
						|||
| 
								 | 
							
								    float3 bitangentDir : TEXCOORD3;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    UNITY_VERTEX_OUTPUT_STEREO
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								VertexOutput vert (VertexInput v) {
							 | 
						|||
| 
								 | 
							
								    VertexOutput o = (VertexOutput)0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    UNITY_SETUP_INSTANCE_ID(v);
							 | 
						|||
| 
								 | 
							
								    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    o.uv0 = v.texcoord0;
							 | 
						|||
| 
								 | 
							
								    float4 objPos = mul ( unity_ObjectToWorld, float4(0,0,0,1) ); //取得物体世界坐标
							 | 
						|||
| 
								 | 
							
								    float2 Set_UV0 = o.uv0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    //TRANSFORM_TEX(v.texcoord,_MainTex);等价于o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
							 | 
						|||
| 
								 | 
							
								    float4 _Outline_Sampler_var = tex2Dlod(_Outline_Sampler,float4(TRANSFORM_TEX(Set_UV0, _Outline_Sampler),0.0,0));//使用_Outline_Sampler的值进行缩放与偏移UV后,在顶点着色器中对_Outline_Sampler进行采样。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    //v.2.0.4.3 baked Normal Texture for Outline
							 | 
						|||
| 
								 | 
							
								    //计算法线以及法向空间矩阵
							 | 
						|||
| 
								 | 
							
								    o.normalDir = UnityObjectToWorldNormal(v.normal);
							 | 
						|||
| 
								 | 
							
								    o.tangentDir = normalize( mul( unity_ObjectToWorld, float4( v.tangent.xyz, 0.0 ) ).xyz );
							 | 
						|||
| 
								 | 
							
								    o.bitangentDir = normalize(cross(o.normalDir, o.tangentDir) * v.tangent.w);
							 | 
						|||
| 
								 | 
							
								    float3x3 tangentTransform = float3x3( o.tangentDir, o.bitangentDir, o.normalDir);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    //UnpackNormal() can't be used, and so as follows. Do not specify a bump for the texture to be used.
							 | 
						|||
| 
								 | 
							
								    //采样_BakedNormal贴图值并解算烘焙法线方向
							 | 
						|||
| 
								 | 
							
								    float4 _BakedNormal_var = (tex2Dlod(_BakedNormal,float4(TRANSFORM_TEX(Set_UV0, _BakedNormal),0.0,0)) * 2 - 1);
							 | 
						|||
| 
								 | 
							
								    float3 _BakedNormalDir = normalize(mul(_BakedNormal_var.rgb, tangentTransform));
							 | 
						|||
| 
								 | 
							
								    //end
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    float Set_Outline_Width = (_Outline_Width*0.001*smoothstep( _Farthest_Distance, _Nearest_Distance, distance(objPos.rgb,_WorldSpaceCameraPos) )*_Outline_Sampler_var.rgb).r;
							 | 
						|||
| 
								 | 
							
								    Set_Outline_Width *= (1.0f - _ZOverDrawMode);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    //v.2.0.7.5
							 | 
						|||
| 
								 | 
							
								    //计算裁剪位置以及按照不同平台来设置_Offset_Z
							 | 
						|||
| 
								 | 
							
								    float4 _ClipCameraPos = mul(UNITY_MATRIX_VP, float4(_WorldSpaceCameraPos.xyz, 1));
							 | 
						|||
| 
								 | 
							
								    //v.2.0.7
							 | 
						|||
| 
								 | 
							
								    #if defined(UNITY_REVERSED_Z)
							 | 
						|||
| 
								 | 
							
								        //v.2.0.4.2 (DX)
							 | 
						|||
| 
								 | 
							
								        _Offset_Z = _Offset_Z * -0.01;
							 | 
						|||
| 
								 | 
							
								    #else
							 | 
						|||
| 
								 | 
							
								        //OpenGL
							 | 
						|||
| 
								 | 
							
								        _Offset_Z = _Offset_Z * 0.01;
							 | 
						|||
| 
								 | 
							
								    #endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								//v2.0.4
							 | 
						|||
| 
								 | 
							
								//根据OutlineMode对顶线位置进行偏移。
							 | 
						|||
| 
								 | 
							
								#ifdef _OUTLINE_NML
							 | 
						|||
| 
								 | 
							
								    //v.2.0.4.3 baked Normal Texture for Outline
							 | 
						|||
| 
								 | 
							
								    o.pos = UnityObjectToClipPos(lerp(float4(v.vertex.xyz + v.normal*Set_Outline_Width,1), float4(v.vertex.xyz + _BakedNormalDir*Set_Outline_Width,1),_Is_BakedNormal));
							 | 
						|||
| 
								 | 
							
								#elif _OUTLINE_POS
							 | 
						|||
| 
								 | 
							
								    Set_Outline_Width = Set_Outline_Width*2;
							 | 
						|||
| 
								 | 
							
								    float signVar = dot(normalize(v.vertex),normalize(v.normal))<0 ? -1 : 1;
							 | 
						|||
| 
								 | 
							
								    o.pos = UnityObjectToClipPos(float4(v.vertex.xyz + signVar*normalize(v.vertex)*Set_Outline_Width, 1));
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								    //v.2.0.7.5
							 | 
						|||
| 
								 | 
							
								    o.pos.z = o.pos.z + _Offset_Z * _ClipCameraPos.z;
							 | 
						|||
| 
								 | 
							
								    return o;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								float4 frag(VertexOutput i) : SV_Target{
							 | 
						|||
| 
								 | 
							
								    //v.2.0.5
							 | 
						|||
| 
								 | 
							
								    if (_ZOverDrawMode > 0.99f)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        return float4(1.0f, 1.0f, 1.0f, 1.0f);  // but nothing should be drawn except Z value as colormask is set to 0
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    _Color = _BaseColor;
							 | 
						|||
| 
								 | 
							
								    float4 objPos = mul ( unity_ObjectToWorld, float4(0,0,0,1) );
							 | 
						|||
| 
								 | 
							
								    //v.2.0.7.5
							 | 
						|||
| 
								 | 
							
								    half3 ambientSkyColor = unity_AmbientSky.rgb>0.05 ? unity_AmbientSky.rgb*_Unlit_Intensity : half3(0.05,0.05,0.05)*_Unlit_Intensity;
							 | 
						|||
| 
								 | 
							
								    float3 lightColor = _LightColor0.rgb >0.05 ? _LightColor0.rgb : ambientSkyColor.rgb;
							 | 
						|||
| 
								 | 
							
								    float lightColorIntensity = (0.299*lightColor.r + 0.587*lightColor.g + 0.114*lightColor.b);
							 | 
						|||
| 
								 | 
							
								    lightColor = lightColorIntensity<1 ? lightColor : lightColor/lightColorIntensity;
							 | 
						|||
| 
								 | 
							
								    lightColor = lerp(half3(1.0,1.0,1.0), lightColor, _Is_LightColor_Outline);
							 | 
						|||
| 
								 | 
							
								    float2 Set_UV0 = i.uv0;
							 | 
						|||
| 
								 | 
							
								    float4 _MainTex_var = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, TRANSFORM_TEX(Set_UV0, _MainTex));
							 | 
						|||
| 
								 | 
							
								    float3 Set_BaseColor = _BaseColor.rgb*_MainTex_var.rgb;
							 | 
						|||
| 
								 | 
							
								    float3 _Is_BlendBaseColor_var = lerp( _Outline_Color.rgb*lightColor, (_Outline_Color.rgb*Set_BaseColor*Set_BaseColor*lightColor), _Is_BlendBaseColor );
							 | 
						|||
| 
								 | 
							
								    //
							 | 
						|||
| 
								 | 
							
								    float3 _OutlineTex_var = tex2D(_OutlineTex,TRANSFORM_TEX(Set_UV0, _OutlineTex)).rgb;
							 | 
						|||
| 
								 | 
							
								//v.2.0.7.5
							 | 
						|||
| 
								 | 
							
								#ifdef _IS_OUTLINE_CLIPPING_NO
							 | 
						|||
| 
								 | 
							
								    float3 Set_Outline_Color = lerp(_Is_BlendBaseColor_var, _OutlineTex_var.rgb*_Outline_Color.rgb*lightColor, _Is_OutlineTex );
							 | 
						|||
| 
								 | 
							
								    return float4(Set_Outline_Color,1.0);
							 | 
						|||
| 
								 | 
							
								#elif _IS_OUTLINE_CLIPPING_YES
							 | 
						|||
| 
								 | 
							
								    float4 _ClippingMask_var = SAMPLE_TEXTURE2D(_ClippingMask, sampler_MainTex, TRANSFORM_TEX(Set_UV0, _ClippingMask));
							 | 
						|||
| 
								 | 
							
								    float Set_MainTexAlpha = _MainTex_var.a;
							 | 
						|||
| 
								 | 
							
								    float _IsBaseMapAlphaAsClippingMask_var = lerp( _ClippingMask_var.r, Set_MainTexAlpha, _IsBaseMapAlphaAsClippingMask );
							 | 
						|||
| 
								 | 
							
								    float _Inverse_Clipping_var = lerp( _IsBaseMapAlphaAsClippingMask_var, (1.0 - _IsBaseMapAlphaAsClippingMask_var), _Inverse_Clipping );
							 | 
						|||
| 
								 | 
							
								    float Set_Clipping = saturate((_Inverse_Clipping_var+_Clipping_Level));
							 | 
						|||
| 
								 | 
							
								    clip(Set_Clipping - 0.5);
							 | 
						|||
| 
								 | 
							
								    float4 Set_Outline_Color = lerp( float4(_Is_BlendBaseColor_var,Set_Clipping), float4((_OutlineTex_var.rgb*_Outline_Color.rgb*lightColor),Set_Clipping), _Is_OutlineTex );
							 | 
						|||
| 
								 | 
							
								    return Set_Outline_Color;
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 |