从零开始实现Unity光照模型_02_为Shader添加简单的多光源支持

  • 为什么需要多光源支持
    • 上一篇的代码存在的问题
    • Unity中的前向渲染路径
    • 仍然存在的问题
      • 参考文献:

为什么需要多光源支持

在标准光照模型中,每次只针对一个光照进行计算,得出漫反射和高光反射,这样在一个光源下就能有一定程度上真实的渲染效果。
但是一旦出现多个光源,which is the case of reallife, 我们第一篇中的代码就无法支持了(当然第一篇中的代码其实啥也没有很多东西都无法支持)。而只有在多光源的照明下,渲染效果才会更真实。

上一篇的代码存在的问题

上一篇代码的渲染效果如下:

如果增加一个点光源:

是没有任何变化的。因此需要添加多光源支持。

Unity中的前向渲染路径

这里主要使用Unity中的前向渲染ForwardRendering
前向渲染分为两种Pass
第一种Pass是BasePass,用来渲染主要光源的光照效果,也就是第一节中的效果。这里要包含所有主要的设置,包括环境光,自发光,最重要光源的漫反射和高光等。
一般来说最主要光源是场景中的平行光。
第二种Pass是AddPass,用来渲染一些额外的光源,一般不需要包括环境光。
下面记录如何用上一节的代码实现多光源效果。

  1. 将subshader中的Pass复制一次,粘到下面。这是因为我们需要针对最主要光源和次要光源绘制两次(当然了,可能有许多个非主要光源,这时候addPass会被执行多次,以把所有光源都绘制出来)
  2. 当然只粘贴是不行的,还要在两个Pass的Tags里分别加上“LightMode”=“ForwardBase”和“LightMode”=“ForwardAdd”
  3. 预编译指令也需要进行处理 各增加一条#pragma multi_compile_fwdbase和#pragma multi_compile_fwdadd
    下面我们试着跑一下:
Shader "Custom/Diffuse"//声明一个shader的名称,格式为 文件夹/文件夹/.../文件夹/shader名称
{Properties//声明材质中可选的属性{_Diffuse ("Diffuse", Color) = (1,1,1,1)//格式为 _PropertyName("Displayed Name",Type)=DefaultValue}SubShader{Tags { "RenderType" = "Opaque" }//表明这个着色器的渲染属性,意思是使用不透明渲染模式LOD 200//这是一个主要PassPass{Tags{"LightMode"="ForwardBase"}//表明这个Pass的渲染属性,这里指定了光照模式,是前向渲染中的Base模式,//会考虑最重要光源进行计算CGPROGRAM//开始一段CG代码段#pragma multi_compile_fwdbase#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"//Unity自带的光照文件,包含了许多内置变量,例如下文用到的UNITY_LIGHTMODEL_AMBIENT//和_WorldSpaceLightPos0fixed4 _Diffuse;//声明外部变量,要求一定要是对应的变量类型和变量名,不能有错。//(吐槽一下如果定的这么死为什么不干脆直接让引擎处理了省的复制粘贴。)struct a2v {//输入结构体float4 vertex:POSITION;//利用语义向变量中填充所需的数据,这里填充的是每个顶点在模型空间下的坐标float3 normal:NORMAL;//模型空间下的法向量。一般来说需要转化为世界坐标使用};struct v2f {//顶点着色器的输出结构体,片元着色器的输入结构体float4 pos:SV_POSITION;//SV_POSITION这个语义会将pos内的数据输出到屏幕坐标上float3 worldNormal:TEXCOORD0;//采用一个寄存器来存储worldNormal变量。};v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);//将模型上的点显示到屏幕上的正确位置o.worldNormal = mul(v.normal, unity_WorldToObject);//获得模型上每个点的世界空间下的法向量方向return o;//将v2f输出传递到片元着色器中。}fixed4 frag(v2f i) : SV_TARGET{float4 worldLightDir = normalize(_WorldSpaceLightPos0);//在这里使用的是平行光,//因此这个系统变量存储的就是光源的方向,//如果不是平行光,那么光源方向要用光源坐标减去顶点坐标才行。//可以考虑使用ifdef语法进行区分float3 ambient = UNITY_LIGHTMODEL_AMBIENT;//利用系统变量直接获得环境光信息。//经过一番实验,这个环境光信息是Unity->windows->//rendering->lighting settings中Enviroment lighting下的颜色信息,//如果采用渐变颜色的话,那么使用的是天空信息。float3 diffuse = _Diffuse.rgb * dot(i.worldNormal, worldLightDir);return fixed4(diffuse.rgb+ambient,1.0);//返回颜色值}ENDCG}//下面是次要pass,addpassPass{Tags{"LightMode" = "ForwardAdd"}CGPROGRAM#pragma multi_compile_fwdadd#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 = mul(v.normal, unity_WorldToObject);return o;}fixed4 frag(v2f i) : SV_TARGET{float4 worldLightDir = normalize(_WorldSpaceLightPos0);float3 ambient = UNITY_LIGHTMODEL_AMBIENT;float3 diffuse = _Diffuse.rgb * dot(i.worldNormal, worldLightDir);return fixed4(diffuse.rgb+ambient,1.0);}ENDCG}}FallBack "Diffuse"
}


