unity shader入门精要_UnityShader入门精要—基础光照

本文是Unity Shader入门精要的一部分,详细介绍了基础光照模型,包括物体接受光照的物理过程、漫反射、高光反射、自发光和环境光。讲解了标准光照模型的数学公式,并通过Unity内置渲染流程展示了如何在顶点和片元着色器中应用这些模型。文章以易于理解的方式探讨了非真实光照模拟,并提供了Unity Shader的代码示例。
摘要由CSDN通过智能技术生成

86b5bf56aca6c078e4beade08c9f664f.png

UnityShader入门精要—基础光照

(此文为易于理解的演讲配合文档,设计到专业词汇和解释可能不当)

一:物体接受光照并显示到摄像机的物理过程

1.光源发射光

2.物体与光交互发生“散射”以及“吸收”两个结果

散射:不改变光本身的物理属性(颜色,密度等),只改变光的方向。但是散射根据最终结果的不同方向又分为两类,到物体内部,这种现象称之为“折射”或“透射”,另一种方向为为散射到物体外部,即反射。

吸收:只改变光的本身物理属性,不改变方向。光被吸收后通常转为其他形式的能量,比如热。

下图反应了实际光与物体表面交互的过程和结果,对于不透明物体,折射到内部的光线还会继续交互,最终部分光线重新从表面出射。

9bddaf065b93a4a89dbdce3e32e196c2.png

3.最终离开物的光到部分到达摄像机,摄像机形成影像

二:模拟物体与光交互结果

光照模型概念:即根据物体表面属性,光源信息,使用某一个数学公式计算,最终得到沿某个观察方向出射的光的集合。

标准光照模型(基于经验的模拟)

标准光照模型最终到传到摄像机的光线,分为自发光,高光反射,漫反射,环境光四个部分即

81ddc9412eebd8d2e60214ab469873b7.png

漫反射(diffuse)

漫反射(diffuse)即光经过表面交互(折射吸收等)后,会向每个方向出射多少量的光,因此在任意方向观察,漫反射结果都是一样的,计算公式(由符合兰伯特定律推出):出射光线强度与表面法线和光源方向之间夹角成正比,即

1db4c5a7dc35a58211c3fa8f85fad787.png

其中,n是法线方向,I是指向光源的单位矢量,

是材质的漫反射颜色,
是光源颜色,最后我们防止n与I点击积为负值,修改公式为突下:

此外,还有一种计算公式,即半兰伯特模型,通过缩放和偏移映射原来的值域到新值域,例如 [-1,1] 映射到 [0,1],这种模型计算的漫反射看起来整体更亮,有些领域也在使用,如下图效果对比

37512c353c21efa04efc92a9e04e6e6c.png

计算公式为:

高光反射(spscular)

高光反射用于计算光跟表面交互后,会在完全镜面反射方向出射多少光,这些镜面反射的光投影到我们的观察方向,也就形成了高光区域

这一部分计算结果使用以下公式(Phong模型)

r=2(ncdot I)n-I

1db4c5a7dc35a58211c3fa8f85fad787.png

其中

是材质的高光度,r 是完全镜面反射方向,v 是观察方向,
是光泽度,控制高光区域的范围,加入 max(0,x) 同样是防止计算结果为负数,此处的 r 需要使用法线 n 和光线方向 I 计算,为避免计算 r,另有人(Blinn)提出了修改方案计算来得到类似效果,新的计算更简单如下,即Blinn-Phong模型

两者都是经验模型,并不是正确的,他们分别在某些情况计算效率会高于另有一种,对比效果如下,Blinn-Phong计算出来的高光区域更大,边缘更硬一些

65ef007cc105107ae03f66444fc7a295.png

自发光(emissive)

自发光描述了物体本身会向观察方向发射什么样的光,如果没有全局关照技术,这些自发光并不会真正照亮周围物体,而只是本身看起来更亮了

环境光(ambient)

描述其他所有的间接光照

三.Unity应用标准光照模型(非真实)

unity内置渲染流程中提供了两个地方进行自定义计算,即顶点着色器,片元着色器

顶点:逐定点计算,模型有n个顶点则计算n次

片元:逐像素计算,整个模型画到屏幕上时如果占了m个像素,则计算m次,一般情况m远大于n

顶点着色器中的数据,会经过插值得到到偏远着色器中使用的数据,如两个顶点颜色分别为白色(1,1,1)和黑色(0,0,0),到了片元着色器里边对应的一系列像素颜色是(1,1,1)(0.9,0.9,0.9)(0.8,0,0.8,)...(0,0,0)。着色计算即可以在定点中着色阶段进行,也可以在片元着色阶段进行,在前者进行更快但是可能由于插值而出现明显边际,在后者计算量大但是效果最好。

这里只展示主要在片元着色器中进行计算

环境光和自发光

