235 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			235 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
## 纯Shader
 | 
						||
- Uniform代表该变量在顶点与片元着色器中值都是相同的。
 | 
						||
- fixed:低精度数字,它们以精度来换取移动设备上的速度。在台式机上,fixed只是float的别名。
 | 
						||
 | 
						||
## 内置库
 | 
						||
- UnityShaderVariables.cginc定义了渲染所需的一堆着色器变量,例如变换,相机和光照数据。这些都在需要时由Unity设置。
 | 
						||
- HLSLSupport.cginc进行了设置,因此无论代码针对的是哪个平台,都可以使用相同的代码进行编写。无需担心使用特定于平台的数据类型等。
 | 
						||
- UnityInstancing.cginc专门用于实例化支持,这是一种减少绘制调用的特定渲染技术。尽管它不直接包含文件,但依赖于UnityShaderVariables。
 | 
						||
 | 
						||
## 关键字
 | 
						||
### PropertyType
 | 
						||
- Int
 | 
						||
- Float
 | 
						||
- Range
 | 
						||
- Color
 | 
						||
- Vector
 | 
						||
- 2D      texture
 | 
						||
- Cube    texture
 | 
						||
- 3D      texture
 | 
						||
 | 
						||
### SubShader
 | 
						||
针对不同性能的显卡适配不同的Shader。
 | 
						||
```
 | 
						||
SubShader{
 | 
						||
    [Tags]
 | 
						||
    
 | 
						||
    [RenderSetup]
 | 
						||
    
 | 
						||
    Pass{
 | 
						||
        
 | 
						||
    }
 | 
						||
}
 | 
						||
```
 | 
						||
### Fallback关键字
 | 
						||
Fallback关键词用于处理匹配失败的情况,指定一个用于处理这个情况的Pass或者直接跳过。
 | 
						||
 | 
						||
>FallBack Off
 | 
						||
 | 
						||
### CGPROGRAM与ENDCG
 | 
						||
里面编写这里编写HLSL/CG,对于VertexShader与PixelShader则写在SubShader的Pass关键字的{}中。
 | 
						||
 | 
						||
## 内置变量
 | 
						||
### 矩阵
 | 
						||
- UNITY_MATRIX_MVP
 | 
						||
- UNITY_MATRIX_MV
 | 
						||
- UNITY_MATRIX_P
 | 
						||
- UNITY_MATRIX_VP
 | 
						||
- UNITY_MATRIX_T_MV
 | 
						||
- UNITY_MATRIX_IT_MV
 | 
						||
- _Object2World
 | 
						||
- _World2Object
 | 
						||
- unity_WorldToObject
 | 
						||
 | 
						||
### 摄像机
 | 
						||
- WorldSpaceCameraPos
 | 
						||
- ProjectionParams
 | 
						||
- ScreenParams
 | 
						||
- ZBufferParams
 | 
						||
- unity_OrthoParams
 | 
						||
- unity_CameraProjection
 | 
						||
- unity_CameraInvProjection
 | 
						||
- unity_CameraWorldClipPlanes[6]
 | 
						||
 | 
						||
### 灯光
 | 
						||
- UNITY_LIGHTMODEL_AMBIENT
 | 
						||
- _WorldSpaceLightPos0
 | 
						||
 | 
						||
## 定义VS与PS名称
 | 
						||
```c++
 | 
						||
#pragma vertex vert
 | 
						||
#pragma fragment frag
 | 
						||
```
 | 
						||
## UnityCG.cginc
 | 
						||
### 常用结构体
 | 
						||
- appdata_base float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord: TEXCOORD0;
 | 
						||
- appdata_tan float4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0;	
 | 
						||
- appdata_full float4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; float4 texcoord1 : TEXCOORD1; float4 texcoord2 : TEXCOORD2; float4 texcoord3 : TEXCOORD3; # if defined(SHADER_API_XBOX360) half4 texcoord4 : TEXCOORD4; half4 texcoord5 : TEXCOORD5; # endif fixed4 color : COLOR;
 | 
						||
