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]着色器的主要内容,如果未能解决你的问题,请参考以下文章
ShaderLab学习小结在标准表面shader中加入顶点着色器函数
Unity Shader入门精要学习笔记 - 第17章 Unity的表面着色器探秘
Unity Shaders and Effects Cookbook (7-1) 在Surface Shader 中 访问 顶点颜色