Shader笔记

比较好的学习博客:

常用的内置Shader:https://www.cnblogs.com/llstart-new0201/p/10194458.html

渲染顺序:https://www.jianshu.com/p/0341f0ab9020

模板测试:https://blog.csdn.net/u011047171/article/details/46928463#t4

描边:https://gameinstitute.qq.com/community/detail/114228

uv坐标的取值范围一般为0-1,也可以小于0或大于1,若小于0,则一直加1到[0,1],若大于1,则一直减1到[0,1]

一个物体有多个Pass的问题:无论它们是否在一个Shader,每个Pass通道都会渲染,怎么渲染取决于代码,如果是相同代码,一般是后面的渲染覆盖前面的渲染。

#pragma multi_compile:

#pragma multi_compile A B C
#if A

#elif B

#else C

#endif
  • 这个Shader会被编译成三个变体:只包含A模块代码的变体A;只包含B模块代码的变体B;只包含C模块代码的变体C
  • 指定的第一个关键字是默认生效的,即默认使用变体A
  • 在脚本里使用material.EnableKeyword("Name");material.DisableKeyword("Name");shader.EnableKeyword("Name");shader.DisableKeyword("Name");来控制使用哪个变体
  • Keyword有数量限制,为256个
  • 请注意Keyword的数量和变体的数量之间的关系,并可能由此导致的性能开销,比如声明#pragma multi_compile A B和#pragma multi_compile D E这样的两组Keyword会产生2*2=4个变体,但若声明十组这样的Keyword,则产生1024个变体

上面已经提到过,最多声明256个Keyword,因此我们要尽量节省Keyword的使用数量。其中一个技巧是使用__(两条下划线),如:

#pragma multi_compile __ A

#if A
    return fixed(1,1,1,1);
#endif

return fixed4(0,0,0,1);
  • 此方式相比#pragma mult_compile A B的方式,我们可以减少使用一个Keyword
  • 此方式仍会编译成两个变体:一是不包含A模块代码的变体非A;二是包含A模块代码的变体A
  • __具有最高的优先级

ShaderProperties语义块支持的属性类型

_Int("Int",Int) = 2
_Float("Float",Float) = 1.5
_Range("Range",Range(0.0,5.0)) = 3.0
_Color("Color",Color) = (1,1,1,1)
_Vector("Vector",Vector) = (2,3,6,1)
_2D("2D",2D) = ""{}
_Cube("Cube",Cube) = "white"{}
_3D("3D",3D) = "black"{}
//_Int表示属性名称,方便在下面Shader中调用,"Int"表示该属性在Unity面板上的显示,Int表示该属性的类型,等号后面为该属性的默认值,在我们第一次把该UnityShader赋给某个材质时,材质面板上显示的就是该默认值
//对于2D、Cube、3D这3种纹理类型,默认值的定义稍微复杂,它们的默认值是通过一个字符串后跟一个花括号来指定的,其中字符串要么是空的,要么是内置的纹理名称,如"white""black""gray"或者"bump"。花括号的用处原本是用于指定一些纹理属性的,现在已被移除

SubShader中常见的渲染状态设置

Cull Cull Back|Front|Off 设置剔除模式,剔除背面/正面/关闭剔除
ZTest ZTest Less Greater|LEqual|GEqual|Equal|NotEqual|Always 设置深度测试时使用的函数
ZWrite ZWrite On|Off 开启/关闭深度写入
Blend Blend SrcFactor DstFactor 开启并设置混合模式
当在SubShader块中设置了上述渲染状态时,将会应用到所有Pass,如果我们不想这样,可以在Pass语义块中单独设置(只需要设置要改的项即可)

SubShader的标签类型(特有,Pass不能用)

