【Unity Shaders】学习笔记——SurfaceShader(三)BasicDiffuse和HalfLambert


转载请注明出处:http://www.cnblogs.com/-867259206/p/5598185.html

写作本系列文章时使用的是Unity5.3。
写代码之前:

  1. 当然啦,如果Unity都没安装的话肯定不会来学Unity Shaders吧?

  2. 阅读本系列文章之前你需要有一些编程的概念。

  3. 在VS里面,Unity Shaders是没有语法高亮显示和智能提示的,VS党可以参考一下这篇文章使代码高亮显示,也可以下载shaderlabvsNShader之类的插件使代码高亮显示。

  4. 这是针对小白的Unity Shaders的基础知识,如果你已经有了基础或者你是大神,那么这些文章不适合你。

  5. 由于作者水平的局限,文中或许会有谬误之处,恳请指出。


还记得前面说的创建Surface Shader的方法吗?按照之前的方法,新建一个Shader,命名为BasicDiffuse。

  1. 先将修改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
}
  1. #pragma surface surf Standard fullforwardshadows改为:

#pragma surface surf BasicDiffuse

这说明我们要用BasicDiffuse光照模型,这是我们自定义的一个光照模型。

  1. 定义在Properties里声明过的变量:

float4 _EmissiveColor;
float4 _AmbientColor;
float _MySliderValue;
  1. 修改你的surf函数:

void surf (Input IN, inout SurfaceOutput o){
float4 c;
c = pow((_EmissiveColor+_AmbientColor), _MySliderValue);
o.Albedo = c.rgb;
o.Alpha = c.a;
}

注意输出结构的类型,做了修改。

  1. 添加下面这个函数,这就是我们自定义的光照模型:

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;
}

解释

  1. 在surf函数里,我们将自发光颜色和漫反射颜色相加的和作为底数,然后将_MySliderValue的值作为次幂,进行幂运算得到四元浮点向量c,输出的反射值等于c的RGB颜色,输出的透明通道等于c的透明通道。这其实就是将自发光颜色和漫反射颜色进行了一定的混合。

  2. 自定义的光照模型的命名规则是“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的更多相关文章

  1. Unity 3D学习笔记(三)——关于脚本

    在脚本中定义的类成员,如果是公共的话,在脚本与游戏对象绑定之后,是可以在Inspector中编辑的,例如下面这个脚本: using UnityEngine; using System.Collecti ...

  2. 【Unity Shaders】学习笔记——SurfaceShader(十一)光照模型

    [Unity Shaders]学习笔记——SurfaceShader(十一)光照模型 转载请注明出处:http://www.cnblogs.com/-867259206/p/5664792.html ...

  3. 【Unity Shaders】学习笔记——SurfaceShader(十)镜面反射

    [Unity Shaders]学习笔记——SurfaceShader(十)镜面反射 如果你想从零开始学习Unity Shader,那么你可以看看本系列的文章入门,你只需要稍微有点编程的概念就可以. 水 ...

  4. 【Unity Shaders】学习笔记——SurfaceShader(一)认识结构

    [Unity Shaders]学习笔记——SurfaceShader(一)认识结构 转载请注明出处:http://www.cnblogs.com/-867259206/p/5595747.html 写 ...

  5. 【Unity Shaders】学习笔记——SurfaceShader(九)Cubemap

    [Unity Shaders]学习笔记——SurfaceShader(九)Cubemap 如果你想从零开始学习Unity Shader,那么你可以看看本系列的文章入门,你只需要稍微有点编程的概念就可以 ...

  6. 【Unity Shaders】学习笔记——SurfaceShader(八)生成立方图

    [Unity Shaders]学习笔记——SurfaceShader(八)生成立方图 转载请注明出处:http://www.cnblogs.com/-867259206/p/5630261.html ...

  7. 【Unity Shaders】学习笔记——SurfaceShader(七)法线贴图

    [Unity Shaders]学习笔记——SurfaceShader(七)法线贴图 转载请注明出处:http://www.cnblogs.com/-867259206/p/5627565.html 写 ...

  8. 【Unity Shaders】学习笔记——SurfaceShader(六)混合纹理

    [Unity Shaders]学习笔记——SurfaceShader(六)混合纹理 转载请注明出处:http://www.cnblogs.com/-867259206/p/5619810.html 写 ...

  9. 【Unity Shaders】学习笔记——SurfaceShader(五)让纹理动起来

    [Unity Shaders]学习笔记——SurfaceShader(五)让纹理动起来 转载请注明出处:http://www.cnblogs.com/-867259206/p/5611222.html ...

随机推荐

  1. 关于双击事件.MouseEvent.DOUBLE_CLICK

    as3提供了双击事件的调用,但有时候碰到双击事件无法响应,所以总结下原因.先摘录一段官方关于 doubleClick 事件发生的条件.如果 InteractiveObject 的 doubleClic ...

  2. Understanding and Managing SMTP Virtual Servers

    Simple Mail Transfer Protocol (SMTP) Service Overview The Simple Mail Transfer Protocol (SMTP) servi ...

  3. sql数据库带补全终端命令

    mysql pip install mycli pgsql pip install pgcli 都是python脚本,记录备忘.

  4. ADB工具 获取ROOT权限及复制文件方法

    adb push d:\tm3_sqlit.db data/zouhao/tm3_sqlit.dbadb pull data/zouhao/tm3_sqlit.db d:\tm3_sqlit.db a ...

  5. Linux下查看和添加环境变量

    转自:http://blog.sina.com.cn/s/blog_688077cf01013qrk.html $PATH:决定了shell将到哪些目录中寻找命令或程序,PATH的值是一系列目录,当您 ...

  6. 黄聪:怎么清理win7、win8更新垃圾(winsxs目录清理)

    windows 系统(特别是Win8系统)在使用了一段时间后,发现C盘的空间降的好厉害,显然,有大量不该存在的文件还继续停留在硬盘里.究其原因,在于系统目录下的WinSxS目录占用了大量的空间!在我们 ...

  7. 二. log4j配置文件

    log4j的配置文件 # Output pattern : date [thread] priority category - message log4j.rootLogger=info,Consol ...

  8. TCP非阻塞通信

    一.SelectableChannel SelectableChannel支持阻塞和非阻塞模式的channel 非阻塞模式下的SelectableChannel,读写不会阻塞 SelectableCh ...

  9. BIP_开发案例01_BI Publisher报表手工提交和控制(案例)

    2014-12-27 Created By BaoXinjian

  10. AD9 笔记:

    1 丝印压焊盘违反规则:关闭规则中的Manufacturing(制造规则)分类 >>> Silkscreen Over Component Pads Clearence(丝印与焊盘间 ...