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

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

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

写在前面

有时候,我们并不想让物体的所有部分都反射,例如一个物体可能某些部分是玻璃材质的可以反射,而有些是塑料材质就不会反射。

在这篇教程里,我们将会学习一种技术来控制反射范围,这是通过一张texture作为遮罩(mask)来实现的。也就是说,我们可以使用一张texture的灰度值去决定该平面该如何反射,这意味着,一个为黑色的灰度值对应一个不会反射的子平面,而一个白色的灰度值对应一个完全反射的子平面。如今,基本所有的游戏制作都是使用这种方法来控制反射效果的。

下面,我们来看看在Unity里怎么使用Surface Shaders来实现它。

准备工作

  1. 首先,我们需要一个Cubemap,你可以生成一个新的或者使用前一篇用到的Cubemap。本教程所用的Cubemap如下(在本书的附带资源中可以找到):
  2. 我们还需要一个texture来描述我们对象的那些部分是可以反射的,而哪些不可以。记住,黑色表示没有任何反射性,而白色表示可以完全反射。下面的图片是我们将会用到的texture:
  3. 最后,我们需要创建一个新的场景以及场景中的一个对象、平面和一个平行光,来让我们观察反射效果。除此之外,新建一个Shader和对应的Material,并命名为MaskedReflection。

实现

  1. 添加新的Properties:
    	Properties {
    _MainTex ("Base (RGB)", 2D) = "white" {}
    _MainTint ("Diffuse Tint", Color) = (1,1,1,1)
    _ReflAmount ("Reflection Amount", Range(0, 1)) = 1
    _Cubemap ("Cubemap", CUBE) = ""{}
    _ReflMask ("Reflection Mask", 2D) = ""{}
    }
  2. 在SubShader块中添加它们的引用变量:
    		CGPROGRAM
    #pragma surface surf Lambert sampler2D _MainTex;
    sampler2D _ReflMask;
    samplerCUBE _Cubemap;
    float4 _MainTint;
    float _ReflAmount;
  3. 修改Input结构体:
    		struct Input {
    float2 uv_MainTex;
    float3 worldRefl;
    };
  4. 修改surf函数:
    		void surf (Input IN, inout SurfaceOutput o) {
    half4 c = tex2D (_MainTex, IN.uv_MainTex);
    float3 reflection = texCUBE(_Cubemap, IN.worldRefl).rgb;
    float4 reflMask = tex2D(_ReflMask, IN.uv_MainTex); o.Albedo = c.rgb * _MainTint;
    o.Emission = (reflection * reflMask.r) * _ReflAmount;
    o.Alpha = c.a;
    }
最后整体代码如下:
Shader "Custom/MaskedReflection" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_MainTint ("Diffuse Tint", Color) = (1,1,1,1)
_ReflAmount ("Reflection Amount", Range(0, 1)) = 1
_Cubemap ("Cubemap", CUBE) = ""{}
_ReflMask ("Reflection Mask", 2D) = ""{}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200 CGPROGRAM
#pragma surface surf Lambert sampler2D _MainTex;
sampler2D _ReflMask;
samplerCUBE _Cubemap;
float4 _MainTint;
float _ReflAmount; struct Input {
float2 uv_MainTex;
float3 worldRefl;
}; void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
float3 reflection = texCUBE(_Cubemap, IN.worldRefl).rgb;
float4 reflMask = tex2D(_ReflMask, IN.uv_MainTex); o.Albedo = c.rgb * _MainTint;
o.Emission = (reflection * reflMask.r) * _ReflAmount;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}

将场景中球体对应的材质设置如下图所示:

最后效果如图,其中左面的球体使用了遮罩反射,对比右面没有使用遮罩反射:

解释

