zoukankan      html  css  js  c++  java
  • 第九章 高级纹理(1)

    @

    立方体纹理

    在图形学中,立方体纹理(Cubemap)是环境映射(Environment Mapping)的一种实现方法。环境映射可以模拟物体周围的环境,而使用了环境映射的物体可以看起来像镀了层金属一样反射出周围的环境。
    和之前见到的纹理不同,立方体纹理一共包含了6张图像,这些图像对应了一个立方体的6个面,立方体的名称也由此而来。立方体的每个面表示沿着世界空间下的轴向(上、下、左、右、前、后)观察所得的图像。那么,我们如何对这样一种纹理进行采样呢?和之前使用的二维纹理坐标不同,对立方体纹理采样我们需要提供一个三维的纹理坐标,这个三维纹理坐标表示我们在世界空间下的一个3D方向。这个方向矢量从立方体中心出发,当它向外部延伸时就会个立方体的6个纹理之一发生相交,而采样得到的结果就是由该交点计算来的。下图给出了使用方向矢量对立方体纹理采样的过程。
    在这里插入图片描述
    使用立方体纹理的好处在于,它的实现简单快捷,而且得到的效果也比较好。但它也有一些缺点,例如当场景中引入了新的物体、光源,或者物体发生移动时,我们就需要重新生成立方体纹理。除此之外,立方体纹理也仅可以反射环境,但不能反射使用了该立方体纹理的物体本身。这是因为,立方体纹理不能模拟多次反射的结果。例如两个金属球相互反射的情况(事实上,Unity5引入的全局光照系统允许我们实现这样的自反射效果,后面会讲到)。由于这样的原因,想要得到令人信服的渲染结果,我们应尽量对凸面体而不要对凹面体使用立方体纹理(因为凹面体纹理会反射自身)。
    立方体纹理在实时渲染时有很多应用,最常见的应用是天空盒子(Skybox)以及环境映射。

    1. 天空盒子

    天空盒子(Skybox)是游戏中用于模拟背景的一种方法。天空盒子这个名字包含了两个信息:它是用来模拟天空的(尽管现在我们仍可以用它模拟室内背景等),它是一个盒子。当我们在场景中使用了天空盒子时,整个场景就被包围在一个立方体内。这个立方体的每个面使用的技术就是立方体纹理映射技术。
    在Unity中,想要使用天空盒子非常简单。我们只需要创建一个Skybox材质,再把它赋值给相应的场景即可。
    我们首先来看如何创建一个Skybox材质。
    (1)新建一个材质,命名为SkyboxMat。
    (2)在Skybox的Unity Shader下拉菜单中选择Unity自带的Skybox/6 Sided,该材质需要6张纹理。
    (3)使用6张纹理对第二步的材质赋值,这一这6张纹理的正确位置(如posz纹理对应了Font[+z]属性)。为了让天空盒子正常渲染,我们需要把这6张纹理的Wrap Mode设置为Clamp,以防止在接缝处出现不匹配现象。
    上述步骤得到的材质如下图所示:
    在这里插入图片描述
    上面的材质中,除了6张纹理属性外还有3个属性:Tint Color,用于控制该材质的整体颜色;Exposure,用于调整天空盒子的亮度;Rotation,用于调整天空盒子沿+y轴方向的旋转角度。
    下面,我们来看一下,如何为场景添加Skybox。
    (1)新建一个场景
    (2)在Window->Lighting菜单中,把SkyboxMat赋给Skybox选项,如下图所示:
    在这里插入图片描述
    为了让摄像机正常显示天空盒子,我们还需要保证渲染摄像机的Camera组件中Clear Flags被设置为Skybox。这样,我们得到的场景如下图所示。
    在这里插入图片描述
    需要说明的是,在Window->Lighting->Skybox中设置的天空盒子会应用于场景中的所有摄像机。如果我们希望某些摄像机可以使用不同的天空盒子,可以通过向该摄像机添加Skybox组件来覆盖掉之前的设置。也就是说,我们可以在摄像机上单击Component->Rendering->Skybox来完成对场景默认天空盒子的覆盖。
    在Unity中,天空盒子是在所有不透明物体之后渲染的,而背后使用的网格是一个立方体或一个细分后的球体,

    2. 创建用于环境映射的立方体纹理

    除了天空盒子,立方体纹理最常见的用处是用于环境映射。通过这种方法,我们可以模拟出金属质感的材质。
    在Unity 5中,创建用于环境映射的立方体纹理的方法有3种:第一种方法是直接由一些特殊布局的纹理创建;第二种方法是手动创建一个Cubemap资源,再把6张图赋给它;第三种方法是由脚本生成。
    如果使用第一种方法,我们需要提供一张具有特殊布局的纹理,例如类似立方体展开图的交叉布局、全景布局等。然后我们只需要把该纹理的Texture Type设置为Cubemap即可,Unity会为我们做好剩下的事情。在基于物理的渲染中,我们通常会使用一张HDR图像来生成高质量的Cubemap(后面会讲到)。读者可以在官方文档(http://docs.unity3d.com/Manual/class-Cubemap.html)中找到更多的资料。
    第二种方法是Unity 5之前的版本中使用的方法,我们首先要在项目资源中创建一个Cubemap,然后把它的6张纹理拖拽到它的面板中。在Unity 5中,官方推荐使用第一种方法创建立方体纹理,这是因为第一种方法可以对纹理数据进行压缩,即可以支持边缘修正、光滑反射(glossy reflection)和HDR等功能。
    前面两种方法都需要我们提前准备好立方体纹理的图像,它们得到的立方体纹理往往是被场景中的物体所共用的。但在理想情况下,我们希望根据物体在场景中位置的不同,生成它们各自不同的立方体纹理。这是我们就可以在Unity中使用脚本来创建。这是通过利用Unity提供的Camera.RenderToCubemap函数来实现的。Camera.RenderToCubemap函数可以把任意位置观察到的场景图像存储到6张图像中,从而创建出该位置上对应的立方体纹理。
    在Unity的脚本手册(http://docs.unity3d.com/ScriptReference/Camera.RenderToCubemap.html)中给出了如何使用Camera.RenderToCubemap函数来创建立方体纹理的代码,关键代码如下

    void OnWizardCreate(){
    //create temporary camera for rendering
    Gameobject go = new GameObject("CubemapCamera");
    go.AddComponent<Camera>();
    //place it on the object
    go.transform.position=renderFromPosition.position;
    //render into cubemap
    go.GetComponent<Camera>().RenderToCubeMap(cubemap);
    //destroy temporary camera
    DestroyImmediate(go);
    }
    

    在上面代码中,我们在renderFromPosition(由用户指定)位置处动态创建一个摄像机,并调用Camera.RenderToCubemap函数把从当前位置观察到的图像渲染到用户指定的立方体纹理cubemap中,完成后再销毁临时摄像机。由于该代码需要添加菜单条目,因此我们需要把它放在Editor文件夹下才能正确执行。
    当准备好上述代码后,要创建一个Cubemap非常简单。
    (1)我们使用和上一节相同的场景,并创建一个空的GameObject对象。我们会使用该GameObject的位置信息来渲染立方体纹理。
    (2)新建一个用于存储的立方体纹理(在Project视图下单击右键,选择Create->Legacy->Cubemap来创建)。为了让脚本可以顺利将图像渲染到该立方体纹理中,我们需要在它的面板中勾选Readable选项。
    (3)从Unity菜单栏选择GameObject->Render into Cubemap,打开我们在脚本中实现的用于渲染立方体纹理的窗口,并把第一步创建的GameObject和第二步中的纹理分别拖拽到窗口中的Render From Position和Cubemap选项,如下图所示:
    在这里插入图片描述
    (4)单击窗口的Render!按钮,就可以把从该位置观察到的世界空间下的6张图像中渲染到纹理中,如下图所示:
    在这里插入图片描述
    需要注意的是,我们需要为Cubemap设置大小,即上图中的Face size选项。Face size值越大,渲染出来的立方体纹理分辨率越大,效果可能更好,单需要占用的内存也越大,这可以由面板最下方显示的内存大小得到。
    准备好需要的立方体纹理后,我们就可以对纹理使用环境映射技术。而环境映射最常见的应用就是反射和折射。

  • 相关阅读:
    -Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME environment variable and mvn script match.
    map合并,相同键对应的值相加
    oracle截取字符串去掉字段末尾指定长度的字符
    springMVC结合AjaxForm上传文件
    hibernate中指定非外键进行关联
    Maven安装及MyEclipse中使用Maven
    js判断字符串出现的次数
    PL/SQL如何调试sql语句、存储过程
    如何让pl/sql developer记住密码,实现快速登录
    【学亮IT手记】jQuery each()函数用法实例
  • 原文地址:https://www.cnblogs.com/xiegaosen/p/12009690.html
Copyright © 2011-2022 走看看