环境光:Unityshader中可以直接使用系统定义的“UNITY_LIGHTMODEL_AMBIENT”获得环境光

自发光:大多数物体并没有自发光,如许添加,只要在最后的运算结果加上自定义的自发光颜色即可

漫反射

漫反射效果:

8ada014548b8fbfadb1b8a20de695f52.png

UnityShader逐像素计算面反射代码段

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_AMBIENT.xyz;
                //光源方向
                fixed3 WorldSpaceLightDir=normalize(_WorldSpaceLightPos0.xyz);
                //diffuse=C(light) * m(diffuse) * max(0,I.n)
                fixed3 diffuse=_LightColor0.xyz * _Diffuse.xyz *saturate(dot(WorldSpaceLightDir,i.WorldNormal))
                return fixed4(diffuse,1);
            }

UnityASE编辑器节点

7ff73b47fc6693acbc82db0f90f4b563.png

漫反射的半兰伯特模型

shader修改只要修改最后部分

//兰伯特diffuse=C(light) * m(diffuse) * max(0,I.n)
//fixed3 diffuse=_LightColor0.xyz * _Diffuse.xyz * saturate(dot(WorldSpaceLightDir,i.WorldNormal));
//半兰伯特diffuse=C(light) * m(diffuse) * (,0.5*I.n+0.5)
fixed3 diffuse=_LightColor0.xyz * _Diffuse.xyz * (0.5h* dot(WorldSpaceLightDir,i.WorldNormal)+0.5h);

ASE编辑器也只需按公式做修改即可

c8f280905e790aa04c817a459d72732b.png

高光反射

Unity效果(Phong模型):

a37ddd825bbb40d83bb28b9355a9c53c.png

Unityshader代码片段:

v2f vert(a2v i){
                v2f o;
                o.pos=UnityObjectToClipPos(i.vertex);
                //保存世界法线
                o.wNormal=UnityObjectToWorldNormal(i.normal);
                //保存世界位置
                o.wPos=mul((float3x3)unity_ObjectToWorld,i.vertex);
                return o;
            }

            fixed4 frag(v2f i):SV_TARGET{
                fixed4 finialColor;
                finialColor.w=1;
                //光源方向
                fixed3 wLightDir=normalize(_WorldSpaceLightPos0.xyz);
                //环境光
                fixed3 GI=UNITY_LIGHTMODEL_AMBIENT.xyz;
                //漫反射
                fixed3 diffuse=_LightColor0.xyz*_Diffuse.xyz*saturate(dot(i.wNormal,wLightDir));
                //反射方向
                fixed3 refDic=normalize(reflect(-wLightDir,i.wNormal));
                //观察方向
                fixed3 vDic=normalize(_WorldSpaceCameraPos.xyz-i.wPos);
                //高光=C(light) * m(Specular) * max(0,r.v)^m(gloss)
                fixed3 specular=_LightColor0.xyz*_Specular.xyz*pow(saturate(dot(refDic,vDic)),_Gloss);
                finialColor.xyz=diffuse+GI+specular;
                return finialColor;
            }

UnityASE编辑器节点

f63b293896ee017328ceca9ad1bfaca6.png

优化的高光计算模型(Blinn-Phong模型)

de44a3111a2f51b32ec35c98e0650414.png

代码修改片段:

fixed3 vDic=normalize(UnityWorldSpaceViewDir(i.wPos));
fixed3 hlfVerc=normalize(wLightDir+vDic);
fixed3 specular=_LightColor0.xyz*_Specular.xyz*pow(saturate(dot(i.wNormal,hlfVerc)),_Gloss);

ASE编辑器修改,代替原点乘部分即可

4cb74859e79407a808cf8a883bab4f29.png

四:总结

  1. 在真实世界中,光接触物体,会发生散射和吸收,散射是一个整体概念,它细分才包括反射和折射现象
  2. 我们所说的“最终颜色=漫发射+高光(+环境光+自发光)”是经验模型,并不能完全反映真实情况,高光反射只反应了真实交互中镜面反射部分,漫反射反应了光被折射被吸收后出射的光量
  3. 计算漫反射Lambert模型(公式),和后来的加强显示效果的Hlf-Lambert模型(公式),是根据经验模拟的结果,只是简单易用以及特殊的显示效果需求
  4. 计算高光Phong模型(公式),以及改良的Blinn-Phong模型(公式),也是根据经验模拟的结果,两者不存在谁对谁错,现在大多数非PBR光照使用的Blinn-Phong模型
  5. Unity中模拟光照可在顶点着色器中计算(计算快,可能产生棱边),以及片元着色器中(计算稍慢,效果细腻)
  6. ASE中生成的代码默认大多会在片元着色器中计算,如要求在顶点着色器中计算,需要使用“Vertex To Fragment”节点来约束


参考文档:

《UnityShader入门精要》

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值