Unity的Shader学习笔记(18)[21/01/12_周二][60-62]

目录

课时60:FragmentShader-UV动画1-偏移

课时61:FragmentShader-UV动画2-水波

1.波动

2.扩散的圆形水波

扩展练习

课时62:FragmentShader-UV动画3-模糊采样


课时60:FragmentShader-UV动画1-偏移

视频:https://www.bilibili.com/video/BV1YK41157AC?p=60

这节课的动画时通过脚本来实现的

1.制作一个贴图

2.写脚本

public class SetTextureUVST : MonoBehaviour
{
    public int width=3;
    public int height=3;
    public int fps=3;
    public int currentIndex;
    // Start is called before the first frame update
    IEnumerator Start()
    {
        Material mat=GetComponent<Renderer>().material;
        float scale_x=1.0f/width;
        float scale_y=1.0f/height;
        float waitTime=1.0f/fps;
        while(true)
        {
            Debug.Log("currentIndex1:"+currentIndex+"|"+waitTime);
            //width=3,height=3;width=3,height=1
            float offset_x=currentIndex % width * scale_x;
            float offset_y=currentIndex / height * scale_y;
            
            //width=1,height=3
            // float offset_x=currentIndex / width * scale_x;
            // float offset_y=currentIndex % height * scale_y;

            mat.SetTextureOffset("_MainTex",new Vector2(offset_x,offset_y));
            mat.SetTextureScale("_MainTex",new Vector2(scale_x,scale_y));
            yield return new WaitForSeconds(waitTime);
            currentIndex=(++currentIndex)%(width * height);
             Debug.Log("currentIndex2:"+currentIndex+"|"+waitTime);
        }
    }
}

3.结合材质,看效果

基本的uv shader

