Unity Shader 学习之旅之SurfaceShader

unity  shader  图形图像


官方文档

一、工作原理

sureface表面着色器相当于unity在顶点片元着色器的基础上进一步的封装。当我们定义一个“surface function”后,可以通过unity已经封装好的的结构体“SurfaceOutput”等直接获取需要的数据,如纹理,法线,光滑度等

二、结构体

2.1标准output结构体

struct SurfaceOutput 



1. {  
        
1. fixed3 Albedo; // 漫反射颜色  
        
1. fixed3 Normal; // 切线空间法线  
        
1. fixed3 Emission;  
        
1. half Specular; // 高光系数  
        
1. fixed Gloss; // 高光强度  
        
1. fixed Alpha; // alpha 通道  
        
1. };

2.2Unity5 output结构体

unity5中表面着色器使用基于物理的光照模型。内建Standard和StantardSpecular光照模型使用如下两种结构体:

1. struct SurfaceOutputStandard  
        
1. {  
        
1. fixed3 Albedo; // base (diffuse or specular) color  
        
1. fixed3 Normal; // tangent space normal, if written  
        
1. half3 Emission;  
        
1. half Metallic; // 0=non-metal, 1=metal  
        
1. half Smoothness; // 0=rough, 1=smooth  
        
1. half Occlusion; // occlusion (default 1)  
        
1. fixed Alpha; // alpha for transparencies  
        
1. };  
        
1. struct SurfaceOutputStandardSpecular  
        
1. {  
        
1. fixed3 Albedo; // diffuse color  
        
1. fixed3 Specular; // specular color  
        
1. fixed3 Normal; // tangent space normal, if written  
        
1. half3 Emission;  
        
1. half Smoothness; // 0=rough, 1=smooth  
        
1. half Occlusion; // occlusion (default 1)  
        
1. fixed Alpha; // alpha for transparencies  
        
1. };


三、SurfaceShader编译指令

SurfaceShader被放置在 CGPROGRAM---ENDCG语块之间,需要注意以下两点:

  • 必须放置在SubShader语块中,不能在Pass语块中,SurfaceShader会自主编译成多个Pass
  • 通过使用 #pragma surface ... 来表明这是一个SurfaceShader
  1. #pragma surface surfaceFunction lightModel [optionalparams] 

3.1必要参数

  • surfaceFuncton:这就是我们在编译指令中指定的表面着色器Cg函数。可以通过 void surf (Input IN, inout SurfaceOutput o) 这种形式定义。其中input是我们定义的结构体,包含该函数需要的数据信息。
  • lightMode:光照模型可以使用内建的基于物理的 Standard 和StandardSpecular。也可以使用非物理的Lambert BlinnPhong。这几种类型可以直接通过在编译指令中指定,无需在自己实现。
  • Standard 光照模型使用SurfaceOutputStandard output结构体
  • StandardSpecular 光照模型使用SurfaceOutputStandardSpecular output结构体
  • Lambert和BlinnPhong 光照模型使用 SurfaceOutput output结构体

3.2可选参数

通过指定可选参数[optionalparams],可以让surfaceshader表现出更丰富的效果,如雾效,半透明,阴影等。可选参数具体类型可参考文首给出的 官方文档 查阅。

3.3示例

示例1:使用内置Lambert光照模型的表面着色器

1. Shader "Example/Rim" {  
        
1. Properties {  
        
1. _MainTex ("Texture", 2D) = "white" {}  
        
1. _BumpMap ("Bumpmap", 2D) = "bump" {}  
        
1. _RimColor ("Rim Color", Color) = (0.26,0.19,0.16,0.0)  
        
1. _RimPower ("Rim Power", Range(0.5,8.0)) = 3.0  
        
1. }  
        
1. SubShader {  
        
1. Tags { "RenderType" = "Opaque" }  
        
1. CGPROGRAM  
        
1. #pragma surface surf Lambert  
        
1. struct Input {  
        
1. float2 uv_MainTex;  
        
1. float2 uv_BumpMap;  
        
1. float3 viewDir;  
        
1. };  
        
1. sampler2D _MainTex;  
        
1. sampler2D _BumpMap;  
        
1. float4 _RimColor;  
        
1. float _RimPower;  
        
1. void surf (Input IN, inout SurfaceOutput o) {  
        
1. o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;  
        
1. o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));  
        
1. half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));  
        
1. o.Emission = _RimColor.rgb * pow (rim, _RimPower);  
        
1. }  
        
1. ENDCG  
        
1. }   
        
1. Fallback "Diffuse"  
        
1. }


示例2:使用可选参数的表面着色器,通过指定decal:blend,该shader会表现出半透明贴画的效果。

1. Shader "Example/Decal" {  
        
1. Properties {  
        
1. _MainTex ("Base (RGB)", 2D) = "white" {}  
        
1. }  
        
1. SubShader {  
        
1. Tags { "RenderType"="Opaque" "Queue"="Geometry+1" "ForceNoShadowCasting"="True" }  
        
1. LOD 200  
        
1. Offset -1, -1  
        
1. CGPROGRAM  
        
1. #pragma surface surf Lambert decal:blend  
        
1. sampler2D _MainTex;  
        
1. struct Input {  
        
1. float2 uv_MainTex;  
        
1. };  
        
1. void surf (Input IN, inout SurfaceOutput o) {  
        
1. half4 c = tex2D (_MainTex, IN.uv_MainTex);  
        
1. o.Albedo = c.rgb;  
        
1. o.Alpha = c.a;  
        
1. }  
        
1. ENDCG  
        
1. }  
        
1. }