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

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

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

写在前面

我们已经学了很多关于反射的内容,但是我们现在的反射并不能实时反射,即当反射物体移动时它们不能正确反射周围的环境。例如,如果你有一个由很多房间和走廊组成的环境,我们不可能提前渲染所有的Cubemap然后放到一个Cubemap中。这意味着我们不能随着房间的移动而正确反射。我们得到的是一个静态的、令人乏味的反射效果。

有很多方法可以解决这个问题,即一个房间的反射不同于另一个房间的反射。一个最基本的方法就是根据在房间中的位置替换Cubemap。因此,当你从一个房间移动到另一个房间时,Cubemap应该被换成当前房间的Cubemap。第二种方法是当我们角色在环境中移动时,实时更新Cubemap,最终在游戏进行的每一帧得到一个新的Cubemap。尽管第二种方法听起来非常吸引人,但是它比较消耗性能,因此你需要在其他游戏资源之间进行权衡。

这一篇将会讲述第一种方法,并且向你展示如何搭建一个非常简单的系统来基于你在环境中的不同位置去替换两个Cubemaps。更多的关于实时反射系统的内容你可以在本节最后找到,因此如果你对实时反射感兴趣并且想要看看两种技术之间的差别,你可以在那里找到!

准备工作

  1. 我们需要创建一个新的场景、一个新的平面以及一个球体。除此之外还需要一个平行光。
  2. 继续添加两个空对象,并分别命名为pos001和pos002。
  3. 给球体添加一个新的材质,并使用Fresnel Shader(上一篇)。这样你的场景应该看起来像下面这样。
  4. 最后,创建一个脚本,并命名为SwapCubemaps.cs,把它赋给球体。
最后的准备效果如下:




实现


  1. 首先在类名之前添加[ExecuteInEditMode]:

    [ExecuteInEditMode]
    public class SwapCubemaps : MonoBehaviour {
  2. 声明一些变量来存储系统需要的变量。我们将在下面解释它们的用途。
    	public Cubemap cubeA;
    public Cubemap cubeB; public Transform posA;
    public Transform posB; private Material curMat;
    private Cubemap curCube;
  3. 为了可以直观地看到Cubemaps所在的位置,我们需要利用Unity3D提供的gizmos 。因此,在脚本的最下方添加下面的代码:
    	void OnDrawGizmos()
    {
    Gizmos.color = Color.green; if(posA)
    {
    Gizmos.DrawWireSphere(posA.position, 0.5f);
    } if(posB)
    {
    Gizmos.DrawWireSphere(posB.position, 0.5f);
    }
    }
  4. 现在,我们需要创建一个新的方程来决定在不同的位置我们应该使用哪个Cubemap:
    	private Cubemap CheckProbeDistance()
    {
    float distA = Vector3.Distance(transform.position, posA.position);
    float distB = Vector3.Distance(transform.position, posB.position); if(distA < distB)
    {
    return cubeA;
    }
    else if(distB < distA)
    {
    return cubeB;
    }
    else
    {
    return cubeA;
    } }
  5. 最后,我们仅仅需要每一帧的时候计算物体距离每一个预定位置的距离,然后为球体的Material替换合适的Cubemap:
    	void Update () {
    curMat = renderer.sharedMaterial;
    if(curMat)
    {
    curCube = CheckProbeDistance();
    curMat.SetTexture("_Cubemap", curCube); }
    }
保存脚本,返回Unity编辑器。当编译完成后,点击Play按钮,并前后左右移动球体。你将会看到类似下面的效果:




解释


一开始,我们为类声明了[ExecuteInEditMode]属性。这将告诉Unity我们想要在编辑器状态时也运行我们的Cubemap替换脚本,而不仅仅是在Play状态。这可以使我们不需要点击Play按钮就可以检验Cubemap替换的脚本——这很方便不是吗~

这个脚本包含一些变量,包括两个Cubemaps和两个位置变量(用于比较距离),我们需要提前赋值给它们。最后我们需要两个私有变量来追踪运行时刻当前的球体材质和Cubemap。

当我们给四个共有变量赋值后,就可以使用内置的OnDrawGizmos()函数来真正显示两个空对象(位置对象)的位置。这些位置将会指导脚本什么时候去替换Cubemaps。

然后我们来看一下脚本中真正替换Cubemaps的函数。我们声明了自己的函数CheckProbeDistance(),它将使用Vector3.Distance计算球体和其他两个位置点的距离。然后它检查哪个距离更近,并返回那个位置对应的Cubemap。

最后,在Update ()函数中我们得到当前球体的材质,或者其他该脚本赋值的对象,然后根据返回的自定义Cubemap来赋值给该材质。

这仅仅是一个非常简单的脚本来参数这个概念,但是它可以被扩展成一个完整的系统,例如你可以每一个房间对应多个Cubemaps。这个系统可以实时自动生成所有的Cubemaps(但不需要每一帧都生成),这对于无法进行完全实时反射的游戏系统将非常有用。



更多……



你还可以看一下,如何创建一个实时反射系统,在这样的系统中每一帧都需要渲染更新Cubemap。这的确是一个非常吸引人的系统,但是需要以牺牲性能为代价:

【Unity Shaders】Reflecting Your World —— 在Unity3D中创建一个简单的动态Cubemap系统的更多相关文章

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

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

  2. 如何在Liferay 7中创建一个简单的JSF Portlet

    这个将在Liferay IDE 3.1 M3的发布版中提供创建的选项,但是你也可以通过命令行来创建. 1.这是Liferay JSF团队的官网:http://liferayfaces.org/ 你能在 ...

  3. 在 Visual Studio 中创建一个简单的 C# 控制台应用程序

    转载:https://blog.csdn.net/qq_43994242/article/details/87260824 快速入门:使用 Visual Studio 创建第一个 C# 控制台应用 h ...

  4. 【Unity Shaders】游戏性和画面特效——创建一个夜视效果的画面特效

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

  5. 【Unity Shaders】游戏性和画面特效——创建一个老电影式的画面特效

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

  6. 在终端中创建一个简单的mysql表格

    打开终端后输入:/usr/local/MySQL/bin/mysql -u root –p 然后输入密码:***** 创建数据库:create database work; 使用当前数据库:use w ...

  7. Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏

    Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏 即使是如今,非常多初学游戏开发的同学.在谈到Unity的时候.依旧会觉得Unity仅仅能用于制作3D游戏的. 实际上.Unity在2013 ...

  8. PS网页设计教程XXVI——如何在PS中创建一个专业的网页布局

    作为编码者,美工基础是偏弱的.我们可以参考一些成熟的网页PS教程,提高自身的设计能力.套用一句话,“熟读唐诗三百首,不会作诗也会吟”. 本系列的教程来源于网上的PS教程,都是国外的,全英文的.本人尝试 ...

  9. PS网页设计教程XXVIII——如何在PS中创建一个干净的网页布局

    作为编码者,美工基础是偏弱的.我们可以参考一些成熟的网页PS教程,提高自身的设计能力.套用一句话,“熟读唐诗三百首,不会作诗也会吟”. 本系列的教程来源于网上的PS教程,都是国外的,全英文的.本人尝试 ...

随机推荐

  1. 【给你一个承诺 - 玩转 AngularJS 的 Promise】

    了解Promise 在谈论Promise之前我们要了解一下一些额外的知识:我们知道JavaScript语言的执行环境是"单线程",所谓单线程,就是一次只能够执行一个任务,如果有多个 ...

  2. bootstrap插件fileinput.js 出现出现$("#xxxx").fileinput({}); 不生效的情况解决

    如果出现$("#xxxx").fileinput({}); 不生效的情况请将fileinput.js中最后几行注释掉: /* $(document).ready(function ...

  3. 浅析java内存管理机制

    内存管理是计算机编程中的一个重要问题,一般来说,内存管理主要包括内存分配和内存回收两个部分.不同的编程语言有不同的内存管理机制,本文在对比C++和Java语言内存管理机制的不同的基础上,浅析java中 ...

  4. Socket网络编程详解

    一,socket的起源 socket一词的起源 在组网领域的首次使用是在1970年2月12日发布的文献IETF RFC33中发现的, 撰写者为Stephen Carr.Steve Crocker和Vi ...

  5. 02 基础设施/Gitlab - DevOps之路

    基础设施/Gitlab - DevOps之路 文章Github地址,欢迎start:https://github.com/li-keli/DevOps-WiKi 源代码管理器选用Gitlab,新版(2 ...

  6. print语句中逗号(,)和反斜杠(\)的区别

    逗号结尾:   禁止输出换行反斜杠结尾:强制输出换行 >>> print ('A','B') #用一个逗号结尾就可以禁止输出换行 A B >>> print ('A ...

  7. PHP 安全 E-mail

    PHP E-mail 注入 首先,请看上一章中的 PHP 代码: <html> <body> <?php if (isset($_REQUEST['email'])) / ...

  8. Kafka系列之-Kafka Protocol实例分析

    本文基于A Guide To The Kafka Protocol文档,以及Spark Streaming中实现的org.apache.spark.streaming.kafka.KafkaClust ...

  9. Java对象的访问定位

    java对象在访问的时候,我们需要通过java虚拟机栈的reference类型的数据去操作具体的对象.由于reference类型在java虚拟机规范中只规定了一个对象的引用,并没有定义这个这个引用应该 ...

  10. NLP系列(3)_用朴素贝叶斯进行文本分类(下)

    作者: 龙心尘 && 寒小阳 时间:2016年2月. 出处: http://blog.csdn.net/longxinchen_ml/article/details/50629110 ...