专注郑州网站建设,做网站汉中,建设征婚网站,淄博临淄信息港[原文1] [参考2]
一 基础知识
1. 1 着色器语言分类:
语言说明HLSL基于 OpenGL 的 OpenGL Shading LanguageGLSL基于 DirectX 的 High Level Shading LanguageCGNVIDIA 公司的 C for GraphicShader LabUnity封装了CG,HLSL,GLSL的Unity专用着色器语言,具有跨平台,图形化编程,便…[原文1] [参考2]
一 基础知识
1. 1 着色器语言分类:
语言说明HLSL基于 OpenGL 的 OpenGL Shading LanguageGLSL基于 DirectX 的 High Level Shading LanguageCGNVIDIA 公司的 C for GraphicShader LabUnity封装了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通信Subshadershader解决方案。每个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的浮点数,xyColor-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最先调用的用来渲染天空盒或背景1000Geometry默认值用来渲染非透明物体一般情况下场景中的绝大多数物体应该是非透明的2000AlphaTest用来渲染经过Alpha Test的像素单独为AlphaTest设定一个Queue是出于对效率的考虑2450Transparent以从后往前的顺序渲染透明物体3000Overlay用来渲染叠加的效果是渲染的最后阶段比如镜头光晕等特效4000
这些预定义的值本质上是一组定义整数在我们实际设置Queue值时不仅能使用上面的几个预定义值我们也可以指定自己的Queue值写成类似这样“Queue”“Transparent100”表示一个在Transparent之后100的Queue上进行调用。通过调整Queue值我们可以确保某些物体一定在另一些物体之前或者之后渲染这个技巧有时候很有用处。(比如遮挡描边效果应该就是这么来的)
2.3.3 LOD
细节等级。大家玩吃鸡的时候从飞机上跳下这时看到地图上的建筑都是比较粗糙的块当距离慢慢拉近建筑模型变得越发精致这就是LOD技术根据不同的范围使用不同的模型。shader的LOD也是同样用法不同细节等级使用不同的LOD。在Unity的Quality Settings中可以设定最大LOD值当当前LOD小于shader LOD时那个sub shader就会失效.
关键字值VertexLit及其系列100Decal, Reflective VertexLit150Diffuse200Diffuse Detail250Reflective Bumped Unlit250Reflective Bumped VertexLit250Bumped, Specular300Bumped Specular400Parallax500Parallax Specular600
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光源和lightmapsForwardAdd“LightMode”“ForwardAdd”用于向前渲染该pass会计算额外的逐像素光源每个pass对应一个光源Deferred“LightMode”“Deferred”用于向前渲染该pass会渲染G缓冲G-bufferShadowCaster“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的程序无效targettarget 2.0、target 3.0、target 4.0、target 5.0#pragma target name设置着色器的编译目标对应不同版本的着色器模型only_renderers space separatedd3d9direct3d 9、d3d11、opengl、gles(opengl 2s 2.0)、xbox360、ps3、flash#pragma only_renderers space separated names仅编译到指定的渲染平台exclude_renderers space separatedd3d9direct3d 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顶点切线 float4TEXCOORD0~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_MVUNITY_MATRIX_MV 的转置矩阵UNITY_MATRIX_IT_MVUNITY_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 或dLDRfloat4 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 _ProjectionParamsx1.0 或-1.0使用反转的投影矩阵渲染时是负数yNearzFarw 1.01.0/Far, 其中near和far分别是近裁剪平面和远裁剪平面与摄像机的距离float4 _ScreenParamsxwidth,yheight,z1.01.0/width,w1.01.0/height, 其中width和height分别是该摄像机的渲染目标 (render target)的像素宽度和高度float4 _ZBufferParamsx1-Far/nearyFar/Near 最x/Farwy/Far该变量用于线性化Z缓存中的深度值floart4 unity_OrhoParamsxwidth,yheight,z无意义w1.0(该相机是正交相机)或w0.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,3tfloat4 _SinTime时间的正弦制(x,y,z,w)分别是t/8,t/4,t/2,tfloat4 _Costime时间的余弦值(x,y,z,w)分别是t/8,t/4.t/2,tfloat4 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
ENDCG2.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)xa返回axb返回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)向量 每个分量比较 xy-exp(x)指数, log(x)-exp2(x)2的x次方 log2(x)-frac(x)返回标量或矢量的小数-faceforward(N, I, Nref)如 dot(Nref, I) 0则N, 否则 -Nfloor(x)底部取整-fmod(x,y)取模-fract(x)取小数部分-frexp(x, out i)将浮点数 x 分解为尾数和指数即 x m* 2^exp返回 m并将指数存入 exp 中如果 x 为 0则尾数和指数都返回 0-greaterThan(vecX, vecY)向量 每个分量比较 xy-greaterThanEqual(vecX, vecY)向量 每个分量比较 xy-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)向量 每个分量比较 xy-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∙L0则为0否则为N∙LZ位代表镜面光的贡献如果N∙L0 或者N∙H0则位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)折射k1.0-etaeta(1.0 - dot(N, I) * dot(N, I)); 如k0.0 则0.0, 否则 etaI - (etadot(N, I)sqrt(k))*Nround(x)四舍五入-rsqrt(x)x的平方根的倒数x必须大于0-saturate(x)把x限制到[0,1]之间-sign(x)取当前数值的正负符号,返回 1, 0 或 -1x0;x0;x0sin(angle), cos(angle), tan(angle)三角函数(正弦,余弦,正切)-sincos(float x, out s, out c)该函数是同时计算x的sin值和cos值其中ssin(x)ccos(x)。该函数用于“同时需要计算sin值和cos值的情况”比分别运算要快很多!-sinh(x)计算x的双曲正弦-smoothstep(min, max, x)值x位于min、max区间中。如果xmin返回0如果xmax返回1如果x在两者之间按照下列公式返回数据–2∗((x–min)/(max–min))33∗((x–min)/(max–min))/2float 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)如果xa, 返回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 表面着色器的输入参数表
数据类型参数说明float3viewDir视角方向float4COLOR每个顶点的插值颜色float4screenPos屏幕坐标使用.xy/.w来获得屏幕2D坐标float3worldPos世界坐标float3worldRefl世界坐标系中的反射向量float3worldNormal世界坐标系中的法线向量-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 { RenderTypeTransparent }LOD 100//固定管线渲染器。背面剔除,并在深度缓冲区中留下背面剔除的深度值Pass{Name BASE//剔除背面Cull Back//保存缓冲区Blend Zero OneSetTexture[_OutlineColor]{ConstantColor(1,0,0,0)Combine constant}}//顶点/片段着色器。正面剔除,那些经过法线伸展后的点会因为与深度剔除的缓存值比较后无法通过而被剔除//也就是说仅仅剩下正面与背面的边缘处因为伸展的原因保留了下来, 于是轮廓就出现了,这就是大体过程了Pass{NameOUTLINETags{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因子值为1Zero因子值为0SrcColor因子为源颜色值当前片元当用于混合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比较的操作函数默认值: alwaysPass定义当模板测试和深度测试通过时则根据stencilOperation值对模板缓冲值stencilBufferValue进行处理默认值keepFail定义当模板测试和深度测试失败时则根据stencilOperation值对模板缓冲值stencilBufferValue进行处理默认值keepZFail定义当模板测试通过而深度测试失败时则根据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。IncrSatstencilBufferValue加1如果stencilBufferValue超过255了那么保留为255即不大于255。DecrSatstencilBufferValue减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.cgincstruct 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 OffFront不绘制面向相机部分的面Cull FrontBack不绘制背对相机的面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-ShaderUnityShader3 效果Shader2D: 一些2D效果的Shader实现Unity Shader入门精讲