Queue 控制渲染顺序,指定该物体属于哪一个渲染队列,通过这种方式可以保证所有透明物体可以在所有不透明物体后面进行渲染,我们也可以自定义使用的渲染队列来控制物体的渲染顺序Tags{"Queue"="Transparent"}
RenderType 对着色器进行分类,例如这是一个不透明的着色器,或是一个透明的着色器等,这可以被用于着色器替换(Shader Replace)功能 Tags{"RenderType"="Qpaque"}
DisableBatching 一些SubShader在使用Unity的批处理功能时会出现问题,例如使用了模型空间下的坐标进行顶点动画。这时可以通过该标签来直接指明是否对该SubShader批处理 Tags{"DisableBatching"="True"}
ForceNoShadowCasting 控制使用该SubShader的物体是否会投射阴影 Tags{"ForceNoShadowCasting"="True"}
IgnoreProjector 如果该标签值为"True",那么使用该SubShader的物体将不会受Projector的影响,通常用于半透明物体 Tags{"IgnoreProjector"="True"}
CanUseSpriteAtlas 当该SubShader是用于sprites时,将该标签设为"False" Tags{"CanUseSpriteAtlas"="False"}
PreviewType 指明材质面板将如何预览该材质。默认情况下,材质将显示为一个球形,我们可以通过把该标签的值设为"Plane""SkyBox"来改变预览类型 Tags{"PreviewType"="Plane"}

RenderType:https://blog.csdn.net/nnsword/article/details/17840439

Queue:

名称 队列索引号 描述
Background 1000 这个渲染队列会在任何其他队列之前被渲染,我们通常使用该队列来渲染那些需要绘制在背景上的物体
Geometry 2000 默认渲染队列,大多数物体都使用这个队列。不透明物体使用这个队列
AlphaTest 2450 需要透明度测试的物体使用这个队列。在Unity5中它从Geometry队列中被单独分出来,这是因为在所有不透明物体渲染之后再渲染它们会更加高效
Transparent 3000 这个队列中的物体会在所有Geometry和AlphaTest物体渲染后,再按从后往前的顺序进行渲染。任何使用了透明度混合(例如关闭了深度写入的Shader)的物体都应该使用该队列
Overlay 4000 该队列用于实现一些叠加效果。任何需要在最后渲染的物体都应该使用该队列

Pass的标签类型(特有)

LightMode 定义该Pass在Unity的渲染流水线中的角色 Tags{"LightMode"="ForwardBase"}
RequireOptions 用于指定当满足某些条件时才渲染该Pass,它的值是一个由空格分隔的字符串。目前,Unity支持的选项有:SoftVegetation。后面的版本中,可能会增加更多选项 Tags{"RequireOptions"="SoftVegetation"}

ShaderLab属性类型和CG变量类型的匹配关系

ShaderLab属性类型              CG变量类型
Color,Vector                  float4,half4,fixed4
Range,Float                   float,half,fixed
2D                            sampler2D
Cube                          samplerCube
3D                            sampler3D

Unity支持的语义

从应用阶段传递模型数据给顶点着色器时Unity支持的常用的语义

//全部都有特殊要求,不能乱用
POSITION 模型空间中的顶点位置,通常是float4类型
NORMAL 顶点法线,通常是float3类型
TANGENT 顶点切线,通常是float4类型
TEXCOORDn,如TEXCOORD0、TEXCOORD1 该顶点的纹理坐标,TEXCOORD0表示第一组纹理坐标,依次类推。通常是float2和float4类型
COLOR 顶点颜色,通常是fixed4或float4类型

从顶点着色器传递数据给片元着色器时Unity使用的常用语义

SV_POSITION 裁剪空间中的顶点坐标,结构体中必须包含一个用该语义修饰的变量。等同于DirectX9中的POSITION,但最好使用SV_POSITION
COLOR0 通常用于输出第一组顶点颜色,但这不是必需的
COLOR1 通常用于输出第二组顶点颜色,但这不是必需的
TEXCOORD0~TEXCOORD7 通常用于输出纹理坐标,但这不是必需的

片元着色器输出时Unity支持的常用语义

SV_Target 输出值将会存储到渲染目标(render target)中,等同于DirectX9中的COLOR语义,但最好用SV_Target

设置混合因子的命令

Blend SrcFactor DstFactor 开启混合,并设置混合因子。源颜色(该片元产生的颜色)会乘以SrcFactor,而目标颜色(已经存在于颜色缓冲的颜色)会乘以DstFactor,然后把两者相加后再存入颜色缓冲中
Blend SrcFactor DstFactor, SrcFactorA DstFactorA 和上面几乎一样,只是使用不同的因子来混合透明通道
注意:第一个命令只提供了两个因子,这意味着将使用同样的混合因子来混合RGB通道和A通道,即此时SrcFactorA将等于SrcFactor,DstFactorA将等于DstFactor

ShaderLab中的混合因子