- appdata_img float4 vertex : POSITION; half2 texcoord : TEXCOORD0;
 | 
						||
- v2f_img 裁剪空间中的位置、纹理坐标
 | 
						||
 | 
						||
### 常用函数
 | 
						||
- float4 WorldSpaceViewDir(float4 v)输入一个模型空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向
 | 
						||
- float4 UnityWorldSpaceViewDir(float4 v)输入一个世界空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向
 | 
						||
- float4 ObjSpaceViewDir(float4 v)输入一个模型空间中的顶点位置,返回模型空间中从该店到摄像机的观察方向
 | 
						||
- float4 WorldSpaceLightDir(flaot4 v)仅用于向前渲染。 输入一个模型空间中的顶点位置,返回世界空间中从该点到光源的光照方向。没有被归一化
 | 
						||
- float4 ObjectSpaceLightDir(float4 v)仅用于向前渲染中,输入一个模型空间中的顶点位置, 返回模型空间中从该点到光源的光照方向。没有被归一化
 | 
						||
- float4 UnityWorldSpaceLightDir(float4 v)仅用于向前渲染中,输入一个世界空间中的顶点位置, 返回世界空间中从该点到光源的光照方向。没有被归一化
 | 
						||
- float3 UnityObjectToWorldNormal(float3 norm)把法线方向从模型空间中转换到世界空间中
 | 
						||
- float3 UnityObjectToWorldDir(float3 dir)把方向矢量从模型空间中变换到世界空间中
 | 
						||
- float3 Unity WorldToObjectDir(float3 dir)把方向矢量从世界空间变换到模型空间中
 | 
						||
 | 
						||
## 浮点格式
 | 
						||
float:32位
 | 
						||
half:16位 -60000~+60000
 | 
						||
fixed:11位 -2.0~+2.0
 | 
						||
 | 
						||
## 贴图
 | 
						||
`Sampler2D _MainTex`使用类似`float4 _MainTex_ST`作为缩放与位移。
 | 
						||
 | 
						||
## 管线LightMode
 | 
						||
定义在Pass内的Tag{}中。
 | 
						||
- Always:总是渲染,但不计算任何光照。
 | 
						||
- ForwardBase:用于前向渲染,该Pass会计算环境光、平行光、逐顶点SH与LightMap。
 | 
						||
- ForwardAdd:用于前向渲染,该Pass会计算额外的逐像素光源,每个Pass对应一个光源。
 | 
						||
- Deferred:用于延迟渲染,该Pass会计算GBuffer。
 | 
						||
- ShadowCaster:把物体的深度信息渲染ShadowMap或是一张深度纹理中。
 | 
						||
- PrepassBase:用于遗留的延迟渲染,该Pass会渲染法线和高光反射的指数部分。
 | 
						||
- PrepassFinal:用于遗留的延迟渲染,该Pass通过合并纹理、光照和自发光来渲染得到最终的颜色。
 | 
						||
- Vertex、VertexLMRGBM、VertexLM:用于遗留的顶点光照渲染。
 | 
						||
 | 
						||
## 不透明物体的渲染顺序
 | 
						||
1. 先渲染所有不透明物体,并开启深度测试与深度写入
 | 
						||
2. 把半透明物体按它距离摄像机的远近进行排序 ,然后按照从后往前的顺序渲染这些半透明物体,并开启它们的深度测试,但关闭深度写入。
 | 
						||
 | 
						||
### Unity3d的解决方案
 | 
						||
定义了5个渲染队列
 | 
						||
- Backgrouond
 | 
						||
- Geometry
 | 
						||
- AlphaTest
 | 
						||
- Transparent
 | 
						||
- Overlay
 | 
						||
 | 
						||
可以在Tags定义队列:
 | 
						||
```
 | 
						||
SubShader{
 | 
						||
    Tags{"Queue"="AlphaTest"}
 | 
						||
    Pass{
 | 
						||
        ZWrite Off
 | 
						||
    }
 | 
						||
}
 | 
						||
```
 | 
						||
 | 
						||
### Blend相关命令
 | 
						||
BlendOff
 | 
						||
