Unity_shader(基本语法,水面波动示例)

Unity_shader

大体结构

  • Shader:先是最大的一层外壳,写上shader再指定其在哪个目录下,名字是什么。
  • Properties:在外壳中第一层结构是Properties所包裹的属性区域,里面定义写入一些属性。
  • SubShader:在属性之后是SubShader,是shader的核心,主要执行里面的代码对物体进行渲染,SubShader可以有多个,一般写为性能逐级递减的多个,当计算机硬件读取到靠前的SubShader,发现其中有硬件不支持的操作,那么就会去读取执行下一个SubShader。
  • Fallback:在Shader的最后写入,当计算机硬件不支持该Shader里的所有SubShader时,会读取Fallback之后跟的’备用‘shader,然后以其代替这个shader的位置。

基本语法

  • 在unity中首先我们创建一个shader(做水面推荐unlit Shader),然后打开其代码,里面会有一些自动生成的代码大致如下:
Shader "Unlit/text"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

这里先提一下,我们在Unity中写shader用的语言是cg语言的Unityshader衍生版,cg语言是基于c语言上的一种语言,与c语言很像,但其主要是作用域GPU上的。(编辑器不支持cg语言识别,所以就直接贴普通代码了)

  • 其中第一句话 Shader "Unlit/text"的意思为,一个shader,在Unlit列表中,命名为text(之后往材质上贴的时候会用到)。
  • 再往下第一个区块
Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }

意为属性定义,在这个里面是得到其2d纹理。需要注意的是,在之后的区块中要定义部分变量时要与这里的变量命名完全一致。

  • 再往下的一个区块(省略其内容)
  SubShader
    {
        Pass
        {
            CGPROGRAM
           #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"
            ENDCG
        }
    }

在这之中,SubShader是子着色器列表,每一个shader至少得有一个子着色器,其中的pass是一个通道,在pass之中,CGPROGRAM意为插入cg代码开始,ENDCG意为插入cg代码结束。

然后再pass里面的#pragma格式为声明变量绑定从GPU上一个工位传来的值使用格式为:
#pragma 上一个工位传来的变量关键词 绑定命名;

在里面的#include "UnityCG.cginc"是指调用Unity内置的cg语言函数库。

水面波动示例

这里就用上面创建好的那个shader进行改写就行了

所用函数与变量简介
  • distance:距离计算函数,得出点与点的距离,第一个参数我们这里使用上一个工位传来的坐标参数,第二个为正弦波发出位置坐标(我这里是平面中心点,平面放在了世界坐标原点)。
  • POSITION:意指传递的坐标参数,从上一工位接受坐标绑定时使用这个,向下一工位传递坐标参数的时候也绑定这个。
  • TEXCOORD0:第一套纹理的传递参数,与其相似的还有第二套第三套纹理等,仅仅是改变了最后一个数字。
  • mul:乘法函数,在这里我们一般作为矩阵相乘使用。
  • _Time:时间参数,其中有四个分量,这里我用了第三个,是游戏开始时间的二倍。四个分量分别为(t/20,t,t2,t3);
  • sampler2D 2d纹理型变量。
  • float4 四个浮点型的绑定类型变量
  • unity_WorldToObject:世界坐标转局部坐标的矩阵,使用方法为让需要转换的目标矩阵左乘这个矩阵。
  • unity_ObjectToWorld:局部坐标转世界坐标,用法同上。
具体实施
  • 首先改一下shader的位置:将第一行代码改为Shader “Custom/Sinshader”,意为我这个Sinshader放在Custom目录下。
  • 然后进入pass中修改cg代码:首先在俩个结构体 之前没什么好改的(但有一点点改动,自己看代码对比吧),因为主要实要在渲染上做手脚。 sampler2D _MainTex;这句话命名与之前的属性命名要完全一致(没改动)。之后主要修改vert函数。
  • 修改vert函数:在其之中的内容基本都改动了。
    为其传入结构体appdata的参数,作为从上一工位传来的坐标与纹理参数,在此基础上修改成为我们需要的v2f型结构体的参数,最后返回这个参数,让之后的函数调用。
    用一些函数得到距离作为sin的初相位,在用_Time的分量作为变动参数实现正弦波动,在其中对整体进行调整可以改变振幅,对_Time的分量参数大小改动可以调整波动速率,调整初相位参数以改变波动密度。
完整代码


Shader "Custom/Sinshader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
				//distance是一个计算距离的函数,第一个参数我们调用appdata结构体的xyz,
				//第二个参数用float3型三个参数都为0即可,得到点到中心的距离
				float dist = distance(v.vertex.xyz,float3(0,0,0));
				//渲染坐标左乘_Object2World矩阵以变换为世界坐标
				o.vertex = mul(unity_ObjectToWorld, v.vertex);
				//取先前得到的距离和距离游戏开始的时间的第三个分量(2t)为sin的参数
				//来得出正弦波的位置
				float hight = sin(dist*3+_Time.z*2);
				o.vertex.y = hight;
				//渲染坐标左乘_World2Object以让其转回局部坐标
				o.vertex = mul(unity_WorldToObject, o.vertex);
				o.vertex = UnityObjectToClipPos(o.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值