Shader "Custom/NewSurfaceShader 20"
{
    Properties
    {
        _MainTex("MainTex",2D) = ""{}
    }
    SubShader
    {
        pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "unitycg.cginc"
            struct v2f{
                float4 pos:POSITION;
                float2 uv:TEXCOORD0;
            };
            sampler2D _MainTex;
            float4 _MainTex_ST;
            v2f vert(appdata_base v){
                v2f o;
                o.pos=UnityObjectToClipPos(v.vertex);
                //o.uv=v.texcoord.xy*_MainTex_ST.xy+_MainTex_ST.zw;
                o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
                return o;
            }
            fixed4 frag(v2f IN) :COLOR
            {
                fixed4 tc = tex2D(_MainTex, IN.uv);
                return tc;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

扩展练习:不通过脚本,都是用shader实现相同的效果。

Shader "Custom/NewSurfaceShader 21"
{
    Properties
    {
        _MainTex("MainTex",2D) = ""{}
        _Width("Width",int) = 3
        _Height("Height",int) = 3
        _FPS("FPS",int)=1
    }
    SubShader
    {
        pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "unitycg.cginc"
            struct v2f{
                float4 pos:POSITION;
                float2 uv:TEXCOORD0;
            };
            sampler2D _MainTex;
            float4 _MainTex_ST;
            int _Width;
            int _Height;
            int _FPS;

            fixed4 getUVST(){
                float t=_Time.y*_FPS;
                int _Index=t % 9;

                float scale_x=1.0f/_Width;
                float scale_y=1.0f/_Height;

                float offset_x=_Index % _Width * scale_x;
                float offset_y=_Index / _Height * scale_y;
                return fixed4(scale_x,scale_y,offset_x,offset_y);
            }
            v2f vert(appdata_base v){
                v2f o;
                o.pos=UnityObjectToClipPos(v.vertex);
                _MainTex_ST=getUVST();
                //o.uv=v.texcoord.xy*_MainTex_ST.xy+_MainTex_ST.zw;
                o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
                return o;
            }
            fixed4 frag(v2f IN) :COLOR
            {
                fixed4 tc = tex2D(_MainTex, IN.uv);
                return tc;
            }
            ENDCG
        }
    }
}

脚本中的代码放到shader里改一下就好了,效果一样。

这越写越习惯了,以前怎么就没学起来呢,没时间练习吗?

 

课时61:FragmentShader-UV动画2-水波

找个贴图先:https://www.textures.com/download/gravelcobble0023/48588

1.波动

写shader,根据uv,时间,sin,变化

Shader "Custom/NewSurfaceShader 22"
{
    Properties
    {
        _MainTex("MainTex",2D) = ""{}
        _F("F",range(0,30))=10 //周期
        _A("A",range(0,0.1))=0.01 //幅度
    }
    SubShader
    {
        pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "unitycg.cginc"
            struct v2f{
                float4 pos:POSITION;
                float2 uv:TEXCOORD0;
            };
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _F;
            float _A;
            v2f vert(appdata_base v){
                v2f o;
                o.pos=UnityObjectToClipPos(v.vertex);
                o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
                return o;
            }
            fixed4 frag(v2f IN) :COLOR
            {
                float2 uv=IN.uv;
                uv+=_A*sin(IN.uv*3.14*_F+_Time.y);
                fixed4 tc = tex2D(_MainTex, uv);
                return tc;
            }
            ENDCG
        }
    }
}

效果:

2.扩散的圆形水波

            fixed4 frag(v2f IN) :COLOR
            {
                float2 uv=IN.uv;
                //uv+=_A*sin(IN.uv*3.14*_F+_Time.y);
                float dis=distance(uv,float2(0.5,0.5));
                uv=uv+uv*_A*sin(dis*3.14*_F+_Time.y);
                fixed4 tc = tex2D(_MainTex, uv);
                return tc;
            }

看不清楚,需要测试一下

                float2 uv=IN.uv;
                float dis=distance(uv,float2(0.5,0.5));
                float scale=_A*sin(dis*3.14*_F+_Time.y);
                uv=uv+uv*scale;
                fixed tc=tex2D(_MainTex,uv)+fixed4(1,1,1,1)*saturate(scale)*100;
                return tc;

扩散的方向反了,dis前面加个负号

float scale=_A*sin(-dis*3.14*_F+_Time.y);

限制波的半径

                float2 uv=IN.uv;
                float dis=distance(uv,float2(0.5,0.5));
                float scale=0;
                if(dis<_R){
                    scale=_A*sin(-dis*3.14*_F+_Time.y);
                    uv=uv+uv*scale;
                }
                fixed tc=tex2D(_MainTex,uv)+fixed4(1,1,1,1)*saturate(scale)*100;
                return tc;

半径边缘太明显了

            fixed4 frag(v2f IN) :COLOR
            {
                float2 uv=IN.uv;
                float dis=distance(uv,float2(0.5,0.5));
                float scale=0;
                if(dis<_R){
                    _A *= 1-dis / _R;//远离了中心的幅度小
                    scale=_A*sin(-dis*3.14*_F+_Time.y);
                    uv=uv+uv*scale;
                }
                fixed tc=tex2D(_MainTex,uv)+fixed4(1,1,1,1)*saturate(scale)*100;
                return tc;
            }

去掉if

            fixed4 frag(v2f IN) :COLOR
            {
                float2 uv=IN.uv;
                float dis=distance(uv,float2(0.5,0.5));
                float scale=0;
                //if(dis<_R){
                    _A *= saturate(1-dis / _R);//远离了中心的幅度小
                    scale=_A*sin(-dis*3.14*_F+_Time.y);
                    uv=uv+uv*scale;
                //}
                fixed tc=tex2D(_MainTex,uv)+fixed4(1,1,1,1)*saturate(scale)*100;
                return tc;
            }

扩展练习

结合脚本,点击事件,世界坐标映射到uv坐标,水波半径逐渐变大,波动能量逐渐变小。

比想象的麻烦,

1.如何获取点击点的uv坐标

public class ClickObject : MonoBehaviour
{

    // Update is called once per frame
    void Update()
    {
        if(Input.GetMouseButtonUp(0)){
            Debug.Log("Click");
            Ray ray=Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if(Physics.Raycast(ray,out hit)){
                GameObject go=hit.collider.gameObject;
                Debug.Log("hit:"+go+"|"+hit.point);
                Debug.Log("Hit Texture coordinates = " + hit.textureCoord.x + "," + hit.textureCoord.y);
                //addHitPoint(hit.textureCoord.x*4-2, hit.textureCoord.y*4-2);
                Material mat=go.GetComponent<Renderer>().material;
                mat.SetFloat("_HitU",hit.textureCoord.x);
                mat.SetFloat("_HitV",hit.textureCoord.y);//uv坐标
                mat.SetFloat("_HitX",hit.point.x);
                mat.SetFloat("_HitY",hit.point.y);
                mat.SetFloat("_HitZ",hit.point.z);//世界坐标
            }
        }
    }
}

Shader测试UV距离

            float _HitX;
            float _HitY;
            float _HitZ;

            float _HitU;
            float _HitV;
            v2f vert(appdata_base v){
                v2f o;
                o.vertex=v.vertex;
                o.pos=UnityObjectToClipPos(v.vertex);//屏幕坐标
                o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);//uv坐标
                return o;
            }
            fixed4 frag(v2f IN) :COLOR
            {
                float2 uv=IN.uv;
                float dis=distance(uv,float2(_HitU,_HitV));
                if(dis<0.3){
                    return fixed4(1,0,0,1);
                }
                else
                {
                    return fixed4(1,1,1,1);
                }
            }

