【Unity Shaders】Diffuse Shading——创建一个自定义的diffuse lighting model(漫反射光照模型)
本系列主要参考《Unity Shaders and Effects
Cookbook》一书(感谢原书作者),同时会加上一点个人理解或拓展。
这里是本书所有的插图。这里是本书所需的代码和资源(当然你也可以从官网下载)。
========================================== 分割线 ==========================================
上一篇中,我们学了怎样在surface shader(这里即指surf函数)中使用自己定义的Properties变量。而在之前的学习中,我们实际上使用的都是Unity内置的Diffuse Lighting Model,即漫反射光照模型。这一次,我们将学习如何让Unity使用我们自己定义的光照模型进行渲染。
准备工作
- 使用上一篇结束时的shader代码即可。
Shader "Custom/BasicDiffuse" {
Properties {
_EmissiveColor ("Emissive Color", Color) = (1,1,1,1)
_AmbientColor ("Ambient Color", Color) = (1,1,1,1)
_MySliderValue ("This is a Slider", Range(0,10)) = 2.5
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert //We need to declare the properties variable type inside of the
//CGPROGRAM so we can access its value from the properties block.
float4 _EmissiveColor;
float4 _AmbientColor;
float _MySliderValue; struct Input
{
float2 uv_MainTex;
}; void surf (Input IN, inout SurfaceOutput o)
{
//We can then use the properties values in our shader
float4 c;
c = pow((_EmissiveColor + _AmbientColor), _MySliderValue);
o.Albedo = c.rgb;
o.Alpha = c.a;
} ENDCG
}
FallBack "Diffuse"
}
实现
- 将上述代码的第11行,即#pragma surface surf Lambert一行,改为如下代码:
#pragma surface surf BasicDiffuse
- 向SubShader中添加如下函数(位置需在#pragma下面):
inline float4 LightingBasicDiffuse (SurfaceOutput s, fixed3 lightDir, fixed atten)
{
float difLight = max(0, dot (s.Normal, lightDir));
float4 col;
col.rgb = s.Albedo * _LightColor0.rgb * (difLight * atten * 2);
col.a = s.Alpha;
return col;
} - 保存,进入Unity查看编译结果。
解释
- "#pragma surface"将直接告诉Shader使用哪个光照模型用于计算。当我们最初创建了一个Shader时,Untiy为我们指定了一个默认的光照模型即Lambert(在Lighting.cginc中定义)。因此我们一开始可以使用这个默认的模型进行渲染。而现在,我们告诉Shader,嘿,使用一个名叫BasicDiffuse的光照模型给我渲染哦!
- 为了创建一个新的光照模型,我们需要声明一个新的光照模型函数。例如上面,我们声明了BasicDiffuse,并且定义了一个函数名叫LightingBasicDiffuse,如你所见,这两者之间的关系即为Lighting<自定义的光照模型名称>。下面有三种可供选择的光照模型函数:
half4 LightingName (SurfaceOutput s, half3 lightDir, half atten){}
这个函数被用于forward rendering(正向渲染),但是不需要考虑view direction(观察角度)时。
half4 LightingName (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten){}
这个函数被用于forward rendering(正向渲染),并且需要考虑view direction(观察角度)时。
half4 LightingName_PrePass (SurfaceOutput s, half4 light){}
这个函数被用于需要使用defferred rendering(延迟渲染)时。
- 观察我们定义的光照模型函数。dot函数是一个Cg的内置数学函数,可以被用于比较空间中两个向量的方向。若两个参数向量均为单位向量(一般如此),-1表示两向量平行但方向相反,1表示两向量平行且方向相同,0表示两向量垂直。
- 为了完成光照模型函数,我们还使用了一个Unity提供的数据——类型为SurfaceOutput的变量s。我们将s.Albedo(从surf函数中输出)和_LightColor0.rgb(Unity提供)相乘,结果再乘以(difLight * atten * 2),最后作为颜色值进行输出。
- 首先是参数。s是上一个surf函数的输出。
void surf (Input IN, inout SurfaceOutput o)
{
//We can then use the properties values in our shader
float4 c;
c = pow((_EmissiveColor + _AmbientColor), _MySliderValue);
o.Albedo = c.rgb;
o.Alpha = c.a;
}由上可以看出,经过surf函数,计算输出了s的Albedo(反射率)和Alpha(透明度)。
LightBasicDiffuse函数输出的将是一个surface上某一点的颜色值和透明度值。因此lightDir对应该点的光照方向。而atten表明了光线的衰减率。 - 光照模型函数中的第一行代码通过dot函数和max函数,计算到达该点的光照值(由于dot函数的两个参数都是单位向量,也可以理解成是入射光线的角度的余弦值,角度越大,余弦值越小,进入人眼的光线也就越少,物体看起来也就越暗)。由于光线有可能从相反射入,因此通过dot得到的值有可能是负数。如果不用max加以限制,之后将会得到非预期的效果,如全黑等。
- 接下来计算颜色值col。col的rgb由三个部分计算而得:第一个部分是surface本身的反射率,这很好理解,因为反射率越大,进入人眼的光线就越多,颜色也就越鲜亮;第二个是_LightColor0.rgb。_LightColor0是Unity内置变量,我们可以使用它得到场景中光源的颜色等;最后便是利用第一步中得到的光照值和衰减率的乘积。细心的童鞋可以发现,这里后面多乘了一个倍数2。按我的猜测,这里仅仅是根据需要自行修改的。例如,没有倍数2时,效果如下:
乘以倍数2后效果如下:
结束语
【Unity Shaders】Diffuse Shading——创建一个自定义的diffuse lighting model(漫反射光照模型)的更多相关文章
- 【Unity Shaders】Diffuse Shading——创建一个基本的Surface Shader
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 如何创建一个自定义jQuery插件
简介 jQuery 库是专为加快 JavaScript 开发速度而设计的.通过简化编写 JavaScript 的方式,减少代码量.使用 jQuery 库时,您可能会发现您经常为一些常用函数重写相同的代 ...
- springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑。为了区别不同的异常通常根据异常类型自定义异常类,这里我们创建一个自定义系统异常,如果controller、service、dao抛出此类异常说明是系统预期处理的异常信息。
springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑. 1.1 异常处理思路 系统中异常包括两类:预期异常和运行时异常RuntimeEx ...
- 怎么在java中创建一个自定义的collector
目录 简介 Collector介绍 自定义Collector 总结 怎么在java中创建一个自定义的collector 简介 在之前的java collectors文章里面,我们讲到了stream的c ...
- 使用 TypeScript,React,ANTLR 和 Monaco Editor 创建一个自定义 Web 编辑器(二)
译文来源 欢迎阅读如何使用 TypeScript, React, ANTLR4, Monaco Editor 创建一个自定义 Web 编辑器系列的第二章节, 在这之前建议您阅读使用 TypeScrip ...
- Unity 3D使用GameObject创建一个简单的可移动物体
于Unity 3D游戏的开发.游戏脚本需要3D模拟组合,该脚本将被写入阻力3D为了达到效果对象. 以下是一个小实例,使用Unity 3D实现一个可控制移动的小人.小人能够向前.向后.向左和向右移动. ...
- 如何创建一个自定义的`ErrorHandlerMiddleware`方法
在本文中,我将讲解如何通过自定义ExceptionHandlerMiddleware,以便在中间件管道中发生错误时创建自定义响应,而不是提供一个"重新执行"管道的路径. 作者:依乐 ...
- 创建一个自定义的Application类
由于每个应用程序必须创建一个Application对象,vs为开发人员提供了模板来减轻开发人员的重复工作.当使用vs创建一个WPF应用程序是,vs会自动创建一个app.xaml文件, <Appl ...
- 创建一个自定义名称的Ceph集群
前言 这里有个条件,系统环境是Centos 7 ,Ceph 的版本为Jewel版本,因为这个组合下是由systemctl来进行服务控制的,所以需要做稍微的改动即可实现 准备工作 部署mon的时候需要修 ...
随机推荐
- Go 语言切片(Slice)
Go 语言切片是对数组的抽象. Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固 ...
- jQuery – AJAX load() 方法
jQuery load() 方法 jQuery load() 方法是简单但强大的 AJAX 方法. load() 方法从服务器加载数据,并把返回的数据放入被选元素中. 语法: $(selector). ...
- 20160227.CCPP体系详解(0037天)
程序片段(01):01.一对一模式.c+02.中介者模式.c+03.广播模式.c 内容概要:事件 ///01.一对一模式.c #include <stdio.h> #include < ...
- 文件一键上传、汉字转拼音、excel文件上传下载功能模块的实现
----------------------------------------------------------------------------------------------[版权申明: ...
- Git 处理tag和branch的命令
最近想给GitHub 上的项目设置tag,可是使用GitHub Desktop,找了一圈都没找到快速设置Tag 的地方,最后只能通过终端命令来添加了. 想要查看Git 的命令,可以使用 git --h ...
- Android简易实战教程--第四十一话《vitamio网络收音机》
在Android初级教程专栏里面,介绍了Android原生的VideoView和vitamio框架Android视频媒体相关,VideoView和开源框架vitamio.并演示了播放网络视频的对应的D ...
- Ajax 异步加载
AJAX (Asynchronous JavaScript and XML,异步的 JavaScript 和 XML).它不是新的编程语言,而是一种使用现有标准的新方法,是在不重新加载整个页面的情况下 ...
- 【完整的App项目】颖火虫笔记
这是本人花大概一个星期开发出来的一款App,这是一款类似印象笔记的App,随时记录您的生活点滴.首先说一下自己为何要开发这款App,因为自己手机系统自带的笔记应用功能太low,界面不够漂亮,所以自己就 ...
- Android Multimedia框架总结(十四)Camera框架初识及自定义相机案例
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52738492 前言:国庆节告一段 ...
- FFmpeg源代码简单分析:内存的分配和释放(av_malloc()、av_free()等)
===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...