摘要: 这篇文章主要介绍Lighting model及自定义Lighting model

上文咱们学了surface shader。这玩意在开始的时候啊,在定义哪个函数处理surface时用一定要指定Lighting model(即光照模型)的。自带的是Lambert和BlinnPhong.本文首先对这两个进行说明,后面讲解如何自定义光照模型及对官方实例的解析。http://docs.unity3d.com/Documentation/Components/SL-SurfaceShaderLighting.html

一、简单光反射模型

1.反射,其实就是光照到物体上,然后再由物体反射出去。这种过程就叫反射。

2.漫反射,物体表面可能是不光滑的,因此自然法线就不是均匀的,那么这种情况下,当几条平行光照向物体时,反射回来的光线就不再是平行的了,这种情况叫漫反射。

3.镜面反射:与漫反射对应,如果物体表面光滑,即法线均匀(不一定都平行,会有曲面的情况),则反射回来的也是均匀的,这种情况叫镜面反射。

4.环境光:光线照到指定物体的周围物体,这时指定物体上有光线反射到,这种光可称为环境光或泛光。

5.光照 = 反射光 + 镜面光 + 环境光 + 自发光。

对于简单光反射模型: 入射光 = 反射光 + 吸引光。而实际上来说还需要加上投射光与散射光。

二、Lambert和BlinnPhong

1.冯式反射模型:Phong reflection 是一种将漫反射与镜面反射进行关联在一些的反射方法。

2.Lambert:一种主要应用于漫反射的光照模型。

3.BlinnPhong: 一种主要应用于镜面反射的光照模型。

三、自定义光照模型

1.规则:定义一个函数,必须以 Lighting开头,可以写在shader文件里的任意位置或其他include的文件。
=>half4 LightingName (SurfaceOutput s, half3 lightDir, half atten);  这种是无viewDir,在上文中有说到viewDir就是返回给视角的方向,不用依赖此值,就类似于漫反射的效果。因为漫反射中出来的光线是由不规则的表面来决定。

=>half4 LightingName (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten); 这个方法是相对于上面的,需要依赖于viewDir。

=>half4 LightingName_PrePass (SurfaceOutput s, half4 light); 这个方法是可选的,如果需要光照延时(deferred),就加上此方法,不写则全部采用快速光照(forward)。

2.自定义解码光照

注意,如果使用了LightingName_PrePass,则光照解码的方法在此方法之前,因此是有了光照延时。具体会针对与SingleLightMapping、DualLightMapping和StandardLightMapping三种的方法,与LightMapping的定义函数类似,具体的这里不介绍,可参考官方文档:http://docs.unity3d.com/Documentation/Components/SL-SurfaceShaderLighting.html

三、实例学习

1.自定义一个简单的漫反射光照模型:

#pragma surface surf SimpleLambert  //1

half4 LightingSimpleLambert (SurfaceOutput s, half3 lightDir, half atten) { //2
half NdotL = dot (s.Normal, lightDir); //3
half4 c; //4
c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten * 2); //5
c.a = s.Alpha; //6
return c; //7
}

//1: 定义使用SimpleLambert做为光照模型

//2: 光照模型的定义。这里说说atten,根据atten的意思(衰减器),可以理解到,这个参数就是光照的衰减值。

//3:算一点积,光照方向与法线的点积,可理解为光照与法线的夹角。

//4:定义输出的颜色四元组。

//5:光照的颜色 = 物体反射颜色 * 原光的颜色* 经过折射的衰减颜色。_LightColor0是在Lighting.cginc 里定义的,我理解成反射光的颜色。另外还有一个_SpecColor,对应是镜面反射光的颜色。此处由于资料稀缺,全部个人的学习所得,如有错误,欢迎指出!

//6:设置光的透明与反射透明一致。

//7:返回。

效果:

2.Diffuse wrap

#pragma surface surf WrapLambert

half4 LightingWrapLambert (SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot (s.Normal, lightDir);
half diff = NdotL * 0.5 + 0.5; //!
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten * 2);
c.a = s.Alpha;
return c;
}

此1不同的只是//! 处,这里算得一个diff,目的是将原得出的点积单位从[-1,1]转换成[0,1]之间。 
这样做的用法,在各方问人,加上自己思想,想到的是将所有的坐标转成正值,这样,在其接受到光源反射的所有地方都会有光,这样使得光照的范围扩大了不少。

3.Toon Ramp

#pragma surface surf Ramp

sampler2D _Ramp;

half4 LightingRamp (SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot (s.Normal, lightDir);
half diff = NdotL * 0.5 + 0.5;
half3 ramp = tex2D (_Ramp, float2(diff)).rgb; //1
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
c.a = s.Alpha;
return c;
}

这里对比于2,把本来是固定的diff,再加上一个材质。

//1中,直接将diff强转成float2的坐标系,向_Ramp的材质中查找出相应的rgb。最终也以此rgb值及其他光照值得出光照的rgb值。这种效果可以考虑来做光晕。这里我用一张具体的图,以float2(diff)为uv找的效果会有点奇怪。不过现象可以反映出来。

效果:

4.Simple Specular

#pragma surface surf SimpleSpecular

half4 LightingSimpleSpecular (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) {
half3 h = normalize (lightDir + viewDir); half diff = max (0, dot (s.Normal, lightDir)); float nh = max (0, dot (s.Normal, h));
float spec = pow (nh, 48.0); half4 c;
c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec) * (atten * 2);
c.a = s.Alpha;
return c;
}

转载:https://my.oschina.net/u/138823/blog/181481