可以看到点光源在起作用,但是平行光却被无视了。
这是因为每个Pass在绘制图形时都是覆盖绘制的,由于Unity会先执行最主要光源的绘制,再执行次要光源的绘制时次要光源的绘制结果会直接覆盖掉主要光源的数据。
因此在次要光源绘制时我们需要打开AddPass的混合命令,让后来的结果叠加,而不是覆盖到原有结果上。

 ...//下面是次要pass,addpassPass{Blend One One//意思是将现在的绘制结果直接叠加到已有结果上,两者的权重都是1。Tags{"LightMode" = "ForwardAdd"}CGPROGRAM#pragma multi_compile_fwdadd#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"...

仍然存在的问题

上一篇的代码在计算漫反射时,并未对点乘结果做处理,要注意这里的结果很可能会出现负值,这是会影响光照的后续计算的。因此这里使用一个saturate函数来进行去除大于255和小于0的部分:

 ...//float3 diffuse = _Diffuse.rgb * dot(i.worldNormal, worldLightDir);//改为如下:float3 diffuse = _Diffuse.rgb *saturate(dot(i.worldNormal, worldLightDir));...

最后的结果如图:

参考文献:

UnityShader入门精要 _ 人民邮电出版社 _ 冯乐乐编著

从零开始实现Unity光照模型_02_为Shader添加简单的多光源支持_技术美术基础学习记录相关推荐

  1. unity沙子堆积_Unity Shader 之 简单实现沙漠干旱热浪的效果

    CameraHotWave 脚本具体代码和代码说明如下: using UnityEngine; /// /// 实现相机热浪效果 /// [ExecuteInEditMode]     // 编辑状态 ...

  2. [Unity动画]给人物模型添加简单的动画

    给unity人物模型添加动画,首先你得有个模型,在预制体中,有导入设置,重点是Rig设置.第一个选项是动画的类型,因为导入的是人物模型,所以应该选择人形:第二个是人物骨骼,这里已经设好了:第三个选项是 ...

  3. 字典添加数据_【Python基础学习】4. 数据类型之字典及其操作

    知行校园汇 记录学习.分享干货.吐槽人生! 关注 相关说明 文章内容:Python数据类型之字典及其操作 作者博客:csdn.cxhit.com www.cxhit.com 1. 什么是字典 在Pyt ...

  4. unity 2020 怎么写shader使其接受光照?_如何在Unity中造一个PBR Shader轮子

    之前有业界大佬建议我去了解下Unity的PBR.说来惭愧,我查找了下资料才发现自己在这方面的知识居然是一片空白.经过几周的学习与尝试我对这一块算是有了初步的了解,于是写了这篇文章,一方面对自己学到的东 ...

  5. unity 太阳自发光_unity shader基础之——unity中实现环境光、自发光

    上篇主要讲的是unity中的光照模型及其原理,还有几种光照类型(自发光.环境光.漫反射.高光反射),后面几篇文章就开始在unity中实现这几种光照类型,本篇在unity实现自发光.环境光. 一.uni ...

  6. Unity Shader - 实现简单水体 - 浅水到深水颜色控制

    文章目录 制作步骤 准备好水体网格 扰动水体网格 添加水体网格色调,纹理 放置海上放哨点(一些随便放的立方体) 添加水的深浅透视效果 添加水光效 重构水顶点法线 正交的相机的深度需要注意 改进 Pro ...

  7. 在Unity 3D中,shader是何时编译的,在何时加载入显存中的?

    在Unity 3D中,shader是何时编译的,在何时加载入显存中的? 是某一对象在实例化时,加载其相关的material与shader还是游戏开始时? 添加评论 分享 按时间排序按投票排序 4 个回 ...

  8. unity 2020 怎么写shader使其接受光照?_用Unity实现半条命Alyx中的液体物理效果

    干了两个月客户端的活终于能闲下来几天,有点空写个玩具了. 前段时间被半条命Alyx里的酒瓶刷屏了,这酒瓶里液体的的物理效果仅仅看录屏都能感受到十分棒,同时据说瓶子中液体的逻辑全部在shader的一个单 ...

  9. Ruby‘s Adventrue游戏制作笔记(十二)Unity给角色添加简单的特效

    Ruby's Adventrue游戏制作笔记(十二)Unity给角色添加简单的特效 前言 一.把特效物品进行切割 二.创建 particle System 三.创建彩色球 四.再设置一下其他属性 五. ...

  10. unity性能最高的Shader:Unlit

    原文链接:http://www.jianshu.com/p/f6a0b6037ada unity性能最高的Shader: Unlit 材质分类 1.现在游戏常用材质分为PBR(Standard)和不受 ...

