位置: 编程技术 - 正文

【浅墨Unity3D Shader编程】之七 静谧之秋篇: 表面着色器的写法(二)—— 自定义光照模式(unity smooth)

编辑:rootadmin

推荐整理分享【浅墨Unity3D Shader编程】之七 静谧之秋篇: 表面着色器的写法(二)—— 自定义光照模式(unity smooth),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:unityos,unityos,unityos,unity color,unity 水墨 shader,unity momo,unitymol,unity水墨,内容如对您有帮助,希望把文章链接给更多的朋友!

本系列文章由@浅墨_毛星云 出品,转载请注明出处。

文章链接: 微博: happylifemxy@.com

本文主要讲解了Unity中SurfaceShader的自定义光照模式的写法。

上篇文章中我们已经说到,表面着色器将分为两次讲解,上一篇文章中介绍了表面着色器的基本概念和一些写法,用内置的兰伯特光照模式来进行Surface Shader的书写,而本文将介绍Surface Shader+自定义的光照模式的写法。

OK,言归正传,依然是先来看看本文配套的游戏场景截图。

运行游戏,音乐响起,金黄色的丰收之秋映入眼帘:

远方:

池塘:

参天大树:

小型村落:

风车:

池塘边:

OK,图先就上这么多。文章末尾有更多的运行截图,并提供了源工程的下载。可运行的exe下载在这里:

【可运行的exe游戏场景请点击这里下载试玩】

好的,我们正式开始。

一、一些光照模型的概念讲解

我们知道,光照模型是真实感图形渲染的基础,从 年 Wylie 等人第一次在显示物体的时候加进光照效果后,该领域迅速的发展。而这一节,我们主要看看最常见的漫反射、Lambert和镜面反射、Phong、Blinn-Phong这五种光照模型。

 

1.1 漫反射

环境光是对光照现像的最简单抽象,因而局限性很大。它仅能描述光线在空间中无方向并均匀散布时的状态。很多情况下,入射光是带有方向的,比如典型的阳光。

如果光照射到比较粗糙的物体表面,如粉笔,由于这些表面从各个方向等强度地反射光,因而从各个视角出发,物体表面呈现相同的亮度,所看到的物体表面某点的明暗程度不随观测者的位置变化的,这种等同地向各个方向散射的现象称为光的漫反射(diffuse reflection)。

简单光照模型模拟物体表面对光的反射作用。光源被假定为点光源,其几何形状为一个点,向周围所有方向上辐射等强度的光,在物体表面产生反射作用。

如图:

 

1.2 Lambert模型

漫反射光的强度近似地服从于Lambert定律,即漫反射光的光强仅与入射光的方向和反射点处表面法向夹角的余弦成正比。

 

由此可以构造出Lambert漫反射模型:

Idiffuse =Id Kd cosθ

Idiffuse表示物体表面某点的漫反射光强

Id为点光源,Kd(0<Kd<1)表示物体表面该点对漫反射光的反射属性

 

θ是入射光线的方向与物体表面该点处法线N的夹角,或称为入射角(0≤θ≤°)

入射角为零时,说明光线垂直于物体表面,漫反射光强最大;

°时光线与物体表面平行,物体接收不到任何光线。

如图:

 

把环境光模型添加进来,最后,Lambert光照模型可写为:

I= IaKa + Id Kdcosθ= IaKa + Id Kd(L·N)

该模型包含环境光和漫反射光。

 

1.3 镜面反射

Lambert模型较好地表现了粗糙表面上的光照现象,如石灰粉刷的墙壁、纸张等

但在用于诸如金属材质制成的物体时,则会显得呆板,表现不出光泽,主要原因是该模型没有考虑这些表面的镜面反射效果。

如果光照射到相当光滑的表面,就产生镜面反射(specular reflection),镜面反射的特点是在光滑表面会产生一块称之为高光(high light)的特亮区域 。

镜面反射遵循光的反射定律:反射光与入射光位于表面法向两侧,对理想反射面(如镜面),入射角等于反射角,观察者只能在表面法向的反射方向一侧才能看到反射。

1.4 Phong光照模型

Lambert模型能很好的表示粗糙表面的光照,但不能表现出镜面反射高光。年Phong Bui Tong发明的Phong模型,提出了计算镜面高光的经验模型,镜面反射光强与反射光线和视线的夹角a相关:

Ispecular = Ks*Is*(cos a) n

其中Ks为物体表面的高光系数,Is为光强,a是反射光与视线的夹角,n为高光指数,n越大,则表面越光滑,反射光越集中,高光范围越小。如果V表示顶点到视点的单位向量,R表示反射光反向,则cos a可表示为V和R的点积。模型可表示为:

Ispecular = Ks*Is*(V●R) n

反射光放向R可由入射光放向L(顶点指向光源)和物体法向量N求出。

R = (2N●L)N – L

我们重新来看Phong光照的另一种表现形式:

Ispec = IsKscosns α(α∈(0,º))

Ks为物体表面某点的高亮光系数

ns为物体表面的镜面反射指数,反映了物体表面的光泽程度, ns越大,表示物体越接近于镜面。

只有视线与光源在物体表面的反射光线非常接近时才能看到镜面反射光,此时,镜面反射光将会在反射方向附近形成很亮的光斑,称为高光现象。ns越小,表示物体越粗糙;当ns为零时,镜面反射光便退化为与视点、光源均无关的环境光。

另外,将镜面反射光与环境光、漫反射光叠加起来形成单一光源照射下更为真实的Phong光照模型:

I = Ia Ka+IdKdcosθ+IsKscosns α

θ :入射角

α :视线与镜面反射方向的夹角

1.5 Blinn-Phong光照模型

图形学界大牛Jim Blinn对Phong模型进行了改进,提出了Blinn-Phong模型。Blinn-Phong模型与Phong模型的区别是,把dot(V,R)换成了dot(N,H),其中H为半角向量,位于法线N和光线L的角平分线方向。Blinn-Phong模型可表示为:

Ispecular = Ks*Is* pow(( dot(N,H), n )

其中H = (L + V) / | L+V |,计算H比计算反射向量R更快速。

Unity中,Phong实际上指的就是Blinn-Phong,两者指的同一种内置光照模型。

PS:光照模型部分的内容主要参考为:

二、关于自定义光照模式(custom lighting model)

在编写表面着色器的时候,我们通常要描述一个表面的属性(反射率颜色,法线,…)、并通过光照模式来计算灯光的相互作用。

通过上篇文章的学习,我们已经知道,Unity中的内置的光照模式有两种, 分别是Lambert (漫反射光diffuse lighting) 和 Blinn-Phong (也就是镜面反射光(高光),specular lighting)模式。

然而,内置的光照模式自然有其局限性。想要自己做主的话,我们可以自定义光照模式。

也就是使用自定义光照模式( custom lighting model)。

其实说白了,光照模式(lighting model)无外乎是几个Cg/HLSL函数的组合。

内置的 Lambert 和 Blinn-Phong定义在 Lighting.cginc文件中。我们不妨先来人肉一下他们的实现源代码。

windows系统下位于:

…UnityEditorDataCGIncludes

Mac系统下位于:

/Applications/Unity/Unity.app/Contents/CGIncludes/Lighting.cginc)

Unity内置的 Lambert 和 Blinn-Phong模型的Shader源代码在这里贴出来:

OK,下面让我们一起来看看光照模式应该怎样声明和定义。

三、光照模式的声明方式

在Unity Shaderlab和CG语言中,光照模式是一个以Lighting开头+自定义文字组合在一起的函数。

即,函数名为:

Lighting+ [自定义部分]

比如,一个可行的函数名为:LightingQianMoLightingMode

我们可以在着色器文件(shader file)或导入文件(included files)中的任何一个地方声明此函数。一般情况下,此函数有五种原型可供选择,具体如下。

一般情况下,于以下五种函数原型中选一种,进行实现就行了。

【形式一】

half4 LightingName (SurfaceOutput s, half3 lightDir, half atten);

此种形式的函数可以表示在正向渲染路径(forward rendering path)中的光照模式,且此函数不取决于视图方向(view direction)。例如:漫反射(diffuse)。

【形式二】

half4 LightingName (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten);

此种形式的函数可以表示在正向渲染路径(forward rendering path)中使用的光照模式,且此函数包含了视图方向(view direction)。

【浅墨Unity3D Shader编程】之七 静谧之秋篇: 表面着色器的写法(二)—— 自定义光照模式(unity smooth)

【形式三】

half4 LightingName_PrePass (SurfaceOutput s, half4 light);

此种形式的函数可以在延时光照路径(deferred lighting path)中使用的。

【形式四】

half4 LightingName_DirLightmap(SurfaceOutput s, fixed4 color, fixed4 scale, bool surfFuncWritesNormal);

这种形式也是不依赖于视图方向(view direction)的光照模式。例如:漫反射(diffuse)。

【形式五】

half4 LightingName_DirLightmap(SurfaceOutput s, fixed4 color, fixed4 scale, half3 viewDir, bool surfFuncWritesNormal,out half3 specColor);

这是使用的依赖于视图方向(view direction)的光照模式(light model)。