BlendSrcFactorDstFactor
 | 
						||
BlendSrcFactorDstFactor,SrcFactorA DstFactorA
 | 
						||
BlendOp BlendOperation
 | 
						||
 | 
						||
### 混合操作
 | 
						||
1. Add
 | 
						||
2. Sub
 | 
						||
3. RevSub
 | 
						||
4. Min
 | 
						||
5. Max
 | 
						||
 | 
						||
### 常见的混合类型
 | 
						||
1. Blend SrcAlpha OneMinusSrcAlpha      正常
 | 
						||
2. Blend OneMinusDstColor One           柔和相加
 | 
						||
3. Blend DstColor Zero                  正片叠底
 | 
						||
4. Blend DstColor SrcColor              两倍相乘
 | 
						||
5. BlendOp Min Blend One One            变暗
 | 
						||
6. BlendOp Max Blend One One            变亮
 | 
						||
7. Blend One One                        线性减淡
 | 
						||
 | 
						||
### 解决半透明乱序问题
 | 
						||
1. 使用两个Pass来渲染模型,第一个Pass开启深度写入,但不输出颜色。第二个Pass进行正常的透明度混合。
 | 
						||
2. 双面渲染的透明效果
 | 
						||
 | 
						||
## 剔除命令
 | 
						||
Cull Back | Front | Off
 | 
						||
 | 
						||
## 内置时间变量
 | 
						||
- _Time:场景加载开始到现在的时间,4个分量为:t/20,t,2t,3t
 | 
						||
- _SinTime:时间的正弦值,4个分量为:t/8,t/4,t/2,t
 | 
						||
- _CosTime:时间的余弦值,4个分量为:t/8,t/4,t/2,t
 | 
						||
- untiy_DeltaTime:dt为时间的增量,4个分量为:dt,1/dt,SmoothDt,1/SmoothDt
 | 
						||
 | 
						||
## 预处理命令
 | 
						||
 | 
						||
### multi_compile
 | 
						||
`multi_compile`定义的宏,如`#pragma multi_compile_fog`,`#pragma multi_compile_fwdbase`等,基本上适用于大部分shader,与shader自身所带的属性无关。
 | 
						||
 | 
						||
### shader_feature
 | 
						||
`shader_feature`定义的宏多用于针对shader自身的属性。比如shader中有`_NormalMap`这个属性(Property),便可通`过#pragma shader_feature _NormalMap`来定义宏,用来实现这个shader在material有无`_NormalMap`时可进行不同的处理。
 | 
						||
 | 
						||
## 优化
 | 
						||
减少Draw Call的方式有动态合批与静态合批。Unity中支持两种批处理方式:一种是动态批处理,一种是静态批处理。对于动态批处理来说,有点是一切处理都是Unity自动完成的,不需要我们自己做任何操作,而且物体是可以移动的,但缺点是,限制很多,可能一不小心就会破坏了这种机制,导致Unity无法动态批处理一些使用了相同材质的物体。
 | 
						||
而对于静态批处理来说,它的优点是自由度很高,限制很少;但缺点是可能会占用更多的内存,而且经过静态批出里的所有物体都不可以再移动了。
 | 
						||
动态批处理的原理是,每一帧把可以进行批处理的模型网格进行合并,再把合并后模型数据传递给GPU,然后使用同一个材质对其渲染。处理实现方便,动态批处理的另一个好处是,经过批处理的物体仍然可以移动,这是由于在处理每帧时Unity都会重新合并一次网格。
 | 
						||
 | 
						||
### 共享材质
 | 
						||
将多张纹理合并到一起,并且制作成材质。
 | 
						||
 | 
						||
### 动态合批
 | 
						||
在使用同一个材质的情况下,满足的条件后就会被动态处理,每帧都会合并一次。条件:
 | 
						||
- 能够进行动态批处理的网格顶点属性规模要小于900.例如,如果Shader中需要使用顶点位置、法线和纹理坐标这3个顶点属性,那么想要让模型能够被动态批处理,它的顶点数目不能超过300。需要注意的是,这个数字未来有可能会发生变化,因此不要依赖这个数据。
 | 
						||
