1. LOD:
通过给SubShader设定一个整型的Level of DetaiI,即LOD数值,可以在运行时根据硬件设备能力来决定是否使用此Shader,以及使用哪一个层级的SubShader。
用法eg:
SubShader
{
LOD 600
Pass { }
}
可以针对某一特定的Shader设置最大LOD,也可以在运行时设置一个全局的LOD。
eg1:
public Shader m_Shader;
void Awake()
{
m_Shader.maximumLOD = 800;//改变指定的
Shader.globalMaximumLOD = 600;// 改变全局的
}
最终结果,如果上述值为全局设为600,特定shader的设为800时,那么Unity所有的Shader(除设置了LOD为800的shader)中LOD为600的SubShader,特定shader的设为800时,选用了LOD为800的SubShader。
测试代码:
Shader "Tut/Shader/Common/_SetShader" {
Properties {
_Color ("Main Color", Color) = (1,1,1,0.5)
_MainTex ("Base (RGB)", 2D) = "white" { }
}
SubShader {
LOD 800
Pass {
Material { Diffuse (0,0,1,1)}
Lighting On
SetTexture [_MainTex] {Combine texture * primary double}
}
}
SubShader {
LOD 600
Pass {
Material { Diffuse (0,1,0,1)}
Lighting On
SetTexture [_MainTex] {Combine texture * primary double}
}
}
SubShader {
LOD 500
Pass {
Material {Diffuse (1,1,0,1)}
Lighting On
}
}
SubShader {
LOD 400
Pass {
color(1,0,0,1)
}
}
}
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class _SetGlobalLOD : MonoBehaviour {
public Shader myShader;
public GUISkin skin;
public Rect rt;
public Rect r1;
public Rect r2;
string tipStr;
private float val=1;
void Update () {
Shader.globalMaximumLOD = (int)val * 100;
myShader.maximumLOD = 800;
}
void OnGUI()
{
GUI.skin = skin;
val =(int) GUI.HorizontalSlider(rt, val, 1, 8);
GUI.Label(r1, "Current Global LOD is: " + val * 100);
GUI.Label(r2, "Current myShader LOD is: " + 800);
}
}
测试结果如下图,想要完整代码工程的留言吧。
2.渲染队列
渲染队列(renderQueue)决定了Unity渲染场景物体的先后顺序。
ZTest可以取的值有Greater/GEqual/Less/LEqual/Equal/NotEqual/Always/Never/Off,默认值为LEqual,通过比较深度来更改颜色缓存的值。eg:默认值LEqual的情况下,如果将要绘制的新像素的z值小于等于深度缓存中的值,则将用新像素的颜色值更新深度缓存中对应像素的颜色值。
renderQueue会改变物体被渲染的先后顺序,但不会改变物体的空间位置,对于ZTest为LEqual的,即使改变了renderQueue,作用也无法体现在渲染输出上;但是对于ZTest为Always就会影响最好的渲染输出。
unity内置的渲染队列:有5个默认适合于Queue的值,它们是Background、Geometry、AlphaTest、Transparent和
overlay,分别对应数值1000、2000、2450、3000和4000。
3.透明
Alpha检测用于在fragment函数完成最终的计算之后,在即将写入帧之前通过和—个固定的数值相比较,来决定当前fragment函数的计算结果要不要写入帧中。AlphaTest的比较条件有Greater、GEqual、Equal、NotEqual、Less、LEqual、Always和Never这8种情况,具体比较值可以运行时确定。
eg:
Properties {
_DstTex ("Dst Tex", 2D) = "white" {}
_SrcTex ("Src Tex", 2D) = "white" {}
_CutOff("_Cut Off",float)=0.5
}
SubShader {
Pass{
AlphaTest Off
SetTexture[_DstTex] {
combine texture alpha
}
}
Pass{
Blend SrcAlpha OneMinusSrcAlpha
AlphaTest GEqual [_CutOff]
SetTexture [_SrcTex] {
combine texture alpha
}
}
}
4.混合
Alpha Blend
用法eg:
Properties {
_DstTex ("DstTex", 2D) ="white"{}
_SrcTex ("SrcTex", 2D) ="white"{}
}
SubShader {
Pass{
SetTexture[_DstTex] {combine texture}
}
Pass {
BlendOp Sub//Min,Max,RevSub
Blend One One
SetTexture [_SrcTex] { combine texture}
}
Pass{//output Alpha to RGB
Blend DstAlpha zero
color(1,1,1,1)
}
}
5.通道遮罩
ColorMask,eg: ColorMask RG 渲染输出只写入RG通道,没有B通道和A通道。
使用:可以单独在一个Pass里产生遮罩,然后在后续Pass里使用,防止穿透
Properties {
_Color ("Main Color", Color) = (1,1,1,1)
}
SubShader {
Tags {"RenderType"="Opaque" "Queue"="Transparent"}
Pass {
ZWrite On
ColorMask 0
}
Pass {
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
ColorMask RGB
Material {
Diffuse [_Color]
}
Lighting On
SetTexture[_]{
Combine primary double
}
}
}
6.ZTest
之前讲过,渲染路径:VertexLit、Forward、Deferred。
默认情况下,只有在渲染路径是Deferred时,输出的_CameraDepthTexture才会有深度值。如果Z深度缓冲在当前的渲染路径下,在当前的硬件设备中不能直接取得,那么Unity会通过Shader Replacement的方法,单独在一个Pass中产生,(所谓的替代渲染),这时会用到RenderType。尽量给RenderType赋值。
Deferred渲染路径下,首先会渲染在Deferred模型下可渲染的材质,然后才是Forward或VertexLit渲染路径。
7.可以干预正常的ZTest,用Offset,只是修正,不是改缓冲中的值。
8.面剔除。可以实现描边,效果图如下。
左边的Cull Front,中间的Cull Back,右边的有两个Pass,第一个Pass用Cull Front,然后将球沿法线往外挤一些,第二个Pass用Cull Back,正常渲染,两个结合就有描边啦。精英怪就是这么实现的哦。
代码:
SubShader {
Cull Front
pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f{
float4 pos:SV_POSITION;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos=v.vertex;
o.pos.xyz+=v.normal*0.03;
o.pos=mul(UNITY_MATRIX_MVP,o.pos);
return o;
}
float4 frag(v2f i):COLOR
{
return (1,0,0,1);
}
ENDCG
}
pass{
Cull Back
Lighting On
Material{ Diffuse(1,1,1,1) }
}
}
9.抓屏
Properties {
_MainTex ("Base (RGB)", 2D) = "white" { }
}
SubShader {
GrabPass {
"_MyGrab"
}
pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MyGrab;
sampler2D _MainTex;
float4 _MainTex_ST;
struct v2f {
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
};
v2f vert (appdata_full v) {
v2f o;
o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
return o;
}
float4 frag(v2f i):COLOR
{
float4 c=tex2D(_MainTex,i.uv);
c=c*tex2D(_MyGrab,i.uv);
return c;
}
ENDCG
}
}
10.Stencil测试,在Fragment函数之前。