比如,一个光照模式(lighting model)要么使用视图方向(view direction)要么不使用。同样的,如果光照模式(lightingmodel)在延时光照(deferred lighting)中不工作,只要不声明成 _PrePass(第三种形式),就是行的。

另外,对于形式四和形式五的选择,主要取决于我们的光照模式(light model)是否依赖视图方向(view direction)。需要注意的是,这两个函数将自动处理正向和延时光照路径(forwardand deferred lighting rendering paths)。

PS: Unity在移动平台中暂时不支持延迟光照渲染。

做个总结,在自定义自己的光照模型函数时,根据需要在五种函数原型中选择一种,且:

光照模式的函数名为:Lighting+ [自定义函数名]

pragma声明为: #pragmasurface surf [自定义函数名]

然后就是需要,仿照着其他的光照模式来填充函数体了。

我们举个例子:

OK,光照模式的声明就是这样。光照模式的函数体是其最核心的部分,需要根据具体的光照模式数学公式进行书写,我们将在接下来的写Shader实战中进行学习。

PS:估计这节的概念有些难懂,大家肯定在第一时间不能完全理解,没事,让我们依旧在Shader实战中把状态找回来。

四、写Shader实战

上文已经提到过了,: Unity在移动平台中暂时不支持延迟光照(Deferred lighting)渲染。因为延时光照不能与一些自定义per-material 光照模式很好的共同运行,所以在下面的例子中我们只在着色器正向渲染(ForwardRendering)中进行实现。

0.内置的漫反射光照

首先,我们根据上一节所学,写一个依靠内置的兰伯特光照模式的漫反射光的Surface Shader:

实现效果:

1.简单的高光光照模型

下面是一个简单的高光光照模式(specular lighting model)Shader。实际上他就是Unity内置的Blinn-Phong光照模型,实际上做起来并不困难。这边我们将它单独拿出来实现一下:

实现效果:

2.自制简单的Lambert光照

对应于Unity内建的Lambert光照,我们可以自定义原理类似的光照模式,实现自己Lambert光照:

实现效果如下:

3.自定义的半Lambert光照

接下来,让我们自制一个半Lambert光照。

Lambert定律认为,在平面某点漫反射光的光强与该反射点的法向量和入射光角度的余弦值成正比(即我们之前使用dot函数得到的结果)。Half Lambert最初是由Valve(大V社)提出来的,用于提高物体在一些光线无法照射到的区域的亮度的。

简单说来,半Lambert光照提高了漫反射光照的亮度,使得漫反射光线可以看起来照射到一个物体的各个表面。

而半Lambert最初也是被用于《半条命2》的画面渲染,为了防止某个物体的背光面丢失形状并且显得太过平面化。这个技术是完全没有基于任何物理原理的,而仅仅是一种感性的视觉增强。

遮蔽的漫反射-漫反射光照的一种改进。照明"环绕(wraps around)"在物体的边缘。它对于假冒子表面(subsurface)散射效果(scattering effect)非常有用。

半Lambert光照Shader的代码如下:

实现效果如下:

4.自定义卡通渐变光照

下面,我们一起实现一个自定义卡通渐变光照,通过一个不同的渐变纹理(渐变纹理可由PS制作),实现各种不同的渐变效果。

自定义卡通渐变光照Shader代码如下:

我们取不同的渐变纹理,可得到不同的效果。以下是五种不同渐变纹理和对应的效果图。

第一组:

第二组:

第三组:

第四组:

第五组:

5.自定义卡通渐变光照v2

让我们在上面这个Shader的基础上,加入更多可选的属性,成为一个功能完备的渐变光照Shader:

我们将此Shader编译后赋给材质,得到如下效果:

可供调节的属性非常多,稍微放几张效果图,剩下的大家可以下载工程源代码,或者拷贝Shader代码,自己回去调着玩吧~

布料细节纹理+灰白渐变纹理+红色边缘光:

布料细节纹理+灰白渐变纹理+浅绿色边缘光:

布料细节纹理+灰白渐变纹理+白色边缘光:

布料细节纹理+灰白渐变纹理+无边缘光(黑色):

五、场景搭建

以大师级美工鬼斧神工的场景作品为基础,浅墨调整了场景布局,加入了音乐,并加入了更多高级特效,于是便得到了如此这次比较唯美的静谧之秋场景。

运行游戏,树影摇曳,我们来到金黄色的丰收之秋。

最后,放一张本篇文章中实现的Shader全家福:

OK,美图就放这么多。游戏场景可运行的exe可以在文章开头中提供的链接下载。而以下是源工程的下载链接。

本篇文章的示例程序源工程请点击此处下载:

【浅墨Unity3D Shader编程】之七 静谧之秋篇配套Unity工程下载

