unityshader学习笔记5
Unity中的光照:
光源
光是由光源发射出来的,实时渲染中,通常把光源当成一个没有体积的点,用L来表示它的方向.
在光学里,用辐照度来量化光.
对于平行光来说,它的辐照度可通过计算在垂直于L的单位面积上单位时间内穿过的能量来得到.
在计算光照模型时,我们需要知道一个物体表面的辐照度,而物体表面往往是和L不垂直的,可以使用光源方向L和表面法线n之间的夹角的余弦值来得到.
因为辐照度是和照射表面时光线之间的距离d/cosθ成反比的,因此辐照度就和cosθ成正比.
cosθ可以使用光源方向L和表面法线n的点积来得到,这就是使用点积来计算辐照度的由来.
吸收和散射
光线由光源发射出来后,就会与物体相交.通常相交结果有两个:散射和吸收.
散射只改变光线的方向,不改变光线的密度和颜色.
吸收只改变光线的密度和颜色,不改变方向.
光线在物体表面经过散射后,有两种方向:
折射(透射),散射到物体内部
反射,散射到物体外部
对于不透明物体,折射进入物体内部的光线还会继续与内部的颗粒进行相交,其中一些光线最后会重新发射出物体表面,而另一些则被物体吸收.那些从物体表面重新发射出的光线将具有和入射光线不同的方向分布和颜色.
为了区分这两种不同的散射方向,我们在光照模型中使用了不同的部分来计算它们:
高光反射:表示物体表面是如何反射光线的.
漫反射:表示有多少光线会被折射、吸收和散射出表面.
根据入射光线的数量和方向,我们可以计算出射光线的数量和方向,通常使用出射度来描述它.
辐照度和出射度之间是满足线性关系的,而它们之间的比值就是材质的漫反射和高光反射属性.
着色
着色指的是,根据材质属性、光源信息,使用一个等式去计算沿某个观察方向的出射度的过程.我们把这个等式称为光照模型.
漫反射
漫反射光照符合兰伯特定律:反射光线的强度与表面法线和光源方向之间夹角的余弦值成正比.
漫反射计算公式:
n:表面法线
I:是指光源的单位矢量
mdiffuse:材质的漫反射颜色
clight:光源颜色
需要防止法线和光源方向点乘的结果为负值,防止物体被从后面来的光源照亮.
CG提供了一个函数,防止取负值
saturate(x) 把x截取在[0,1]范围内,如果x是一个矢量,那么会对它的每一个分量进行这样的操作.
辐照度计算: 光线方向与法线方向的点乘
如果L的向量与N一样(N Dot L=1),那么表示模型的这个点正对着光源,应该最亮,相反,如果两个向量呈相反方向(N Dot L=-1),那么则表示这个点背对光源,应该最暗。
漫反射计算:
Cdiffuse = Clight * Mdiffuse * saturate(0, dot(n, I))
漫反射颜色 = 光照颜色① * 材质颜色② * 辐照度(用法线方向③和光照方向④进行点乘,取值0~1)
①光照颜色:通过内置变量_LightColor0得到(需要引入Lighting.cginc)
②材质颜色:自定义
辐照度:通过法线方向和光照方向进行点乘得到
③法线方向:模型传入
④光照方向:通过内置变量_WorldSpaceLightPos0得到,定义在Lighting.cginc里,只可以在Tag中的LigthMode为ForwardBase时被使用
特别注意: 法线是在模型空间中进行计算的,而光照方向是从世界坐标出发指向光源的,因此在使用法线前,我们需要先用mul方法对其进行矩阵转换,将其从模型空间转换到世界空间。
Shader "Custom/SimpleDiffuseShader" { 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 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(i.worldNormal, _WorldSpaceLightPos0)); return fixed4(diffuse, 1.0); } ENDCG } } Fallback "Diffuse" }
高光反射计算:
Phone模型
Clight光线颜色
Mspcular材质的高光反射系数
v视角方向
r反射方向(通过法线和光源方向计算得到)
CG提供了计算反射方向的函数reflect(i入射方向, n法线)
Blinn-Phone模型
Blinn模型没有使用反射方向,而是引入了新的矢量h,它是通过对视角方向和光照方向相加后再归一化得到的
Shader "Custom/SimpleSpecularShader" { 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 = 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; //漫反射 fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir)); //高光反射 Phone模型 //fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));//反射方向 = reflect(入射方向, 法线方向) //fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos); //fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss); //高光反射 Blinn-Phone模型 fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos); fixed3 halfDir = normalize(worldLightDir + viewDir); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(dot(worldNormal, halfDir), _Gloss); return fixed4(ambient + diffuse + specular, 1.0); } ENDCG } } FallBack "Specular" }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!