本系列主要参考《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. 小白的Python之路_day2

    Python 的逻辑运算符具有短路原则,例如: or 运算符前面只要是 True,后面都不需要看了,结果就是 True.  Python 中表示为真必须用 True,如果用 true 则会当成是变量, ...

  2. jsp&servlet初体验——用户登录功能实现

    数据库准备-创建db_login数据库  t_user表 1.创建web工程 2.创建用户model   user.java package com.gxy.model; public class U ...

  3. 【图文详解】Hadoop集群搭建(CentOs6.3)

    本文主要详细地描述了hadoop集群的搭建以及一些配置文件的说明,用于自己复习以及供新人学习,若有错误之处还请指出. 前期准备 先给出我的集群架构: 到hadoop官网下载好hadoop安装包http ...

  4. JAVA中抽象类的使用

    抽象类是从多个具体类中抽象出来的父类,它具有更高层次的抽象.抽象类体现的就是一种模板模式的设计,抽象父类可以只定义需要使用的某些方法,把不能实现的某些部分抽象成抽象方法,留给其子类去实现.具体来说,抽 ...

  5. win2008r2 AD用户账户的批量导入方法

    win2008r2 AD用户账户的批量导入方法 http://www.jb51.net/article/38423.htm

  6. MacOS和iOS开发中异步调用与多线程的区别

    很多童鞋可能对Apple开发中的异步调用和多线程的区别不是太清楚,这里本猫将用一些简单的示例来展示一下它们到底直观上有神马不同. 首先异步调用可以在同一个线程中,也可以在多个不同的线程中.每个线程都有 ...

  7. Android基于JsBridge封装的高效带加载进度的WebView

    Tamic http://blog.csdn.net/sk719887916/article/details/52402470 概述 从去年4月项目就一直用起了JsBridge,前面也针对jsBrid ...

  8. FORM实现中打开图片,链接,文档(参考自itpub上一篇帖子,整理而来)

    FORM实现中打开图片,链接,文档 参考自itpub上一篇帖子,整理而来 1.添加PL程序库D2kwutil.pll 2.主要实现程序 /*过程参数说明: v_application --打开文件的应 ...

  9. JSP简单隔行变色和日期格式化

    以前好像在找,都没找到简单点的,所以后面就自己写了一个,感觉超级简单又好理解,分享给大家 <%@ page language="java" import="java ...

  10. SELinux策略语言--客体类别和许可

    1. 简介 SELinux策略语言主要描述policy.conf的相关语法,其相关部分如下图所示: 2. 客体类别 定义内核支持的客体类别和许可的策略语言指令,并对SELinux系统中内核客体类别标准 ...