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

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

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


写在前面


为了在Shaders中创建反射的效果,我们将首先开始学习如何创建我们自己的Cubemaps。当然,你可以在网上找到许多已经做好的Cubemaps,但是你很快就会想,怎么制作自己的Cubemaps,因为网上那些是不能反射你自己游戏中的场景的。
制作你自己的Cubemaps是创建更真实的反射效果的关键。我们将会学习几个可以在Unity editor中直接使用的方法。另外,我们还将看看在单机游戏中的效果。这些知识将会帮助你理解下一章(光照模型)中的内容。

好啦,下面我们就正式学习如何为我们的Shaders创建Cubemaps吧!


开始工作


Unity为我们提供了JavaScript的代码来从我们创建的场景中生成Cubemap。所以,让我们来看一下它是怎么工作的。这个链接中的脚本是我们脚本的基础。接下来,我们将把它翻译成C#。在本章的最后一节(动态创建Cubemaps)中,我们将会学习如何创建一个简单的系统来从不同的位置创建Cubemaps,然后使用这些数据在reflection
maps中转换,模拟游戏角色在场景内移动的效果,这将最终得到一个半实时的反射系统。

这里,我们仅仅学习如何创建一个单独的Cubemap。
  1. 我们需要创建一些元素来当做Cubemaps的光源。因此,我们需要在场景中放置一些几何平面。你可以使用一个建模软件,例如Maya或者Max,当然你也可以使用Unity自带的plane。哪一种方式都行,这无所谓。你的场景应该可以像这样:

  2. 场景中的物体如下所示:



    其中,Position是一个空对象,它将仅仅作为观察的位置将从该点观察到的环境信息渲染到我们的Cubemap上。


