Unity 3d Shader实践 —— 第一个Shader


  1. 在Project标签的Assets下选择合适的目录,单击右键选择Create(或者直接点击Project下的Create按钮),当鼠标移动至Shader上时,我们可以看到四种Shader模版,如图1-1所示

              

              图1-1

  • Standard Surface Shader   包含surface函数,默认置于Custom域中,用于处理光照模型,这是我们接下来将要使用的模版
  • Unlit Shader                            包含vertex和fragment函数,默认置于Unlit域中,不涉及光照处理
  • Image Effect Shader             包含vertex和fragment函数,默认置于Hidden域中,用于处理RenderTexture实现图形特效
  • Compute Shader                    如文档中所描述:“Compute Shaders are programs that run on the graphics card, outside of the normal rendering pipeline. They can be used for massively parallel GPGPU algorithms, or to accelerate parts of game rendering”,Compute Shader的主要作用是利用GPU进行大规模运算,如粒子系统中粒子的位置等,并不涉及网格和纹理处理
2. 在图1-1界面中,选择Standard Surface Shader创建我们的第一个Shader脚本,双击打开,可以看到已经有如下代码:
Shader "Custom/NewSurfaceShader" {
<span style="white-space:pre">	</span>Properties {
<span style="white-space:pre">		</span>_Color ("Color", Color) = (1,1,1,1)
<span style="white-space:pre">		</span>_MainTex ("Albedo (RGB)", 2D) = "white" {}
<span style="white-space:pre">		</span>_Glossiness ("Smoothness", Range(0,1)) = 0.5
<span style="white-space:pre">		</span>_Metallic ("Metallic", Range(0,1)) = 0.0
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>SubShader {
<span style="white-space:pre">		</span>Tags { "RenderType"="Opaque" }
<span style="white-space:pre">		</span>LOD 200
<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>CGPROGRAM
<span style="white-space:pre">		</span>// Physically based Standard lighting model, and enable shadows on all light types
<span style="white-space:pre">		</span>#pragma surface surf Standard fullforwardshadows


<span style="white-space:pre">		</span>// Use shader model 3.0 target, to get nicer looking lighting
<span style="white-space:pre">		</span>#pragma target 3.0


<span style="white-space:pre">		</span>sampler2D _MainTex;


<span style="white-space:pre">		</span>struct Input {
<span style="white-space:pre">			</span>float2 uv_MainTex;
<span style="white-space:pre">		</span>};


<span style="white-space:pre">		</span>half _Glossiness;
<span style="white-space:pre">		</span>half _Metallic;
<span style="white-space:pre">		</span>fixed4 _Color;


<span style="white-space:pre">		</span>void surf (Input IN, inout SurfaceOutputStandard o) {
<span style="white-space:pre">			</span>// Albedo comes from a texture tinted by color
<span style="white-space:pre">			</span>fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
<span style="white-space:pre">			</span>o.Albedo = c.rgb;
<span style="white-space:pre">			</span>// Metallic and smoothness come from slider variables
<span style="white-space:pre">			</span>o.Metallic = _Metallic;
<span style="white-space:pre">			</span>o.Smoothness = _Glossiness;
<span style="white-space:pre">			</span>o.Alpha = c.a;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>ENDCG
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>FallBack "Diffuse"
}
 
  
每一个Shader脚本都包含在Shader标签中,语法如下
Shader "name" { [Properties] Subshaders [Fallback] [CustomEditor] }
  • name 定义了Shader名,Shader名可以用"/"分隔,使Shader出现在Material Inspector中的不同层级中
  • Properties Shader可以声明不同格式的属性,这些属性会出现在Material Inspector中
  • SubShader 每个Shader脚本都必须包含一个或多个SubShader,Shader的功能都是在SubShader中实现的,虽然Shader中可以包含多个SubShader,但只会选择第一个适合运行时平台的执行,因此我们可以根据不同平台要求实现多个SubShader,以达到跨平台的目的
  • FallBack 当运行时平台不能支持所有的SubShader时,系统会执行FallBack 提供的备选Shader
我们的第一个Shader脚本L1C1_FirstShader中,在Properties块中声明了四个属性:_Color、_MainTex、_Glossiness和_Metallic,同时,为了使用这四个属性,在SubShader中声明了四个同名变量,值得注意的是,我们在SubShader中使用的是Cg/HLSL(包含在CGPROGRAM/ENDCG中的部分),因此需要将Properties中的类型映射成对应的HLSL类型。

在SubShader中,我们的首先Tags指令配置Tag,Tag为一系列键值对,传递部分渲染引擎配置,如渲染次序(render order)、渲染类别(render type)等,常用Tags如下:
  • Queue: 渲染次序(Render Order),决定使用该Shader的Game Object的渲染时机,预设Queue值有五个:
    • Background:在其他所有对象之前渲染,也就是出现在所有对象的后面;
    • Geometry:这是Queue的默认值,适用于大部分对象,不透明物体需要使用该值;
    • AlphaTest:需要进行Alpha Test的对象使用该值,排在Geometry之后,因为当所有不透明物体被渲染之后单独渲染需要Alpha Test的对象会更高效(不满足alpha条件的像素会被舍弃);
    • Transparent:排在Geometry和AlphaTest之后,需要使用Alpha混合(Alpha Blending)的对象,如玻璃或粒子效果等需要使用该值;
    • Overlay:排在最后,需要叠加在所有其他对象上的物体如镜头闪光(lens flares)在此时被渲染;
                      本质上,预设Queue值是一组整数,Background是1000,Geometry是2000,AlphaTest是2450,Transparent是3000,Overlay是4000,我们也可以采用如下方式设置Queue值:
Tags {"Queue"="Geometry+1"}
  • RenderType: 将Shader归入不同预设类别,参考RenderType的所有类型,可用值为:Opaque/Transparent/TransparentCutout/Background/Overlay/TreeOpaque/TrueeTransparentCutout/TreeBillboard/Grass/GrassBillboard;
  • DisableBatching: 由于Batching会使object space丢失,所以部分Shader(大部分进行了object-space节点变换)在Draw Call Batching被应用时无法执行,这时需要设置RenderType为DisableBatching;
  • ForceNoShadowCasting:将此Tag设置为true禁用阴影;
  • IgnoreProjector: 将此Tag设置为true禁用projection变换;
  • CanUseSpriteAtlas:将此Tag设置为false禁用sprite atlas
  • PreviewType:设置Material在Inspector中的预览方式,默认为"Sphere",也可以设置为"Plane"或"Skybox";
  • LightMode:LightMode tag defines Pass’ role in the lighting pipeline.
接下来,LOD指令设置了该SubShader可运行的LOD值,运行时我们可以通过Shader.maximumLOD来设置Shader的LOD值或者Shader.globalMaximumLOD设置全局Shader的LOD,如果SubShader的LOD值高于该值,则SubShader会被跳过,如以下代码:

SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
                // other codes
}
SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 400
                // other codes
}
当Shader的LOD为300时,第一个SubShader将被跳过而执行第二个SubShader

CGPROGRAM/ENDCG 语句之间包含了我们的Cg/HLDL脚本。
第一个#pragma指令#pragma surface ... 暗示了这是一个surface shader,其格式为:
#pragma surface surfaceFunction lightModel [optionalparams]
参考文档
第二个#pragma指令指定了 Shader模型
然后我们声明了与Properties对应的变量从而能让我们在cg脚本中使用传入的属性,这在上文中我们已经提到。
除了变量,我们还声明了一个struct Input作为surface函数的输入参数,由于本例中只需要用到纹理的uv坐标,因此struct中只包含该属性。关于更多该struct的信息,请 参考文档
最后,也就是脚本的核心,就是我们在上面指定的surfaceFunction啦,注意到这个函数有两个参数,出来Input结构体,还有一个SurfaceOutputStandard结构体作为输入输出参数,这是因为我们指定的lightModel为Standard,如果lightModel为StandardSpecular,则需要使用SurfaceOutputStandardSpecular结构体。这个结构体的定义如下:
struct SurfaceOutputStandard
{
	fixed3 Albedo;		// base (diffuse or specular) color
	fixed3 Normal;		// tangent space normal, if written
	half3 Emission;
	half Metallic;		// 0=non-metal, 1=metal
	half Smoothness;	// 0=rough, 1=smooth
	half Occlusion;		// occlusion (default 1)
	fixed Alpha;		// alpha for transparencies
};
我们可以在CGIncludes/UnityPBSLighting.cginc里找到。在第一个Shader里,我们只是简单地计算并设置了Albedo,把通过Properties传入的参数传递给了输出参数,接下来就可以交给rendering pipeline中的其他步骤去完成渲染了。

猜你喜欢

转载自blog.csdn.net/winchyy/article/details/51317282