- 一般来说,所有对象都需要使用同一个缩放尺度。一个例外的情况是,如果所有的物体都使用了不同的非统一缩放,那么它们也是可以被动态批处理的。但在Unity 5 中,这种对模型缩放的限制已经不存在了。
 | 
						||
- 使用光照纹理的物体需要格外小心处理。这些物体需要额外的渲染参数,例如,在光照纹理上的索引、偏移量和缩放信息等。因此,为了让这些物体可以被动态批处理,我们需要保证它们指向光照纹理中的同一个位置。
 | 
						||
- 多Pass的Shader会中断批处理。在前向渲染中,我们有时需要使用额外的Pass来为模型添加更多的光照效果,但这样一来模型就会被动态批处理了。
 | 
						||
 | 
						||
### 静态合批
 | 
						||
在运行开始阶段,把需要进行静态批处理的模型合并到一个新的网格结构中。
 | 
						||
 | 
						||
## GeometryShader
 | 
						||
>ShaderModel必须4.0以上`#program target 4.0`,如果低于这个目标,u3d会自定提升至该级别。
 | 
						||
 | 
						||
- maxvertexcount定义输出顶点数,如果只是处理三角形只需要设置为3即可。
 | 
						||
- triangle为输入类型关键字。
 | 
						||
- TriangleStream为输出流类型。
 | 
						||
 | 
						||
```
 | 
						||
[maxvertexcount(3)]
 | 
						||
void MyGeometryProgram (
 | 
						||
	triangle InterpolatorsVertex i[3],
 | 
						||
	inout TriangleStream<InterpolatorsGeometry> stream
 | 
						||
)
 | 
						||
```
 | 
						||
 | 
						||
### Flat线框效果(CatLikeCoding中的案例)
 | 
						||
向三角形添加重心坐标的一种方法是使用网格的顶点颜色存储它们。每个三角形的第一个顶点变为红色,第二个顶点变为绿色,第三个顶点变为蓝色。但是,这将需要具有以此方式分配的顶点颜色的网格,并且无法共享顶点。我们想要一种适用于任何网格的解决方案。幸运的是,我们可以使用我们的几何程序添加所需的坐标。
 | 
						||
 | 
						||
由于网格不提供重心坐标,因此顶点程序不了解它们。所以,它们不属于InterpolatorsVertex结构。要使几何程序输出它们,我们必须定义一个新结构。首先在MyGeometryProgram上方定义InterpolatorsGeometry。它应包含与InterpolatorsVertex相同的数据,因此使用它作为其内容
 | 
						||
```hlsl
 | 
						||
struct InterpolatorsGeometry {
 | 
						||
	InterpolatorsVertex data;
 | 
						||
	CUSTOM_GEOMETRY_INTERPOLATORS
 | 
						||
};
 | 
						||
```
 | 
						||
- MyGeometryProgram的作用为调整按照面法线调整顶点法线;在调整barycentricCoordinates值,最后塞入inout TriangleStream<InterpolatorsGeometry>中。
 | 
						||
- GetAlbedoWithWireframe为线控效果控制,最终会在My Lighting.cginc中以宏替换的方式整合至渲染流程中。
 | 
						||
```hlsl
 | 
						||
float3 GetAlbedoWithWireframe (Interpolators i) {
 | 
						||
	float3 albedo = GetAlbedo(i);
 | 
						||
	float3 barys;
 | 
						||
	barys.xy = i.barycentricCoordinates;
 | 
						||
	barys.z = 1 - barys.x - barys.y;
 | 
						||
	float3 deltas = fwidth(barys);
 | 
						||
	float3 smoothing = deltas * _WireframeSmoothing;
 | 
						||
	float3 thickness = deltas * _WireframeThickness;
 | 
						||
	barys = smoothstep(thickness, thickness + smoothing, barys);
 | 
						||
	float minBary = min(barys.x, min(barys.y, barys.z));
 | 
						||
	return lerp(_WireframeColor, albedo, minBary);
 | 
						||
}
 | 
						||
```
 |