更复杂的光照

  • 效果图
  • 理论
    • unity的光源类型
    • unity的渲染路径
    • 在这里插入图片描述
  • 实验
    • 多光源
    • 阴影
      • 不透明物体的阴影
      • 让物体接收阴影
      • 统—管理光照衰减和阴影
      • 透明度物体的阴影
  • 代码
    • 多光源
    • 阴影
      • 接收阴影
      • Alpha Test With Shadow

效果图

【多光源前向渲染】

Unity 处理这些点光源的顺序是按照它们的重要度排序的,和光源强度、颜色、距离物体的远近有关系
原顺序:

红色point light的intensity改为2:

把红光设置为not important
unity不会把该光源当成逐像素处理,由于代码的Bass Pase 中没有计算逐顶点和 SH 光源,那么红光上不会对物体造成任何影响
(消失的小红)

【阴影】
小球的Cast Shadows On ,地面Recieve Shadows On

小球的Cast Shadows Off ,或者地面Recieve Shadows Off, 或者注销FallBack

默认情况下把物体渲染到 深度图阴影映射纹理 中仅考虑物体的正面
正 VS 反 VS 反Two Sided

【让物体接收阴影】

【Alpha Test 中实现阴影】
Cast Shadows On VS Cast Shadows Two Sided

【Alpha Blend 中实现阴影】
FallBack “Transparent/VertexLit” VS FallBack “VertexLit”

理论

unity的光源类型

【光源类型】:平行光、点光源(point light)、聚光灯(spot light)和面光源(area light,仅在烘焙时才可发挥作用)
【光源属性】位置、方向、颜色、强度、衰减
平行光:
属性只有方向,也没有衰减的概念,光照强度不会随着距离而发生改变
点光源:
由空间中的球体定义

聚光灯:
是3种光源类型中最复杂的 ,由空间中的一块锥形区域定义的
``

unity的渲染路径

渲染路径 (Rendering Path) 决定了光照是如何应用到 Unity Shader 中,支持的有前向渲染路径 (Forward Rendering Path) 、延迟渲染路径 (Deferred Rendering Path)。
大多数情况下,一个项目只使用一种渲染路径,默认为前向渲染路径,可以在Edit – Project Settings – Player – Other Settings – Rendering Path 中选择项目所需的渲染路径,如果当前的显卡并不支持所选择的渲染路径,会自动使用更低一级的渲染路径。然后,就可以在每个 Pass 中使用LightMode 标签来指定该 Pass 使用的渲染路径,通过 Unity提供的内置光照变量来访问相关的光照属性。

前向渲染路径

1、更新颜色缓冲区,深度缓冲区

2、如果一个物体在多个逐像素光源的影响区域内,那么该物体就需要执行多个 Pass, 每个 Pass 计算一个逐像素光源的光照结果,然后在帧缓冲中把这些光照结果混合起来得到最终的颜色值。
假设场景中有N个物体,每个物体受M个光源的影响,那么渲染整个场景一共需要 N*M Pass 。

前向渲染的问题是当场景中包含大量实时光源时 ,前向渲染的性能会急速下降。如果我们在场景的某一块区域放置了多个光源,每执行一个 Pass 都需要重新渲染一遍物体,但很多计算实际上是重复的

3、前向渲染路径有3种处理光照(即照亮物体)的方式: 逐顶点处理、逐像素处理,球谐函数 (Spherical Harmonics, SH) 处理。
unity会对这些光源进行一个重要度排序,根据光源的类型和渲染模式,一定数目的光源会按逐像素的方式处理,然后最多有4个光源按逐顶点的方式处理,剩下的光源可以按SH方式处理。
1)场景中最亮的平行光总是按逐像素处理的。
2)渲染模式被设置成Important的光源, 会按逐像素处理,NotImportant的光源,会按逐顶点或者SH处理。
3)如果根据以上规则得到的逐像素光源数量小于Quality Setting中的逐像素光源数量(Pixel
Light Count), 会有更多的光源以逐像素的方式进行渲染

4、前向渲染有两种Pass: Base Pass和AdditionalPass