Unity Shader系列文章到目前已经更新了7篇,一共实现了个详细注释、循序渐进、功能各异的Shader,对Unity中的固定功能Shader、Surface Shader都已经有了比较详细、系统的讲解和实现。而可编程Shader按学习计划来说是以后的计划,目前还是未涉及,有机会在以后的文章中一起和大家一起探讨。

而大家如果仔细参考和阅读这七篇文章,会发现Unity中Shader的书写其实是非常容易和有章可循的。这大概就是浅墨写这个系列文章的初衷吧。

天下没有不散的宴席。

浅墨接下来的一段时间有一些大的游戏项目要接触,所以,Unity Shader系列文章每周周一的固定更新只能改为不定期的更新了。以后浅墨有了空余时间,会继续写博文来与大家交流分享。

OK,于未来某天更新的下篇文章中,我们后会有期。:)

判断一个点在三角形内 判断点是否在三角形内本文只是翻译和整理,原文在此

Unity中解析ini配置文件----INIParser 大家好,我是孙广东。转载请注明出处:

unity学习之添加图片作为背景 unity学习,希望我的博客能给喜欢unity的朋友带来帮助准备了几天的项目今天开始做了,我今天主要的任务就是做登陆注册界面,登陆注册界面要想好看

标签: unity smooth

本文链接地址:https://www.jiuchutong.com/biancheng/377353.html 转载请保留说明!

上一篇:Unity UI系统–动画整合(unity ulua)

下一篇:手把手教你使用vue-cli脚手架(图文解析)(手把手教你使用opc)

  • 小规模纳税人零申报是每季度报吗
  • 没有认证的发票怎么做分录
  • 月饼礼盒发票
  • 房地产开发企业预收款预缴增值税
  • 加工费可以开批吗
  • 预缴增值税是否要预缴印花税
  • 行政单位暂付款怎么记账
  • 个人工资税收怎么申报
  • 预计退货会计英语
  • 耕地占用税和契税什么时候交
  • 小型微利企业所得税优惠政策2022
  • 公司买的固定资产还没使用
  • 销售折扣账务怎么处理
  • 建筑工程甲方提供给乙方的材料
  • 收到厂房租金要交税吗
  • 委托加工物资合并报表
  • 如何调用金三接口?
  • 短期借款利息的处理
  • 研发过程中材料费计入
  • 去年的进项票今年可以抵吗
  • 网络销售平台优势有哪些
  • 总资产平均余额是资产总额吗
  • 民非组织可以接受捐赠吗
  • php函数返回值类型
  • 公司之间债务转让合法吗
  • linux系统基础教程
  • php数组函数,选班长
  • kb4592440安装失败
  • ppap是什么意思中文
  • 金融资产的会计处理方法
  • 巨人堤道上的玄关图片
  • 职工福利费入账依据
  • php json 对象
  • phpize安装
  • 论文resit
  • nodejs官方文档
  • php魔术方法autoload
  • 企业销售固定资产房屋都要交什么税
  • 10-Ajax&Vue
  • 正则动量
  • 装修公司管理费是什么
  • 发票收款人与复核人为空
  • 单位之间的争议由谁处理
  • 建筑业先预缴还是先扣税
  • 出口企业的出口比例怎么算
  • MongoDB的mongo shell常用操作方法及操作脚本笔记
  • 购买固定资产未入账
  • 企业会计准则和企业会计制度的区别
  • 个人捐赠支出税前扣除条件
  • 固定资产清理包括什么会计科目
  • 契税并入土地价值吗
  • 公对公转账货款是指往来款吗
  • 交易性金融资产公允价值变动怎么算
  • 销售发票已开进项发票未收到怎么处理?
  • 单价合同如何计算印花税
  • 固定资产怎么记入账本明细科目
  • 如何进行企业建账
  • SQL Server在AlwaysOn中使用内存表的“踩坑”记录
  • linux获取主目录的命令
  • win8如何删除登录密码
  • macbook硬盘中的其他
  • 怎样把系统及软件迁移到固态
  • 如何用u盘安装win8操作系统
  • ubuntu怎么将文件传送到电脑
  • 围绕摄像机旋转怎么设置
  • node.js编译
  • 安卓开源部分叫什么
  • android入门书
  • 手机物理游戏
  • java dao框架
  • 深入解析java编译器:源码剖析与实例详解
  • vue router routes
  • bat批处理的if里面双感叹号
  • python怎么编写二维码
  • 细说java
  • django教程推荐
  • 福建省地税局副局长 阮
  • 深圳国家税务总局
  • 代理记账公司账务处理
  • 查册证明怎么自动生成
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设