One 因子为1
Zero 因子为0
SrcColor 因子为源颜色值。当用于混合RGB的混合等式时,使用SrcColor的RGB分量作为混合因子;当用于混合A的混合等式时,使用SrcColor的A分量作为混合因子
SrcAlpha 因子为源颜色的透明度值(A通道)
DstColor 因子为目标颜色。当用于混合RGB通道的混合等式时,使用DstColor的RGB分量作为混合因子;当用于混合A的混合等式时,使用DstColor的A分量作为混合因子
DstAlpha 因子为目标颜色的透明度值(A通道)
OneMinusSrcColor 因子为(1-源颜色)。当用于混合RGB的混合等式时,使用结果的RGB分量作为混合因子;当用于混合A的混合等式时,使用结果的A分量作为混合因子
OneMinusSrcAlpha 因子为(1-源颜色的透明度值)
OneMinusDstColor 因子为(1-目标颜色)。当用于混合RGB的混合等式时,使用结果的RGB分量作为混合因子;当用于混合A的混合等式时,使用结果的A分量作为混合因子
OneMinusDstAlpha 因子为(1-目标颜色的透明度值)
例如:实现输出颜色的透明度值就是源颜色的透明度,可以使用下面的命令:
Blend SrcAlpha OneMinusSrcAlpha, One Zero

ShaderLab中的混合操作

Add 将混合后的源颜色和目标颜色相加。默认的混合操作
Sub 用混合后的源颜色减去混合后的目标颜色
RevSub:用混合后的目标颜色减去混合后的源颜色
Min 使用源颜色和目标颜色中较小的值,是逐分量比较的
Max 使用源颜色和目标颜色中较大的值,逐分量比较
注意:使用Min或Max混合操作时,混合因子实际上是不起任何作用,它们仅会判断原始的源颜色和目的颜色之间的比较结果

常见的混合操作

Blend SrcAlpha OneMinusSrcAlpha 正常(Normal),即透明度混合
Blend OneMinusDstColor One 柔和相加(Soft Additive)
Blend DstColor Zero 正片叠底(Multiply),即相乘
Blend DstColor SrcColor 两倍相乘(2x Multiply)

//变暗(Darken)
BlendOp Min
Blend One One

//变亮(Lighten)
BlendOp Max
Blend One One

Blend OneMinusDstColor One 滤色(Screen)等同于 Blend One OneMinusSrcColor
Blend One One 线性减淡(Linear Dodge)

将模型空间的坐标变换到裁剪空间中:UnityObjectToClipPos(v.vertex) 其中v.vertex是模型空间的坐标

将模型空间的法线变换到世界空间中:UnityObjectToWorldNormal(v.normal) 其中v.normal是模型空间的法线,返回值为单位化的三维向量,参数可以是非单位化的三维向量

UnityObjectToViewPos,将传入的模型空间下的坐标转换为视角空间下的坐标

将模型空间的坐标变换到世界空间中:mul(unity_ObjectToWorld,v.vertex) 即模型空间的坐标左乘相应矩阵

获得世界空间的光源方向:UnityWorldSpaceLightDir(i.worldPos) 其中i.worldPos为相应点在世界空间中的坐标,另外要注意该方法返回的是一个指向光源的三维非单位向量

获得世界空间的相机坐标:UnityWorldSpaceViewDir(i.worldPos) i.worldPos的含义同上,需要注意的是该方法返回的是一个指向相机的三维非单位向量

TRANSFORM_TEX:拿顶点的uv去和材质球的tiling和offset作运算,确保材质球里的缩放和偏移设置是正确的(v.texcoord就是顶点的uv)

下面两个函数是等价的:

o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);

o.uv = v.texcoord.xy*_MainTex_ST.xy+_MainTex_ST.zw;

_MainTex_ST.xy是tiling

_MainTex_ST.zw是offset

tex2D():根据贴图和uv计算出当前片元的着色信息,并返回,以供着色器正确为模型着色

注:这里的着色信息并不一定就要是颜色信息,还可以存储一些其它的信息,如延迟渲染第二个Pass中在Gbuffer中的取样

tex2DCUBE()类似,可以取样天空盒贴图的着色信息

UNITY_LIGHTMODEL_AMBIENT得到当前场景中的环境光,常通过.rgb来得到环境光的rgb通道