• 一个Unity Shader通常会定义一个Base Pass (需要双面渲染等情况除外)以及一个Additional Pass。 一个Base Pass仅会执行一次, 而每个影响该物体的其他逐像素光源都会执行一次AdditionalPass

• Base Pass
  环境光和自发光是在Base Pass中计算的。如果我们在AdditionalPass中计算这两种光照, 就会造成叠加多次环境光和自发光
  渲染的平行光默认是支持阴影的(如果开启了光源的阴影功能)
• Additional Pass
  开启和设置了混合模式(一般是Blend One One)。 每个AdditionalPass可以与上一次的光照结果在帧缓存中进行叠加,否则会覆盖掉之前的渲染结果,看起来就好像该物体只受该光源的影响。
  渲染的光源在默认情况下是没有阴影效果的, 即便我们在它的Light组件中设置了有阴影的Shadow Type。

5、内置光照变量和函数


延迟渲染路径 链接
1、延迟渲染的效率不依赖于场景的复杂度,而是和我们使用的屏幕空间的大小有关;适合在场景中光源数目很多、如果使用前向渲染会造成性能瓶颈的情况下使用。
2、延迟渲染主要包含了两个 Pass :
  第一个Pass 用于渲染G缓冲
  我们不进行任何光照计算,而是仅仅计算哪些片元是可见的,这主要是通过深度缓冲技术来实现,当发现一个片元是可见的,我们就把它的相关信息存储到G缓冲区中(物体的漫反射颜色、高光反射颜色、平滑度 、法线、 自发光和深度等信息)
  第二个Pass用于计算真正的光照模型
  使用上一个Pass中渲染的数据来计算最终的光照颜色,再存储到帧缓冲中


3、缺点。
• 不支持真正的抗锯齿MSAA 功能。
• 不能处理半透明物体。
• 对显卡有一定要求。如果要使用延迟渲染的话,显卡必须支持 MRT ( Multiple Render Targets) Shader Mode 3.0 及以上、 深度渲染纹理以及双面的模板缓冲。

4、

实验

多光源

本示例处理一个平行光,三个点光源
1、Base Pass
选择最亮的平行光进行逐像素处理其他平行光会按照逐顶点,或在 Additional Pass 中按逐像素的方式处理
计算一次环境光和自发光
方向不变,衰减为1

2、Additional Pass
其他每个光源调用一次该Pass:可以是平行光、点光源或是聚光灯(除了面光源),默认情况下1个物体可以接收除最亮的平行光外的4个逐像素光照
开启并设置混合模式
根据光源类型计算方向和衰减(利用衰减纹理)

【代码解析】

  • Base Pass
 Properties{_Diffuse("Diffuse", Color) = (1, 1, 1, 1)_Specular("Specular", Color) = (1, 1, 1, 1)_Gloss("Gloss", Range(8.0, 256)) = 20}
Pass { // base PassTags { "LightMode" = "ForwardBase" }CGPROGRAM#pragma multi_compile_fwdbase

#pragma multi_compile_fwdbase,该编译指令可以保证在 Shader 中使用光照衰减等光照变量时被正确赋值

struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;
};struct v2f {float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;
};

VS略
FS

fixed4 frag(v2f i) : SV_Target {fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);fixed3 halfDir = normalize(worldLightDir + viewDir);fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;// 只需要计算一次即可,后面的 Additional Pass不会再计算(环境光+自发光)fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);fixed atten = 1.0; // 平行光没有衰减return fixed4(ambient + (diffuse + specular) * atten, 1.0); // 此处多×了一个atten
}

return fixed4(ambient + (diffuse + specular) * atten, 1.0);
  环境光和自发光(虽然这里没有)算一次
  atten = 1,平行光没有衰减
  atten 影响 diffuse + specular

  • Additional Pass
  • 去掉 Base Pass 中环境光、自发光、逐顶点光照、SH 光照的部分
