Unity ShaderLab基础
[原文1] [参考2]
一 基础知识
1. 1 着色器语言分类:
| 语言 | 说明 | 
|---|---|
| HLSL | 基于 OpenGL 的 OpenGL Shading Language | 
| GLSL | 基于 DirectX 的 High Level Shading Language | 
| CG | NVIDIA 公司的 C for Graphic | 
| Shader Lab | Unity封装了CG,HLSL,GLSL的Unity专用着色器语言,具有跨平台,图形化编程,便于与Unity通信等优点 | 
1.2 Mesh,材质,着色器与模型的关系
模型比作兔子,Mesh就是兔子的骨骼,顶点就是骨骼的各个节点,片元就是顶点组成的面,材质就是皮肉装饰片元的,Shader就是控制如何显示材质的
1.3 关于顶点,片元着色器
顶点着色器和片元着色器都有自己独立的硬件处理单元。该硬件处理单元拥有非常强大的并行运算能力,非常擅长矩阵计算,片元处理器还可以告诉查询纹理信息,顶点着色器负责定位像素位置/片元着色器负责修改像素颜色
顶点着色程序与片元着色程序通常是同时存在,相互配合,前者的输出作为后者的输入。不过,也可以只有顶点着色程序。如果只有顶点着色程序,那么只对输入的顶点进行操作,而顶点内部的点则按照硬件默认的方式自动插值。
例如,输入一个三角面片,顶点着色程序对其进行phong光照(实图形学中提出的第一个有影响的光照明模型)计算,只计算三个顶点的光照颜色,而三角面片内部点的颜色按照硬件默认的算法(Gourand明暗处理或者快速phong明暗处理)进行插值,如果图形硬件比较先进,默认的处理算法较好(快速phong明暗处理),则效果也会较好;如果图形硬件使用Gourand明暗处理算法,则会出现马赫带效应(条带化)。
而片元着色程序是对每个片元进行独立的颜色计算,并且算法由自己编写,不但可控性好,而且可以达到更好的效果。
由于GPU对数据进行并行处理,所以每个数据都会执行一次shader程序程序。即,每个顶点数据都会执行一次顶点程序;每个片元都会执行一次片段程序。
片元就是所有三维顶点在光栅化之后的数据集合,这些数据没有经过深度值比较,而屏幕显示的像素是经过深度比较的
1.4 顶点着色器、片元着色器与表面着色器的关系
顶点着色器负责顶点坐标变换,片元着色器负责像素的颜色计算。顶点着色器计算好坐标信息后传入片元着色器计算颜色。所以顶点着色器和片元着色器是合作关系。
 表面着色器是封装了顶点和片元着色器的新api。与他们属于上下层关系。
 shader编译时会将表面渲染代码编译成多个pass代码块,再分解成顶点/片元着色器。
1.5 区别
- 顶点着色器用于处理顶点。片段元色器用于处理面。
 - 表面着色器是对顶点着色器与片元着色器的进一步封装。即是说,表面着色器有一套即成的处理办法,不用去搞那些细节。
 - 顶点着色器和片元着色器更接近底层,可以处理一些细节问题。
 
1.6 着色器的工作流程