实现


  1. 首先,我们需要创建一个新的脚本,但是由于我们想要一个弹出的编辑器窗口,因此我们必须把脚本放到一个叫做Editor的文件夹里。在你的Project面板中创建一个叫Editor的文件夹,然后再创建一个C#脚本,叫做GenerateStaticCubemap。

  2. 打开上述脚本,为了使用特定的函数,我们需要使用新的using指令:
    using UnityEngine;
    using UnityEditor;
    using System.Collections
  3. 为了让Unity认识到,这个脚本会是一个弹出的编辑器窗口,我们需要让GenerateStaticCubemap类继承ScriptableWizard类。这使得我们可以使用一些很好的底层函数。
    public class GenerateStaticCubemap : ScriptableWizard {
  4. 然后,我们需要添加一些新的变量来存储新的CubeMap以及它的位置(即上面提到的position空对象)。
    	public Transform renderPosition;
    public Cubemap cubemap;
  5. 第一个函数是Unity的内置函数OnWizardUpdate()。它在向导(wizard)第一次弹出或者当GUI被用户改变时(如拖进去某些对象,输入某些字符等)时被调用。因此,我们可以在这里检查用户已经向向导中填入我们需要的所有的资源。在这里,如果Cubemap或者它的位置(一个transform)没有被填充,那么就设置内置变量isValid为false,直到拿到所有资源。
    	void OnWizardUpdate() {
    helpString = "Select transform to render" +
    " from and cubemap to render into";
    if (renderPosition != null && cubemap != null) {
    isValid = true;
    }
    else {
    isValid = false;
    }
    }
  6. 当isValid变量为true时,向导将调用OnWizardCreate()函数。在这个函数里,我们将创建一个新的摄像机,然后把它放到之前设置的transform的位置上,再调用RenderToCubemap函数得到最终的Cubemap。
    	void OnWizardCreate() {
    GameObject go = new GameObject("CubeCam", typeof(Camera)); go.transform.position = renderPosition.position;
    go.transform.rotation = Quaternion.identity; go.camera.RenderToCubemap(cubemap); DestroyImmediate(go);
    }
  7. 最后,我们需要从Unit编辑器的菜单栏打开这个向导。这需要MenuItem关键词。
    	[MenuItem("CookBook/Render Cubemap")]
    static void RenderCubemap() {
    ScriptableWizard.DisplayWizard("Render CubeMap", typeof(GenerateStaticCubemap), "Render!");
    }

最后,整体代码如下:
using UnityEngine;
using UnityEditor;
using System.Collections; public class GenerateStaticCubemap : ScriptableWizard { public Transform renderPosition;
public Cubemap cubemap; void OnWizardUpdate() {
helpString = "Select transform to render" +
" from and cubemap to render into";
if (renderPosition != null && cubemap != null) {
isValid = true;
}
else {
isValid = false;
}
} void OnWizardCreate() {
GameObject go = new GameObject("CubeCam", typeof(Camera)); go.transform.position = renderPosition.position;
go.transform.rotation = Quaternion.identity; go.camera.RenderToCubemap(cubemap); DestroyImmediate(go);
} [MenuItem("CookBook/Render Cubemap")]
static void RenderCubemap() {
ScriptableWizard.DisplayWizard("Render CubeMap", typeof(GenerateStaticCubemap), "Render!");
}
}

此时,回到Unity编辑器页面,点击一下Unity菜单栏(有时需要点击才会刷新)就会看到出现一个新的选项:CookBook/Render Cubemap,如下所示:



点击它你将会打开一个向导界面,如下所示。它需要两个资源,一个是Render Position,这将决定观察位置(你可以理解成你将会在该位置放一面镜子,这里需要注意的是由于代码里设置的摄像机的rotation为初始值,这意味着摄像机将看向图中蓝色箭头所指方向),一个是Cubemap,可以理解成就是镜子反射的图像。我的例子中设置如下。



点击Render!按钮后,查看你的Cubemap,就会看到类似下面这样的情景。


可以发现,我们已经把图像渲染到了一个立方体里了。恭喜你,你已经完成了自己的一个Cubemap!你可以尝试在不同的场景中试验。



解释


还记得一开始我们继承了ScriptableWizard类,这是为了告诉Unity3D我们想要制作一个新的弹出窗口类型的用户编辑器,这也是为什么我们需要把脚本放到Editor文件夹里的原因。如果我们不这么做,Unity将不会把它识别为一个用户编辑器类型的脚本。

接下来我们声明的参数是用于存储Cubemap的渲染位置,以及把新的渲染得到的Cubemap放到Project的哪里,例如上面的名为First的Cubemap就是我提前在工程文件下创建的一个Cubemap。有了这些我们就可以生成自己的Cubemap了。

然后我们使用了OnWizardUpdate()函数,它是由ScriptableWizard类提供给我们的。同样的,isValid变量也是一个内置变量。它让我们可以方便的打开或者关闭向导下方的Create按钮(这里指的是Render!按钮)。这样可以防止用户使用空的transform或者Cubemap进行下面的操作。

一旦我们确定用户提供了正确的数据,我们就可以进入到OnWizardCreate()函数了。这是Cubemap真正被创建的地方。它首先创建了一个新的GameObject构造器,并把它的类型创建为Camera。然后把它放到用户提供的transform的位置上。

到了这里,我们剩下要做的就是把用户提供的Cubemap传递给RenderToCubemap函数,生成六张图片。

最后,我们为向导创建了一个菜单选项,以便让用户可以从Unity顶部的菜单栏打开这个工具。除了需要[MenuItem("CookBook/Render Cubemap")]关键词以外,我们还需要将函数声明为static函数。

至此,我们就完成了一个简单的工具,可以用于在Unity编辑器中直接生成Cubemaps!


【Unity Shaders】Reflecting Your World —— 在Unity3D中创建Cubemaps的更多相关文章

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

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

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

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

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

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

  4. [转]unity3d中创建双面材质

    在其它三维软件中设置好的双面材质导入到unity3d中就失去了效果,不过我们可以通过自定义材质来在unity3d中实现双面材质的效果.步骤如下:1.在资源库中新建一新shader:代码如下: Shad ...

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

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

  6. 【Unity Shaders】Diffuse Shading——创建一个基本的Surface Shader

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

  7. Unity3D中的shader基础知识

    1.Unity中配备了强大的阴影和材料的语言工具称为ShaderLab,以程式语言来看,它类似于CgFX和Direct3D的效果框架语法,它描述了材质所必须要的一切咨询,而不仅仅局限于平面顶点/像素着 ...

  8. Unity3d中使用log4net

    原地址:http://www.cnblogs.com/koalaylj/archive/2012/09/04/2670629.html 最近在用unity3d开发Android上的游戏,一直Debug ...

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

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

随机推荐

  1. jupyter notebook 更换主题的方法

    参考 https://github.com/dunovank/jupyter-themes install with pip # install jupyterthemes pip install j ...

  2. MFC多线程

    当前流行的Windows操作系统能同时运行几个程序(独立运行的程序又称之为进程),对于同一个程序,它又可以分成若干个独立的执行流,我们称之为线程,线程提供了多任务处理的能力.用进程和线程的观点来研究软 ...

  3. Linux 查看CPU温度

    安装 lm-sensors sudo apt-get install lm-sensors # 安装yes | sudo sensors-detect # 侦测所有感测器 sensors # 查看温度 ...

  4. C++框架_之Qt的窗口部件系统的详解-上

    C++框架_之Qt的窗口部件系统的详解-上 第一部分概述 第一次建立helloworld程序时,曾看到Qt Creator提供的默认基类只有QMainWindow.QWidget和QDialog三种. ...

  5. MongoDB 查询分析

    MongoDB 查询分析可以确保我们建议的索引是否有效,是查询语句性能分析的重要工具. MongoDB 查询分析常用函数有:explain() 和 hint(). 使用 explain() expla ...

  6. AbstractQueuedSynchronizer源码解读--续篇之Condition

    1. 背景 在之前的AbstractQueuedSynchronizer源码解读中,介绍了AQS的基本概念.互斥锁.共享锁.AQS对同步队列状态流转管理.线程阻塞与唤醒等内容.其中并不涉及Condit ...

  7. Android服务——Service

    服务 Service 是一个可以在后台执行长时间运行操作而不使用用户界面的应用组件.服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行. 此外,组件可以绑定到服务,以与之进行 ...

  8. Netty 4源码解析:请求处理

    Netty 4源码解析:请求处理 通过之前<Netty 4源码解析:服务端启动>的分析,我们知道在最前端"扛压力"的是NioEventLoop.run()方法.我们指定 ...

  9. Android Multimedia框架总结(二十)MediaCodec状态周期及Codec与输入/输出Buffer过程(附实例)

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53183718 前言:前面几节都是 ...

  10. 联想G510 在新的SSD上安装Win8.1系统,启动的时候自己加载机械硬盘的Win8.1系统

    进入BIOS,选择Boot,将Boot Priority(优先),修改为Legacy(传统) First: 启动的时候就不会使用UEFI First的windows Boot Manager(wind ...