测试结果Plane能够用,Cube等立方体模型不能用。

结合原来的水波shader,效果

发现是物体上必须有MeshCollider,其他Collider不行。

hit.textureCoord还是以前找热力图时的例子里面的代码的,找了半天也没找到从世界坐标转换到uv坐标的方法。

和uv热力图一样的问题,模型uv不连贯的话,波纹无法连贯,一样,改成世界坐标

            fixed4 frag(v2f IN) :COLOR
            {
                float2 uv=IN.uv;
                //float dis=distance(uv,float2(_HitU,_HitV));//uv坐标
                float3 wpos=mul(unity_ObjectToWorld,IN.vertex);//世界坐标
                float dis=distance(wpos,float3(_HitX,_HitY,_HitZ));
                float scale=0;
                _A *= saturate(1-dis / _R);//远离了中心的幅度小
                scale=_A*sin(-dis*3.14*_F+_Time.y);
                uv=uv+uv*scale;
                fixed tc=tex2D(_MainTex,uv)+ fixed4(1,1,1,1)*saturate(scale)*100 *_Debug;
                return tc;
            }

模型坐标

                float3 objHit=mul(unity_WorldToObject,float4(_HitX,_HitY,_HitZ,1));//模型坐标
                float dis=distance(IN.vertex,objHit);

再加上 “水波半径逐渐变大,波动能量逐渐变小”

