本系列主要参考《Unity Shaders and Effects
Cookbook》
一书(感谢原书作者),同时会加上一点个人理解或拓展。

这里是本书所有的插图。这里是本书所需的代码和资源(当然你也可以从官网下载)。

========================================== 分割线 ==========================================

写在前面


有很多情况你可能想要使用法线去影响反射效果。比如,你想要模拟一个被霜雪覆盖的玻璃材质的表面,或者一个冰块。如果你根据物理知识真实的模拟这个平面的每一个细节部分,那么你就不要希望你游戏的FPS还可以达到60帧了。相反的,我们可以使用法线贴图来伪造一个视觉体验,因此我们需要学习如何将法线贴图的信息传递给反射效果。

为了完成这个任务,我们将要学习Input结构体的另一个内置参数,它可以将由法线贴图技术生成的修改后的平面法线信息传递进来。下面,让我们来具体看一下如何修改Input结构体来达到这个效果吧!



准备


  1. 首先,我们需要一个Cubemap来产生反射效果。所以你可以使用前一节中的Cubemap,或者生成一个新的。这一节中,我们使用的如下所示(你可以在本书资源中找到它):

  2. 我们还需要一张法线贴图来产生基于法线的反射效果。

  3. 最后,创建一个新的场景、一个球体、一个平面以及一个平行光。同时,还需要创建一个新的Shader和Material,命名为NormalMappedReflection。


实现


  1. 首先让我们添加新的properties,使得我们能够添加自己的Cubemap和法线贴图。这个步骤你应该非常熟悉了。向Properties块添加下列代码:

    	Properties {
    _MainTint ("Diffuse Tint", Color) = (1,1,1,1)
    _MainTex ("Base (RGB)", 2D) = "white" {}
    _NormalMap ("Normal Map", 2D) = "bump" {}
    _Cubemap ("Cubemap", CUBE) = ""{}
    _ReflAmount ("Reflection Amount", Range(0,1)) = 0.5
    }
  2. 然后,我们需要在SubShader块声明这些properties,使得我们能够访问Properties块中的这些数据:
    		CGPROGRAM
    #pragma surface surf Lambert samplerCUBE _Cubemap;
    sampler2D _MainTex;
    sampler2D _NormalMap;
    float4 _MainTint;
    float _ReflAmount;
  3. 然后,修改Input结构体。这是基于法线贴图的反射的精华所在。通过使用INTERNAL_DATA声明,我们可以访问经过法线贴图修改后的平面的法线信息:
    		struct Input {
    float2 uv_MainTex;
    float2 uv_NormalMap;
    float3 worldRefl;
    INTERNAL_DATA
    };
  4. 最后,我们需要修改surf函数,来得到最后的基于法线贴图的反射效果:
    		void surf (Input IN, inout SurfaceOutput o) {
    half4 c = tex2D (_MainTex, IN.uv_MainTex); float3 normals = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap)).rgb;
    o.Normal = normals; o.Emission = texCUBE (_Cubemap, WorldReflectionVector (IN, o.Normal)).rgb * _ReflAmount;
    o.Albedo = c.rgb * _MainTint;
    o.Alpha = c.a;
    }

最后,整体代码如下:
Shader "Custom/NormalMappedReflection" {
Properties {
_MainTint ("Diffuse Tint", Color) = (1,1,1,1)
_MainTex ("Base (RGB)", 2D) = "white" {}
_NormalMap ("Normal Map", 2D) = "bump" {}
_Cubemap ("Cubemap", CUBE) = ""{}
_ReflAmount ("Reflection Amount", Range(0,1)) = 0.5
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200 CGPROGRAM
#pragma surface surf Lambert samplerCUBE _Cubemap;
sampler2D _MainTex;
sampler2D _NormalMap;
float4 _MainTint;
float _ReflAmount; struct Input {
float2 uv_MainTex;
float2 uv_NormalMap;
float3 worldRefl;
INTERNAL_DATA
}; void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex); float3 normals = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap)).rgb;
o.Normal = normals; o.Emission = texCUBE (_Cubemap, WorldReflectionVector (IN, o.Normal)).rgb * _ReflAmount;
o.Albedo = c.rgb * _MainTint;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}

效果如下(一个表明凹凸不平的反射球):


而下图是不加法线影响的效果(一个光滑的反射球):




解释


你可能已经注意到这一节的Shader和上一节中的非常类似,而有一个非常重要的不同点(上一节直接使用IN.worldRefl来查找Cubemap)。我们想要使用逐像素的法线贴图来修改我们的反射贴图。为了完成这个目的,我们需要得到在应用法线贴图后、物体的平面法线信息。这意味着,我们需要下列代码:
			float3 normals = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap)).rgb;
o.Normal = normals;

一旦上述代码在Shader中执行后,物体的平面法线将被修改;因此,我们需要使用它来影响我们的反射。我们可以通过声明INTERNAL_DATA来访问修改后的法线信息,然后使用WorldReflectionVector (IN, o.Normal)去查找Cubemap中对应的反射信息。这是Unity提供给我们的另一个内置函数,因此我们不需要再自己写那些冗长的代码,而仅仅需要关注编写Shader中产生关键效果的部分。




更多…


结构体中还有很多内置函数(变量),而在将来的章节中我们的确会接触到它们。下面的表格描述了每一个内置函数的作用以及如何使用它们。你也可以访问官网来得到更多的关于内置函数的信息:

float3 viewDir 包含了视角的观察方向,主要用于计算视差效应(Parallax effects ),边缘光照,等等。
float4 COLOR 包含了经过内插值(interpolated )的每个顶点的颜色值。
float4 screenPos 包含了用于反射效果的屏幕坐标系的位置信息。例如,在Unity专业版的WetStreet shader中使用了它。
float3 worldPos 包含了世界坐标系中的位置。
float3 worldRefl 包含了世界坐标系中的反射向量,如果Surface Shader没有重写o.Normal。参考Reflect-Diffuse shader。
float3 worldNormal 包含了世界坐标系中的法线向量,如果Surface Shader没有重写o.Normal。
float3 worldRefl;

INTERNAL_DATA
包含了世界坐标系的反射向量,如果Surface Shader重写了o.Normal。为了得到基于逐像素的法线贴图的反射向量,请使用WorldReflectionVector (IN,o.Normal) 。参考Reflect-Bumped shader。
float3 worldNormal;

INTERNAL_DATA
包含了世界坐标系的发现向量,如果Surface Shader重写了o.Normal。为了得到基于逐像素的法线贴图的法线向量,请使用WorldNormalVector (IN,o.Normal) 。参考Reflect-Bumped shader。





【Unity Shaders】Reflecting Your World —— Unity3D中的法线贴图和反射的更多相关文章

  1. 【Unity Shaders】Reflecting Your World —— Unity3D中简单的Cubemap反射

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  2. 【Unity Shaders】Reflecting Your World —— Unity3D中的遮罩反射(Masking Reflections)

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  3. Unity 着色器训练营(2) - MVP转换和法线贴图

    https://mp.weixin.qq.com/s/Qf4qT15s9bWjbVGh7H32lw 我们刚刚公布了Unity 2018.1中,Unity将会内置可视化编程工具Shader Graph, ...

  4. Unity Shaders and Effects Cookbook (4-1)(4-2)静态立方体贴图的创建与使用

    開始学习第4章 - 着色器的反射 看完了1.2节,来记录一下.反射主要是利用了 Cubemap 立方体贴图. 认识Cubemap 立方体贴图.就如同名字所说.在一个立方体上有6张图.就这样觉得吧. 假 ...

  5. 【Unity Shaders】Reflecting Your World(反射吧!)介绍

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  6. 【Unity Shaders】学习笔记——SurfaceShader(二)两个结构体和CG类型

    [Unity Shaders]学习笔记——SurfaceShader(二)两个结构体和CG类型 转载请注明出处:http://www.cnblogs.com/-867259206/p/5596698. ...

  7. Unity3D ShaderLab法线贴图

    Unity3D ShaderLab法线贴图 说到法线贴图,应该算是我们最常使用的一种增强视觉效果的贴图.将法线贴图的各个像素点座位模型的法线,这样我们的光照可以模拟出高分辨率的效果, 同时也保持较低的 ...

  8. (转)Unity3D 游戏贴图(法线贴图,漫反射贴图,高光贴图)

    原帖网址http://www.u3dpro.com/read.php?tid=207  感谢jdk900网友的辛苦编写 我们都知道,一个三维场景的画面的好坏,百分之四十取决于模型,百分之六十取决于贴图 ...

  9. 【Unity Shaders】Reflecting Your World —— 在Unity3D中创建一个简单的动态Cubemap系统

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

随机推荐

  1. webstorm 设置uglify 压缩js文件

    第一步:打开npm,全局安装 npm install uglify-js -g 第二步: 打开webstorm的file->settings ->External Tools,点击左上角的 ...

  2. Mac 上Tomcat装载

    I recently installed Tomcat 7 and got it working with Eclipse Helios on Mac OSX Lion.Install Homebre ...

  3. 1. 两数之和 LeetCode

    给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 给定 nums = [, , , ], target = 因为 n ...

  4. Java第5次实验提纲(Java图形界面编程)

    1. Swing与NetBeans 使用NetBeans编写简单界面.见GUI实验参考文件中的0.第06次实验(图形程序设计.事件处理与Swing).doc 题目1: Swing用户界面组件与事件处理 ...

  5. Java内存泄漏分析系列之六:JVM Heap Dump(堆转储文件)的生成和MAT的使用

    原文地址:http://www.javatang.com JVM Heap Dump(堆转储文件)的生成 正如Thread Dump文件记录了当时JVM中线程运行的情况一样,Heap Dump记录了J ...

  6. Bootstrap3 表格-基本表格

    为任意 <table> 标签添加 .table 类可以为其赋予基本的样式 - 少量的内补(padding)和水平方向的分隔线.这种方式看起来很多余!?但是我们觉得,表格元素使用的很广泛,如 ...

  7. Lua判断OS并添加cpath

    Lua判断OS并添加cpath(金庆的专栏)Lua初始化时需要根据OS来设置package.cpath, 如果是Windows系统则添加 ?.dll, 否则添加 ?.so.不然加载错误后缀名的动态库会 ...

  8. 用户创建,删除and并发注册and系统登陆的API研究(学习汇总网上资料)

    一.系统登陆链接实现 比如有一个外围支持系统,用户需要在外围系统登录之后点个link就可以登录到Oracle ERP系统中,那么我们需要先把外围系统的用户创建在Oracle ERP中,并且分配职责给他 ...

  9. ActiveMQ入门示例

    1.ActiveMQ下载地址 http://activemq.apache.org/download.html 2.ActiveMQ安装,下载解压之后如下目录

  10. 分析MapReduce执行过程+统计单词数例子

    MapReduce 运行的时候,会通过 Mapper 运行的任务读取 HDFS 中的数据文件,然后调用自己的方法,处理数据,最后输出.Reducer 任务会接收 Mapper 任务输出的数据,作为自己 ...