光学概念简单介绍
1.辐射照度
量化光的单位(W/m²)
2.光线与物体相交,要么被散射要么被吸收
1.散射:(改变光线方向,不改变光线密度和颜色)
-
散射到物体内部,称为折射或透射。折射到物体内部的光线,有些还会重新发射出物体表面。
- 另一种散射到物体外部,称为反射。
2.吸收:(改变光线密度和颜色,不改变光线方向)
光照模型
1.标准光照模型(Blinn Phong)
把进入摄像机范围内的光线分为4个部分:
1.1 自发光() - 物体表面向某个方向发射的辐射量,如果没有全局光照技术,自发光表面不会照亮周围物体,只是本身看起来更亮而已。标准光照模型中
= (材质自发光颜色)
1.2 高光反射() - 当光源光线照到模型表面时,该表面在完全镜面反射方向散射的辐射量。
求反射光线:
Phong模型计算高光反射:
= 光泽度(gloss) or 反光度(shininess) = 材质高光反射颜色 = 光源颜色和强度
计算反射光线耗时,Blinn提出用 I 和 v取平均后,再归一化得到。
Blinn模型计算高光反射:
1.3 漫反射() - 当光源光线照到模型表面时,该表面向每个方向散射的辐射量。
兰伯特光照模型:反射光线强度和物体表面法线与光源方向的余弦值成正比。防止点乘为负,加个max限制一下
半兰伯特光照模型:使用a和b参数将n和I的点积从[-1,1]映射到[0,1]范围内。
= 光源颜色 = 漫反射颜色 n表面法线 I指向光源的单位矢量
1.4 环境光() - 描述其他间接光照。标准光照模型中所有物体都使用一个环境光
=
Unity设置环境光,Shader设置通过变量可直接获取,UNITY_LIGHTMODEL_AMBIENT
逐像素光照(Phong着色)
基于每像素,用每个像素的法线进行光照计算,每个像素的法向量是通过顶点的法向量插值得到的。
逐顶点光照(高洛德着色 Gouraud)
基于顶点计算光照计算,然后计算得到的颜色插值顶点所在三角面。
实践1
1.兰伯特逐顶点计算的漫反射
Shader "Chan/Chapter6_DiffuseVertexLevel" {
Properties
{
_Diffuse("Diffuse",Color) = (1,1,1,1)
}
SubShader
{
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
//输入结构体
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
//输出结构体
struct v2f
{
float4 pos:SV_POSITION;
fixed3 color:COLOR;
};
//顶点着色器
v2f vert(a2v v)
{
v2f o;
//顶点从模型空间转换到裁剪空间
o.pos = UnityObjectToClipPos(v.vertex);
//获取环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//顶点法线转换到模型空间转化到世界空间
fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
//世界空间下的光源方向 _WorldSpaceLightPos0(只有一个光源,并且是平行光时)
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
//兰伯特光照模型计算漫反射
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLight));
//环境光 + 漫反射 = 最终颜色
o.color = ambient + diffuse;
return o;
}
//片元着色器 - 输出顶点颜色
fixed4 frag(v2f i):SV_Target
{
return fixed4(i.color,1.0);
}
ENDCG
}
}
Fallback "Diffuse"
}
2.兰伯特逐像素计算的漫反射
Shader "Chan/Chapter6_DiffusePixelLevel" {
Properties
{
_Diffuse("Diffuse",Color) = (1,1,1,1)
}
SubShader
{
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
//输入结构体
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
//输出结构体
struct v2f
{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
};
//顶点着色器
v2f vert(a2v v)
{
v2f o;
//顶点从模型空间转换到裁剪空间
o.pos = UnityObjectToClipPos(v.vertex);
//顶点法线转换到模型空间转化到世界空间
o.worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
return o;
}
//片元着色器 - 输出顶点颜色
fixed4 frag(v2f i):SV_Target
{
//获取环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//世界空间下的光源方向 _WorldSpaceLightPos0(只有一个光源,并且是平行光时)
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
//世界空间下归一化的法线
fixed3 worldNormal = normalize(i.worldNormal);
//兰伯特光照模型计算漫反射
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLight));
fixed3 color = ambient + diffuse;
return fixed4(color,1.0);
}
ENDCG
}
}
Fallback "Diffuse"
}
3.半兰伯特逐像素计算的漫反射
Shader "Chan/Chapter6_HalfLambert" {
Properties
{
_Diffuse("Diffuse",Color) = (1,1,1,1)
}
SubShader
{
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
//输入结构体
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
//输出结构体
struct v2f
{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
};
//顶点着色器
v2f vert(a2v v)
{
v2f o;
//顶点从模型空间转换到裁剪空间
o.pos = UnityObjectToClipPos(v.vertex);
//顶点法线转换到模型空间转化到世界空间
o.worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
return o;
}
//片元着色器 - 输出顶点颜色
fixed4 frag(v2f i):SV_Target
{
//获取环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//世界空间下的光源方向 _WorldSpaceLightPos0(只有一个光源,并且是平行光时)
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
//世界空间下归一化的法线
fixed3 worldNormal = normalize(i.worldNormal);
//
fixed halfLambert = dot(worldNormal,worldLight) * 0.5 + 0.5;
//半兰伯特光照模型计算漫反射
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert;
fixed3 color = ambient + diffuse;
return fixed4(color,1.0);
}
ENDCG
}
}
Fallback "Diffuse"
}
实践2
1.逐顶点的Phong光照模型计算
Shader "Chan/Chapter6_SpecularVertexLevel" {
Properties {
_Diffuse("Diffuse",Color) = (1,1,1,1)
_Specular("Specular",Color) = (1,1,1,1)//高光反射系数
_Gloss("Gloss",Range(8,256)) = 20//光泽度or反光度
}
SubShader {
Pass
{
Tags{"LightMode" = "Forwardbase"}
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f
{
float4 pos:SV_POSITION;
fixed3 color:COLOR;
};
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
//环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//法线从模型空间转化到世界空间
fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
//世界空间下的光源方向 _WorldSpaceLightPos0(只有一个光源,并且是平行光时)
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
//兰伯特光照模型计算漫反射
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir));
//光源方向和法线,求得反射光线方向
//-----worldLightDir = 交点指向光源方向,公式需要光源指向交点,因此取反-----
fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));
//世界空间下的摄像机座标 - 世界空间下的顶点座标 = 顶点的的视角方向
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld,v.vertex).xyz);
//Phong光照模型高光反射
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir,viewDir)),_Gloss);
//环境光 + 漫反射 + 高光反射 = 最终颜色
o.color = ambient + diffuse + specular;
return o;
}
fixed4 frag(v2f i):SV_Target
{
return fixed4(i.color,1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
2.逐像素的Phong光照模型
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
Shader "Chan/Chapter6_SpecularPixelLevel" {
Properties {
_Diffuse("Diffuse",Color) = (1,1,1,1)
_Specular("Specular",Color) = (1,1,1,1)//高光反射系数
_Gloss("Gloss",Range(8,256)) = 20//光泽度or反光度
}
SubShader {
Pass
{
Tags{"LightMode" = "Forwardbase"}
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f
{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
fixed3 worldPos:TEXCOORD1;
};
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
//得到世界空间下的法线和顶点
//unity_WorldToObject = 模型空间到世界空间的变换矩阵的逆矩阵
o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
return o;
}
fixed4 frag(v2f i):SV_Target
{
//环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
float3 worldNormal = normalize(i.worldNormal);
//世界空间下的光源方向 _WorldSpaceLightPos0(只有一个光源,并且是平行光时)
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
//兰伯特光照模型计算漫反射
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir));
//光源方向和法线,求得反射光线方向
//-----worldLightDir = 交点指向光源方向,公式需要光源指向交点,因此取反-----
fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));
//世界空间下的摄像机座标 - 世界空间下的顶点座标 = 顶点的的视角方向
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
//Phong光照模型高光反射
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir,viewDir)),_Gloss);
//环境光 + 漫反射 + 高光反射 = 最终颜色
return fixed4(ambient + diffuse + specular,1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
实践3
1.Binn-Phong光照模型
Shader "Chan/Chapter6_BlinnPhong" {
Properties {
_Diffuse("Diffuse",Color) = (1,1,1,1)
_Specular("Specular",Color) = (1,1,1,1)//高光反射系数
_Gloss("Gloss",Range(8,256)) = 20//光泽度or反光度
}
SubShader {
Pass
{
Tags{"LightMode" = "Forwardbase"}
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f
{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
fixed3 worldPos:TEXCOORD1;
};
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
return o;
}
fixed4 frag(v2f i):SV_Target
{
//环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
float3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir));
fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
fixed3 halfDir = normalize(worldLightDir + viewDir);
//Blinn-Phong光照模型高光反射
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal,halfDir)),_Gloss);
return fixed4(ambient + diffuse + specular,1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}