Pass { // Additional Pass// Pass for other pixel lightsTags { "LightMode" = "ForwardAdd" }Blend One One // 开启和设置了混合模式CGPROGRAM#pragma multi_compile_fwdadd

开启和设置了混合模式,Additional Pass 计算得到的光照结果可在帧缓存中与之前的光照结果进行叠加

VS略

FS
光源属性:位置、方向、颜色、强度以及衰减,颜色和强度可以使用_LightColor0来得到

计算不同光源的方向

#ifdef USING_DIRECTIONAL_LIGHT // 平行光fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
#elsefixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz); // 光源位置-顶点位置
#endif

平行光:_WorldSpaceLightPos0.xyz
其他光:光源位置-顶点位置

计算不同光源的衰减

#ifdef USING_DIRECTIONAL_LIGHTfixed atten = 1.0;
#else#if defined (POINT) // 利用衰减纹理得到衰减值,可以避免数学计算float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz; // 光源空间中的相对位置fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL; // 这个坐标的模的平方对_LightTexture0进行采样,得到衰减值 // UNITY_ATTEN_CHANNEL得到衰减值所在的分量#elif defined (SPOT)float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1));fixed atten = (lightCoord.z > 0) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;#elsefixed atten = 1.0;#endif
#endif

使用一张纹理作为查找表 (Lookup Table, LUT)得到光源的衰减,不依赖数学公式的复杂性。 首先得到光源空间下的坐标,然后使用坐标的模的平方对衰减纹理进行采样,得到衰减值:

如果一个物体不在一个光源的光照范围内, Unity 是不会为这个物体调用Pass 来处理这个光源的

阴影

使用Shadow Map(阴影映射纹理, 本质上是深度图), 光看不到的地方就是阴影

  • 在计算阴影映射纹理时,我们如何判定距离它最近的表面位置呢?

  一种方法是,先把摄像机放置到光源的位置上,然后按正常的渲染流程,即调用 Base Pass、dditional Pass 来更新深度信息,得到阴影映射纹理。
  但这种方法很浪费,因为我们实际上仅仅需要深度信息而已,而 Base Pass dditional Pass 中往往涉及很多复杂的光照模型计算

  因此 Unity选择使用LigbtMode 标签为ShadowCaster的Pass,这个 Pass 的渲染目标不是帧缓存,而是阴影映射纹理(或深度纹理)
  Unity 首先把摄像机放置到光源的位置上,然后调用该 Pass, 通过对顶点变换后得到光源空间下的位置,并据此来输出深度信息到阴影映射纹理中

因此,当开启了光源的阴影效果后,底层渲染引擎首先会在Unity Shader 里的Pass和 Fallback 中找到LigbtMode为ShadowCaster的Pass。

  • 一个物体接收来自其他物体的阴影,以及它向其他物体投射阴影的原理

1)一个物体接收来自其他物体的阴影
必须在 Shader 中: 采样的阴影映射纹理 × 光照结果
2)一个物体向其他物体投射阴影
就必须把该物体加入到光源的阴影映射纹理的计算中,从而让其他物体对阴影映射纹理采样时可以得到该物体的相关信息。

  • 屏幕空间的阴影映射技术 (Screenspace Shadow Map)

Unity 首先会通过调用 LigbtMode 为shadowCaster的Pass来得到可投射阴影的光源的阴影映射纹理以及摄像机的深度纹理。然后,根据光源的阴影映射纹理和摄像机的深度纹理来得到屏幕空间的阴影图

不透明物体的阴影

通过 Mesh Renderer 组件中的 Cast Shadows、Receive Shadows 属性设置某个物体投射或接收阴影

让物体接收阴影

在多光源的基础上修改Base Pass代码:

// Need these files to get built-in macros
#include "Lighting.cginc"
#include "AutoLight.cginc" // 增加

需要"AutoLight.cginc"

计算阴影中用到三个宏
输出结构体 v2f 中添加了一个内置宏 SHADOW_COORDS: 声明了 一个名为_ShadowCoord 的阴影纹理坐标变址
顶点着色器返回之前添加另一个内置宏 TRANSFER_SHADOW:调用内置的ComputeScreenPos函数来计算_ ShadowCoord
片元着色器中计算阴影值,同样使用了一个内置宏 SHADOW
ATTENUATION: 使用 _ShadowCoord对相关的纹理进行采样

