【Unity Shaders】学习笔记——SurfaceShader(三)BasicDiffuse和HalfLambert
【Unity Shaders】学习笔记——SurfaceShader(三)BasicDiffuse和HalfLambert
转载请注明出处:http://www.cnblogs.com/-867259206/p/5598185.html
写作本系列文章时使用的是Unity5.3。
写代码之前:
当然啦,如果Unity都没安装的话肯定不会来学Unity Shaders吧?
阅读本系列文章之前你需要有一些编程的概念。
在VS里面,Unity Shaders是没有语法高亮显示和智能提示的,VS党可以参考一下这篇文章使代码高亮显示,也可以下载
shaderlabvs或NShader之类的插件使代码高亮显示。这是针对小白的Unity Shaders的基础知识,如果你已经有了基础或者你是大神,那么这些文章不适合你。
由于作者水平的局限,文中或许会有谬误之处,恳请指出。
还记得前面说的创建Surface Shader的方法吗?按照之前的方法,新建一个Shader,命名为BasicDiffuse。
先将修改Properties里的内容:
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
}
将
#pragma surface surf Standard fullforwardshadows改为:
#pragma surface surf BasicDiffuse
这说明我们要用BasicDiffuse光照模型,这是我们自定义的一个光照模型。
定义在Properties里声明过的变量:
float4 _EmissiveColor;
float4 _AmbientColor;
float _MySliderValue;
修改你的surf函数:
void surf (Input IN, inout SurfaceOutput o){
float4 c;
c = pow((_EmissiveColor+_AmbientColor), _MySliderValue);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
注意输出结构的类型,做了修改。
添加下面这个函数,这就是我们自定义的光照模型:
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;
}
解释
在surf函数里,我们将自发光颜色和漫反射颜色相加的和作为底数,然后将_MySliderValue的值作为次幂,进行幂运算得到四元浮点向量c,输出的反射值等于c的RGB颜色,输出的透明通道等于c的透明通道。这其实就是将自发光颜色和漫反射颜色进行了一定的混合。
自定义的光照模型的命名规则是“Lighting”+“自定义的光照名称”。这样就定义了一个光照模型。
光照模型有5种原型:half4 LightingName (SurfaceOutput s, fixed3 lightDir, half atten);
half4 LightingName (SurfaceOutput s, fixed3 lightDir, fixed3 viewDir, half atten);
half4 LightingName_PrePass (SurfaceOutput s, half4 light);
half4 LightingName_DirLightmap(SurfaceOutput s, fixed4 color, fixed4 scale, bool surfFuncWritesNormal);
half4 LightingName_DirLightmap(SurfaceOutput s, fixed4 color, fixed4 scale, fixed3 viewDir, bool surfFuncWritesNormal,out half3 specColor);
这里我们用的就是第一种原型。第一个参数是输出结构,第二个参数是光线方向,也就是光源到物体表面上的点的向量,是单位向量,第三个参数衰减度,attenuation的缩写,因为光线被物体反射之后,会有能量损失,所以会有衰减。我们看到,这个参数没有被赋值,所以它是Unity内置的一个参数,我们知道它表示衰减就可以了。
函数里第一句计算的是漫反射的光强。dot是点乘。将表面的法向量和光线角度点乘,也就是光线和法向量的夹角越大,光线在法向量方向的分量越小,即反射的光越弱。因为夹角超过90度的时候,是负值,所以用max函数使结果大于0。max(x,y)就是取x,y中的最大值。
第三句的意思就是颜色值=反射值×平行光的颜色×漫反射光强×衰减度×2.
_LightColor0也是Unity内置的一个变量,它在不同的render path和pass里的意义不同,在这里就是平行光的颜色。
后面的这个2应该是个经验数值,可以根据自己想要的效果修改。
这就是基本漫反射的计算方法。
我们来看一下它的效果:
新建一个Sphere,将BasicDiffuse材质赋给它。将Slider的数值调为0.不出意外的话,你看到的效果是这样的:

更改自发光的颜色,然后调节Slider,我们发现,Slider数值越大,自发光颜色越明显:


现在将自发光改回白色,更改漫反射的颜色,然后调节Slider:
不出意外的话,看到的效果和自发光一样,Slider=0时,阴影是灰色的,自发光和漫反射的颜色不起作用,数值越大,则自发光和漫反射的颜色越明显。
接下来,同时更改自发光和漫反射的颜色,比如红色和绿色,我们看到球变成了黄色,也就是红光和绿光混合的效果:

你还可以自己再调节其他颜色试试看,看看都会有些什么效果。
还有那个函数里的数值2,你也可以改改试试看哟~
HalfLambert
接下来再学习一个经典的光照模型——HalfLambert(半兰伯特)。
很简单,我们先把光照模型改名为HalfLambert,也就是修改光照函数和#pragma。
先修改一句:
float difLight = dot (s.Normal, lightDir);
然后添加一句:
float hLambert = 0.5 * difLight + 0.5;
再改一句:
col.rgb = s.Albedo * _LightColor0.rgb * (hLambert * atten * 2);
原先difLight区间[-1,0]的部分变成了[0,0.5],如果直接用max函数使结果大于0的话,小于0的部分都会等于0,也就是背光面都会是黑色。如果用半兰伯特公式的话,小于0的部分就会从0渐变到0.5,颜色的灰度是会有变化。同时,亮部的亮度也提高了。
HalfLambert是由Valve公司提出的技术,是一种用于在低光照区域照亮物体的技术。它用来防止某个物体的背光面丢失形状并且显得太过平面化。这个技术是没有任何物理原理的,是一种感性的视觉增强。
附:代码清单
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
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf BasicDiffuse
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
float4 _EmissiveColor;
float4 _AmbientColor;
float _MySliderValue;
struct Input{
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o){
float4 c;
c = pow((_EmissiveColor+_AmbientColor), _MySliderValue);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
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;
}
ENDCG
}
FallBack "Diffuse"
}
HalfLambert光照模型函数:
inline float4 LightingHalfLambert (SurfaceOutput s, fixed3 lightDir, fixed atten){
float difLight = dot (s.Normal, lightDir);
float hLambert = 0.5 * difLight + 0.5;
float4 col;
col.rgb = s.Albedo * _LightColor0.rgb * (hLambert * atten * 2);
col.a = s.Alpha;
return col;
}
【Unity Shaders】学习笔记——SurfaceShader(三)BasicDiffuse和HalfLambert的更多相关文章
- Unity 3D学习笔记(三)——关于脚本
在脚本中定义的类成员,如果是公共的话,在脚本与游戏对象绑定之后,是可以在Inspector中编辑的,例如下面这个脚本: using UnityEngine; using System.Collecti ...
- 【Unity Shaders】学习笔记——SurfaceShader(十一)光照模型
[Unity Shaders]学习笔记——SurfaceShader(十一)光照模型 转载请注明出处:http://www.cnblogs.com/-867259206/p/5664792.html ...
- 【Unity Shaders】学习笔记——SurfaceShader(十)镜面反射
[Unity Shaders]学习笔记——SurfaceShader(十)镜面反射 如果你想从零开始学习Unity Shader,那么你可以看看本系列的文章入门,你只需要稍微有点编程的概念就可以. 水 ...
- 【Unity Shaders】学习笔记——SurfaceShader(一)认识结构
[Unity Shaders]学习笔记——SurfaceShader(一)认识结构 转载请注明出处:http://www.cnblogs.com/-867259206/p/5595747.html 写 ...
- 【Unity Shaders】学习笔记——SurfaceShader(九)Cubemap
[Unity Shaders]学习笔记——SurfaceShader(九)Cubemap 如果你想从零开始学习Unity Shader,那么你可以看看本系列的文章入门,你只需要稍微有点编程的概念就可以 ...
- 【Unity Shaders】学习笔记——SurfaceShader(八)生成立方图
[Unity Shaders]学习笔记——SurfaceShader(八)生成立方图 转载请注明出处:http://www.cnblogs.com/-867259206/p/5630261.html ...
- 【Unity Shaders】学习笔记——SurfaceShader(七)法线贴图
[Unity Shaders]学习笔记——SurfaceShader(七)法线贴图 转载请注明出处:http://www.cnblogs.com/-867259206/p/5627565.html 写 ...
- 【Unity Shaders】学习笔记——SurfaceShader(六)混合纹理
[Unity Shaders]学习笔记——SurfaceShader(六)混合纹理 转载请注明出处:http://www.cnblogs.com/-867259206/p/5619810.html 写 ...
- 【Unity Shaders】学习笔记——SurfaceShader(五)让纹理动起来
[Unity Shaders]学习笔记——SurfaceShader(五)让纹理动起来 转载请注明出处:http://www.cnblogs.com/-867259206/p/5611222.html ...
随机推荐
- Neutron分析(3)—— neutron-l3-agent
一.Layer-3 Networking Extension neutron l3作为一种API扩展,向租户提供了路由和NAT功能. l3扩展包含两种资源: router:在不同内部子网中转发数据包: ...
- Linux下Wi-Fi的实现:wireless_tools和wpa_supplicant
平台为hi35XX,在Liunx下借助wireless_tools和wpa_supplicant(因为现在的无线WIFI网络大多是wpa加密.所以需要移植wpa_supplicant工具)等工具实现w ...
- 242. Valid Anagram
Given two strings s and t, write a function to determine if t is an anagram of s. For example,s = &q ...
- iphone dev 入门实例2:Pass Data Between View Controllers using segue
Assigning View Controller Class In the first tutorial, we simply create a view controller that serve ...
- mvc 权限管理 demo
http://blog.csdn.net/zht666/article/details/8529646 new http://www.cnblogs.com/fengxing/archive/2012 ...
- MyEclipse背景色不伤眼+字体大小调节+代码格式化不换行
- PLSQL_Oracle Lock锁的处理(案例)
2014-06-21 Created By BaoXinjian
- 类(class)、构造函数(constructor)、原型(prototype)
类 Class 类的概念应该是面向对象语言的一个特色,但是JavaScript并不像Java,C++等高级语言那样拥有正式的类,而是多数通过构造器以及原型方式来仿造实现.在讨论构造器和原型方法前,我可 ...
- Input gameobject vector3 c#
Input类中的常用方法 bool w=Input.GetKey(KeyCode.W);//检测是否按下键盘W Input.GetKeyDown(KeyCode.W);//表示检测按下时 Input. ...
- Win7玩游戏偶尔自动跳转到桌面的解决办法[转]
新装的win7旗舰版SP1,怎么玩wow (魔兽世界.极品飞车.全屏游戏.按键精灵.挂机)总是过一会就自己返回桌面了.刚开始以为是显卡的毛病,更新了驱动还是一样(在这之前,排除病毒,其他驱动问题).因 ...