读书笔记09《Unity Shader入门精要》

铁名_IronName Lv4

第 10 章 高级纹理

立方体纹理

立方体纹理(Cubemap)环境映射(Environment Mapping) 的一种实现方法。环境映射可以模拟物体周围的环境,而使用了环境映射的物体可以看起来像镀了层金属一样反射出周围的环境。
立方体纹理包含 6 张图像,对应了一个立方体的 6 个面。采样方法:从立方体中心出发,向外延伸,与 6 个纹理之一的交点,就是采样结果。

天空盒子(Skybox)

用于模拟天空。整个场景都被包围在这个立方体中。

实践

在 Unity 中创建并使用 Skybox 材质。

  • 在摄像机上可以添加单独的天空盒子
  • 在 Unity 中,天空盒子是在所有不透明物体之后渲染的。(用 帧调试器 也能看出来)

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

3 种方法:
1.提供特殊布局的纹理,例如类似立方体展开图的交叉布局、全局布局等;然后将该纹理的 Texture Type 设置为 Cubemap。支持对纹理数据压缩,还支持边缘修正、光滑反射(glossy reflection)。
2.老版本中,在项目资源中创建 Cubemap ,然后把 6 张纹理拖进去。不支持对纹理数据压缩,不支持边缘修正、光滑反射。
3.在 Unity 中使用脚本创建。利用 Unity 提供的 Camera.RenderToCubemap 函数实现。

实践

在 Unity 中创建一个 Cubemap,使用第 3 种方法。用脚本编写工具,然后使用。

反射

通过入射光线的方向和表面法线的方向来计算反射方向,再利用反射方向对立方体纹理采样即可。

实践

在 Unity 中编写 Shader,创建反射效果的材质。

折射

用斯涅尔定律(Snell‘s Law)计算反射角。当光从介质 1 沿着和表面法线夹角为θ1\theta_1的方向斜射入介质 2 时,夹角θ2\theta_2:

η1sinθ1=η2sinθ2\eta_1\sin\theta_1=\eta_2\sin\theta_2

其中η1\eta_1η2\eta_2是两个介质的折射率(index of refraction)。折射率是物理常数,例如真空的折射率是 1,玻璃的折射率一般是 1.5。对透明物体来说,更准确的模拟方式是计算两次折射(进入和射出时),但是模拟第二次折射比较复杂,而且只模拟一次的效果看上去“差不多”。所以实时渲染中通常只模拟第一次折射。

实践

在 Unity 中编写 Shader,创建折射效果的材质。

菲涅耳反射

菲涅耳反射(Fresnel reflection)描述了一种光学现象,即当光线照射到物体表面上时,一部分发生反射,一部分进入物体内部,发生折射或散射。被反射的光和入射光之间存在一定比率关系,这个关系可以通过菲涅耳等式计算。常见的菲涅耳反射是:近处的水能看到水底,远处的水倒映出天空。
真实世界的菲涅耳等式是非常复杂的。所以在实时渲染中我们用近似公式,其中一个著名的就是 Schlick 菲涅耳近似等式:

Fschlick(v,n)=F0+(1F0)(1vn)5F_{schlick}(\textbf{v},\textbf{n})=F_0+(1-F_0)(1-\textbf{v}\cdot\textbf{n})^5 F0F_0 是反射系数,用于控制菲涅耳反射的强度,v\textbf{v} 是视角方向,n\textbf{n} 是表面法线。

另一个应用广泛的等式是 Empricial 菲涅耳近似等式:

FEmpricial(v,n)=max(0,min(1,bias+scale×(1vn)power))F_{Empricial}(\textbf{v},\textbf{n})=max(0,min(1,bias+scale\times(1-\textbf{v}\cdot\textbf{n})^{power}))

其中,biasscalebias\text{、}scalepowerpower 是控制项。

菲涅耳近似等式常用于车漆、水面等材质的渲染。

实践

在 Unity 中编写 Shader,使用 Schlick 菲涅耳近似等式来模拟菲涅耳反射。