struct v2f {float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;SHADOW_COORDS(2) // 内置宏,声明一个用于对阴影纹理采样的坐标
};v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;TRANSFER_SHADOW(o); // 返回return o;
}

VS

fixed shadow = SHADOW_ATTENUATION(i);
return fixed4(ambient + (diffuse + specular) * atten * shadow, 1.0);

(ambient + (diffuse + specular) * atten * shadow, 1.0)

统—管理光照衰减和阴影

(ambient + (diffuse + specular) * atten * shadow, 1.0)
再来一遍这个式子,光照衰减和阴影对物体最终的渲染结果的影响本质上是相同的,unity Shader提供了这样的功能,通过内置的 UNITY_LIGHT _ATTENUATION 同时计算两个信息

UNITY _LIGHT _ATTENUATION是Unity 内置的用于计算光照衰减和阴影的宏。Unity 内置文件的魅力所在,不需要在 Base Pass 里单独处理阴影 ,也不需要在 Additional Pass 中判断光源类型来处理光照哀减

透明度物体的阴影

  • 在alphaTest中实现阴影

1、FallBack “VertexLit” 中提供的 ShadowCaster 来投射阴影,并没有进行任何透明度测试的计算,而Transparent/Cutout/VertexLit 同时具有透明度测试和_Cutoff属性
2、默认情况下把物体渲染到 深度图 和 阴影映射纹理 中仅考虑物体的正面,所以要在面板中设置为two side

  • 在alphaBlend中实现阴影

透明度混合需要关闭深度写入 由此也影响了阴影的生成。 在Unity 中,所有内置的半透明 Shader 是不会产生任何阴影效果的
通过把它们的 Fallback 设置为VertexLit、Diffuse来强制为半透明物体生成阴影


代码

多光源