二 基础知识
2.1 基本结构
Shader "path/name" {Properties{//_CG变量名 ("unity可见的变量名", 属性类型) = 值_Color ("My Color", Color) = (1, 1, 1, .5) } Subshader{}} 
结构说明
- path/name: Unity编辑器检索位置和Shader名,Shader名和文件名尽量保持一致
 - Properties: Shader属性,用于cg变量与Unity通信
 - Subshader:shader解决方案。每个Shader程序包含至少一个Subshader,用于解决硬件性能兼容问题。Shader的主代码部分都写在这里
 
2.2 Properties
- 结构: _CG变量名(“Unity可见描述”, 属性类型) = 值
 - 例: _LineColor(“Line Color”, Color) = (1,1,1,0.5)
 - 属性列表
项目 | Value 
| 类型 | 实例 | 说明 | 
|---|---|---|
| Int | - | 整型 | 
| Float | - | 浮点型 | 
| Vector | - | 四维向量 | 
| Range | _Range(“Range”, x,y) | 范围x-y的浮点数,x<y | 
| Color | - | RGBA颜色 | 
| 2D | ”white”{} | 2d贴图, 2d纹理,默认值可以为一个代表默认tint颜色的字符串,可以是空字符串或者”white”,”black”,”gray”,”bump”中的一个 | 
| 3D | - | 3d贴图 | 
| Cube | - | 6面立方贴图 | 
| Rect | - | 矩形贴图 | 
2.3 SubShader
SubShader { Tags { "RenderType" = "Opaque" "ForceNoShadowCasting" = "True" "IgnoreProjector" = "True"}LOD 100Pass{Fog{Mode OFF}//固定渲染器Material{Diffuse[_Color]  //设置漫反射}Lighting OnSeparateSpecular On   //启用高光颜色//设置纹理SetTexture[_MainTex]//表面渲染器#pragma surface surf Lambert//顶点渲染器#pragma vertexvert//片段渲染器#pragma fragment frag}Pass{}
}
 
2.3.1 Tags
| 类型 | 说明 | 
|---|---|
| “RenderType”=“Opaque” | 系统在渲染不透明物体时调用该shader | 
| “RenderType” = “Transparent” | 系统在渲染透明物体时调用该shader,绝大部分透明的物体、包括粒子特效都使用这个 | 
| “RenderType” = “Background” | 系统渲染背景时调用,天空盒都使用这个 | 
| “RenderType” = “Overlay” | 系统渲染gui镜头时调用,GUI、镜头光晕都使用这个 | 
| “IgnoreProjector”=“True” | 忽略Projectors | 
| “ForceNoShadowCasting”=“True” | 不生成阴影 | 
| “Queue”=“xxx” | 指定渲染队列顺序,下面有详细说明 | 
2.3.2 Queue的说明
| 关键字 | 说明 | 值 | 
|---|---|---|
| Background | 最先调用的,用来渲染天空盒或背景 | 1000 | 
| Geometry | 默认值,用来渲染非透明物体(一般情况下,场景中的绝大多数物体应该是非透明的) | 2000 | 
| AlphaTest | 用来渲染经过Alpha Test的像素,单独为AlphaTest设定一个Queue是出于对效率的考虑 | 2450 | 
| Transparent | 以从后往前的顺序渲染透明物体 | 3000 | 
| Overlay | 用来渲染叠加的效果,是渲染的最后阶段(比如镜头光晕等特效) | 4000 | 
这些预定义的值本质上是一组定义整数,在我们实际设置Queue值时,不仅能使用上面的几个预定义值,我们也可以指定自己的Queue值,写成类似这样:“Queue”=“Transparent+100”,表示一个在Transparent之后100的Queue上进行调用。通过调整Queue值,我们可以确保某些物体一定在另一些物体之前或者之后渲染,这个技巧有时候很有用处。(比如遮挡描边效果,应该就是这么来的)
2.3.3 LOD
细节等级。大家玩吃鸡的时候,从飞机上跳下,这时看到地图上的建筑都是比较粗糙的块,当距离慢慢拉近,建筑模型变得越发精致,这就是LOD技术,根据不同的范围使用不同的模型。shader的LOD也是同样用法,不同细节等级,使用不同的LOD。在Unity的Quality Settings中可以设定最大LOD值,当当前LOD小于shader LOD时,那个sub shader就会失效.
| 关键字 | 值 | 
|---|---|
| VertexLit及其系列 | 100 | 
| Decal, Reflective VertexLit | 150 | 
| Diffuse | 200 | 
| Diffuse Detail | 250 | 
| Reflective Bumped Unlit | 250 | 
| Reflective Bumped VertexLit | 250 | 
| Bumped, Specular | 300 | 
| Bumped Specular | 400 | 
| Parallax | 500 | 
| Parallax Specular | 600 | 
2.3.4 pass
pass是实现着色器具体代码的地方。一个subshader内可以有多个pass。但尽可能用较少的pass实现是对性能的考虑。
2.3.4.1 pass内的tags说明
pass内的tags有别与subshader中的tags
| 取值 | 举例 | 说明 | 
|---|---|---|
| Always | “LightMode”=“Always” | 不管是用哪种渲染路径,该pass总是会被渲染。但不计算任何光照 | 
| Forwardbase | “LightMode”=“ForwardBase” | 用于向前渲染,该pass会计算环境光,重要的平行光,逐顶点/SH光源和lightmaps | 
| ForwardAdd | “LightMode”=“ForwardAdd” | 用于向前渲染,该pass会计算额外的逐像素光源,每个pass对应一个光源 | 
| Deferred | “LightMode”=“Deferred” | 用于向前渲染,该pass会渲染G缓冲,G-buffer | 
| ShadowCaster | “LightMode”=“ShadowCaster” | 把物体的深度信息渲染到盈盈映射纹理(shadowmap)或一张深度纹理中,用于渲染产生阴影的物体 | 
| ShadowCollector | “LightMode”=“ShadowCollector” | 用于收集物体阴影到屏幕坐标Buff里 | 
| PrepassBase | - | 用于遗留的延迟渲染,该pass会渲染法线和高光反射的指数部分 | 
| PrepassFinal | - | 用于遗留的延迟渲染,该pass通过合并纹理、光照和自发光来渲染得到最后的颜色 | 
| Vertex | - | 用于遗留的顶点照明渲染 | 
| VertexLMRGBM | - | 用于遗留的顶点照明渲染 | 
| VertexLM | - | 用于遗留的顶点照明渲染 | 
2.3.4.2 pass内的代码
| 管线 | 说明 | 
|---|---|
| 固定渲染管线 | 图形API提供了一个对硬件进行操作的标准接口;从内部实现上来说,API对程序员提出的各种绘制图元或属性的请求都采用固定的方式来处理 | 
| 可编程顶点/片元渲染管线 | - | 
| 可编程表面渲染管线 | (Scriptable Render Pipeline, SRP) 是 Unity 内置渲染管线的替代方案。 使用 SRP 可以通过 C# 脚本控制和定制渲染方式。稍微修改或完全构建并自定义渲染管线可满足需求 | 
2.3.4.3 pass内的pragma
pragma用于对渲染器的控制。参数表
| 命令 | 参数 | 实例 | 说明 | 
|---|---|---|---|
| vertex | - | #pragma vertex name | 将函数name的代码编译为顶点程序 | 
| fragment | - | #pragma fragment name | 将函数name的代码编译为片元程序 | 
| geometry | - | #pragma geometry name | 将函数name的代码编译为DX10的几何着色器 | 
| hull | - | #pragma hull name | 将函数name 的代码编译为DX11hull着色器 | 
| domain | - | #pragma domain name | 将函数name 的代码编译为DX11 domain着色器 | 
| fragmentoption option | - | #pragma fragmentoption option | 添加选项到编译的OpenGL片段程序。对顶点程序或编译目标不是opengl的程序无效 | 
| target | target 2.0、target 3.0、target 4.0、target 5.0 | #pragma target name | 设置着色器的编译目标,对应不同版本的着色器模型 | 
| only_renderers space separated | d3d9(direct3d 9)、d3d11、opengl、gles(opengl 2s 2.0)、xbox360、ps3、flash | #pragma only_renderers space separated names | 仅编译到指定的渲染平台 | 
| exclude_renderers space separated | d3d9(direct3d 9)、d3d11、opengl、gles(opengl 2s 2.0)、xbox360、ps3、flash | #pragma exclude_renderers space separated names | 不编译到指定的渲染平台 | 
| glsl | #pragma glsl | 为桌面系统的opengl进行编译时,将cg/hlsl代码转为glsl代码 | - | 
| glsl_no_auto_normalization | #pragma glsl_no_auto_normalization name | 编译到移动平台glsl时(ios/android), 关闭在定点着色器中对法线向量和切线向量自动进行规范化 | - | 
2.3.5 着色器中的参数
从应用阶段传递模型数据给顶点着色器时 常用的语义
| 命令 | 说明 | 
|---|---|
| POSITION | 模型空间中的顶点位置,一般是float4类型 | 
| NORMAL | 顶点法线,float3类型 | 
| TANGENT | 顶点切线 float4 | 
| TEXCOORD0~N | 该顶点纹理坐标,0是第一组,一般是flkoat2 或float4类型 | 
| COLOR | 定点颜色,通常是fixed4或float4类型 | 
2.3.6 从顶点着色器传递给片元着色器时 常用的语义
| 命令 | 说明 | 
|---|---|
| SV_POSITION | 裁剪空间中的顶点坐标,结构体中必须包含一个用该语义修饰的变量 | 
| COLOR0 | 用于输出第一组顶点颜色 | 
| COLOR1 | 通常用于输出第二组顶点颜色 | 
| TEXCOORD0~TEXCOORD7 | 通常用于输出纹理坐标 | 
2.3.7 片元着色器输出给unity时常用的语义
| 命令 | 说明 | 
|---|---|
| SV_Target | 输出值将会存到渲染目标(render target)中 | 
2.3.8 unity 内置的矩阵变换
| 命令 | 说明 | 
|---|---|
| UNITY_MATRIX_MVP | 模型观察投影矩阵,用于将顶点/方向矢量从模型空间变换到裁剪空间 | 
| UNITY_MATRIX_MV | 模型观察矩阵,用于将顶点/方向矢量从模型空间变换到观察空间 | 
| UNITY_MATRIX_V | 观察矩阵,用于将顶点/方向矢量从世界空间变换到观察空间 | 
| UNITY_MATRIX_P | 投影矩阵,用于将顶点/方向矢量从观察空间变换到裁剪空间 | 
| UNITY_MATRIX_VP | 观察投影矩阵,用于将顶点/方向矢量从世界空间变换到裁剪空间 | 
| UNITY_MATRIX_T_MV | UNITY_MATRIX_MV 的转置矩阵 | 
| UNITY_MATRIX_IT_MV | UNITY_MATRIX_MV的逆转置矩阵,用于将法线从模型空间变换到观察空间,也可以用于得到UNITY_MATRIX_MV的逆矩阵 | 
| _Object2World | 模型矩阵,用于将顶点/方向矢量从模型空间变换到世界空间 | 
| _World2Object | _Object2World的逆转矩阵,用于将顶点/方向矢量从世界空间变换到模型空间 | 
2.4 Shader函数及变量
2.4.1 unity 顶点转换函数
| 命令 | 实例 | 
|---|---|
| float4 UnityObjectToClipPos(float3 pos) | 从object空间转换成相机在均匀坐标下的剪辑空间。与 mul(UNITY_MATRIX_MVP, float4(pos, 1.0)) 等价 | 
| float3 UnityObjectToViewPos(float3 pos) | 从object空间转换为view空间。与 mul(UNITY_MATRIX_MV, float4(pos, 1.0)).xyz 等价 | 
2.4.2 辅助函数
| 函数 | 实例 | 
|---|---|
| float2 ParallaxOffset (half h, half height, half3 viewDir) | 为视差法线贴图计算UV偏移 | 
| fixed Luminance (fixed3 c) | 将颜色转换为亮度(灰度) | 
| fixed3 DecodeLightmap (fixed4 color) | 从Unity光照贴图解码颜色(基于平台为RGBM 或dLDR) | 
| float4 EncodeFloatRGBA (float v) | 为储存低精度的渲染目标,编码[0…1)范围的浮点数到RGBA颜色。 | 
| float DecodeFloatRGBA (float4 enc) | 解码RGBA颜色到float。 | 
| float2 EncodeFloatRG (float v) | 为储存低精度的渲染目标,编码[0…1)范围的浮点数到RGBA颜色,使用的是两个颜色通道。 | 
| float DecodeFloatRG (float2 enc) | 解码RGBA颜色到float。使用的是两个颜色通道。 | 
| float2 EncodeViewNormalStereo (float3 n) | 编码视图空间法线到在0到1范围的两个数。 | 
| float3 DecodeViewNormalStereo (float4 enc4) | 从enc4.xy解码视图空间法线 | 
2.4.3 unity 内置的摄像机和屏幕参数
| 命令 | 说明 | 
|---|---|
| float3 _WorldSpaceCameraPos | 该摄像机在世界空间中的位置 | 
| float4 _ProjectionParams | x=1.0 或-1.0(使用反转的投影矩阵渲染时是负数),y=Near,z=Far,w= 1.0+1.0/Far, 其中near和far分别是近裁剪平面和远裁剪平面与摄像机的距离 | 
| float4 _ScreenParams | x=width,y=height,z=1.0+1.0/width,w=1.0+1.0/height, 其中width和height分别是该摄像机的渲染目标 (render target)的像素宽度和高度 | 
| float4 _ZBufferParams | x=1-Far/near,yFar/Near, 最x/Far,wy/Far,该变量用于线性化Z缓存中的深度值 | 
| floart4 unity_OrhoParams | x=width,y=height,z无意义,w=1.0(该相机是正交相机)或w=0.0(透视相机),其中width和height是正交投影相机的宽和高 | 
| float4x4 unity_CameraProjection | 该摄像机的投影矩阵 | 
| floart4x4 unity_CameraInvProjection | 该摄像机的投影矩阵的逆矩阵 | 
| float4 unity_CameraWorldClipPlanes | 该摄像机的6个裁剪屏幕在世界空间下的等式,按左右上下近远的顺序裁剪平面 | 
2.4.4 时间变量
| 命令 | 说明 | 
|---|---|
| float4 _Time | 自该场景加载开始所经过的时间,(x,y,z,w)分别是t/20,t,2t,3t | 
| float4 _SinTime | 时间的正弦制,(x,y,z,w)分别是t/8,t/4,t/2,t | 
| float4 _Costime | 时间的余弦值,(x,y,z,w)分别是t/8,t/4.t/2,t | 
| float4 unity_DeltaTime | 时间增量,(x,y,z,w)分别是t,1/t,smoothDt,1/smoothDt | 
2.4.5 光照相关参数
前向渲染(ForwardBase 和 ForwardAdd 通道类型):
| 参数名 | 描述 | 
|---|---|
| fixed4 _LightColor0 (在 Lighting.cginc 中声明) | 光源颜色。 | 
| float4 _WorldSpaceLightPos0 | 方向光:(世界空间方向,0)。其他光源:(世界空间位置,1)。 | 
| float4x4 _LightMatrix0 | (在 AutoLight.cginc 中声明) 世界/光源矩阵。用于对剪影和衰减纹理进行采样。 | 
| float4 unity_4LightPosX0、unity_4LightPosY0、unity_4LightPosZ0 | (仅限 ForwardBase 通道)前四个非重要点光源的世界空间位置。 | 
| float4 unity_4LightAtten0 | (仅限 ForwardBase 通道)前四个非重要点光源的衰减因子。 | 
| half4[4] unity_LightColor | (仅限 ForwardBase 通道)前四个非重要点光源的颜色。 | 
| float4x4[4] unity_WorldToShadow | 世界/阴影矩阵。聚光灯的一个矩阵,方向光级联最多有四个矩阵。 | 
延迟着色和延迟光照,在光照通道着色器中使用(全部在 UnityDeferredLibrary.cginc 中声明):
| 参数名 | 描述 | 
|---|---|
| fixed4 unity_AmbientSky | 梯度环境光照情况下的天空环境光照颜色。 | 
| fixed4 unity_AmbientEquato | 梯度环境光照情况下的赤道环境光照颜色。 | 
| fixed4 unity_AmbientGround | 梯度环境光照情况下的地面环境光照颜色。 | 
| fixed4 UNITY_LIGHTMODEL_AMBIENT | 环境光照颜色(梯度环境情况下的天空颜色)。旧版变量。 | 
| fixed4 unity_FogColor | 雾效颜色。 | 
| float4 unity_FogParams | 用于雾效计算的参数:(density / sqrt(ln(2))、density / ln(2)、–1/(end-start) 和 end/(end-start))。x 对于 Exp2 雾模式很有用;y 对于 Exp 模式很有用,z 和 w 对于 Linear 模式很有用。 | 
2.4.6 与颜色空间相关
| 函数名 | 描述 | 
|---|---|
| bool IsGammaSpace() | 根据宏UNITY_COLORSPACE_GAMMA是否被启用了,判断当前是否启用了伽马颜色空间。 | 
| float GammaToLinearSpaceExact (float value) | 把一个颜色值精确地从伽马颜色空间(sRGB颜色空间)变化到线性空间(CIE-XYZ颜色空间)。 | 
| half3 GammaToLinearSpace (half3 sRGB) | 用一个近似模拟的函数把颜色值近似地从伽马空间变换到线性空间。 | 
| float LinearToGammaSpaceExact (float value) | 把一个颜色值精确地从线性空间变换到伽马颜色空间。 | 
| half3 LinearToGammaSpace (half3 linRGB) | 用一个近似模拟的函数把颜色值近似地从线性空间变换到伽马颜色空间。 | 
2.4.7 数学常数
#ifndef UNITY_CG_INCLUDED#define UNITY_CG_INCLUDED#define UNITY_PI 3.14159265359f //圆周率#define UNITY_TWO_PI 6.28318530718f //2倍圆周率#define UNITY_FOUR_PI 12.56637061436f //4倍圆周率#define UNITY_INV_PI 0.31830988618f //圆周率的倒数#define UNITY_INV_TWO_PI 0.15915494309f //2倍圆周率的倒数#define UNITY_INV_FOUR_PI 0.07957747155f //4倍圆周率的倒数#define UNITY_HALF_PI 1.57079632679f //半圆周率#define UNITY_INV_HALF_PI 0.636619772367f //半圆周率的倒数
 
2.5 UnityCG.cginc 库
UnityCG.cginc 该文件中包含了很多即成的参数方法。使用十分方便
CGPROGRAM
#include "UnityCG.cginc"
ENDCG
 
2.5.1 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 | 顶点位置 顶点切线 顶点法线 多组纹理坐标  | cfloat4 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 | 裁剪空间中的位置 纹理坐标  | - | 可用于顶点着色器的输出 | 
2.5.2 unitycg.cginc 常用函数
| 函数 | 说明 | 
|---|---|
| float4 UnityWorldToClipPos(float3 pos) | 世界坐标空间中的点pos变换到齐次裁剪空间 | 
| float4 UnityViewToClipPos(float3 pos) | 观察坐标空间中点pos变换到齐次裁剪空间 | 
| float3 UnityObjectToViewPos(float3 pos或float4 pos) | 模型局部空间坐标系中某一个点pos变换到观察空间坐标系 | 
| float3 UnityWorldToViewPos(float3 pos) | 把世界坐标系下的点pos变换到观察空间坐标系 | 
| float3 UnityObjectToWorldDir(float3 dir) | 把方向矢量从模型空间转换到世界空间(方向已单位化) | 
| float3 UnityWorldToObjectDir(float3 dir) | 把方向矢量从世界空间转换到模型空间(方向已单位化) | 
| float3 UnityObjectToWorldNormal(float3 norm ) | 将法线从模型空间转换到世界空间(方向已单位化) | 
| float3 UnityWorldSpaceLightDir(float3 worldPos) | 输入参数worldPos是一个世界坐标系下的坐标,得到世界空间中从该点到光源(_WorldSpaceLightPos0)的光照方向。(方向没单位化) | 
| float3 WorldSpaceLightDir(float4 localPos) | 输入一个模型顶点坐标,得到世界空间中从该点到光源(_WorldSpaceLightPos0)的光照方向。(方向没单位化) | 
| float3 ObjSpaceLightDir(float4 v) | 输入一个模型顶点坐标,得到模型空间中从该点到光源(_WorldSpaceLightPos0)的光照方向。(方向没单位化) | 
| float3 UnityWorldSpaceViewDir(float3 worldPos) | 输入参数worldPos是一个世界坐标系下的坐标,得到世界空间中从该点到摄像机的观察方向。(方向没单位化) | 
| float3 WorldSpaceViewDir(float4 localPos) | 输入一个模型顶点坐标,得到世界空间中从该点到摄像机的观察方向。(方向没单位化) | 
| float3 ObjSpaceViewDir(float4 v) | 输入一个模型顶点坐标,得到模型空间中从该点到摄像机的观察方向。(方向没单位化) | 
2.5.3 屏幕空间相关函数
| 函数 | 说明 | 
|---|---|
| float4 ComputeScreenPos (float4 clipPos) | 计算用于执行屏幕空间贴图纹理采样的纹理坐标。输入是裁剪空间位置。 | 
| float4 ComputeGrabScreenPos (float4 clipPos) | 计算用于 GrabPass 纹理采样的纹理坐标。输入是裁剪空间位置。 | 
2.5.4 shader数学函数:
| 函数 | 说明 | 实例 | 
|---|---|---|
| abs(x) | 绝对值 | - | 
| acos(x) | arc cosine,返回弧度 [0, PI] | - | 
| all(bvecX) | 所有分量是true(非0), 则true | - | 
| any(bvecX) | 只要有一个分量是true(非0), 则true | - | 
| asin(x) | arc sine, 返回弧度 [-PI/2, PI/2]; | - | 
| atan(y, x) | arc tangent, 返回弧度 [-PI, PI]; | - | 
| atan(y/x) | arc tangent, 返回弧度 [-PI/2, PI/2]; | - | 
| ceil(x) | 顶部取整 | - | 
| clamp(x, min, max) | x<=a,返回a;x>=b,返回b;否则,返回x | - | 
| cosh(x) | 双曲余弦(hyperbolic cosine)函数,计算x的双曲余弦值。 | - | 
| cross(x, y) | 差积 | 结果(x[1]*y[2]-y[1]*x[2], x[2]*y[0] - y[2]*x[0], x[0]*y[1] - y[0]*x[1])  | 
| degrees(radian) | 弧度变角度 | - | 
| determinant(m) | 计算矩阵的行列式因子 | - | 
| distance(p0, p1) | 两点距离, length(p0-p1); | - | 
| dot(x, y) | 点积,各分量分别相乘 后 相加 | - | 
| equal(vecX, vecY) | 向量 每个分量比较 x==y | - | 
| exp(x) | 指数, log(x) | - | 
| exp2(x) | 2的x次方, log2(x) | - | 
| frac(x) | 返回标量或矢量的小数 | - | 
| faceforward(N, I, Nref) | 如 dot(Nref, I)< 0则N, 否则 -N | |
| floor(x) | 底部取整 | - | 
| fmod(x,y) | 取模 | - | 
| fract(x) | 取小数部分 | - | 
| frexp(x, out i) | 将浮点数 x 分解为尾数和指数,即 x = m* 2^exp,返回 m,并将指数存入 exp 中;如果 x 为 0,则尾数和指数都返回 0 | - | 
| greaterThan(vecX, vecY) | 向量 每个分量比较 x>y | - | 
| greaterThanEqual(vecX, vecY) | 向量 每个分量比较 x>=y | - | 
| ldexp(x, n) | 计算x∗2n的值 | - | 
| length(x) | 向量长度 | - | 
| lerp(a, b, f) | 计算或者的值。即在下限a和上限b之间进行插值,f表示权值。注意,如果a和b是向量,则权值f必须是标量或者等长的向量。 | - | 
| lessThan(vecX, vecY) | 向量 每个分量比较 x < y | - | 
| lessThanEqual(vecX, vecY) | 向量 每个分量比较 x<=y | - | 
| inversesqrt(x) | x根号的倒数 | - | 
| isfinite(x) | 判断标量或者向量中的每个数据是否是有限数,如果是返回true;否则返回false; | - | 
| isinf(x) | 判断标量或者向量中的每个数据是否是无限,如果是返回true;否则返回false; | - | 
| isnan(x) | 判断标量或者向量中的每个数据是否是非数据(not-a-number NaN),如果是返回true;否则返回false; | - | 
| lit(NdotL, NdotH, m) | 函数计算环境光、散射光、镜面光的贡献,返回的4元向量。 N表示法向量; L表示入射光向量; H表示半角向量; m表示高光系数。 X位表示环境光的贡献,总是1.0; Y位代表散射光的贡献,如果 N∙L<0,则为0;否则为N∙L Z位代表镜面光的贡献,如果N∙L<0 或者N∙H<0,则位0;否则为(N∙L)m; W位始终位1.0  | - | 
| log(x) | 计算2x的值 | - | 
| log2(x) | 计算log2(x)的值,x必须大于0 | - | 
| log10(x) | 计算lg2(x)的值,x必须大于0 | - | 
| max(x, y) | 取最大值 | - | 
| matrixCompMult(matX, matY) | 矩阵相乘, 每个分量 自行相乘 | r[j] = x[j]*y[j]; | 
| min(x, y) | 取最小值 | - | 
| mix(x, y, a) | x, y的线性混叠, x(1-a) + y*a; | - | 
| mod(x, y) | 取模, x - y*floor(x/y) | - | 
| modf(x, out ip) | 将浮点数 x 分解为尾数和指数,即 x = m* 2^exp,返回 m,并将指数存入 exp 中;如果 x 为 0,则尾数和指数都返回 0 | - | 
| mul(M, N) | 矩阵M和矩阵N的积 | - | 
| mul(M, v) | 矩阵M和列向量v的积 | - | 
| mul(v, M) | 行向量v和矩阵M的积 | - | 
| noise(x) | 根据它的参数类型,这个函数可以是一元、二元或三元噪音函数。返回的值在0和1之间,并且通常与给定的输入值一样 | - | 
| normalize(x) | 归一化 | length(x)=1; | 
| not(bvecX) | 所有分量取反 | - | 
| notEqual(vecX, vexY) | 向量 每个分量比较 x!=y | - | 
| pow(x, y) | x的y次方 | - | 
| radians(degree) | 角度变弧度(一般默认都用弧度) | - | 
| reflect(I, N) | I的反射方向 I -2*dot(N, I)*N, N必须先归一化 | - | 
| refract(I, N, eta) | 折射 | k=1.0-etaeta(1.0 - dot(N, I) * dot(N, I)); 如k<0.0 则0.0, 否则 etaI - (etadot(N, I)+sqrt(k))*N  | 
| round(x) | 四舍五入 | - | 
| rsqrt(x) | x的平方根的倒数,x必须大于0 | - | 
| saturate(x) | 把x限制到[0,1]之间 | - | 
| sign(x) | 取当前数值的正负符号,返回 1, 0 或 -1 | (x>0;x=0;x<0) | 
| sin(angle), cos(angle), tan(angle) | 三角函数(正弦,余弦,正切) | - | 
| sincos(float x, out s, out c) | 该函数是同时计算x的sin值和cos值,其中s=sin(x),c=cos(x)。 该函数用于“同时需要计算sin值和cos值的情况”,比分别运算要快很多!  | - | 
| sinh(x) | 计算x的双曲正弦 | - | 
| smoothstep(min, max, x) | 值x位于min、max区间中。 如果x=min,返回0; 如果x=max,返回1; 如果x在两者之间,按照下列公式返回数据: –2∗((x–min)/(max–min))3+3∗((x–min)/(max–min))/2 float smoothstep(float a, float b, float x) { float t = saturate((x - a)/(b - a)); return tt(3.0 - (2.0*t)); }  | - | 
| sqrt(x) | x的根号; | - | 
| step(edge, x) | 如果x<a, 返回0;否则返回1 | - | 
| tanh(x) | 计算x的双曲线切线 | - | 
| transpose(M) | 返回M(AxB)的转置矩阵m(BxA)矩阵 | - | 
三 着色器实例
3.1 固定渲染管线
固定功能管线着色器的关键代码都在Pass的材质设置Material{}和纹理设置SetTexture{}部分。
 目前固定着色器已经逐渐退出市场,只在为兼容一些老旧硬件设备而存在。
Shader "Custom/VertexList"{Properties{//设置与Unity通信的变量,用来通过Unity编辑器获取素材资源和参数_Color("Main Color", Color) = (0,1,1,0.5)_SpecColor("Space Color", Color) = (1,1,1,1)_Emission("Emission Color", Color) = (0,0,0,0)_Shininess("Shininess", Range(0.01, 1)) = 0.7_MainTex("Base (RGB)", 2D) = "white"{}}//PropertiesSubShader{Pass{Material{Diffuse[_Color] //设置漫反射Ambient[_Color] //环境光Shininess[_Shininess]  //设置光泽度Specular[_SpecColor]  //设置高光Emission[_Emission]   //自发光}//MaterialLighting OnSeparateSpecular On //启用高光SetTexture[_MainTex]{constantColor[_Color]  //设置颜色常量//混合命令combine texture * primary DOUBLE,texture *constant}//SetTexture[_MainTex]}//Pass}//SubShader
}//
 
3.2 定点/片元着色器
功能强大,用途广
 顶点/片段渲染管线 卸载pass块中,用CGPROGRAM 标签包裹。
Shader "Custom/ChestVertex"
{Properties {_MainTex("Texture", 2D) = "white"{}_ScreenFix("ScreenFix", Range(0.01, 0.5)) = 0.25}SubShader {pass {CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma target 3.0//该结构没有SV_POSITIONstruct v2f{float2 uv : TEXCOORD;};sampler2D _MainTex;float _ScreenFix;v2f vert(float4 vertex : POSITION,//顶点位置输入float2 uv : TEXCOORD,//纹理坐标输入out float4 outpos: SV_POSITION)//裁切空间位置输出{v2f o;o.uv = uv;outpos = UnityObjectToClipPos(vertex);return o;}//vert// UNITY_VPOS_TYPE:在不同平台,屏幕空间位置输入的基础类型会有所不同 // 获取可移植性(多数平台为float4, Direct3D 9上float2)// VPOS是在着色器模型 3.0 开始存在,指定版本: #pragma target 3.0fixed4 frag(v2f i, UNITY_VPOS_TYPE screenPos : VPOS): SV_Target{// screenPos.xy 包含像素实现渲染 8*8 的像素块棋盘图案// 棋盘图案中 8*8 像素块的 checker 值为负screenPos.xy = floor(screenPos.xy * _ScreenFix) * 0.5;float checher = -frac(screenPos.r + screenPos.g);// 如果为负数,则使用Clip HLSL指令停止渲染像素clip(checher);// 对于保留的像素,读取纹理并将其输出fixed4 c = tex2D(_MainTex, i.uv);return c;} //fragENDCG}//pass}//SubShader
}
 
3.3 表面渲染管线
在Unity中,表面着色器的关键代码用Cg/HLSL语言编写,然后嵌在ShaderLab的结构代码中使用。使用表面着色器,用户仅需要编写最关键的表面函数,其余周边代码将由Unity自动生成,包括适配各种光源类型、渲染实时阴影以及集成到前向/延迟渲染管线中等。
 光照模型可以是内置的Lambert和BlinnPhong,或者是自定义的光照模型。
 表面函数的作用是接收输入的UV或者附加数据,然后进行处理,最后将结构填充到输出结构体SurfaceOutPut中。
3.3.1 表面着色器的输入参数表
| 数据类型 | 参数 | 说明 | 
|---|---|---|
| float3 | viewDir | 视角方向 | 
| float4 | COLOR | 每个顶点的插值颜色 | 
| float4 | screenPos | 屏幕坐标(使用.xy/.w来获得屏幕2D坐标) | 
| float3 | worldPos | 世界坐标 | 
| float3 | worldRefl | 世界坐标系中的反射向量 | 
| float3 | worldNormal | 世界坐标系中的法线向量 | 
| - | INTERNAL_DATA | 当输入结构包含worldRefl或worldNormal且表面函数会写入输出结构的Normal字段是需包含此声明 | 
3.3.2 表面着色器的输出参数表
struct SurfaceOutput{half3 Albedo;//反射光half3 Normal;//法线half3 Emission;//自发光half Specular;//高光half Gloss;//光泽度half Alpha;//透明度
};
 
3.3.2 实例
Shader "Custom/surfShader"
{Properties{_Color("Main Color",Color) = (1,1,1,1)_MainTex("Base",2D) = "white"{}_BumpMap("Normalmap",2D) = "bump"{}}SubShader{//当系统渲染不透明物体时 调用该shaderTags{"RenderType" = "Opaque"}LOD 300//表面着色器代码块  不放在pass中,编译后会分放至各个pass中CGPROGRAM//定义着色器类型为surface(表面着色器),并使用光照模型Lambert#pragma surface surf Lambert //编译指令#pragma target 3.0 //制定着色器版本sampler2D _MainTex;sampler2D _BumpMap;fixed4 _Color;//定义输入数据的结构体struct Input{float2 uv_MainTex;float2 uv_BumpMap;};//定义输出数据的结构体//struct SurfaceOutput{//		    half3 Albedo;//反射光//		    half3 Normal;//法线//		    half3 Emission;//自发光//		    half Specular;//高光//		    half Gloss;//光泽度//		    half Alpha;//透明度//    };void surf(Input IN,inout SurfaceOutput o){fixed4 tex = tex2D(_MainTex,IN.uv_MainTex);o.Albedo = tex.rgb * _Color.rgb;o.Alpha = tex.a * _Color.a;o.Normal = UnpackNormal(tex2D(_BumpMap,IN.uv_BumpMap));}ENDCG}Fallback "Diffuse"//备选着色器
}
 
3.4 着色器效果集
3.4.1 描边着色器
Shader "Custom//UnlitShader"
{Properties{//定义与unity通信的变量名_MainColor("Main Color", Color) = (0.5,0.5,0.5,1)_OutlineColor("Outline Color",Color) = (0,0,0,1)   //轮廓颜色_Outline("Outline width",Range(0.0,10)) = 0.005    //轮廓线宽度}SubShader{Tags { "RenderType"="Transparent" }LOD 100//固定管线渲染器。背面剔除,并在深度缓冲区中留下背面剔除的深度值Pass{Name "BASE"//剔除背面Cull Back//保存缓冲区Blend Zero OneSetTexture[_OutlineColor]{ConstantColor(1,0,0,0)Combine constant}}//顶点/片段着色器。正面剔除,那些经过法线伸展后的点会因为与深度剔除的缓存值比较后无法通过而被剔除//也就是说仅仅剩下正面与背面的边缘处因为伸展的原因保留了下来,  于是轮廓就出现了,这就是大体过程了Pass{Name"OUTLINE"Tags{"LightMode" = "Always"}Cull FrontBlend One OneMinusDstColor//顶点片元着色器代码CGPROGRAM#pragma vertex vert #pragma fragment frag //引入unitycg库#include "UnityCG.cginc"//定义从应用到顶点着色器的数据,此处用于获取顶点位置信息和法线信息struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;};//定义顶点着色器输出给片元着色器的数据,此处输出片元位置,及颜色struct v2f{float4 pos :POSITION;float4 color : COLOR;};uniform float _Outline;uniform float4 _OutlineColor;//顶点着色器程序块v2f vert(appdata v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);float3 norm = mul((float3x3)UNITY_MATRIX_IT_MV,v.normal);float2 offset = TransformViewToProjection(norm.xy);o.pos.xy += offset * o.pos.z* _Outline;o.color = _OutlineColor;return o;}//片段着色器代码块half4 frag(v2f i) :COLOR{return i.color;}ENDCG}}
} 
3.5 三大测试与剔除、透明混合
- 深度测试
 - 透明度测试
 - 模板测试
重点:三大测试与剔除都是决定是否显示像素条件!混合是指有透明物体的情况下像素该如何叠加显示
深度测试依据物体在镜头前的空间位置排序。
透明测试依据颜色透明度,也就是alpha值。
模版测试依据自定义的值,当同样带有模版值的元素叠加时触发
剔除与三种测试渲染顺序按先后排列。 
3.5.1 AlphaTest 透明测试
| 命令 | 说明 | 实例 | 
|---|---|---|
| Greater | 大于,只渲染大于该值的像素 | alphatest greater [_alphaValue] //类似于抠图 | 
| Less | 小于,只渲染小于该值的像素 | 类似于反向抠图 | 
| GEqual | 大于等于 | - | 
| LEqual | 小于等于 | - | 
| Equal | 等于 | - | 
| NotEqual | 不等于 | - | 
| Always | 总是 | - | 
| Never | 永不 | - | 
| Off | 关闭 | alphatest Off | 
实例1: 表面着色器
//只要声明 alphatest greater [_alphaValue] 即可。
Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_alphaValue("alphavalue",range(0,1))=0.3}SubShader {Pass{alphatest greater [_alphaValue]CGPROGRAM...............ENDCG}}
 
实例2: 片元着色器
fixed4 frag(v2f i):SV_Target{fixed4 texColor = tex2D(_MainTex, i.uv);clip(texColor.a - _Cutoff);//等同于//if((texColor.a - _Cutoff)<0.0){//	discard;//}
}
 
3.5.2 Blend 透明度混合
混合命令:
| 指令 | 说明 | 
|---|---|
| Blend Off | 关闭混合 | 
| Blend SrcFactor DstFactor | 开启混合,并设置混合因子,片元颜色胡i成因SrcFactor,而已经存在颜色缓存中的颜色会诚意DstFactor,然后把两者相加后再存入颜色缓冲中 | 
| Blend SrcFactor DstFactor, SrcFactorA DstFactorA | 上同,使用不同因子来混合透明通道 | 
| BlendOp BlendOperation | 并非是把源颜色和目标颜色简单相加后混合,而是使用BlendOperation对他们进行其他操作 | 
混合因子:
| 指令 | 说明 | 
|---|---|
| One | 因子值为1 | 
| Zero | 因子值为0 | 
| SrcColor | 因子为源颜色值(当前片元),当用于混合rgb时,使用SrcColor的RGb分量作为混合因子,当用于混合a的混合时,使用SrcColor的A分量作为混合因子 | 
| SrcAlpha | 因子为源颜色的透明度,A通道 | 
| DstColor | 因子为目标颜色(已经存在颜色缓存中的颜色),当用于混合rgb时,使用DstColor的RGb分量作为混合因子,当用于混合a的混合等式时,使用DstColor的A分量作为混合因子 | 
| DstAlpha | 因子为源颜色的透明度,A通道 | 
| OneMinusSrcColor | 因子 = 1 - 源颜色,其余与SrcColor相同 | 
| OneMinusSrcAlpha | 因子 = 1 - 源颜色的透明度值 | 
| OneMinusDstColor | 因子 = 1 - 目标颜色,其余与DstColor相同 | 
| OneMinusDstAlpha | 因子 = 1 - 目标颜色透明度 | 
混合操作 BlendOp:
| 指令 | 说明 | 
|---|---|
| Add | 将混合后的源颜色和目标颜色相加 | 
| Sub | 将混合后的源颜色减去混合后的目标颜色 | 
| RevSub | 用混合后的目标颜色减去混合后的源颜色 | 
| Min | 使用源颜色和目标i颜色中较小的值 | 
| Max | 使用源颜色和目标颜色中较大的值 | 
| Blend SrcAlpha OneMunusSrcAlph | 正常 | 
| Blend OneMinusDstColor One | 柔和相加 | 
| Blend DstColor Zero | 正片叠底 | 
| Blend DstColor SrcColor | 两倍相乘 | 
| BlendOp Min | 变暗 | 
| BlendOp Max | 变亮 | 
| Blend One One | 线性减淡 | 
| Blend OneMinusDstColor One | 滤色,等偶同于Blend One OneMinusSrcColor | 
3.5.3 StencilTest 模板测试
模板测试,每个像素都有一个stencil值,在同一个像素上,所有shader的stencil都共享这一个值,当有其他带有遮罩像素与其重合时就能获取到该值,并根据自身的stencil值处理。典型的应用就是遮罩显示。你可以选择每次重合都增加1,然后再指定某个物体,当值达到某个数量级再显示。这样的场景,比如,有个隐身的怪物,你只有使用圣水喷雾才能让他现行,但必须喷3次才行,这样,空中就存在了3次叠加的雾,透过这个3层雾就能看到怪物了。但你偏一下角度,透过两层雾就看不到。
 Stencil完整语法:
stencil{//Ref referenceValue 每个像素都有一个stencil值,在同一个像素上,//所有shader的stencil都共享这一个值,//当有其他带有遮罩像素与其重合时就能获取到该值,并根据自身的stencil值处理触发小狗Ref referenceValueReadMask  readMask  //读遮罩WriteMask writeMask  //写遮罩Comp comparisonFunction   //条件判断  大于小于等触发Pass stencilOperation    //满足条件后,相应的处理办法   是替换值还是增长值等Fail stencilOperation    //没有通过模板测试怎么办ZFail stencilOperation    //通过了模板测试怎么办
}
 
模板语法:
| 参数 | 说明 | 
|---|---|
| Ref | 用来设定参考值(范围0-255)。这个值用来与stencilbuffer比较 | 
| ReadMask | 读遮罩,与referenceValue以及stencilBufferValue进行按位与运算,取值范围: [0,255],默认值: 255,即读取时不对referenceValue和stencilBufferValue产生效果,读取的还是原始值 | 
| WriteMask | 当写入模板缓冲时进行掩码操作(按位与运算),取值范围: [0-255],默认值: 255,即当修改stencilBufferValue值时,写入的仍然是原始值。 | 
| Comp | 定义参考值(referenceValue)与缓冲值(stencilBufferValue)比较的操作函数,默认值: always | 
| Pass | 定义当模板测试(和深度测试)通过时,则根据(stencilOperation值)对模板缓冲值(stencilBufferValue)进行处理,默认值:keep | 
| Fail | 定义当模板测试(和深度测试)失败时,则根据(stencilOperation值)对模板缓冲值(stencilBufferValue)进行处理,默认值:keep | 
| ZFail | 定义当模板测试通过而深度测试失败时,则根据(stencilOperation值)对模板缓冲值(stencilBufferValue)进行处理,默认值:keep | 
模板对比:
| 指令 | 说明 | 实例 | 
|---|---|---|
| Greater | 大于,只渲染大于该值的像素 | alphatest greater [_alphaValue] //类似于抠图 | 
| Less | 小于,只渲染小于该值的像素 | 类似于反向抠图 | 
| GEqual | 大于等于 | - | 
| LEqual | 小于等于 | - | 
| Equal | 等于 | - | 
| NotEqual | 不等于 | - | 
| Always | 总是 | - | 
| Never | 永不 | - | 
| Off | 关闭 | alphatest Off | 
模板操作
| 指令 | 说明 | 
|---|---|
| Keep | 保留当前缓冲中的内容,即stencilBufferValue不变 | 
| Zero | 将0写入缓冲,即stencilBufferValue值变为0。 | 
| Replace | 将参考值写入缓冲,即将referenceValue赋值给stencilBufferValue。 | 
| IncrSat | stencilBufferValue加1,如果stencilBufferValue超过255了,那么保留为255,即不大于255。 | 
| DecrSat | stencilBufferValue减1,如果stencilBufferValue超过为0,那么保留为0,即不小于0。 | 
| Invert | 将当前模板缓冲值(stencilBufferValue)按位取反 | 
| IncrWrap | 当前缓冲的值加1,如果缓冲值超过255了,那么变成0,(然后继续自增) | 
| DecrWrap | 当前缓冲的值减1,如果缓冲值已经为0,那么变成255,(然后继续自减) | 
实例1: 遮罩物体使用
Shader "Custom/MaskShader" {SubShader{Tags { "RenderType" = "Opaque" "Queue" = "Geometry-1"}CGINCLUDEstruct appdata {float4 vertex : POSITION;};struct v2f {float4 pos : SV_POSITION;};v2f vert(appdata v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);//剔除return o;}half4 frag(v2f i) : SV_Target {return half4(1,1,0,1);}ENDCGPass {ColorMask 0ZWrite OffStencil{Ref 1Comp AlwaysPass Replace}CGPROGRAM#pragma vertex vert#pragma fragment fragENDCG}}
}
 
实例2: 被遮罩物体使用
Shader "Custom/MaskedShader" {Properties{_MainTex("Base (RGB)", 2D) = "white" {}}SubShader{Tags { "Queue" = "Geometry" "RenderType" = "Opaque" }LOD 100Pass {Stencil{Ref 2Comp Equal}CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fog#include "UnityCG.cginc"struct appdata_t {float4 vertex : POSITION;float2 texcoord : TEXCOORD0;};struct v2f {float4 vertex : SV_POSITION;half2 texcoord : TEXCOORD0;UNITY_FOG_COORDS(1)};sampler2D _MainTex;float4 _MainTex_ST;v2f vert(appdata_t v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);UNITY_TRANSFER_FOG(o,o.vertex);return o;}fixed4 frag(v2f i) : SV_Target{fixed4 col = tex2D(_MainTex, i.texcoord);UNITY_APPLY_FOG(i.fogCoord, col);UNITY_OPAQUE_ALPHA(col.a);return col;}ENDCG}}
}
 
3.5.4 DepthTest 深度测试
Cull Back | Front | Off
ZWrite On | Off:用于控制是否将对象的像素写入深度缓冲(默认开启),如果需要绘制纯色物体,便将此项打开。如需绘制半透明效果,则关闭深度缓冲。
 开启深度写入:当两个像素重合时,根据深度缓冲中的值对比,剔除掉离相机较远的那个,留下最近的那个显示。
 关闭深度写入:不剔除任何像素,按顺序覆盖像素。(半透明物体需要这个)
ZTest Less | Greater | LEqual | GEqual | Equal | NotEqual | Always
 用于控制深度测试如何执行, 缺省值是LEqual。如果要绘制的像素的Z值 小余等于深度缓冲区中的值,那么就用新的像素颜色值替换。
Offset Factor,Units
 利用Factor和Units来定义深度偏移
 Factor参数表示Z缩放的最大斜率的值
 Units参数表示可分辨的最小深度缓冲区的值
 利用该句法,我们就可以强制使位于同一位置上的两个集合体中的一个几何体绘制在另一个的上层
 以上几个值可以行内写。
	//顶点着色器正文v2f vert(a2v v) {v2f o;//获取顶点的裁剪坐标,将模型顶点坐标转换为裁剪坐标o.pos = UnityObjectToClipPos(v.vertex);//获取纹理坐标,贴图与顶点对应的uv,必须配合下面的TRANSFER_SHADOW(o)o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);//顶点法线 * 世界转模型法线  获取世界法线o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);//获取世界顶点o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;TRANSFER_SHADOW(o);return o;}		ColorMask 0   //屏蔽所有颜色fiexed4 frag(v2f i):color{//纹理寻址fixed4 colo = tex2D(_MainTex, i.texcoord);//给贴图上色colo = _Color * col;}		
 
3.6 Cull剔除
| 命令 | 说明 | 实例 | 
|---|---|---|
| Off | 绘制所有的面 | Cull Off | 
| Front | 不绘制面向相机部分的面 | Cull Front | 
| Back | 不绘制背对相机的面 | Cull Back | 
四 参考
- 原文
 - 着色器(Shader)
 - Shader开发之三大着色器
 - HLSL GLSL CG着色语言比较
 - Unity ShaderLab学习
 - ShaderLab基础(Pass定义)
 - 神临的 Unity shader 学习之多Pass渲染 (八)
 - Unity Shader (一)ShaderLab 语法
 - Unity3D–Stencil Test模板测试
 - https://github.com/QianMo/Awesome-Unity-Shader
 - UnityShader3 效果
 - Shader2D: 一些2D效果的Shader实现
 - Unity Shader入门精讲
 
相关文章:
Unity ShaderLab基础
[原文1] [参考2] 一 基础知识 1. 1 着色器语言分类: 语言说明HLSL基于 OpenGL 的 OpenGL Shading LanguageGLSL基于 DirectX 的 High Level Shading LanguageCGNVIDIA 公司的 C for GraphicShader LabUnity封装了CG,HLSL,GLSL的Unity专用着色器语言,具有跨平台,图形化编程,便…...
用代理IP会频繁掉线是什么原因?HTTP和SOCKS5协议优劣势是什么?
在使用代理IP的过程中,频繁掉线是一个常见且令人头痛的问题。要解决这一问题,我们需要先了解其原因,然后比较HTTP和SOCKS5两种代理协议的优劣势,以选择最适合的解决方案。 一、代理IP频繁掉线的原因 1. 代理服务器稳定性 代理服…...
MongoDB教程(十三):MongoDB覆盖索引
💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 文章目录 引言什么是覆盖…...
快速认识EA(Enterprise Architecture)
前言 企业架构,英文是:Enterprise Architecture,简称:EA,是承接企业战略规划与IT建设之间的桥梁,是企业信息化的核心,主要包括业务架构和IT架构。 架构的本质是管理和解决系统的复杂性&#x…...
词云图制作
词云图制作 一、什么是词云 这就是词云。 “词云”的概念最早是美国西北大学新闻学副教授、新媒体专业主任里奇•戈登( Rich Gordon )提出的。词云( Word Cloud ),又称文字云、标签云( Tag Cloud &#x…...
AndroidStudio与手机进行无线调试
(一)、前提条件 一部手机一条USB数据线一部电脑手机和电脑连接到同一个 Wifi开启手机的USB调试功能开启手机的无线调试功能 (二)、操作步骤 1、 将手机和电脑用USB数据线连接 2、 打开 终端,输入 adb devices ,查看手机和电脑是否连接成功。如下图: 2、…...
脉冲编码调制(PCM,Pulse Code Modulation)简介
脉冲编码调制(PCM,Pulse Code Modulation) 脉冲编码调制(PCM,Pulse Code Modulation)是一种将模拟信号转换为数字信号的技术。在音频处理、电话通信以及其他许多领域都有广泛应用。PCM通过采样、量化、编码等三个主要步骤将模拟信号转换为数…...
Pytorch transforms 的研究
绝对路径与相对路径差别 transforms的使用 from torchvision import transforms from PIL import Imageimg_path "dataset/train/bees/16838648_415acd9e3f.jpg" img Image.open(img_path) tensor_trans transforms.ToTensor() tensor_img tensor_trans(img) prin…...
一个C++模板工厂的编译问题的解决。针对第三方库的构造函数以及追加了的对象构造函数。牵扯到重载、特化等
一窥模板的替换和匹配方式:偏特化的参数比泛化版本的还要多:判断是不是std::pair<,>。_stdpair模板参数太多-CSDN博客 简介 在一个项目里,调用了第三封的库,这个库里面有个类用的很多,而且其构…...
《昇思 25 天学习打卡营第 20 天 | Pix2Pix实现图像转换 》
《昇思 25 天学习打卡营第 20 天 | Pix2Pix实现图像转换 》 活动地址:https://xihe.mindspore.cn/events/mindspore-training-camp 签名:Sam9029 Pix2Pix模型概述 Pix2Pix是一种基于条件生成对抗网络(cGAN)的图像转换模型&#x…...
关于c#的简单应用三题
#region 输入一个正整数,求1~这个数的阶乘 public static void Factorial(int a) { int result 1; for (int i 1; i < a; i) { result result * i; } Console.WriteLine(result); } #endregion #region 一个游戏&#…...
(十三)Spring教程——依赖注入之工厂方法注入
1.工厂方法注入 工厂方法是在应用中被经常使用的设计模式,它也是控制反转和单例设计思想的主要实现方法。由于Spring IoC容器以框架的方式提供工厂方法的功能,并以透明的方式开放给开发者,所以很少需要手工编写基于工厂方法的类。正是因为工厂…...
Redission中的Lua脚本写法、理解
对于Redission看门狗机制中的为了保证原子性的Lua脚本的写法规则是什么样的呢 ? 对于源码中的Lua脚本又是什么意思? 我们一起来看一下 首先,我们先基本的熟悉一下lua脚本的逻辑 在Lua脚本中,if (…) then … end 语句的执行过程…...
视频共享融合赋能平台LntonCVS视频监控管理平台视频云解决方案
LntonCVS是基于国家标准GB28181协议开发的视频监控与云服务平台,支持多设备同时接入。该平台能够处理和分发多种视频流格式,包括RTSP、RTMP、FLV、HLS和WebRTC。主要功能包括视频直播监控、云端录像与存储、检索回放、智能告警、语音对讲和平台级联&…...
GraphRAG + GPT-4o mini 低成本构建 AI 图谱知识库
更好的效果,更低的价格,听起来是不是像梦呓? 限制 首先,让我们来介绍一个词:RAG。 简单来说,RAG(Retrieval-Augmented Generation,检索增强生成) 的工作原理是将大型文档…...
全国区块链职业技能大赛第十套区块链产品需求分析与方案设计
任务1-1:区块链产品需求分析与方案设计 养老保险平台中涉及到参保人、社保局、公安局、工作单位等参与方,他们需要在区块链养老保险平台中完成账户注册、身份上链、社保代缴、信息核查等多种业务活动。通过对业务活动的功能分析,可以更好的服务系统的开发流程。基于养老保险…...
分布式Apollo配置中心搭建实战
文章目录 环境要求第一步、软件下载第二步、创建数据库参考文档 最近新项目启动,采用Apollo作为分布式的配置中心,在本地搭建huanj 实现原理图如下所示。 环境要求 Java版本要求:JDK1.8 MySql版本要求:5.6.5 Apollo版本要求&…...
Android monkey命令和monkey脚本详解
Monkey命令 monkey 是 Android 平台上一个非常有用的工具,它可以帮助开发者在设备上生成随机的用户事件流,如按键输入、触摸屏手势等,以此来测试应用的稳定性。这对于发现应用中的崩溃、异常和性能问题特别有用。 基本语法 adb shell monk…...
vue 实现对图片的某个区域点选, 并在该区域上方显示该部分内容
目录 1、通义灵码实现: 2、csdn的C知道: 3、百度comate: 1、通义灵码实现: 在 Vue 中实现对图片某个区域的点选并显示该区域属于哪一部分,通常涉及到几个关键步骤: 图片区域划分: 首先&#…...
配置文件格式 INI 快速上手
文章目录 1.简介2.语法节键值对注释大小写空白行数据类型字符串 (String)整数 (Integer)浮点数 (Float)布尔值 (Boolean)列表 (List) 3.示例4.解析参考文献 1.简介 INI 的全称是 Initialization,即为初始化文件,最早是 Windows 系统配置文件所采用的格式…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...
在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
