Unity 的基础光照

简介: Unity 的基础光照

b08544ef97c94ea79d58162a8505b1f1.jpg

前言


光学中,我们是用辐射度来量化光。

光照按照不同的散射方向分为两种形式:漫反射(diffuse)和高光反射(specular)。

高光反射描述物体是如何反射光线的,漫反射则表示有多少光线会被折射、吸收和散射出表面。根据入射光线的数量和方向,我们可以计算出射光线的数量和方向,通常使用出射度描述它。辐射度和出射度之间是线性关系的,它们之间的比值就是材质的漫反射和高光反射属性。


接下来将会介绍Unity内的两种光照方式实现的原理以及代码实现:

内容


BRDF 模型


早期的游戏引擎一般只有一个光照模型,BRDF 模型,即标准光照模型(Bidirectional Reflectance Distribution Function),又称 Phong 模型。

它的基本方法是,把进入到摄像机内的光线分为 4 部分,每部分使用一种方法来计算它的贡献度。

  • 自发光  描述当给定一个方向时,一个表面本身会向该方向发射多少辐射量。注意,如果没有使用全局光照,这些自发光的表面并不会照亮周围的物体,只是他本体看起来更亮而已。
  • 高光反射(金属之类的)  描述当光线从光源照射到模型表面时,该表面会在完全镜面反射方向散射多少辐射量。
  • 漫反射  该表面会向四周散射多少辐射量
  • 环境光  描述其他所有的间接光照(就是其他物体的发射的光线)。

兰伯特定律


发射光线的强度与表面法线和光源方向之间的夹角余弦值成正比。

漫发射的计算公式


  C = (c * m) * max( 0 , n * l )。

小写 c 为光源颜色,m 为漫反射颜色,n 是表面法线,l 是指向光源的单位矢量。需要注意应该防止发现和光源点乘的结果为负值(避免物体被从后面来的光源照亮),所以用 max 函数限制其为正数。

高光反射的计算公式


  •  r = 2(n * l)n - l
  • C = (c * m) * (max(0,v * r)) ^ gloss

n,l 代表意义与漫反射公式相同,r 为光的反射方向矢量,m 为高光反射颜色,v 为 视角方向矢量,gloss 为材质的光泽度,gloss 越大亮点就越小。

Blinn 模型的高光反射计算公式


 与上述 Phong 模型不同的是,Blinn 模型引入了一个新矢量 h,通过对 v 和 l 的取平均后再归一化得到:h = (v + l) / | v + l |。

 公式为:C = (c * m) * (max ( 0, n * h ))^gloss

逐像素与逐顶点光照


在片元着色器中计算,称为逐像素光照。在顶点着色器中计算,称为逐顶点光照(高罗德着色)。逐顶点光照是在每个顶点上计算光照,然后在渲染图元内部进行线性插值,最后输出成像素颜色。由于顶点数目小于像素数目,所以其计算量小于逐像素光照,因此在阴影交界处会出现锯齿,精细度不如逐像素光照。

Unity 的环境光和自发光


环境光可以通过 Shader 的内置变量 UNITY_LIGHTMODEL_AMBIENT 访问

自发光只需要在片元着色器输出最后的颜色之前,把材质的自发光颜色添加到输出颜色上就行。

漫反射和高光反射的 Shader 实现


漫反射光照模型(逐顶点)


Shader "Unity Shader Book/Chapter6/Diffuse Vertex-Level"
{
       Properties
       {
             _Diffuse("Diffuse",Color) = (1.0,1.0,1.0,1.0)
       }
       SubShader
       {
             Tags { "LightMode"="ForwardBase" }   
             Pass
             {
                    CGPROGRAM
                    #pragma vertex vert
                    #pragma fragment frag
                    #include "Lighting.cginc"
                    fixed4 _Diffuse;
                    struct appdata
                    {
                          float4 vertex : POSITION; //顶点在模型空间的坐标
                          float3 normal : NORMAL;  //法线
                    } ;
                    struct v2f
                    {
                          fixed3 color : COLOR;  //输出颜色
                          float4 pos : SV_POSITION;  //输出位置
                    } ;
                    v2f vert (appdata v)
                    {
                          v2f o;
                          o.pos = UnityObjectToClipPos(v.vertex);  //模型空间转换到裁剪空间
                          fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;  //环境光
                          fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); //法线方向n
                          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
             }
       }
}

