unityShader入门了解

我之前的写过一个关于渲染流水线,接下来聊聊shader。
shader的数据类型和c#是有一些相似的,我下面的Properties里面写了几个类型(这个函数里面写的类型都会在unity里面以显示的形式展现出来,下面一个图片就是在unity界面里面所展示的一个效果),只是列举了几个常用的类型。然后它还有一些其他的类型,我写在Pass函数里面,因为这些类型是不去显示的。
首先在unity里面定义一个shader,在Proect中右键选择Shader下的StandardSurfaceShader这个shader是基本的shader框架,其他的几个都是不同的shader框架,所有我们选择基本就可以。
shader有两个必须有的函数Properties只能定义一个,它是用来和用户进行一个交互方式存在,可以显示在Inspector里面,让用户进行选择以及设置一些值,还有一个是SubShader,这个函数可以定义很多个,但一般情况下是只用一个,如果定义多个的情况下就是当前显卡不支持第一个SubShader,然后一次筛选后面的SubShader选择当前电脑显卡所支持的SubShader。然后还会有一个备用的显示方式–Fallback “VertexLit”。我在下面也加了备注,这是一种后备方案。

Shader "MyShaderOne"
{
    //属性块只能有一个
    Properties{
        _Color("color",Color)=(1,1,1,1)//float4
        _Verctor("Verctor",Vector)=(1,2,3,4)//float4
        _Int("Int",Int)=123//float
        _Float("Float",Float)=4.5//float
        _Range("Range",Range(1,20))=5//Range(1,20)这是一个定义范围--float
        _2D("Texture",2D)="white"{}//"white" 的作用的当我们不指定图片会默认使用白色--sampler2D
        _Cube("Cube",Cube)="while"{}//可以指定一个图片形成的效果是一个立方体的天空盒--samplerCube
        _3D("Texure",3D)="black"{}//--sampler3D
    }
        //subshader可以有很多个
        //它会分以不同的显卡用不同的subshader
        //当发现当前显卡不能支持当前的subshader会运行下一个subshader
    SubShader
    {
        //pass块相当于方法--可以有很多个,但一般只用一个
        Pass
        {
            //在这里可以直接编写shader代码
            CGPROGRAM

            //使用cg语言编写代码
            //float  half  fixed------float4  float3  float2  float 
            //float 是32位存储 
            //half 是16位 -6万到6万
            //fixed 是11位 -2到2

            float4 _Color;
            float4 _Vector;
            float _Int;
            float _Range;
            sampler2D _2D;
            samplerCube _Cube;
            sampler3D _3D;

            ENDCG
            
        }
    }
    //后备方案,当上面的subshader都不能执行的时候执行此
    Fallback "VertexLit"
}