渲染纹理

现代的 GPU 允许我们把整个三维场景渲染到一个中间缓冲中,即渲染目标纹理(Render Target Texture,RTT),而不是传统的帧缓冲或后备缓冲(back buffer)。与之相关的是多重渲染目标(Multiple Render Target,MRT),这种技术指的是 GPU 允许我们把场景同时渲染到多个渲染目标中,而不再需要为每个渲染目标纹理单独渲染完整的场景。

Unity 为渲染目标纹理定义了专门的纹理类型——渲染纹理(Render Texture)。
使用渲染纹理有两种方式:
一、在 Project 目录下创建一个渲染纹理,然后把某个摄像机的渲染目标设置成该渲染纹理。使用这种方法,可以选择渲染纹理的分辨率、滤波模式等纹理属性。
二、在屏幕后处理时使用 GrabPass 命令或 OnRenderImage 函数来获取当前屏幕图像。

镜子效果

实践

在 Unity 中编写 Shader,使用渲染纹理来模拟镜子效果。

哎呦喂,这摄像机也太难调整了,我觉得应该有 利用摄像机信息和“镜子”平面的信息 计算镜子摄像机信息 的方法。

玻璃效果

实践

在 Unity 中编写 Shader,使用 GrabPass 来模拟玻璃效果。

  • GrabPass 通常用于渲染透明物体,需要把物体的渲染队列设置为透明队列(“Queue”=“Transparent”),保证渲染该物体时,所有的不透明物体都已经被绘制在屏幕上。
  • GrabPass{ "_RefractionTex" }直接声明纹理名称的方法可以获得更高的性能。因为有名称的纹理可以被多个 Shader 共用。
  • 调用内置的 ComputeGrabScreenPos 函数来得到对应被抓取的屏幕图像的采样坐标。针对平台差异造成的采样坐标问题进行了处理。

法线贴图的 bump.xy 偏移方向,是对真实折射光线方向在屏幕空间投影的一种巧妙且高效的近似。

渲染纹理 vs. GrabPass

渲染纹理GrabPass
使用渲染纹理 + 额外摄像机在 Shader 中写几行代码
可以自定义渲染纹理的大小;可以通过调整摄像机的渲染层来减少二次渲染时的场景大小图像分辨率和屏幕一致,在高分辨率的设备上可能造成严重的带宽影响;需要 CPU 直接读取后备缓冲,破坏了 CPU 和 GPU 的并行性,耗时
Unity 5 引入了命令缓冲(Command Buffers),也可以实现类似抓屏的效果。

程序纹理

程序纹理(Procedural Texture)指的是由计算机生成的图像,可以使用各种参数来控制纹理的外观。Unity 中有一类专门使用程序纹理的材质——程序材质。

实践

在 Unity 中编写 Shader,使用算法来生成一个波点纹理。

安装开源插件,有点麻烦。。。还要自己补充函数,目前最麻烦的实践。
在保存场景时,纹理变为空白,是因为这个纹理没有保存下来。

Unity 的程序材质

程序材质(Procedural Materials) 和它使用的程序纹理并不是在 Unity 中创建的,而是用 Substance Designer (软件)生成的。Substance Designer 是一个非常出色的纹理生成工具。Substance 材质以 .sbsar 为后缀,导入 Unity 后,会自动生成程序纹理资源(Procedural Material Asset)

在 Unity 2022.3 中,需要额外的插件,才能识别并使用 .sbsar 文件,它不再是引擎的内置功能。

程序材质的自由度很高,而且可以和 Shader 配合得到非常出色的视觉效果,它是一种非常强大的材质类型。

  • 标题: 读书笔记09《Unity Shader入门精要》
  • 作者: 铁名_IronName
  • 创建于 : 2026-01-24 11:09:37
  • 更新于 : 2026-02-15 15:20:56
  • 链接: https://blog.ironname.top/2026/01/24/读书笔记09《Unity-Shader入门精要》/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论