本系列主要参考《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. Servlet技术 Cookie与Session

    会话过程:用户打开浏览器,点击链接访问资源,最后到关闭浏览器的整个过程称之为会话. 会话使用:与服务器进行会话的过程中产生数据,数据被保存下来,服务器根据数据对客户进行辨别,做出个性化的响应. 介绍两 ...

  2. net框架运行原理

    核心是CLR(通用语言运行时), c#或者其它各种语言编译原理:将原代码通过相对的编译器(语法检查原代码分析)生成IL代码托管(IL也称托管代码),最后得到一个托管模块,一个或多个托管模块组成程序集( ...

  3. [转载]致创业者:APP已死 服务永生

    前几日,有位创业者和我讲他在带领团队做一个将爱踢球的人集中在一起的App,我告诉他你的创业方向错了.原因在于你的目的是要为爱踢球的人提供服务,而你现在却在竭尽全力的做App,你应该做的是设计你为爱踢球 ...

  4. try_files 居然有这种用法

    try_files 参考:https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/ Use the tr ...

  5. 让你的代码量减少3倍!使用kotlin开发Android(三) 缩短五倍的Java Bean

    回顾一下 哈,没想到你已经坚持不懈看到第三篇了,不错哈~坚持就是胜利. 本文同步自博主的私人博客wing的地方酒馆 在上一篇文章中,我们介绍了扩展函数,这里对上一篇进行一点小小的补充. 还记得text ...

  6. MyBatis批量新增和更新

    之前有开发任务一个接口里面有大量的数据新增和更新操作,导致十分缓慢.使用了批量操作之后速度有明显提升,几乎百倍千倍的速度提升. 博主之前统计过,通过普通接口一次数据库插入大概需要200ms,对于大量新 ...

  7. 浏览器加载和渲染html的顺序(html/css/js)

    最近在学习前端的技术,把html.js.css的基础知识看了看.感觉越看越觉得前端并不比后端容易,技术含量还是相当大的.今天突然想弄明白浏览器到底是怎么加载和渲染html的?html中的DOM.js文 ...

  8. 使用spark ml pipeline进行机器学习

    一.关于spark ml pipeline与机器学习 一个典型的机器学习构建包含若干个过程 1.源数据ETL 2.数据预处理 3.特征选取 4.模型训练与验证 以上四个步骤可以抽象为一个包括多个步骤的 ...

  9. Struts1基础、使用Struts实现登录、使用Struts HTML标签简化开发

    Struts 1基础 为什么重拾Struts 1 曾经是最主流的MVC框架 市场份额依然很大 很多遗留系统中依旧使用 维护和升级都需要熟悉Struts 1 与Struts 2相比 编码.配置繁琐 侵入 ...

  10. Apache commons email 使用过程中遇到的问题

    apache-commons-email是对mail的一个封装,所以使用起来确实是很方便.特别的,官网上的tutorial也是极其的简单.但是我也仍然是遇到了没有解决的问题. jar包的添加 mail ...