高光反射模型(逐顶点)


Shader "Unity Shader Book/Chapter6/SpecularVertexLevel"
{
       Properties
       {
             _Diffuse("Diffuse",Color) = (1.0,1.0,1.0,1.0)
             _Specular("Specular",Color) = (1.0,1.0,1.0,1.0)
             _Gloss("Gloss",Range(8.0,256)) = 20 //镜面反射面积大小
       }
       SubShader
       {
             Tags { "LightMode"="ForwardBase" }   //小心,如果没有这个光源会反向
             Pass
             {
                    CGPROGRAM
                    #pragma vertex vert
                    #pragma fragment frag
                    #include "Lighting.cginc"
                    fixed4 _Diffuse;
                    fixed4 _Specular;
                    float  _Gloss;
                    struct appdata
                    {
                          float4 vertex : POSITION;
                          float3 normal : NORMAL;
                    } ;
                    struct v2f
                    {
                          float3 color: COLOR;
                          float4 pos : SV_POSITION;
                    } ;
                    v2f vert (appdata v)
                    {
                          v2f o;
                          o.pos = UnityObjectToClipPos(v.vertex);
                          //等同于 "o.pos = mul(UNITY_MATRIX_MVP,v.vertex);"
                          fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                          fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
                          //或使用 UnityObjectToWorldNormal(v.normal)
                          fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                          fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir));
                          fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal)); //反射方向矢量r
                          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
             }
       }
}


目录
相关文章
|
图形学
Unity光照概述
一:光源参数 属性面板的属性含义:Type:四种光源类型之一 。1.平行光:最为简单的光照,我们认为受平行光影响的物体接收到的光线方向是一致的,unity中平行光源的位置是无所谓的,可以放在任何位置,这并不会影响光源的方向。
4837 0
|
图形学
【Unity Shader】(七) ------ 复杂的光照(下)
笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题。              【Unity Shader】(三)------ 光照模型原理及漫反射和高光反射的实现         【Uni...
1721 0
|
存储 Shell 图形学
【Unity Shader】(六) ------ 复杂的光照(上)
 笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题。              【Unity Shader】(三)------ 光照模型原理及漫反射和高光反射的实现         【Un...
1356 0
|
图形学
【Unity Shader】(三) ------ 光照模型原理及漫反射和高光反射的实现
【Unity Shader】(三) ---------------- 光照模型原理及漫反射和高光反射的实现 【Unity Shader】(四) ------ 纹理之法线纹理、单张纹理及遮罩纹理的实现 【Unity Shader】(五) ------ 透明效果之半透明效果的实现及原理   本文主要参考了冯乐乐老师的《Unity Shader入门精要 》一书,再加上网上一些参考资料而写。
1933 0
|
图形学
【Aladdin Unity3D Shader编程】之三 光照模型(二)
高光反射模型 Specular=直射光*pow(cosθ,高光的参数) θ:是反射光和视野方向的夹角 编写高光反射Shader Shader "AladdinShader/07 Specular Vertex Shader" { Prop...
1563 0
|
图形学
【Aladdin Unity3D Shader编程】之二 光照模型(一)
光照模型 光照模型就是一个公式,使用这个公式来计算在某个点的光照效果。 在标准光照模型里面,我们把进入摄像机的光分为下面四个部分: * 自发光 类似生活中的萤火虫等自己能够发光 * 高光反射 类似生活中的镜子,近似认为百分百反射出去 * 漫反射 类似生活中的光照射到墙壁上、桌子上的反光不会百分百反射出去,各个方向都会反射。
1734 0
|
4月前
|
C# 图形学
【Unity 3D】元宇宙案例之虚拟地球信息射线实战(附源码、演示视频和步骤 超详细)
【Unity 3D】元宇宙案例之虚拟地球信息射线实战(附源码、演示视频和步骤 超详细)
50 0