光
物理学中,光是电磁波。
1.光由太远或者其他光源被发射出来
2.与场景中的对象相交 ==>吸收、散射
3.最后光线被一个感应器(眼睛)吸收成像
- 基础光照
光线与物体相交的结果
光线方向 | 光线颜色 | 结果 | ||
吸收 | 由于光被转化成了其他能量 | 不改变 | 改变密度和颜色 | |
散射 | 改变 | 不改变 | 折射、反射 物体表面重新发射出光线 | |
自发光 |
散射方向 | 光照模型 | 定义 |
反射 | 高光反射 | 物体表面是如何反射的 |
折射 | 漫反射 | 有多少光线会被折射、吸收和散射出表面 |
- 标准光照模型
只关心直接光照,即那些直接从光源发射处理照射到物体表面后,经过物体表面的一次反射直接进入摄像机的光线
描述 | unity表示 | |
自发光 | 当给定一个方向时,一个表面本身会向该方向发射多少辐射量 | 材质的自发光颜色 |
高光反射 | 光线照射到模型表面时,表面会在完全镜面反射方向散射多少辐射量 | Phong 模型1 Blinn模型2 |
漫反射 | 光线照射到模型表面时, 表面会向每个方向散射多少辐射量 | 兰伯特定律3 |
环境光 | 其他所有的间接光照4 | UNITY_LIGHTMODEL_AMBIENT.xyz |
在硬件实现中,如果摄像机和光源距离模型足够远的话,Blinn模型会快于Phong模型
- UnityShader中实现漫反射光照模型
/**********************************
* 逐顶点光照的漫反射效果
***********************************/
Shader "Unit/VertexLight" {
Properties{
_Diffuse("Diffuse", Color) = (1.0,1.0,1.0,1.0) //声明一个Color类型的属性
}
SubShader{
Pass{
Tags{"LightMode" = "ForwardBase"}
CGPROGRMA
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
struct a2v{
float4 vertext:POSITION;
float3 normal:NORMAL;
};
struct v2f{
float4 pos:SV_POSITION;
float3 color:COLOR;
};
float4 _Diffuse;
v2f vert(a2v v){
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
//环境光
float3 ambient = UNITY_LIGHTMODEL_AMBINET.xyz;
//光线方向
float3 worldlight = normalize(_WorldSpaceLightPos0.xyz);
//法线==>世界空间中的法线
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
float3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldlight));
//把所有的颜色相加
o.color= ambient + diffuse ;
return o;
}
fixed4 frag(v2f i):SV_Target{
fixed3 color = i.color;
return fixed4(color, 1.0);
}
ENDCG
}
}
Fallback "Diffuse"
}
名词解析:
saturate(x)
/// < summary>
/// 防止点积结果为负值
/// < /summary>
/// < param name=“x”> 用于操作的标量或矢量
/// < returns>在[0,1]范围内
/**********************************
*逐像素光照实现漫反射效果
***********************************/
Shader "Unit/PixDiffuseLight" {
Properties{
_Diffuse("Diffuse", Color) = (1.0,1.0,1.0,1.0) //声明一个Color类型的属性
}
SubShader{
Pass{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
};
fixed4 _Diffuse;
//顶点函数
v2f vert(av2 v){
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal= UnityObjectToWorldNormal(v.normal);
return o;
}
//片元函数
fixed4 frag(v2f i):SV_Target{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(i.worldNormal, worldLightDir ));
fixed3 color = ambient + diffuse;
return fixed4(color,1.0);
}
ENDCG
}
}
Fallback "Diffuse"
}
/************************************
逐像素光照效果
*半伯兰特光照模型--Half Lambert
*************************************/
Shader "Unit/HalfLambertLight" {
Properties{
_Diffuse("Diffuse", Color) = (1,1,1,1)
}
SubShader{
Pass{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
};
float4 _Diffuse;
v2f vert(a2v v){
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 frag(v2f i) : SV_Target{
fixed3 ambient = UNITY_LIGHTMODEL_AMBINET.xyz;
fixed3 worldLightDir = Normalize(_WorldSpaceLightPos0.xyz);
//半兰伯特光照计算替换了直接 dot(法线方向,光线方向)
fixed3 halfLambert = dot(i.worldNormal , worldLightDir )*0.5 + 0.5;
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert ;
fixed3 color = diffuse + ambient;
return fixed4(color, 1.0);
}
ENDCG
}
}
Fallback "Diffuse"
}
总结
特点 | 缺陷 | 计算公式 | 计算位置 | |
逐顶点光照 | 细分程度高的模型,可以得到比较好的效果 | 背光面与向光交界有锯齿 | diffuse = light * diffuse * max(0,dot(法线方向,光线方向)) | 顶点着色器–高洛德着色 |
逐像素光照 | 平滑的光照效果 | 在光照无法到达的区域,模型外观为黑色,没有明暗变化 | 同上 | 片元着色器–Phong着色 |
半兰伯特光照 | 背光面也有明暗变化 | diffuse = light * diffuse * (dot(法线方向,光线方向)*0.5+0.5)) | 片元着色器 |
- 高光反射光照模型
/********************************************
逐顶点实现高光反射效果
*********************************************/
Shader"VertexSpecular"
{
Properties {
_Diffuse("Diffuse", Color) = (1,1,1,1)
_Specular("Specular", Color) = (1,1,1,1)
_Glosss("Gloss", Range(8,256)) = 10
}
Pass {
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f{
float4 pos:SV_POSITION;
float3 color:COLOR;
};
float4 _Diffuse;
float4 _Specular;
float _Glosss;
v2f vert(a2v v){
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
//法线方向==>转换到世界空间中
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
//光线方向归一化
float3 worldLightdir = normalize(UnityWorldSpaceLightDir(mul(unity_ObjectToWorld, v.vertex).xyz));
//环境光
float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//漫反射--半兰伯特光照模型
float3 diffuse = _LightColor0.rgb * _Diffuse.rgb * (dot(worldNormal, worldLightdir)*0.5 +0.5);
//反射方向
fixed3 relfdir = normalize(reflect(-worldLightDir, worldNormal));
//视角方向==>世界空间中
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(mul(unity_ObjectToWorld, v.vertex).xyz));
float3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(relfdir, viewDir )), _Glosss);
//环境光+漫反射+高光反射
o.color = ambient + diffuse + specular;
return o;
}
fixed4 frag(v2f i):SV_Target{
return fixed4(i.color, 1);
}
ENDCG
}
Fallback "Specular"
}
reflect(i,n)
/// <summary>
/// 获取顶点的反射方向
/// < /summary>
/// <param name="i">入射方向</param>
/// <param name="n">法线方向</param>
/*******************************************
逐像素实现高光效果 -- Phong模型
********************************************/
Shader"PiexSpecular"
{
Properties{
_Diffuse("Diffuse", Color) = (1,1,1,1)
_Speculr("Specular", Color) = (1,1,1,1)
_Gloss("Gloss", Range(8,256)) = 10
}
Pass{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fargment frag
#include "Lighting.cginc"
struct a2v{
float4 vertex : POSITION;
float3 normal:NORMAL;
};
struct v2f{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
float3 worldPos:TEXCOORD1;
};
float4 _Diffuse;
float4 _Speculr;
float _Gloss;
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 = i.worldNormal;
//光线方向
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
//视角方向
fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
//反射方向
fixed3 reflDir = normalize(reflect(-worldLightDir , worldNormal));
//环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//漫反射
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir ));
//高光反射
fixed3 specular = _LughtColor0.rgb * _Speculr.rgb * pow(max(0, dot(worldNormal, reflDir )), _Gloss);
fixed3 color = ambient + diffuse + specular ;
return fixed4(color, 1);
}
ENDCG
}
Fallback"Specular"
}
/******************************************
逐像素实现高光效果 --Blinn-Phong光照模型
******************************************/
Shader"BlinnPhongSpecular"
{
Properties{
_Diffuse("Diffuse", Color) = (1,1,1,1)
_Speculr("Specular", Color) = (1,1,1,1)
_Gloss("Gloss", Range(8,256)) = 10
}
Pass{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#progam vertex vert
#progam fragment frag
#include "Lighting.cginc"
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
float3 worldPos:TEXCOORD1;
};
float4 _Diffuse;
float4 _Speculr;
float _Gloss;
v2f vert(a2v v){
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNoraml(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
fixed4 frag(v2f i):SV_Target{
//法线
fixed3 worldNormal = i.worldNormal;
//光照方向
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
//视角方向
fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
//反射方向
fixed3 reflDir = normalize(reflect(-worldLightDir, worldNormal));
//环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//漫反射
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir ));
//Blinn光照 ==>视角方向与光照方向归一化
fixed3 halfDir = normalize(worldLightDir + worldViewDir );
//高光反射
fixed3 specular = _LightColor0.rgb * _Speculr.rgb * pow(saturate(dot(worldNormal, halfDir )), _Gloss);
fixed3 color = ambient + diffuse + specular ;
return fixed4(color, 1);
}
ENDCG
}
}
总结
缺陷 | ||
逐顶点高光反射 | 高光部分不平滑 高光反射计算是非线性的,顶点计算光照再插值也是线性,破坏了原非线性 | |
逐像素高光反射 | 高光部分更加平滑 | Phong光照模型 |
Blinn-Phong高光反射 | 高光反射部分更大更亮 | Blinn-Phong光照模型 |
- 光源类型
光源类型 | 几何定义 | 方向 | 位置 | 颜色 | 强度 | 例子 | 放置 |
平行光 | 照亮的范围是无限的 | 只有方向,到场景中所有点的方向一样 | 没有唯一的位置 | 不发生改变 | 太阳 | 光线方向略微向下,与场景中的对象形成一个小角度。 | |
点光源 | 有限的空间,球体 | 方向=点光源的位置-某点的位置 | 由Position定义 | Light面板 | 中心–>边缘减小 | 模拟火花或爆炸照亮周围环境 | 场景对象决定 |
聚光灯 | 有限的空间,锥形区域 | 方向=聚光灯的位置-某点的位置 | 由Position定义 | 中心–>边缘减小 | 人造光源,例如手电筒、汽车前照灯和探照灯 | 场景对象决定 | |
面光源 | 通过空间中的矩形来定义 | 表面区域上均匀地向所有方向上发射,但仅从矩形的所在的面发射 | 无法手动控制面光源的范围 | 远离光源时,强度将按照距离的平方呈反比衰减 | 计算对处理器性能消耗较大,不能实时处理,仅烘培的时才可发挥作用,路灯、室内光照 | ||
发光材质 | 发光材质在其表面区域发光 | 以方差速率衰减 | 自发光材质产生氖灯或其他可见光源之类的效果 | ||||
环境光 | 场景周围存在的光,并且不来自任何特定的光源对象 |
- 前向渲染中处理不同的光源类型
/***********************************************
使用平行光和一个点光源共同照亮物体
前向渲染、Blinn-Phong 光照模型
***********************************************/
Shader "ForwardRendering"
{
Properties{
_Diffuse("Diffuse", Color) = (1,1,1,1)
_Specular("Specular", Color) = (1,1,1,1)
_Gloss("Gloss", Range(8,256)) = 10
}
Pass{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//正确使用光照衰减等光照
#pragma multi_compile_fwdbase
#include "Lighting.cginc"
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
float3 worldPos:TEXCOORD1;
};
float4 _Diffuse;
float4 _Specular;
float _Gloss;
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 wnormal = normalize(i.worldNormal);
//光照方向
fixed3 wlightdir = normalize(_WorldSpaceLightPos0.xyz);
//视角方向
fixed3 wViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
//half
fixed3 halfView = normalize(wlightdir + wViewDir );
//环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//漫反射
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(wnormal, wlightdir ));
//高光反射
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(wnormal, halfView)), _Gloss);
fixed3 color = ambient + diffuse +specular ;
fixed3 atten = 1.0;//平行光无衰减
return fixed4(color * atten, 1);
}
ENDCG
}
Pass{
Tags{"LightMode" = "ForwardAdd"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdadd
#include "Lighting.cginc"
#include "Autolight.cginc"
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
float3 worldPos:TEXCOORD1;
};
float4 _Diffuse;
float4 _Specular;
float _Gloss;
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 wnormal = normalize(i.worldNormal);
fixed3 tarantLightDir = UnityWorldSpaceLightDir(i.worldPos);
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(tarantNormal, tarantLightDir));
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(tarantNormal, halfDir)), _Gloss);
//平行光没由衰减
#ifdef USING_DIRECTIONAL_LIGHT
fixed atten = 1.0;
#else
//光源在空间中的位置
float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;
//对_LightTexture0纹理采样得到定点到该光源的衰减值
fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;//获取衰减纹理中衰减值的分量
#endif
fixed3 color = (diffuse + specular) * atten;
return fixed4(color, 1.0);
}
ENDCG
}
Fallback"Specular"
}
- Unity的光照衰减
- Unity的阴影
为了让场景看起来更加真实,具有深度信息。
判断距离的表面位置?
方法 | 缺陷 | |
一 | 1.摄像机处于光源处 2.按正常的渲染流程更新深度信息 3.得到阴影映射纹理 | 性能浪费 只需要深度信息,但却计算了光照模型 |
二 使用额外的Pass专门更新光源的阴影映射纹理 | 1…摄像机处于光源处 2.调用ShadowCaster Pass 3. 顶点变换到光源空间下 4.输出深度信息到阴影映射纹理 |
过程 | 结果 | 实现 | |
物体接收其他物体的阴影 | shader中对阴影映射纹理采样 | 采样结果*光照结果 = 产生阴影效果 | |
向其他物体投射阴影 | 把物体加入到光源的阴影映射纹理的计算中 | 其他物体对阴影映射纹理采样时可以得到物体的相关信息 | LightMode = ShadowCaster 的Pass |
/******************************************
//不透明物体的阴影
//Light组件开启阴影->让物体接收阴影
统一管理光照衰减和阴影
******************************************/
Shader "Shadow"
{
Properties{
_Diffuse("Diffuse", Color) = (1,1,1,1)
_Specular("Specular", Color) = (1,1,1,1)
_Gloss("Gloss", Range(8,256)) = 10
}
Pass{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "AutoLight.cginc"
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL; };
struct v2f{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
float3 worldPos:TEXCOORD1;
SHADOW_COORDS(2); //宏:声明一个用于对阴影纹理采样的坐标。参数:占用插值寄存器的索引
};
float4 _Diffuse;
float4 _Specular;
float _Gloss;
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); //宏:用于计算上一步中声明的阴影纹理坐标
}
fixed4 frag(v2f i):SV_Target{
//fixed shadow = SHADOW_ATTENUATION(i);//宏:计算阴影值
SHADOW_LIGHT_ATTENUATION(atten, i, i.worldPos); //宏:内置计算光照衰减和阴影
fixed3 wNormal = normalize(i.worldNormal);
fixed3 wLightdir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 wViewdir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 halfdir = normalize(wLightdir + wViewdir );
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(wNormal, wLightdir));
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(wNormal, halfdir)), _Gloss);
fixed3 color = ambient +(diffuse + specular)* atten;
return fixed4(color, 1);
}
ENDCG
}
Pass{
Tags{"LightMode" = "ForwardAdd"}
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "AutoLight.cginc"
struct a2v{
float4 vertex : POSITION;
float3 normal:NORMAL;
};
struct v2f{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
float3 worldPos:TEXCOORD1;
SHADOW_COORD(2)
};
float4 _Diffuse;
float4 _Specular;
float _Gloss;
v2f vert(a2v v){
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
TRANFER_SHADOW(o);
return o;
}
fixed4 frag(v2f i):SV_Target{
fixed3 wNormal = normalize(i.worldNormal);
fixed3 wLightdir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 wViewdir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 halfdir = normaize(wLightdir + wViewdir);
fixed3 diffuse = _LightColor0.rgb * _Diffus.rgb * saturate(dot(wNormal , wLightdir ));
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(wNormal, halfdir)),_Gloss);
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
fixed3 color = (diffuse + specular)*atten;
return fixed4(color, 1);
}
ENDCG
}
Fallback "Specular"
}
透明度物体的阴影
透明物体的实现会使用透明度测试或透明度混合
透明度测试 | |
透明度混合 |
/*********************************************************
透明度物体的阴影
1.透明度测试 + 阴影
**********************************************************/
Shader "AlphaTestAtten"{
Properties{
_Color("Color Tint", Color) = (1,1,1,1)
_MainTex("Main Tex", 2D) = "white"{}
_Cutoff("Cut Off", Range(0,1)) = 0.5
}
SubShader{
Tags{"Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType"="TransparentCutout"}
Pass{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "AutoLight.cginc"
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
float4 texcoord:TEXCOORD0;
};
struct v2f{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
float3 worldNormal:TEXCOORD1;
float4 worldPos:TEXCOORD2;
SHADOW_COORDS(3)
};
float4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
half _Cutoff;
v2f vert(a2v v){
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.worldPos = mul(unity_ObjetToWorld, v.vertex).xyz;
TRANSFER_SHADOW(o);
return o;
}
fixed4 frag(v2f i):SV_Target{
fixed3 wNormal = normalize(i.worldNormal);
fixed3 wLightdir = normalize(UnityWorldLightDir(i.worldPos));
fixed4 texcoord = tex2D(_MainTex, i.uv);
clip(texcoord.a - _Cutoff);
fixed3 albedo = texcoord.rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(wNormal, wLightdir));
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
fixed3 color = ambient + diffuse * atten;
return fixed4(color, 1.0);
}
ENDCG
}
}
FallBack "VertexLit"
}
/*********************************************************
透明度物体的阴影
1.透明度混合 + 阴影
**********************************************************/
Shader "AlphaBlendAtten"{
Properties{
_Color("Color Tint", Color) = (1,1,1,1)
_MainTex("Main Tex",2D) = "white"{}
_AlphaScale("Alpha Scale", Range(0,1)) = 1.0
}
SubShader{
Tags{"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
Pass{
Tags{"LightMode" = "ForwardBase"}
ZWrite Off //深度写入关闭
Blend SrcAlpha OneMinusSrcAlpha //混合开启
CGPROGRAM
#pragma multi_compile_fwdbase //前向渲染
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
#include "AutoLight.cginc"
struct a2v {
float4 vertex : POSITION;
float3 normal:NORMAL;
float4 texcoord:TEXCOORD0;
};
struct v2f {
float4 pos:SV_POSITION;
float3 worldPos:TEXCOORD0;
float3 worldNormal:TEXCOORD1;
float2 uv:TEXCOORD2;
SHADOW_COORDS(3)
};
float4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _AlphaScale;
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;
}
fixed4 frag(v2f i):SV_Target{
fixed3 wNormal = normalize(i.worldNormal);
fixed3 wLightdir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texcoord = tex2D(_MainTex, i.uv);
fixed3 albedo = texcoord.rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(wNormal, wLightdir));
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
fixed3 color = ambient + diffuse * atten;
return fixed4(color, texcoord.a * _AlphaScale);
}
ENDCG
}
}
Fallback "VertexLit" //透明物体可以显示阴影强制生成阴影
//"Transparent/VertexLit" 不会投射阴影,也不会接收阴影
}
在Unity中,所有内置的半透明Shader是不会产生任何阴影效果
Lighting面板
2018版本
Scene | 设置适用于整体场景,而不是个别游戏对象。控制光照效果和优化选项 | Other Setting |
Global maps | 显示 GI 光照过程生成的所有光照贴图资源文件 | |
Object maps | 显示当前所选游戏对象的 GI 光照贴图纹理(包括阴影遮罩)的预览 | |
Auto Generate | Unity 将在您编辑场景时更新光照贴图数据 | 非立即完成 |
Generate Lighting | 需要的时候触发光照贴图更新 | 不清除 GI 缓存的情况下清除场景中的烘焙数据使用 |
面板统计信息:
Memory Usage 内存使用量 | 当前光照贴图所需的内存量 |
Occupied Texels 占用的纹理像素 | 在光照贴图 UV 空间中占用的纹理像素数量 |
Lightmaps in view 视图中的光照贴图 | Scene 视图中的光照贴图数量 |
Lightmaps not in view | 不在视图中的光照贴图数量 |
Converged 融合 | 光照贴图的所有计算都已完成 |
Not Converged 未融合 | 光照贴图的烘焙仍在进行中 |
Bake Performance: | 每秒的射线数。 如果此值较低(即小于2),则应调整设置或硬件以一次处理更多光线 |
实时全局光照(Global Illumination, GI)流水线
场景中的物体不仅可以受直接光照的影响,还可以接受间接光照的影响。
全局光照:模拟光线是如何在场景中传播的考虑那些直接光照、间接光照
直接光照:直接把光照射到物体表面的光源
间接光照:那些被场景中其他物体反弹的光
光照贴图
Unity 采用了 Enlighten (2019已弃用) 和 渐进 CPU 光照贴图 (Progressive CPU Lightmapper)
渐进 CPU 光照贴图 | 一种基于路径追踪的光照贴图系统,提供了能在Edtior中逐渐刷新的烘焙光照贴图和光照探针 |
- Phong 模型
- 为负数 ↩︎
- Blinn模型
- ↩︎
- 兰伯特定律
- ↩︎
- 光线通常会在多个物体之间反射,最后进入摄像机。 ↩︎