Unity Shader学习笔记:标准光照模型

来源:互联网 发布:linux操作vasp计算 编辑:程序博客网 时间:2024/05/17 07:56

变量设定:
l:把光源当成一个没有体积的点,用l来表示它的方向。

概念解析:
辐照度:用来量化一个光源发射出了多少光。对于平行光来说:它的辐照度可通过计算在垂直于l的单位面积上单位时间内穿过的能量来得到。
物体表面的辐射度 = 光源方向l和物体表面法线n之间的夹角的余弦值。
注意:这里默认方向矢量的模都为1.
着色:根据材质属性(如漫反射属性等)、光源信息(如光源方向、辐射度等),使用一个等式(也叫做光照模型)去计算沿某个观察方向的出射度的过程。

标准光照模型:自发光计算公式 + 高光反射计算公式 + 漫反射计算公式 + 环境光计算公式
标准光照模型只关心直接光照,也就是那些直接从光源发射出来照射到物体表面后,经过物体表面的一次反射直接进入摄像机的光线。
它的基本方法是,把进入到摄像机内的光线分为4个部分,每个部分使用一种方法计算它的贡献度。这四个部分是:
自发光:使用Cemissive来表示。这个部分描述当给定一个方向时,一个表面本身会向该方向发射多少辐射量。需要注意的是,如果没有使用全局光照技术。这些自发光的表面并不会真的照亮周围的物体,而是它本身看起来更亮了而已。
高光反射:使用Cspecular来表示。这个部分用于描述当光线从光源照射到模型表面时,该表面会在完全镜面反射方向散射多少辐射量。
漫反射:使用Cdiffuse来表示。这个部分用于描述当光线从光源照射到模型表面时,该表面会向每个方向散射多少辐射量。
环境光:使用Cambient来表示。它用于描述其他所有的间接光照。

环境光计算公式:
在真实世界中,物体也可以被间接光照所照亮。间接光照指的是:光线通常会在多个物体之间反射,最后进入摄像机,也就是说,在光线进入摄像机前,经过了不止一次的物体反射。
在标准光照模型中,我们使用了一种被称为环境光的部分来近似模拟间接光照。环境光的计算非常简单,它通常是一个全局变量,即场景中的所有物体都使用这个环境光。
Cambient = Gambient

自发光:
光线可以直接由光源进入摄像机,而不需要经过任何物体的反射。标准光照模型使用自发光来计算这个部分的贡献度。它的计算也很简单,就是直接使用了该材质的自发光颜色。
Cemissive = Memissive

漫反射:
漫反射光照是用于对那些被物体表面随机散射到各个方向的辐射度进行建模的。在漫反射中,视角的位置是不重要的,因为反射是完全随机的,因此可以认为在任何反射方向上的分布都是一样的。但是,入射光线的角度很重要。
1.使用兰伯特定律计算漫反射:反射光线的强度与表面法线和光源方向之间夹角的余弦值成正比
Cdiffuse = (Clight · Mdiffuse)max(0,^n · ^l)
其中^n是表面法线,^l是指向光源的单位矢量,Mdiffuse是材质的漫反射颜色,Clight是光源颜色
2.使用半兰伯特光照模型:
Cdiffuse = (Clight · Mdiffuse)(a(^n · ^l) + b)
绝大多数情况下:a和b的值均为0.5,即公式为:Cdiffuse = (Clight ·Mdiffuse)(0.5(^n · ^l) + 0.5)

高光反射:
这里的高光反射是一种经验模型,也就是说,它并不完全符合真实世界中的高光反射现象。它可用于计算那些沿着完全镜面反射方向被反射的光线,这可以让物体看起来是有光泽的。例如:金属材质
1.使用Phong模型来计算高光反射的部分:Cspecular = pow((Clight ·Mspecular)max(0,^v · ^r),Mgloss)
其中^r表示反射方向,^r = 2(^n · ^r)^n - ^l
其中Mgloss是材质的光泽度,也被称为反光度。它用于控制该材质对于高光反射的强度和颜色。Clight则是光源的颜色和强度。
2.(大多数情况下采用)使用Blinn模型来计算高光反射的部分:Cspecular = pow((Clight · Mspecular)max(0,^n · ^h),Mgloss)
其中^h = (^v + ^l)/(|^v + ^l|);