在这里插入图片描述
上面对shader的一些基本数据有了一个了解之后我们再了解一下必须要有的两个函数(#pragma vertex vert)、(#pragma fragment frag)这两个是必须要定义的,它们是进行一些shader功能的必要函数,在vertex 中会进行定点函数的处理,就是对于买一个定点数据的处理,fragment 是对于片元的处理,可以参考渲染流水线的几何阶段。
在函数定义的方法里面,有人会想玩什么会加一个:还有后面的参数名是个什么意思,首先我们第一个函数(float4 vert(float4 v:POSITION) :SV_POSITION)POSITION他是一个宏,相当于将物体的数据传入函数中变成float4 v的参数,然后括号后面的SV_POSITION是类似以返回值,在前面将参数获取到之后得返回回去,不然我们获取、计算值就没有什么意义,所以在函数定义前面会加一个float4,这个相当于c#中定义函数会写一个返回值类型意义下面这个函数。
下面这个函数中SV_Target 也是一样的,将片元的参数返回到物体中,让物体显示出来。在下面我们返回了一个float4的值,物体就会将这个值进行转换成颜色,然后显示出来,这个参数会显示出来下面这个物体的颜色。

Shader "MyShaderTwo"
{
    SubShader
    {
        //pass块相当于方法--可以有很多个,但一般只用一个
        Pass
        {
            CGPROGRAM
            //基本作用 完成顶点坐标从模型看见到裁剪空间的转换(从游戏环境转到视野相机屏幕)
            //定点函数 这里只是声明了,定点函数的函数名
#pragma vertex vert
            //基本作用 返回模型对应的屏幕上的每一个像素的颜色值
            //片元函数 这里只是声明了,片元函数的函数名
#pragma fragment frag
        //position是一种语义好让函数知道数据的来源括号后面的语义是给数据来源做语义通过语义告诉系统我这个参数是什么的
            float4 vert(float4 v:POSITION) :SV_POSITION {
                //通过这个宏就可以将模型空间转到剪裁空间(float4类型)
                return UnityObjectToClipPos(v);
            }
            float4 frag() : SV_Target {
                return float4(0.5,0.5,1,1);
            }
            ENDCG
            
        }
    }
    Fallback "VertexLit"
}

在这里插入图片描述
然后会有人想之前说的Properties为什么一直没有用,因为上面只是对shader让你有一个基本的了解,得有金刚钻才能揽瓷器活。所以在写shader之前,要先将框架有一个基本的了解,以及知道每一个步骤是干什么的,为什么要这么定义,以及一些必要的宏的使用方法。
当了解了框架之后我们来了解一下基本的逻辑处理。

Shader "MyShaderFour"
{
    Properties{
        _Diffuse("Diffuse Color",Color) = (1,1,1,1)
    }
        SubShader{
            Pass{
                Tags{"LightMode" = "ForwardBase"}
                CGPROGRAM
        //获取第一个直射光的颜色 _LightColor0 第一个直射光的位置_WorldSpaceLightPos0
        #include "Lighting.cginc"

        #pragma vertex vert
        #pragma fragment frag
            fixed4 _Diffuse;
            //application to vertex从应用传递到顶点
            struct a2v {
                float4 vertex:POSITION;//告诉unity把模型空间下的顶点坐标填充给vertex
                float3 normal:NORMAL;
            };
            //SV_POSITION是必须有的没有的话就不会显示出物体的模型
            struct v2f {
                float4 position:SV_POSITION;
                fixed3 color : COLOR;
            };
            //用结构体返回值可以返回多个值,对后面的一些操作有帮助
            //系统自动调用,会给屏幕上的每一个顶点调用
            v2f vert(a2v v){
                v2f f;
                f.position = UnityObjectToClipPos(v.vertex);
                fixed3 normalDir = normalize( mul(v.normal,(float3x3) unity_WorldToObject));//3x3是shader的一个表示方式,可以将数据转换成3x3
                fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//获取到场景中灯光的位置
                fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir, lightDir), 0)*_Diffuse.rgb;//获取漫反射颜色--_Diffuse.rgb是之前定义的_Diffuse的值
                f.color = diffuse; 
                return f;
            }

            //系统自动调用,会模型所对应在屏幕上的像素点对应--调用的多
            fixed4 frag(v2f f): SV_Target {
                return float4(f.color,1);
            }
            ENDCG
            
        }
    }
    Fallback "VertexLit"
}

上面我所写的这个函数就是对shader的一个基础的编写,首先Properties中定义的是一个对于颜色的修改,在我们的Inspector里面会出现下面这个图片中红框所标记的。在这里插入图片描述
然后下面(Tags{“LightMode” = “ForwardBase”})与(#include “Lighting.cginc”)是获取场景中直射光的数据在后面的函数中科院使用。在Properties中定义的_Diffuse需要在Pass里面定义一个(fixed4 _Diffuse;)才可能在线面的函数中使用,不然会报错。然后定义了(a2v)函数和(v2f)函数是通过这两个函数进行传值的一些操作,用函数会比直接传值增加效率。
对于定点函数(vert)中的一些方法具体是干什么的,我在函数里面也做了相对应的注释,在最后(f.color = diffuse; )就是将值进行一个赋值可以使这个值在下面的片元函数(frag)中使用。
在片元函数中会有人想一个float4的值为什么float3的值也可以用,还有(f.color)后面的,1是干什么的,其实在上面我们定义的(f.color)是一个现对于unity中(Vector3)的一个参数,但我们在Properties中定义的(_Diffuse)是一个float4的值相当于unity中(Quaternion)是有四个参数的,所以我们在(f.color)后面加了一个(,1)是补全他们所相差的一个参数值。
上述所说三个基本案例只是对shader的一个基本了解,仅限于入门,shader更重要的对于数学的一个逻辑思维能力,以及算法的研究,对于定点函数以及片元函数而言,片元函数所执行的次数会更多。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逐·風

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值