public class ClickObject : MonoBehaviour
{
    public float minR=0.5f;
    public float maxR=5;
    public float R=5;
    public float A=0.01f;
    public Material clickMat;
    public float startTime;
    public float usedTime;
    // Update is called once per frame
    void Update()
    {
        if(Input.GetMouseButtonUp(0)){
            Debug.Log("Click");
            Ray ray=Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if(Physics.Raycast(ray,out hit)){
                GameObject go=hit.collider.gameObject;
                Debug.Log("hit:"+go+"|"+hit.point);
                Debug.Log("Hit Texture coordinates = " + hit.textureCoord.x + "," + hit.textureCoord.y);
                //addHitPoint(hit.textureCoord.x*4-2, hit.textureCoord.y*4-2);
                Material mat=go.GetComponent<Renderer>().material;
                mat.SetFloat("_HitU",hit.textureCoord.x);
                mat.SetFloat("_HitV",hit.textureCoord.y);//uv坐标
                mat.SetFloat("_HitX",hit.point.x);
                mat.SetFloat("_HitY",hit.point.y);
                mat.SetFloat("_HitZ",hit.point.z);//世界坐标

                clickMat=mat;
                startTime=Time.time;
                R=0;
                // _F("F",range(0,30))=10 //周期
                // _A("A",range(0,0.1))=0.01 //幅度
                // _R("R",range(0,1))=1 //半径
            }
        }

        if(clickMat!=null){
            usedTime=Time.time-startTime;//水波半径逐渐变大,波动能量逐渐变小
            R=usedTime+minR;
            A=(1-R / maxR) * 0.01f;
            if(A<0){
                A=0;
            }
            clickMat.SetFloat("_A",A);
            clickMat.SetFloat("_R",R);
            if(A==0){
                clickMat=null;
            }
        }
    }
}

再来个多点波纹?不会。后续再找找资料。

 

课时62:FragmentShader-UV动画3-模糊采样

取样模糊

Shader "Custom/NewSurfaceShader 25"
{
    Properties
    {
        _MainTex("MainTex",2D) = ""{}
        _OffsetUV("OffsetUV",range(0,0.01))=0.001 //采样距离
    }
    SubShader
    {
        pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "unitycg.cginc"
            struct v2f{
                float4 pos:POSITION;
                float2 uv:TEXCOORD0;
            };
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _OffsetUV;
            v2f vert(appdata_base v){
                v2f o;
                o.pos=UnityObjectToClipPos(v.vertex);//屏幕坐标
                o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);//uv坐标
                return o;
            }
            fixed4 frag(v2f IN) :COLOR
            {
                float offset_uv=_OffsetUV;//采样距离 0.001
                float2 uv=IN.uv;
                fixed4 color=tex2D(_MainTex,uv);

                uv=IN.uv;
                uv.x=IN.uv.x+offset_uv;
                color.rgb+=tex2D(_MainTex,uv);

                uv=IN.uv;
                uv.x=IN.uv.x-offset_uv;
                color.rgb+=tex2D(_MainTex,uv);

                uv=IN.uv;
                uv.y=IN.uv.y+offset_uv;
                color.rgb+=tex2D(_MainTex,uv);

                uv=IN.uv;
                uv.y=IN.uv.y-offset_uv;
                color.rgb+=tex2D(_MainTex,uv);
                color.rgb/=5;
                return color;
            }
            ENDCG
        }
    }
}

使用tex2D做模糊采样

            fixed4 frag(v2f IN) :COLOR
            {
                float offset_uv=_OffsetUV;
                fixed4 color=tex2D(_MainTex,IN.uv,float2(offset_uv,offset_uv),float2(offset_uv,offset_uv));
                return color;
            }

效果类似。

各个分量的左右类似,应该时各个方向的模拟采样距离吧。

 

偏导数 ddx/ddy,特性值的变化率,变化量

uv从0-1

            fixed4 frag(v2f IN) :COLOR
            {
                float dx=ddx(IN.uv.x)*_OffsetUV;
                float2 dsdx =float2(dx,dx);
                float dy=ddy(IN.uv.y)*_OffsetUV;
                float2 dsdy=float2(dy,dy);
                fixed4 color=tex2D(_MainTex,IN.uv,dsdx,dsdy);
                return color;
            }

效果类似,有点差别。

根据z的变化,设置模糊度

            fixed4 frag(v2f IN) :COLOR
            {
                float2 dsdx =ddx(IN.z)*_OffsetUV;
                float2 dsdy=ddx(IN.z)*_OffsetUV;
                fixed4 color=tex2D(_MainTex,IN.uv,dsdx,dsdy);
                return color;
            }

理摄像机近的清晰,原的模糊。

还有个,聚焦,焦点清晰,其他模糊。

 


版权声明:本文为llhswwha原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>