【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. Nova分析(1)——整体架构

    Conceptual Diagram Logical diagram Nova is the most complicated and distributed component of OpenSta ...

  2. 【转】SVN服务器客户端以及环境的搭建和使用

    vss,cvs,svn三者都是版本控制工具 vss是锁定-编辑-解锁模式,svn虽然也支持锁定,但默认是修改-冲突-合并模式 vss的版本号对应的是单个文件,svn的版本号对应的是整个版本库 vss是 ...

  3. uva 437 巴比伦塔(DAG上dp)

    巴比伦塔 紫书P269 看完紫书,终于可以自己写一个dp了 :) [题目链接]巴比伦塔 [题目类型]DAG上dp &题意: 有n种立方体 n<=30,每种有无穷个,要求选一些立方体摞成一 ...

  4. 查询oracle中所有用户信息

    1.查看所有用户:select * from dba_users;   select * from all_users;   select * from user_users; 2.查看用户或角色系统 ...

  5. Mac 10.10下安装MySQL5.6.21提示安装失败

    只要要在安装的第三步在自定里不要选Startup item就可以了

  6. CSS如何实现数字分页效果

    代码实例如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...

  7. CSS如何实现图片上下垂直居中

    方法一: 使用margin方式,使图片在div中上下垂直居中.margin-top值的计算方式是:div的高度/2-图片高度/2. 代码实例如下: <!DOCTYPE html><h ...

  8. Gatling的进阶二

    1. 参数化     Gatling可以很方便使用csv文件进行参数化,例如一个用户信息表:   /* user_information.csv */ username,password,accoun ...

  9. mysql 按年度、季度、月度、周、日SQL统计查询

    创建Table CREATE TABLE `test` ( `cdate` datetime DEFAULT NULL, `id` ) DEFAULT NULL, `name` ) DEFAULT N ...

  10. expdp和impdp的用法

    源地址:http://blog.chinaunix.net/uid-23622436-id-2394094.html