// 本示例处理一个平行光,四个点光源
//
// base Pass,
// 处理平行光,如果有多个平行光,选择最亮的进行逐像素处理,其他平行光会按照逐顶点  或在 Additional Pass 中按逐像素的方式处理
// 计算一次环境光和自发光
// 方向不变,衰减为1
//
// Additional Pass
// 其他每个光源调用一次该Pass:可以是平行光、点光源或是聚光灯(除了面光源)
// 开启并设置混合模式
// 根据光源类型计算方向和衰减(利用衰减纹理)  // 光源5属性:位置、方向、颜色、强度以衰减
//
// 认情况下1个物体可以接收除最亮的平行光外的4个逐像素光照Shader "Custom/ForwardRenderingMat"
{Properties{_Diffuse("Diffuse", Color) = (1, 1, 1, 1)_Specular("Specular", Color) = (1, 1, 1, 1)_Gloss("Gloss", Range(8.0, 256)) = 20}SubShader{Tags { "RenderType" = "Opaque" }Pass { // base Pass// Pass for ambient light & first pixel light (directional light)Tags { "LightMode" = "ForwardBase" }CGPROGRAM// Apparently need to add this declaration #pragma multi_compile_fwdbase    // 保证在Shader中使用光照衰减等光照变量#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"fixed4 _Diffuse;fixed4 _Specular;float _Gloss;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f {float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;};v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;return o;}fixed4 frag(v2f i) : SV_Target {fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;// 只需要计算一次即可,后面的 Additional Pass不会再计算(环境光+自发光)fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);fixed3 halfDir = normalize(worldLightDir + viewDir);fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);fixed atten = 1.0; // 平行光没有衰减return fixed4(ambient + (diffuse + specular) * atten, 1.0); // 此处多×了一个atten}ENDCG}Pass { // Additional Pass// Pass for other pixel lightsTags { "LightMode" = "ForwardAdd" }Blend One One // 开启和设置了混合模式CGPROGRAM// Apparently need to add this declaration#pragma multi_compile_fwdadd#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"#include "AutoLight.cginc"fixed4 _Diffuse;fixed4 _Specular;float _Gloss;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f {float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;};v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;return o;}fixed4 frag(v2f i) : SV_Target {fixed3 worldNormal = normalize(i.worldNormal);// 计算不同光源的方向#ifdef USING_DIRECTIONAL_LIGHT // 平行光fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);#elsefixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz); // 光源位置-顶点位置#endiffixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);fixed3 halfDir = normalize(worldLightDir + viewDir);fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);// 计算不同光源的衰减#ifdef USING_DIRECTIONAL_LIGHTfixed atten = 1.0;#else#if defined (POINT) // 利用衰减纹理得到衰减值,可以避免数学计算float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz; // 光源空间中的相对位置fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL; // 这个坐标的模的平方对_LightTexture0进行采样,得到衰减值 // UNITY_ATTEN_CHANNEL得到衰减值所在的分量#elif defined (SPOT)float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1));fixed atten = (lightCoord.z > 0) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;#elsefixed atten = 1.0;#endif#endifreturn fixed4((diffuse + specular) * atten, 1.0); // 没有再计算环境光;跟阴影的本质一样:都是与光照结果相乘}ENDCG}}FallBack "Specular" // 默认有LightMode为ShadowCaster的Pass,所以可以透射阴影
}

阴影

接收阴影

// 在ForwardRenderingMat的基础上,实现阴影的接收
// 使用三个内置宏 SHADOW_COORDS,TRANSFER_SHADOW, SHADOW_ATTENUATIONShader "Custom/shadow"
{Properties{_Diffuse("Diffuse", Color) = (1, 1, 1, 1)_Specular("Specular", Color) = (1, 1, 1, 1)_Gloss("Gloss", Range(8.0, 256)) = 20}SubShader{Tags { "RenderType" = "Opaque" }Pass {// Pass for ambient light & first pixel light (directional light)Tags { "LightMode" = "ForwardBase" }CGPROGRAM// Apparently need to add this declaration #pragma multi_compile_fwdbase #pragma vertex vert#pragma fragment frag// Need these files to get built-in macros#include "Lighting.cginc"#include "AutoLight.cginc" // 添加fixed4 _Diffuse;fixed4 _Specular;float _Gloss;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f {float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;SHADOW_COORDS(2) // 内置宏,声明一个用于对阴影纹理采样的坐标};v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;// Pass shadow coordinates to pixel shaderTRANSFER_SHADOW(o);return o;}fixed4 frag(v2f i) : SV_Target {fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);fixed3 halfDir = normalize(worldLightDir + viewDir);fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);fixed atten = 1.0;fixed shadow = SHADOW_ATTENUATION(i);return fixed4(ambient + (diffuse + specular) * atten * shadow, 1.0);}ENDCG}Pass {// Pass for other pixel lightsTags { "LightMode" = "ForwardAdd" }Blend One OneCGPROGRAM// Apparently need to add this declaration#pragma multi_compile_fwdadd// Use the line below to add shadows for point and spot lights//           #pragma multi_compile_fwdadd_fullshadows#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"#include "AutoLight.cginc"fixed4 _Diffuse;fixed4 _Specular;float _Gloss;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f {float4 position : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;};v2f vert(a2v v) {v2f o;o.position = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;return o;}fixed4 frag(v2f i) : SV_Target {fixed3 worldNormal = normalize(i.worldNormal);#ifdef USING_DIRECTIONAL_LIGHTfixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);#elsefixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);#endiffixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);fixed3 halfDir = normalize(worldLightDir + viewDir);fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);#ifdef USING_DIRECTIONAL_LIGHTfixed atten = 1.0;#elsefloat3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;#endifreturn fixed4((diffuse + specular) * atten, 1.0);}ENDCG}}FallBack "Specular"
}

Alpha Test With Shadow

// 在alphaTest中实现阴影
// FallBack "VertexLit" 中提供的 ShadowCaster 来投射阴影,并没有进行任何透明度测试的计算
// ransparent/Cutout/VertexLit 同时具有透明度测试和_Cutoff属性
// ,默认情况下把物体渲染 深度图 和阴 影映射纹理中仅考虑物体的正面,面板中设置为two sideShader "Unity Shaders Book/Chapter 9/Alpha Test With Shadow" {Properties {_Color ("Color Tint", Color) = (1, 1, 1, 1)_MainTex ("Main Tex", 2D) = "white" {}_Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5}SubShader {Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}Pass {Tags { "LightMode"="ForwardBase" }Cull OffCGPROGRAM#pragma multi_compile_fwdbase#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"#include "AutoLight.cginc"fixed4 _Color;sampler2D _MainTex;float4 _MainTex_ST;fixed _Cutoff;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;float4 texcoord : TEXCOORD0;};struct v2f {float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;float2 uv : TEXCOORD2;SHADOW_COORDS(3) // 声明阴影纹理坐标,3代表是第四个插值寄存器};v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);// Pass shadow coordinates to pixel shaderTRANSFER_SHADOW(o); // 用内置宏 TRANSFER_SHADOW 算阴影纹理坐标后传递给片元着色器return o;}fixed4 frag(v2f i) : SV_Target {fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));fixed4 texColor = tex2D(_MainTex, i.uv);clip (texColor.a - _Cutoff); // 透明度测试fixed3 albedo = texColor.rgb * _Color.rgb;fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));// UNITY_LIGHT_ATTENUATION not only compute attenuation, but also shadow infosUNITY_LIGHT_ATTENUATION(atten, i, i.worldPos); // 使用内置宏 UNITY_LIGHT_ATTENUATION 计算阴影和光照衰减:return fixed4(ambient + diffuse * atten, 1.0);}ENDCG}} FallBack "Transparent/Cutout/VertexLit"// FallBack "VertexLit"
}

Alpha Blend With Shadow

// FallBack "Transparent/VertexLit"  --->  FallBack "VertexLit"Shader "Unity Shaders Book/Chapter 9/Alpha Blend With Shadow" {Properties {_Color ("Color Tint", Color) = (1, 1, 1, 1)_MainTex ("Main Tex", 2D) = "white" {}_AlphaScale ("Alpha Scale", Range(0, 1)) = 1}SubShader {Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}Pass {Tags { "LightMode"="ForwardBase" }ZWrite OffBlend SrcAlpha OneMinusSrcAlphaCGPROGRAM#pragma multi_compile_fwdbase#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"#include "AutoLight.cginc"fixed4 _Color;sampler2D _MainTex;float4 _MainTex_ST;fixed _AlphaScale;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;float4 texcoord : TEXCOORD0;};struct v2f {float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;float2 uv : TEXCOORD2;SHADOW_COORDS(3)};v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);// Pass shadow coordinates to pixel shaderTRANSFER_SHADOW(o);return o;}fixed4 frag(v2f i) : SV_Target {fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));fixed4 texColor = tex2D(_MainTex, i.uv);fixed3 albedo = texColor.rgb * _Color.rgb;fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));// UNITY_LIGHT_ATTENUATION not only compute attenuation, but also shadow infosUNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);return fixed4(ambient + diffuse * atten, texColor.a * _AlphaScale);}ENDCG}} // FallBack "Transparent/VertexLit"// Or  force to apply shadowFallBack "VertexLit"
}

unity shader学习---光照模型(二)相关推荐

  1. Unity Shader 常规光照模型代码整理

    Unity Shader 常规光照模型代码整理 本次整理在Unity中几种常见的光照模型,包含 1.BlinnPhong(常规光照模型) 2.ForwardRender(多灯光带有衰弱前向渲染) 3. ...

  2. Unity Shader学习-高光反射

    Unity Shader学习-高光反射 高光反射计算公式 高光反射 = 光源的色彩和强度 * 材质的高光反射系数 * pow(max(0,视角方向 · 反射方向),_Gloss) 视角方向 = ref ...

  3. Unity Shader 学习笔记(27)渲染轮廓线(描边)方法、卡通风格渲染、素描风格渲染

    Unity Shader 学习笔记(27)渲染轮廓线(描边)方法.卡通风格渲染.素描风格渲染 参考书籍:<Unity Shader 入门精要> 渲染轮廓线(描边) 五种方法: 基于观察角度 ...

  4. Unity Shader 学习笔记(33) 全局光照(GI)、反射探针、线性空间和伽马空间、高动态范围(HDR)

    Unity Shader 学习笔记(33) 全局光照(GI).反射探针.线性空间和伽马空间.高动态范围(HDR) 参考书籍:<Unity Shader 入门精要> [<Real-Ti ...

  5. Unity Shader学习:SSAO屏幕环境光遮蔽

    Unity Shader学习:SSAO屏幕环境光遮蔽 主要思路:1.随机采样像素法线半球周围的像素,平均对比与该像素深度是否处在暗处.2.双边滤波去噪点.3.后期AO图与原图混合. 原文链接:http ...

  6. Unity Shader学习:动态模糊(shutter angle方式)

    Unity Shader学习:动态模糊 动态模糊一般有帧混合和motion vector两种,这里主要介绍motion vector的方法. Keijiro源码:https://github.com/ ...

  7. Unity Shader学习:水墨效果

    Unity Shader学习:水墨效果 偶然在网上看到9级铁甲蛹大神的水墨风格后处理觉得挺有意思,参照着实现一下,还是涉及到之前油画效果的算法,叫什么滤波暂时不清楚,应该用来处理手绘效果挺多的. 水墨 ...

  8. Unity Shader学习:体积光/体积阴影

    Unity Shader学习:体积光/体积阴影 在前向渲染下实现平行光的体积光影效果,需要全屏深度图,延迟渲染会更划算. 思路:通过ray marching的步进点位置计算该点是否在阴影中,采样阴影贴 ...

  9. Unity Shader学习:SSR屏幕空间反射

    Unity Shader学习:SSR屏幕空间反射 本文在前向渲染模式下实现,延迟渲染更适合SSR,这里只简单的实现下,未作更深入的优化. 思路:沿视线和法线的反射向量步进光线,判断打到物体(这里用的是 ...

最新文章

  1. python程序设计报告-Python程序设计实验一报告
  2. 《 Spring1之第二次站立会议(重发)》
  3. 10倍!微软开源深度学习优化库DeepSpeed,可训练1000亿参数模型
  4. 带你自学Python系列(六):列表解析和列表切片
  5. RabbitMQ安装---rpm安装
  6. weblogic启动项目失败查看_weblogic启动报错常见错误解决办法
  7. ADO.NET Command对象简介
  8. php根据图片地址获取图片原始高宽,Js获取图片原始宽高的实现代码
  9. 计算一条3d空间直线和一个3d空间平面的交点
  10. python双色球代码_python实现双色球随机选号
  11. 平面坐标转大地坐标(经纬度)
  12. matlab 双均线,[转载]百年一人的双均线系统及双均线系统公式
  13. 为什么篮球一进游戏就服务器中断,街头篮球手游进不去 进不去游戏无非这两种原因...
  14. SpringBoot整合IoTDB
  15. 2021/05/07 1031 查验身份证 (15 分)
  16. VS2019中Git源代码管理总结
  17. 《Windows 8 权威指南》——2.4 Aero与Metro的触摸对比
  18. Kubectl(完整)基本操作命令
  19. ym——物联网入口之一Android蓝牙4.0
  20. 货币金融学之基本概念

热门文章

  1. MUR1100-ASEMI轴向快恢复二极管MUR1100
  2. 奥比中光 astra 乐视三合一体感摄像头采集深度图彩色图并保存
  3. html网页鼠标样式、css精灵、iconfont、过渡动画笔记
  4. MEM/MBA数学基础(05)应用题 关键点
  5. PHP:简单数学勾股定理
  6. c语言定义max和命令,C语言#define定义函数
  7. 普通计算机如何按照mac,普通电脑怎么装苹果系统_普通笔记本能装苹果系统吗-win7之家...
  8. NYOJ 买牛奶(水题)
  9. scp 解除链接问题的两个解决方案
  10. 阿里巴巴构架重大调整:六个子公司变七大事业群