这个Shader非常的简单,仅仅使用了texCUBE函数在Cubemap中采样。这个函数是内置的CGFX函数,它提供给我们一个Cubemap中的颜色值,然后我们将该值应用到平面上。Unity通过Input结构体中的worldRefl变量来帮我们在Cubemap中找到对应的采样位置。正如上一篇解释的一样,这个属性将会把摄像机视角的反射向量传递给我们。
一旦我们知道了反射元素(即反射的颜色值),我们就需要接着去采样我们的遮罩贴图。我们可以使用tex2D函数来完成它,这个函数在第二章中就接触过。
当我们知道了两个textures对应的值后,我们就可以把Cubemap的颜色值乘以反射贴图的颜色值,并传递给o.Emission。最后,为了可以全局控制反射密度,我们需要把结果再乘以_ReflAmount属性。这可以帮我们控制平面的整体反射量(越大表明反射度越高,越接近镜子的效果)。
下面展示了不同的_ReflAmount值对应的不同的反射效果:

【Unity Shaders】Reflecting Your World —— Unity3D中的遮罩反射(Masking Reflections)的更多相关文章

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

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

  2. 【Unity Shaders】Reflecting Your World —— Unity3D中的法线贴图和反射

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

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

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

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

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

  5. 【Unity Shaders】Reflecting Your World —— 在Unity3D中创建Cubemaps

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

  6. 【Unity Shaders】Shader中的光照

    写在前面 自己写过Vertex & Fragment Shader的童鞋,大概都会对Unity的光照痛恨不已.当然,我相信这是因为我们写得少...不过这也是由于官方文档对这方面介绍很少的缘故, ...

  7. 【unity shaders】:Unity中的Shader及其基本框架

    shader和Material的基本关系 Shader(着色器)实际上就是一小段程序,它负责将输入的Mesh(网格)以指定的方式和输入的贴图或者颜色等组合作用,然后输出.绘图单元可以依据这个输出来将图 ...

  8. 【Unity Shaders】使用Unity Render Textures实现画面特效——画面特效中的亮度、饱和度和对照度

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

  9. 【Unity Shaders】Diffuse Shading——在Surface Shader中使用properties

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

随机推荐

  1. js求和运算在可变参数的情况下ES3、ES5和ES6的写法区别

    //ES3.ES5的写法 function foo(){ var arr = Array.prototype.slice.call(arguments); var sum = 0; arr.forEa ...

  2. 关于ES7中的async/await在客户端和服务端上的实践

    一.前言 在项目中经常遇到处理异步请求的情况,面对层层的嵌套,回调显示那么苍白无力: async / await是ES7的重要特性之一,也是目前社区里公认的优秀异步解决方案,既然这样就用上吧. 二.配 ...

  3. C# WMI 远程PC(开机、关机、重启)

    啥也不多说,直接上码: //远程重启方法 public static bool Shutdown(ManagementScope scope) { ObjectQuery query=new Obje ...

  4. Python中enumerate用法详解

    enumerate()是python的内置函数.适用于python2.x和python3.xenumerate在字典上是枚举.列举的意思enumerate参数为可遍历/可迭代的对象(如列表.字符串)e ...

  5. Oracle中SQL语句分类

    Oracle中SQL语句分类如下:1.DML语句 insert/delete/update/select/merge/explan plan/lock table2.DDL语句 create/atlt ...

  6. Eleven

    A. Eleven time limit per test : 1 second memory limit per test:  256 megabytes input:  standard inpu ...

  7. git 撤销没有提交的变化

    参考: https://stackoverflow.com/questions/5807137/how-to-revert-uncommitted-changes-including-files-an ...

  8. [Gradle系列]Gradle打包apk多版本,多渠道,多环境,多功能,多模块随心所欲

    Tamic: http://blog.csdn.net/sk719887916/article/details/53411771 开始 上篇Gradle发布Module(Maven)到jcenter, ...

  9. Dynamics CRM 产品视图列上自带按钮的隐藏

    CRM中对command bar的处理都是使用ribbon workbench,但是很多系统自带的按钮你是没法在ribbon workbench看到的,咱们以产品为例,比如我要隐藏form上的保存按钮 ...

  10. Redis工作系列之一 与 Memcached对比理解

         近期公司项目在使用Redis,这几年Redis很火,Redis也常常被当作Memcached的挑战者被提到桌面上来.关于Redis与Memcached的比较更是比比皆是.然而,Redis真的 ...