25 Shader 表面[Surface]着色器

Posted zpy1993-09

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了25 Shader 表面[Surface]着色器相关的知识,希望对你有一定的参考价值。

表面着色器简介:

       在使用Surface Shader时,它可以自动生成一些代码,比直接去使用低阶的顶点和像素着色器来说要容易的多。但是需要注意的是Surface Shader并不是一种定制的语言,也不是一种神奇的东西,它只不过是自动生成了以前必须去手写的代码。Surface Shader 还是使用CG或HLSL语言编写 Surface Shader实际上就是对定点和像素着色器一种包装,它让我们不用去关注更多的顶点和片段程序的细节,能够快速的得到想要的着色器。

基本属性:

  _Color为颜色值

  _MainTex是主纹理

  _Glossiness 是一个浮点值,用于计算高光的光泽度。

  _Metallic 也是一个浮点值,用于计算表现金属的关泽度。

       表面着色器,在该shader中有一个SubShader【子着色器】,在这个子着色器中没有Pass通道。因为SurfaceShader是对顶点或片段着色器的一种包装,能够自动生成着色器代码,生成过程中不需要任何干预,Pass也会自己生成。如果手动的添加一个Pass反而会报错。当然该shader后面也有 FallBack

stuct SurfaceOutput
{
fixed3 Albedo;
fixed3 Normal;
fixed3 Emission;
half Specular;
fixed Gloss;
fixed Alpha;
}
struct SurfaceOUtputStandard
{
fixed3 Albedo;
fixed3 Normal;
half3 Emisson;
half Metallic;
half Smoothness;
half Occlusion;
fixed Alpha;
}

 