逐像素光照:在片元着色器中计算光照模型
逐顶点光照:在顶点着色器中计算光照模型

实现代码:
逐顶点光照

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'Shader "Own/Chapter6-Light"{    Properties    {        //漫反射颜色        _Diffuse("Diffuse",Color) = (1,1,1,1)        //高光反射颜色        _Specular("Specular",Color) = (1,1,1,1)        //高光区域的大小        _Gloss("Gloss",Range(8.0,256)) = 20    }    SubShader    {        Pass        {            Tags{"LightMode" = "ForwardBase"}            CGPROGRAM            #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;                fixed3 color : COLOR;            };            v2f vert(a2v v)            {                v2f o;                //从模型空间变换到裁剪空间                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);                //环境光                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;                //将法线从模型空间变换到世界空间,可以使用顶点变换矩阵的逆转置矩阵对法线进行相同的变换:mul(逆转置矩阵,normal) = mul(normal,逆矩阵)                //_World2Object是模型空间到世界空间的变换矩阵的逆矩阵                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));                //_WorldSpaceCameraPos:世界空间中的摄像机位置                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld,v.vertex).xyz);                //高光反射计算                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 "Specular"}

逐像素光照

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'Shader "Own/Chapter6-Light"{    Properties    {        //漫反射颜色        _Diffuse("Diffuse",Color) = (1,1,1,1)        //高光反射颜色        _Specular("Specular",Color) = (1,1,1,1)        //高光区域的大小        _Gloss("Gloss",Range(8.0,256)) = 20    }    SubShader    {        Pass        {            Tags{"LightMode" = "ForwardBase"}            CGPROGRAM            #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 = mul(UNITY_MATRIX_MVP,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;                fixed3 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 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir,viewDir)),_Gloss);                return fixed4(ambient + diffuse + specular,1.0);            }            ENDCG        }    }    Fallback "Specular"}

1.saturate(x):x为用于操作的标量或矢量,可以是float,float2,float3等类型。函数作用:为了把x截取在[0,1]范围内,如果x是一个矢量,那么会对它的每一个分量进行这样的操作。
2.Unity内置变量UNITY_LIGHTMODEL_AMBIENT就可以得到环境光的颜色和强度信息
3._World2Object是模型空间到世界空间的变换矩阵的逆矩阵
4._WorldSpaceLightPos0可以得到光源方向,需要假设场景只有一个光源且该光源是平行光
5._LightColor0可以访问该Pass处理的光源的颜色和强度信息
6.normalize:归一化操作
7.reflect(i,n):其中i是入射方向,n是法线方向。可以是float,float2,flaot3等类型。函数作用:当给定入射方向i和法线方向n时,reflect函数可以返回反射方向。

UnityCG.cginc中一些常见的帮助函数

函数名                                           描述float3 WorldSpaceViewDir(float4 v)                输入一个模型空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向。内部实现使用了                                                              UnityWorldSpaceViewDir函数float3 UnityWorldSpaceViewDir(float4 v)           输入一个世界空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向float3 ObjSpaceViewDir(flaot4 v)                  输入一个模型空间中的顶点位置,返回模型空间中从该点到摄像机的观察方向float3 WorldSpaceLightDir(float4 v)               仅可用于前向渲染中。输入一个模型空间中的顶点位置,返回世界空间中从该点到光源方向的光照方向。内部实现使用                                                  了UnityWorldSpaceLightDir函数,没有被归一化float3 UnityWorldSpaceLightDir(float4 v)          仅可用于前向渲染中。输入一个世界空间中的顶点位置,返回世界空间中从该点到光源的光照方向。没有被归一化float3 ObjSpaceLightDir(float4 v)                 仅可用与前向渲染中。输入一个模型空间中的顶点位置,返回模型空间中从该点到光源的光照方向。没有被归一化float3 UnityObjectToWorldNormal(flaot3 norm)      把法线方向从模型空间转换到世界空间中float3 UnityObjectToWorldDir(float3 dir)          把方向矢量从模型空间变换到世界空间中float3 UntiyWorldToObjectDir(float3 dir)          把方向矢量从世界空间变换到模型空间中                                                      
阅读全文
0 0
原创粉丝点击