最新文章

  1. 祝大家春节快乐身体健康
  2. 中国矿业大学计算机控制技术英语,中国矿业大学计算机控制系统参考试卷4及答案.pdf...
  3. JSON.parseObject(String str)与JSONObject.parseObject(String str)的区别
  4. 火爆网络的《神经网络与深度学习》,有人把它翻译成了中文版!
  5. Retrofit2源码解析——网络调用流程(下)
  6. 自制串口示波器小工具
  7. 上传更新的代码到gitlab
  8. 个人成长中,关于规划设计的思考
  9. js 下拉框选中跳转
  10. [独孤九剑]持续集成实践(二)– MSBuild语法入门
  11. 用户增长 - BG/NBD概率模型预测用户生命周期LTV(二)
  12. 2.windows-and-mac在控制台创建ASP.NET-Core应用程序
  13. 纯c语言设计的打字母游戏代码,纯c语言编写的打字游戏代码
  14. 手游内存辅助开发教程
  15. leaflet+D3
  16. 天津大学仁爱学院2014计算机系毕业晚会,天津大学仁爱学院什么专业好
  17. mysql 复合索引 悲观锁_对MySQL索引、锁及事务的简单分析
  18. vs全项目搜索关键词
  19. CodeCombat代码全记录(Python学习利器)--边地森林(第二章)代码4
  20. Matlab怎么从table变成matrix

热门文章

  1. 最新大淘客php加淘口令,淘口令转淘口令
  2. HTML中怎么点击超链接让新页面在另一个窗口打开?
  3. fgo服务器维护中,FGO维护更新公告 更新内容一览
  4. fgo服务器维护2018,fgo迦勒底男性精选2018推荐召唤开启 fgo4月20日维护公告_游侠手游...
  5. macbook pro配置maven环境变量
  6. Excel对比数据差异方法总结
  7. Excel 对比两个表的相同列内容是否一致
  8. YbSoftwareFactory 代码生成插件【二十三】:集成强大的公文流转系统
  9. 深度强化学习——A3C
  10. 服务器端网站自适应,[移动SEO]PC端和移动端最佳适配方案