//表面着色器
Shader "CustomLearn/First_Surface"
{
    Properties{
        _Color("Color",color)=(1,1,1,1)
        //2D、Rect、Cube这三种都是对于贴图来说的,其初始值可以是代表Tint
        //颜色的字符串来表示,其值也可以为空,可填写的类型有:white,black
        //,gray,bump(凹凸),对于后面的大括号表示打开当前图片的特殊设置,这
        //些设置可以是:ObjectLinear、SphereMap、CubeNomal等,这些值可以省略
        _MainTex("Albedo(RGB)",2D)="white"{}
        _Glossiness("Smoothness",Range(0,1))=0.5
        _Metallic("Metallic",Range(0,1))=0
    }
    SubShader{
        //表面着色器中,可以对若干个标签所修饰,而硬件就会根据这些标签决定什么时候来调用这些着色器
        //1、"RenderType"="Opaque":表示渲染不透明物体是调用
        //2、"RenderType"="Transparent":表示渲染不透明物体时,或者粒子特效时,使用这个
        //3、"RenderType"="Background":表示天空盒和背景时使用这个
        //4、"RenderType"="Overlay":表示渲染叠加效果,比如镜头光晕
        Tags{"RenderType"="Opaque"}
        //LOD时Level Of Detail的缩写,我们能够使用什么类型的shader,是需要
        //它来决定,如果我们在Unity中设置了LOD的最大值,当小于SubShader中所指
        //定放入LOD值时,则这个SubShader就不可用
        //在Unity内部的shader中,制定了一种LOD值,我们在编写shader时,可以将
        //这些值作为参考,这样以后根据设备图形性能调整画质时,就可以进行比较精准
        //的控制,形同提供的LOD值:
        //VertexLit=100(顶点光照)及其系列
        //Reflective Vertex Lit(反射顶点光照)=150
        //Diffuse(漫反射光照)=200
        //Diffuse Detail(漫反射细节)、Reflective Bumped VertexLit = 250
        //Bumped、Specular(凹凸高光)=400
        //Parallax(视差、更加逼近)= 500
        //Parallax Specular(视差高光)=600
        LOD 200
        //表面着色器实现代码需要放在CGPROGRAM...ENDCG之间,而不是放在Pass通道中
        //CG: C for Graphics是计算机图形编程语言,是C的超集,CG程序可以根据运行时
        //的需要实现编译成GPU汇编代码
        CGPROGRAM
        //下面是一条编译指令,他声明了我们要写的一个表面着色器,并且指定了光照模型
        //它的语法格式为:
        //#pragma surface surfaceFuctionName lightModel [optional params]
        //surface:表示声明表面着色器
        //surfaceFuctionName:着色器中处理渲染的函数名字
        //lightModel:使用的光照模型,Lambert表示普通的diffuse光照模型
        //optional params:表示可选参数,是可设置包括透明度、顶点与颜色的
        //函数、投影等相关的一些配置
        #pragma surface surf Standard fullforwardshadows
        //表示使用Shader3.0版本
        #pragma target 3.0

        //我们在使用shader文件时,所实例化的shader是由两个独立的模块组成,属性声明和
        //回调都是Unity可直接使用或编译的shader语法而在CG代码块中,想要访问Properties
        //中的所定义的变量,必须声明和属性名字相同的变量来进行使用,这里的sampler2D _MainTex
        //是和Properties中声明的2D类型的_MainTex关联,之后的CG程序使用的都是变量
        sampler2D _MainTex;

        //输入结构体,float2和Vector2一样,里面可以存放两个float类型的数据,这里定义的
        //变量包含的两个数据可以使用 变量名.x 的方式得到某个值,在CG程序中约定一个贴图的变量
        //名前加uv_,就表示提取这个贴图的uv值(uv值表示两个代表贴图上的二维坐标点),后续
        //的CG代码中就可以通过这个变量名获取图片上的坐标值
        struct Input{
            //输入结构体中一般会包含着色器所需要的纹理坐标,为例坐标命名为uv+纹理名
            //其他成员:float3 viewDir:表示视角的方向
            //    float4 COLOR:表示每个顶点的颜色差值
            //    float3 worldPos:表示世界坐标
            //    float3 screenPOS:表示屏幕坐标
            //    float3 worldRef:表示坐标系中的发射向量
            //    float3 worldNormal:世界坐标系中的法线向量
            float2 uv_MainTex;
        };
        //half:浮点类型,表示半精度浮点,精度最低,但是运算的性能比高精度的浮现类型要高一些
        //在GPU编程中大量使用
        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        //CG规定了表面着色器代码的方法的参数类型和语法结构
        //语法格式:surf(Input IN,inout SurfaceOutputStandard o)
        //作用是将其接收到的uv坐标挥着附加数据进行处理,最后将结果填充到输出的结构体中。
        //第一个参数:Input是我们要定义的输入结构体,可以把所需要的参与计算的数据都放到
        //这个结构体中,传入方法使用
        //第二个参数:定义输出的结构体的类型,需要把方法里得到的结构赋值给该结构体里面的
        //成员变量
        //SurfaceOutputStandard:标准输出结构定义如下:
        //1、fixed3 Albedo:基础颜色
        //2、fixed3 Normal:切线空间法线
        //3、half Metallic:表示是否有金属特性:0--非金属,1--金属
        //4、half Smoothness:是否光滑:0--粗糙,1--光滑
        //5、half Occlusion :遮挡(默认)
        //6、fixed Alpha :透明度

        //SurfaceOutput:的输出结构体定义如下:
        //1、half3 Albedo:像素的颜色
        //2、half3 Normal:像素的法向向量值
        //3、half3 Emission:像素的发散颜色
        //4、half Specular:像素的镜面高光
        //5、half Alpha:像素的透明度
        void surf(Input IN,inout SurfaceOutputStandard o){
        //tex2D方法是CG程序里面的用来在一张贴图上对某一个点进行采样的方法,
        //返回一个fixed4 类型的值
            fixed4 c=tex2D(_MainTex,IN.uv_MainTex)*_Color;
            //获取基础颜色值
            o.Albedo=c.rgb;
            //金属含量
            o.Metallic=_Metallic;
            //平滑值
            o.Smoothness=_Glossiness;
            //设置透明度
            o.Alpha=c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

案例1:

效果图:

 技术图片

 

//法线贴图案例,为了解决模型不能有一些凹凸之类的细节表现问题
Shader "CustomLearn/Fourth_Bump" 
{
    //属性值
    Properties{
        //普通纹理属性
        _MainTex("Texture",2D)="white"{}
        //法线纹理属性
        _BumpMap("BumpMap",2D)="bump"{}
    }
    //子着色器
    SubShader{
        //渲染非透明物体
        Tags{"RenderType"="Opaque"}
        //CG代码块
        CGPROGRAM
        //指定着色器处理函数以及光照模型
        #pragma surface surf Lambert
        //参与计算的结构体
        struct Input{
            //普通图片uv坐标
            float2 uv_MainTex;
            //法线贴图uv坐标
            float2 uv_BumpMap;
        };
        //在CG中获取属性中的两张图片
        sampler2D _MainTex;
        sampler2D _BumpMap;

        void surf(Input IN,inout SurfaceOutput o)
        {
            //采样获取普通纹理上的像素点的颜色值
            o.Albedo=tex2D(_MainTex,IN.uv_MainTex).rgb;
            //在计算法线时,需要根据采样获取到法先贴图的像素点信息,传递给UnpackNormal
            //函数即可,这个函数可以实现区间的重新映射,或者说UnpackNormal函数是对法线纹理进行采样的方法
            o.Normal=UnpackNormal(tex2D(_BumpMap,IN.uv_BumpMap));
        }

        ENDCG
    }
    FallBack "Diffuse"
}

案例二:渲染数带有自转效果的球

技术图片

 

 技术图片

 

 

Shader "CustomLearn/Fifth_Bubble" {
    //属性
    Properties{
        _MainTex("Albedo(RGB)",2D)="white"{}
        _Color("Color",color)=(0,0,0,0)
        _Alpha("Alpha",Range(0,1))=0.5
        //设置水平速度
        _SpeedX("X_Speed",Range(0.5,10))=0.6
        //设置垂直速度
        _SpeedY("Y_Speed",Range(0.5,10))=0.6
        }

    SubShader{
        Tags{"RenderType"="Transparent"}
        //CG代码块儿
        CGPROGRAM
        //alpha表示透明兰伯特(Diffuse)光照模型
        #pragma surface surf Lambert alpha
        //在CG代码中声明属性中对应的各个属性
        sampler2D _MainTex;
        fixed _Alpha;
        fixed _SpeedX;
        fixed _SpeedY;
        fixed4 _Color;
        //声明输入纹理结构体
        struct Input{
            float2 uv_MainTex;
        };

        //实现surf函数
        void surf(Input IN,inout SurfaceOutput o)
        {
            //速度
            fixed xSpeed=_SpeedX*_Time*0.1;
            fixed ySpeed=_SpeedY*_Time*0.1;
            //获取uv坐标
            fixed2 uv=IN.uv_MainTex-fixed2(xSpeed,ySpeed);
            //获取采样信息
            fixed4 c=tex2D(_MainTex,uv) * _Color;
            //
            o.Albedo= c.rgb;
            o.Alpha=_Color.a*c.a*_Alpha;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

 

 

 

 

 

 

 

     

 

以上是关于25 Shader 表面[Surface]着色器的主要内容,如果未能解决你的问题,请参考以下文章

Surface Shader的研究

ShaderLab学习小结在标准表面shader中加入顶点着色器函数

Unity Shader的形式

Unity Shader入门精要学习笔记 - 第17章 Unity的表面着色器探秘

Unity Shaders and Effects Cookbook (7-1) 在Surface Shader 中 访问 顶点颜色

shader开发_4.Surface shader初探