免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Unity3d游戲角色描邊

本文發(fā)布于游戲程序員劉宇的個人博客,歡迎轉(zhuǎn)載,請注明來源https://www.cnblogs.com/xiaohutu/p/10834491.html 

 

游戲里經(jīng)常需要在角色上做描邊,這里總結(jié)一下平時幾種常見的描邊做法。

一,兩批次法:

優(yōu)點是簡單,效果直接,性價比高。

1. 定點對著法線方向外移,缺點是可以看出頂點之間有斷裂

 

Shader "ly/Outline_2Pass_1"{    Properties    {        _MainTex("Texture", 2D) = "white"{}        _Outline("Outline", range(0, 1)) = 0.02        _OutlineColor("Outline Color", Color) = (1,1,1,1)    }            SubShader    {        //第一個批次,畫描邊        Pass        {            //Cull掉前面的一半,只讓描邊顯示在后面            Cull Front            CGPROGRAM            #pragma vertex vert            #pragma fragment frag            #include "UnityCG.cginc"            fixed _Outline;            fixed4 _OutlineColor;            struct v2f            {                float4 pos : SV_POSITION;                float4 color : COLOR;            };            v2f vert (appdata_full v)            {                v2f o;                //源頂點位置添加法線方向乘以參數(shù)的偏移量                v.vertex.xyz += v.normal * _Outline;                //位置從自身坐標系轉(zhuǎn)換到投影空間                //舊版本o.pos = mul(UNITY_MATRIX_MVP,v.vertex);                o.pos = UnityObjectToClipPos(v.vertex);                //描邊顏色                o.color = _OutlineColor;                return o;            }                        float4 frag (v2f i) : COLOR            {                return i.color; //描邊            }            ENDCG        }        //第二個批次        Pass        {            CGPROGRAM            #pragma vertex vert            #pragma fragment frag            #include "UnityCG.cginc"            sampler2D _MainTex;            half4 _MainTex_ST;            struct v2f            {                float4 pos : SV_POSITION;                float2 uv : TEXCOORD0;                fixed4 color : COLOR;            };            v2f vert(appdata_base v)            {                v2f o;                o.pos = UnityObjectToClipPos(v.vertex);                o.uv = v.texcoord;                o.color = fixed4(0, 0, 0, 1);                return o;            }            fixed4 frag(v2f i) : SV_Target            {                fixed4 col = tex2D(_MainTex, i.uv);                return col;            }            ENDCG        }    }}

 

2. 得到法線在投影空間上的xy軸,作為偏移方向?qū)㈨旤c外移,得到的結(jié)果類似1,也有斷裂

 

3. 頂點的位置作為方向矢量,則不會因為方向差距較大而斷裂

 

Shader "ly/Outline_2Pass_2"{    Properties    {        _MainTex("Texture", 2D) = "white"{}        _Outline("Outline", range(0, 1)) = 0.02        _OutlineColor("Outline Color", Color) = (1,1,1,1)    }            SubShader    {        //第一個批次,畫描邊        Pass        {            //Cull掉前面的一半,只讓描邊顯示在后面            Cull Front            CGPROGRAM            #pragma vertex vert            #pragma fragment frag            #include "UnityCG.cginc"            fixed _Outline;            fixed4 _OutlineColor;            struct v2f            {                float4 pos : SV_POSITION;                float4 uv : TEXCOORD0;            };            v2f vert (appdata_full v)            {                v2f o;                //位置從自身坐標系轉(zhuǎn)換到投影空間                //舊版本o.pos = mul(UNITY_MATRIX_MVP,v.vertex);                o.pos = UnityObjectToClipPos(v.vertex);                //方式二,擴張頂點位置                //法線變換到投影空間                //float3 normal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);                //得到投影空間的偏移                //float2 offset = TransformViewToProjection(normal.xy);                ////方式三,把頂點當做方向矢量,在方向矢量的方向偏移                float3 dir = normalize(v.vertex.xyz);                dir = mul((float3x3)UNITY_MATRIX_IT_MV, dir);                float2 offset = TransformViewToProjection(dir.xy);                //有一些情況下,側(cè)邊看不到,所以把方式一和二的算法相結(jié)合                //float3 dir = normalize(v.vertex.xyz);                //float3 dir2 = v.normal;                //float D = dot(dir, dir2);                //D = (1 + D / _Outline) / (1 + 1 / _Outline);                //dir = lerp(dir2, dir, D);                //dir = mul((float3x3)UNITY_MATRIX_IT_MV, dir);                //float2 offset = TransformViewToProjection(dir.xy);                //offset = normalize(offset);                //在xy兩個方向上偏移頂點的位置                o.pos.xy += offset * o.pos.z * _Outline;                return o;            }                        float4 frag (v2f i) : COLOR            {                return _OutlineColor; //描邊            }            ENDCG        }        //第二個批次,略}

 

二,邊緣光

頂點的視角dir和法線dir點乘,得出偏離度,越靠近邊緣,顏色的強度越高。

優(yōu)點是節(jié)約批次。

v2f vert (appdata_full v){  v2f o;  //
  //_RimColor邊緣光顏色  
  //_RimPower邊緣光強度
  float3 viewDir = normalize(ObjSpaceViewDir(v.vertex));  float dotProduct = 1 - dot(normalize(v.normal), viewDir);  fixed3 rimCol = smoothstep(1 - _RimPower, 1.0, dotProduct) * _RimColor;  o.color = rimCol;  //  return o; }

  

三,后處理方式來畫描邊

優(yōu)點是效果完美,缺點是消耗性能。

攝像機上掛一個腳本,處理后處理的步驟,outlineCamera 為臨時攝像機,參數(shù)與主攝像機相同,看著同樣的Unit層。

臨時攝像機渲染到RT上,先畫剪影,然后用自定義的描邊shader畫上去。

using UnityEngine;using UnitySampleAssets.ImageEffects;[RequireComponent(typeof(Camera))][AddComponentMenu("Image Effects/Other/Post Effect Outline")]class PostEffectOutline : PostEffectsBase{    public enum OutLineMethod    {        eIteration,        eScale,    }    private Camera attachCamera;    private Camera outlineCamera;    private Shader simpleShader;    private Shader postOutlineShader;    private Material postOutlineMat;    private RenderTexture mTempRT;    public Color outlineColor = new Color(0, 1f, 0, 1f);// Color.green;    [Range(0, 10)]    public int outlineWidth = 1;    [Range(1, 9)]    public int iterations = 1;    public OutLineMethod outlineMethod = OutLineMethod.eIteration;    void Awake()    {        FindShaders();    }    void FindShaders()    {        if (!simpleShader)            simpleShader = Shader.Find("ly/DrawSimple");        if (outlineMethod == OutLineMethod.eIteration)        {            if (!postOutlineShader)                postOutlineShader = Shader.Find("ly/PostOutlineIteration");        }        else        {            if (!postOutlineShader)                postOutlineShader = Shader.Find("ly/PostOutlineScale");        }    }    protected override void Start()    {        base.Start();        attachCamera = GetComponent<Camera>();        if (outlineCamera == null)        {            outlineCamera = new GameObject().AddComponent<Camera>();            outlineCamera.enabled = false;            outlineCamera.transform.parent = attachCamera.transform;            outlineCamera.name = "outlineCam";        }        postOutlineMat = new Material(postOutlineShader);    }    public override bool CheckResources()    {        CheckSupport(false);        if (!isSupported)            ReportAutoDisable();        return isSupported;    }    private void OnRenderImage(RenderTexture source, RenderTexture destination)    {        if (CheckResources() == false)        {            Graphics.Blit(source, destination);            return;        }        outlineCamera.CopyFrom(attachCamera);        outlineCamera.clearFlags = CameraClearFlags.Color;        outlineCamera.backgroundColor = Color.black;        outlineCamera.cullingMask = 1 << LayerMask.NameToLayer("Unit");        if (mTempRT == null)            mTempRT = RenderTexture.GetTemporary(source.width, source.height, source.depth);        mTempRT.Create();        outlineCamera.targetTexture = mTempRT;        outlineCamera.RenderWithShader(simpleShader, "");        postOutlineMat.SetTexture("_SceneTex", source);        postOutlineMat.SetColor("_Color", outlineColor);        postOutlineMat.SetInt("_Width", outlineWidth);        postOutlineMat.SetInt("_Iterations", iterations);        //畫描邊混合材質(zhì)        Graphics.Blit(mTempRT, destination, postOutlineMat);        mTempRT.Release();    }}

 

先用簡單的shader畫出剪影

Shader "ly/DrawSimple"{    FallBack OFF}

 

然后就是這個自定義的描邊shader畫的過程。

第一種是類似高斯模糊的方式來迭代,迭代次數(shù)越多則越細膩。

// ly 類似高斯模糊方式迭代循環(huán)處理描邊Shader "ly/PostOutlineIteration"{    Properties    {        _MainTex("Main Texture", 2D) = "black"{}        //畫完物體面積后的紋理        _SceneTex("Scene Texture", 2D) = "black"{}        //原場景紋理        _Color("Outline Color", Color) = (0,1,0,0.8)        //描邊顏色        _Width("Outline Width", int) = 1                //描邊寬度        _Iterations("Iterations", int) = 1                //描邊迭代次數(shù)(越多越平滑,消耗越高)    }    SubShader    {        Pass        {            CGPROGRAM            sampler2D _MainTex;            float2 _MainTex_TexelSize;            sampler2D _SceneTex;            fixed4 _Color;            float _Width;            int _Iterations;            #pragma vertex vert            #pragma fragment frag                #include "UnityCG.cginc"            struct v2f            {                float4 pos : SV_POSITION;                float2 uv : TEXCOORD0;            };            v2f vert(appdata_base v)            {                v2f o;                o.pos = UnityObjectToClipPos(v.vertex);                o.uv = v.texcoord.xy;                return o;            }            half4 frag(v2f i) : COLOR            {                //迭代次數(shù)為奇數(shù),保證對稱                int iterations = _Iterations * 2 + 1;                float ColorIntensityInRadius;                float Tx_x = _MainTex_TexelSize.x * _Width;                float Tx_y = _MainTex_TexelSize.y * _Width;                //計算是否大于0,則此像素屬于外邊的范圍內(nèi)                for (int k=0; k<iterations; k+=1)                {                    for (int j=0; j<iterations; j+=1)                    {                        ColorIntensityInRadius += tex2D(_MainTex, i.uv.xy + float2((k - iterations / 2) * Tx_x, (j - iterations / 2) * Tx_y));                    }                }                //如果有顏色,或者不在外邊的范圍內(nèi),則渲染原場景。否則,在外邊內(nèi),渲染描邊。                if (tex2D(_MainTex, i.uv.xy).r > 0 || ColorIntensityInRadius == 0)                    return tex2D(_SceneTex, i.uv);                else                    return  _Color.a * _Color + (1 - _Color.a)*tex2D(_SceneTex, i.uv);            }            ENDCG        }    }}

第二種方法簡單些,直接把剪影的部分uv擴大,再把原圖疊上去。

// ly 擴張剪影uv來填充描邊Shader "ly/PostOutlineScale"{    Properties    {        _MainTex("Main Texture", 2D) = "black"{}        //畫完物體面積后的紋理        _SceneTex("Scene Texture", 2D) = "black"{}        //原場景紋理        _Color("Outline Color", Color) = (0,1,0,1)        //描邊顏色        _Width("Outline Width", float) = 1                //描邊寬度    }    SubShader    {        Pass        {            CGPROGRAM            sampler2D _MainTex;            sampler2D _SceneTex;            float2 _SceneTex_TexelSize;            fixed4 _Color;            float _Width;            #pragma vertex vert            #pragma fragment frag                #include "UnityCG.cginc"            struct v2f            {                float4 pos : SV_POSITION;                half2 uv[2] : TEXCOORD0;                half2 uv2[4] : TEXCOORD2;            };            v2f vert(appdata_base v)            {                v2f o;                o.pos = UnityObjectToClipPos(v.vertex);                o.uv[0] = v.texcoord.xy;                o.uv[1] = v.texcoord.xy;                half2 offs = _SceneTex_TexelSize.xy * _Width;                o.uv2[0].x = v.texcoord.x - offs.x;                o.uv2[0].y = v.texcoord.y - offs.y;                o.uv2[1].x = v.texcoord.x + offs.x;                o.uv2[1].y = v.texcoord.y - offs.y;                o.uv2[2].x = v.texcoord.x + offs.x;                o.uv2[2].y = v.texcoord.y + offs.y;                o.uv2[3].x = v.texcoord.x - offs.x;                o.uv2[3].y = v.texcoord.y + offs.y;                if (_SceneTex_TexelSize.y < 0)                {                    o.uv[1].y = 1 - o.uv[1].y;                    o.uv2[0].y = 1 - o.uv2[0].y;                    o.uv2[1].y = 1 - o.uv2[1].y;                    o.uv2[2].y = 1 - o.uv2[2].y;                    o.uv2[3].y = 1 - o.uv2[3].y;                }                return o;            }            half4 frag(v2f i) : COLOR            {                fixed4 stencil = tex2D(_MainTex, i.uv[1]);                // 有剪影的部分,顯示原圖                if (any(stencil.rgb))                {                    fixed4 framebuffer = tex2D(_SceneTex, i.uv[0]);                    return framebuffer;                }                // 沒有剪影的部分,先把剪影擴張,擴張出顏色的部分用剪影,沒有顏色的用原圖                else                {                    fixed4 color1 = tex2D(_MainTex, i.uv2[0]);                    fixed4 color2 = tex2D(_MainTex, i.uv2[1]);                    fixed4 color3 = tex2D(_MainTex, i.uv2[2]);                    fixed4 color4 = tex2D(_MainTex, i.uv2[3]);                    fixed4 color;                    color.rgb = max(color1.rgb, color2.rgb);                    color.rgb = max(color.rgb, color3.rgb);                    color.rgb = max(color.rgb, color4.rgb);                    if (any(color.rgb))                    {                        return _Color;                        //color.a = (color1.a + color2.a + color3.a + color4.a) * 0.25;                        //return color;                    }                    else                    {                        fixed4 framebuffer = tex2D(_SceneTex, i.uv[0]);                        return framebuffer;                    }                }            }            ENDCG        }    }    SubShader    {        Pass        {            SetTexture[_MainTex]{}        }    }    Fallback Off}

 

本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
初入shader的教程第一課 想了解shader來看看吧 | Imagination中文技術(shù)社區(qū)
邊緣高光(附上代碼)
Unity3D Shader 使指定顏色過濾成透明
【UnityShader屏幕后處理】
RenderDoc[03] 還原粒子特效shader
URP下快速實現(xiàn)高度霧
更多類似文章 >>
生活服務
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服