这个例子是自定义一个镜面反射的例子。c.rgb 的组成可拆成一个漫反射和一个镜面反射的组合。

c.rgb = (s.Albedo * _LightColor0.rgb * diff * (atten * 2)) + (_LightColor0.rgb * spec * (atten * 2));

前半段就是漫反射,不讲了。后面半段区别用到了镜面反射值。而这个值来自于:

float nh = max (0, dot (s.Normal, normalize (lightDir + viewDir)));

首先,光的方向和视角方向都是决定镜面反射的重要因素,不能没lightDir,否则镜面反射则只跟视角来了,那样是不现实的。因此此处需要让两个方向的向量之和与表面法线进行点积。这个nh范围是在大于0的。由于两个单位向量点积,因此得出的值则是 0到1之间。

后面取pow是为了放小nh的值,其值越小,则镜面反射就越小。

上效果:

Unity shader 官网文档全方位学习(二)的更多相关文章

  1. Unity shader 官网文档全方位学习(一)

    转载:https://my.oschina.net/u/138823/blog/181131 摘要: 这篇文章主要介绍Surface Shaders基础及Examples详尽解析 What?? Sha ...

  2. Spring Security 官网文档学习

    文章目录 通过`maven`向普通的`WEB`项目中引入`spring security` 配置 `spring security` `configure(HttpSecurity)` 方法 自定义U ...

  3. 【VR】Leap Motion 官网文档 FingerModel (手指模型)

    前言: 感谢关注和支持这个Leap Motion系列翻译的朋友们,非常抱歉因为工作原因非常久没有更新,今后这个翻译还会继续(除非官方直接给出中文文档).本篇献给大家的是 <FingerModel ...

  4. Hortonworks官网文档怎么找?

    Hortonworks官网文档怎么找? 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 俗话说,授人予鱼不如授人予渔,网上部署HDP的部署方式的博客有很多,看得你是眼花缭乱的.其实万 ...

  5. mybatis官网文档mybatis_doc

    在平时的学习中,我们可以去参考官网的文档来学习,这个文档有中文的,方便我们去阅读,而且这里的分类很详细. 官网文档链接:http://www.mybatis.org/mybatis-3/zh/inde ...

  6. 你会阅读appium官网文档吗

    高效学习appium第一步,学会查看appium官方文档.如果能把appium文档都通读一遍,对学习appium大有益处. 而能做到通读appium官方文档的人,想必不是很多,刚开始学习appium的 ...

  7. 部署openstack的官网文档解读mysql的配置文件

    部署openstack的官网文档解读mysql的配置文件(使用与ubutu和centos7等系统) author:headsen chen  2017-10-12 16:57:11 个人原创,严禁转载 ...

  8. redis过期机制(官网文档总结)

    官网地址:https://redis.io/commands/expire redis过期定义如下: Set a timeout on key. After the timeout has expir ...

  9. redis module 学习—官网文档整理

    前言 redis在4.0版本中,推出了一个非常吸引的特性,可以通过编写插件的模式,来动态扩展redis的能力.在4.0之前,如果用户想拥有一个带TTL的INCRBY 命令,那么用户只能自己去改代码,重 ...

随机推荐

  1. 剑指offer 11. 位运算 二进制中1的个数

    题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示.   //思想:用1(1自身左移运算,其实后来就不是1了)和n的每位进行位与,来判断1的个数     private stat ...

  2. NetCore部署到Linux服务器+Supervisor的步骤及过程中踩过的坑

    本文作备忘使用 服务器配置: 下面是所有操作的具体步骤: 1.安装nginx   参考 1.1 添加源:默认情况Centos7中没有Nginx源,最近Nginx官网提供了Centos的源地址. sud ...

  3. 【Oracle】group by 和partition by的区别

    总结: group 单纯分组 partition 也能分组,但还具备累计的功能 order by 排序,与计算函数联用,需要累加计算 0.select * from test;     ---测试数据 ...

  4. Windows Server 2008 R2 /2012 修改密码策略

    今天建了域环境,在添加新用户的时候,发现用简单的密码时域安全策略提示密码复杂度不够,于是我就想在域安全策略里面把密码复杂度降低一点. 问题:    在“管理工具 >> 本地安全策略 > ...

  5. 纵观 jBPM:从 jBPM3 到 jBPM5 以及 Activiti5

    https://www.infoq.cn/article/rh-jbpm5-activiti5# 对jBPM来说,今年最大的事件莫过于 jBPM 的创建者Tom Baeyens离开 JBoss 了.T ...

  6. C# 利用Unity 实现IOC+AOP

    public interface INoticy { void Noticy(string msg); } public class SMSNoticy : INoticy { public void ...

  7. piggy.lzo

    编译内核的时候出现错误:arch/arm/boot/compressed/piggy.lzo.S:4: Error: file not found: arch/arm/boot/compressed/ ...

  8. [python,2018-06-25] 高德纳箭号表示法

    概念 高德纳箭号表示法是种用来表示很大的整数的方法,由高德纳于1976年设计.它的意念来自幂是重复的乘法,乘法是重复的加法. 定义 计算 一个箭头 2↑3=2×2×2=8 2↑4=2×2×2×2=16 ...

  9. leetCode191. 位1的个数

    编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量) 示例 1: 输入:00000000000000000000000000001011 输出:3 解 ...

  10. Win10启动tomcat控制台乱码解决方案

    1.找到${CATALINA_HOME}/conf/logging.properties 2.添加语句:java.util.logging.ConsoleHandler.encoding = GBK ...