_WorldSpaceLightPos0得到世界空间中主光源的位置,如果该光源为平行光,w分量为0,否则w分量为1,注意看作向量时该向量并不是单位向量

_WorldSpaceCameraPos,得到世界空间中相机的位置

_LightColor0得到当前场景中主光源的颜色

UnityShader内置结构体变量

struct appdata_base {
    float4 vertex : POSITION;//顶点位置
    float3 normal : NORMAL;//发现
    float4 texcoord : TEXCOORD0;//纹理坐标
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct appdata_tan {
    float4 vertex : POSITION;
    float4 tangent : TANGENT;//切线
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct appdata_full {
    float4 vertex : POSITION;
    float4 tangent : TANGENT;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
    float4 texcoord1 : TEXCOORD1;//第二纹理坐标
    float4 texcoord2 : TEXCOORD2;//第三纹理坐标
    float4 texcoord3 : TEXCOORD3;//第四纹理坐标
    fixed4 color : COLOR;//顶点颜色
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

reflect:算反射光的方向,reflect方法第一个参数为入射光方向(注意该光的方向是由光源指向入射光与法线的交点的,与我们调用Unity内置函数得到的光源方向正好相反),第二个参数是法线方向,参数和返回值均为三维单位化向量

refract:算折射光的方向,第一个参数为入射光方向(方向与反射方法同),第二个参数为法线方向,第三个参数为折射率,0-1之间,参数和返回值均为三维单位化向量

mul()矩阵乘法

dot()向量点积

pow(a,b)求a的b次方

saturate(x)将x限制在[0,1]之间

smoothstep(l,r,x),将x的值限制在[l,r]

cross()向量叉乘

TANGENT_SPACE_ROTATION:求物体空间到切线空间的矩阵,由于这里仅涉及方向,所以得到的是一个3×3的矩阵

源码:

float3 binormal = cross(normalize(v.normal), normalize(v.tangent.xyz)) * v.tangent.w;
float3x3 rotation = float3x3(v.tangent.xyz, binormal, v.normal);

ObjSpaceLightDir:求物体空间光源的方向

ObjSpaceViewDir:求物体空间的相机方向

上面两个函数返回值均为三维非单位向量,方向是指向光源和相机的

UnpackNormal:当法线贴图类型设置为Normal map时,采样完贴图后需要使用该函数对结果解压,详细可参考源码:

inline fixed3 UnpackNormal(fixed4 packednormal)
{
#if defined(UNITY_NO_DXT5nm)
    return packednormal.xyz * 2 - 1;
#else
    return UnpackNormalmapRGorAG(packednormal);
#endif
}
if ((texColor.a - _Cutoff) < 0) //透明测试,如果小于我们制定的值则裁去
{
    discard;
}

UnpackScaleNormal,可以将解压得到的法线结果的xy分量乘上第二个参数,两个参数,第一个参数同UnpackNormal,第二个参数为要乘的值

注意:以上得到的法线值均位于切线空间中

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的逆矩阵,用于将顶点/方向矢量从世界空间变换到模型空间
unity_CameraToWorld,用于将顶点/方向矢量从视角空间转换到世界空间

TransformViewToProjection,观察空间到裁剪空间,参数可以是三维向量也可以是二维,返回值分别为三维和二维非单位向量

UnityObjectToWorldDir,将一个三维向量从模型空间转换到世界空间,返回一个单位化的三维向量

#ifdef LIGHTMAP_OFF //判断灯光贴图有无开启,只要在关闭的情况下,才可以做球谐函数的计算
#endif

ShadeSH9(float4(v.normal, 1)),计算球谐函数,参数为法线向量,最好要单位化,返回一个三维向量

#ifdef VERTEXLIGHT_ON //判断顶点光源是否开启,只有开启才能进行逐顶点光照的计算
#end
Shade4PointLights(unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,unity_4LightAtten0, o.worldPos, o.worldNormal);//计算顶点光照,返回一个三维向量,参数要严格按照该要求来写

#pragma exclude_renderers norm,排除不支持MRT的设备

#pragma target 3.0 指定Shader Target等级

ComputeScreenPos(),传入一个裁剪空间的坐标,将其转换为屏幕空间的坐标,注意该坐标并没有做齐次除法,在我们手动为返回值做齐次除法之后会得到[0,1]之间的屏幕坐标,后期再乘上屏幕的宽度或者高度的像素值即可得到确切的屏幕坐标

ComputeGrabScreenPos(); //传入一个裁剪空间的坐标,计算屏幕坐标,与ComputeScreenPos相似,最大的不同是为不同平台做了适配,常用于为捕获的图像生成采样uv(在作为uv之前一定要记得齐次除法)

float2 uv = i.uv.xy / i.uv.w;//对上述得到的屏幕坐标进行齐次除法
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);//取样深度纹理_CameraDepthTexture,得到深度
depth = Linear01Depth(depth);//得到线性的0到1之间的深度

延迟渲染:

float3 worldPos;
float2 uv;
half3 lightDir;
float atten;
float fadeDist;
UnityDeferredCalculateLightParams(i, worldPos, uv, lightDir, atten, fadeDist);
用于延迟渲染第二个Shader文件中第一个Pass(非转码Pass)的片元着色器中,用来处理光照和阴影,源码可以参照UnityDeferredLibrary.cginc文件

接受和产生阴影:

接受(源码见AutoLight.cginc):
SHADOW_COORDS(),用于v2f结构体,有一个参数,表示TEXCOORD的下标
TRANSFER_SHADOW(),用于顶点着色器最后,有一个参数,即顶点着色器输出的结构体名
SHADOW_ATTENUATION(),用于片元着色器return之前,有一个参数为当前片元着色器的参数结构体,返回计算出的一维阴影系数,将该系数与片元着色器最后计算出的高光和漫反射相乘即可

产生阴影:
增加FallBack "Diffuse"即可

对于透明度测试(有透明的部分也有不透明的部分)的物体可以使用FallBack "Transparent/Cutout/VertexLit"投射阴影,而半透明的物体想要投射阴影只能用FallBack "Diffuse"(由于Unity默认半透明物体是不投射阴影的,所以使用FallBack "Transparent/VertexLit"不会有阴影)
接受阴影时上述两种情况均可以通过将渲染队列索引号调制小于等于2500实现,具体下限可以自行测试

光照衰减及其对阴影造成的影响(查看源码的话会发现它们包含对阴影的处理):

(源码见AutoLight.cginc)
LIGHTING_COORDS(),用于v2f结构体中,有两个参数,分别表示TEXCOORD的下标
TRANSFER_VERTEX_TO_FRAGMENT(),用于顶点着色器最后,一个参数,即顶点着色器的参数
LIGHT_ATTENUATION(),用于片元着色器return前,一个参数,即片元着色器的参数,返回一个一维的光照衰减系数,将该系数与最终的计算结果中的高光和漫反射相乘即可

UNITY_LIGHT_ATTENUATION,同时计算阴影和光照的函数,很方便,用在片元着色器return前。有三个参数,第一个参数不需要我们定义,用来存放计算结果,第二个参数为片元着色器的参数(v2f),第三个参数为第二个参数中所存的世界坐标(也就是模型的世界坐标)。使用时将第一个参数与片元着色器计算的漫反射和高光反射相乘即可。注意,该函数的源码中没有对阴影的前两步处理,所以需要我们手动加

Ps:为节省性能,逐顶点光源不需要计算阴影和光照衰减

clip:https://blog.csdn.net/qq_37190129/article/details/105184132

属性块中也可以加标签,如:

[HDR]_Color ("Color", Color) = (1,1,1,1) //HDR标签,可以对当前颜色进行增强和减弱等操作
[Toggle]_ToggleBulr("ToggleBulr", Range(0,1)) = 0 //Toggle或者MaterialToggle标签用来将该属性转换为bool类型

Shader中的时间变量:https://docs.unity3d.com/462/Documentation/Manual/SL-BuiltinValues.html

//t是自该场景加载开始所经过的时间,4个分量分别是 (t/20, t, t*2, t*3)
_Time   float4  Time: (t/20, t, t*2, t*3),   
//t 是时间的正弦值,4个分量分别是 (t/8, t/4, t/2, t)
_SinTime    float4  Sine of time: (t/8, t/4, t/2, t).
//t 是时间的余弦值,4个分量分别是 (t/8, t/4, t/2, t)
_CosTime    float4  Cosine of time: (t/8, t/4, t/2, t).
//dt 是时间增量,4个分量的值分别是(dt, 1/dt, smoothDt, 1/smoothDt)
unity_DeltaTime  float4  Delta time: (dt, 1/dt, smoothDt, 1/smoothDt).

step函数,当第二个参数大于第一个参数时返回1,否则返回0

UNITY_INITIALIZE_OUTPUT(Input, o);当函数参数o被out关键字修饰时需要加上,第一个参数为变量类型,第二个参数为变量名

lerp,严格按照公式计算,不会对第三个参数做限制

颜色分量相加时值是会超过1的,且超过1时依旧按照原来的逻辑着色

SurfaceShader相关知识点:

两个结构体:

两个结构体就是指struct Input和SurfaceOutput

Input结构体中,在一个贴图变量之前加上uv两个字母,就代表提取它的uv值,例如uv_MainTex。该结构体除uv_MainTex等uv坐标外内置的其他变量(指只需要使用变量名声明,Unity自动帮助我们计算的变量,除这些变量之外的自定义变量都要自己计算):
float3 viewDir 包含了视角方向,可用于计算边缘光照等
使用COLOR语义定义的float4变量 包含了插值后的逐顶点颜色
float4 screenPos 包含了屏幕空间的坐标,可以用于反射或屏幕特效
float3 worldPos  包含了世界空间下的位置
float3 worldRefl 包含了世界空间下的反射方向。前提是没有修改表面法线o.Normal
float3 worldRefl; 如果修改了表面法线o.Normal,需要使用该变量告诉Unity要基于修改后的法线计算世界
INTERNAL_DATA 空间下的反射方向。在表面函数中,我们需要使用WorldReflectionVector(IN, o.Normal)来得到世界空间下的反射方向
float3 worldNormal 包含了世界空间的法线方向。前提是没有修改表面法线o.Normal
float3 worldNormal; 如果修改了表面法线o.Normal,需要使用该变量告诉Unity要基于修改后的法线计算世
INTERNAL_DATA 界空间下的法线方向。在表面函数中,我们需要使用WorldNormalVector(IN, o.Normal)来得到世界空间下的法线方向

另一个结构体是(SurfaceOutput、SurfaceOutputStandard和SurfaceOutputStandardSpecular)。我们也可以自定义这个结构体内的变量,自定义最少需要有4个成员变量:Albedo、Normal、Emission和Alpha,缺少一个都会报错(如果没有对某些变量赋值,就会使用默认值)
下面主要介绍SurfaceOutput(对应于非基于物理的光照模型,也就是Lambert和BlinnPhong),关于另外两种(分别对应于Standard和StandardSpecular基于物理的光照模型)可以参考Shader库文件
struct SurfaceOutput
{
    fixed3 Albedo;
    fixed3 Normal;
    fixed3 Emission;
    half Specular;
    fixed Gloss;
    fixed Alpha;
}
Albedo:对光源的反射率。通常由纹理采样和颜色属性的乘积计算而得
Normal:表面法线方向
Emission:自发光。Unity通常会在片元着色器最后输出前(并在最后的顶点函数被调用前,如果定义了的话),使用类似下面的语句进行简单的颜色叠加:
c.rgb += o.Emission;
Specular:高光反射中的指数部分的系数,影响高光反射的计算。例如,如果使用了内置的BlinnPhong光照函数,它会使用如下语句计算高光反射的强度:
float spec = pow(nh, s.Specular*128.0) * s.Gloss;
Gloss:高光反射中的强度系数。与上面的Specular类似,计算公式一般见上面的代码。一般包含在了高光反射中的光照模型里使用
Alpha:透明通道。如果开启了透明度的话,会使用该值进行颜色混合

GrabPass{"GrabPass"} //定义一种特殊的Pass,用来捕获图像,该Pass可以使用Name盒Tag,但在其它Shader中不能使用UsePass引用,引用的方法只需要再写一个同名的GrabPass即可
//注意在其它Shader中除非特殊需要,否则不要写其它名字的GrabPass,会造成多次捕获,消耗性能
//在使用该Pass时要注意渲染顺序,即要在所有不透明物体绘制完后再绘制,所以Queue一般设置为Transparent+x

sampler2D GrabPass;
//对应于上面的GrabPass,名字要与双引号中的相同,存取捕获图像
float4 GrabPass_TexelSize;
//获得捕获图像纹理的纹素大小,例如一个256*512的纹理,其纹素大小为(1/256,1/512)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值