目录

1 高亮的高光

1.1 光滑度

1.2 表面数据

1.3 漫反射光

1.4 镜面选项

1.5 镜面高光

1.6 逐物体平滑度

2 反射环境

2.1 采样环境

2.2 调制反射

2.3 菲涅尔

2.4 金属表面

3 非同一的缩放值

3.1 移除假设条件

4 反射探针

4.1 盒投影

4.2 探针混合

4.3 HDR解码

5 透明表面

5.1 预乘Alpha

5.2 预设

本文重点:

1、添加镜面高光

2、反射环境

3、支持非同一的缩放

4、和反射探针一起工作

5、结合反射和透明度

这是涵盖Unity的可脚本化渲染管道的教程系列的第七部分。它涵盖了反射,镜面高光和采样反射探针的添加。

本教程是CatLikeCoding系列的一部分,原文地址见文章底部。“原创”标识意为原创翻译而非原创教程。

本教程使用Unity 2018.3.0f2制作。

(倒影生动起来)

1 高亮的高光

到目前为止,我们仅使用了简单的漫射照明,没有任何照明。我们现在将改变它,增加对镜面照明的支持。我们将使用与Unity的Lightweight渲染管道中使用的模型相同的模型。“渲染4,拳头照明”教程介绍了镜面照明的原理,但使用了不同的模型。

1.1 光滑度

完美的漫反射表面(即完美的漫射器)根本没有镜面反射。表面是如此粗糙,以至于没有聚焦反射发生。表面越光滑,反射的光线就越多,而不是扩散。我们将通过从0到1的平滑度材料属性(默认值为?)进行控制。

(光滑度 滑动条)

添加相应的着色器变量。

1.2 表面数据

囊括镜面反射会使我们的照明模型更加复杂。让我们将其所有代码放在一个单独的文件Lighting.hlsl中。在里面定义一个LitSurface结构,该结构包含执行照明计算所需的所有表面数据。那就是表面的法线,位置,漫反射和镜面反射的颜色及其粗糙度。还会包含视图方向,它实际上不是表面的属性,但是相对于我们正在使用的表面点而言是恒定的。

添加一个GetLitSurface函数,该函数返回Lit的表面数据。在此HLSL文件中,我们将不依赖于着色器特定的属性,纹理或定义,因此必须将所有相关数据定义为参数。尽管我们把平滑度作为输入,但是在内部,我们使用粗糙度,只是反过来而已。此外,我们现在使用金属工作流程并将自己局限于电介质材质。介电材质是非金属的,仅反射少量的光,相当于平均0.04的灰度镜面反射。就像Unity的光照代码一样,我们将对其进行硬编码。

根据迪斯尼模型(Disney model),此时我们拥有的粗糙度实际上是一个称为感知粗糙度的值。物理粗糙度是其平方。我们都需要。

在Lit.hlsl中包含Lighting.hlsl。

现在,在执行任何光照计算之前,我们可以在LitPassFragment中获取表面。视线方向就是相机位置减去片段位置(归一化)。

1.3 漫反射光

我们将把照明计算移到Lighting.hlsl。为此,为其提供一个LightSurface函数,以表面和光的方向为参数。它执行漫反射点乘积,并将其乘以表面的漫反射色。我们假设这里是理想的光线,纯白色而没有衰减。

调整MainLight,使其仅将表面作为参数,而不是位置和法向矢量。让它调用LightSurface而不是执行点乘积本身。和以前一样,在此处应用衰减和光色。

以相同的方式调整DiffuseLight,将其重命名为GenericLight,从现在开始可以更好地描述其目的。

现在,LitPassFragment必须将表面作为参数传递。而且,漫反射现在也沿途(而不是在末尾)计入颜色。在开始时,我们仍然必须将其纳入顶点照明。

我们还必须对顶点灯光使用GenericLight。顶点照明是纯漫反射的,因此仅需要位置和法线。颜色为白色,其他值无关紧要。让我们为Lighting.hlsl添加一个方便的包装函数。

然后在LitPassVertex中使用它。

1.4 镜面选项

在添加镜面高光之前,让我们可以跳过它,以便仍然支持完美的漫反射材质。我们将通过添加到表面并作为GetLitSurface的参数的布尔字段来指示默认情况下将其设置为false。这个想法是,你可以对参数进行硬编码,或者使其依赖于着色器关键字。

如果是完美的散光器(diffuser),则平滑度和镜面反射度应始终为零。

同样,我们可以使所有镜面反射计算都以该布尔为条件。始终只需要最终的点积。

这正是我们顶点照明所需要的。

1.5 镜面高光

镜面反射高光背后的想法是,它代表纯粹的反射。光线照射到表面,并且其中一些反射。如果相机对准的话,使其与反射完美匹配,那么它将看到光线,否则看不到。但是,如果表面不是十分光滑,则反射会散布一些,因此即使未完全对准,照相机仍会看到一些反射。表面越粗糙,过渡区域越大。这样就创建了镜面高光。

Unity的轻量级渲染管线使用修改后的简约CookTorrance BRDF计算高光。我们将执行相同的计算。有关详细信息和链接,请参见Lightweight RP软件包中的Lighting.hlsl。

被反射的光也不会散射,因此,除非表面是完美的散射体,否则在GetLitSurface中相应地减少散射体的颜色。

(有和没有镜面高光)

1.6 逐物体平滑度

我们制作了InstancedColor组件,因此我们可以为每个对象提供自己的颜色,而无需使用单独的材质。为了实现平滑,我们也可以这样做。可以使用相同的组件来做这两个事情,但是我们应该重命名它以更好地描述其更通用的功能。

首先,在“Project”窗口中将资产文件从InstancedColor重命名为InstancedMaterialProperties,然后在代码中重命名类定义并添加平滑度。按此顺序进行操作可使Unity编辑器保持所有组件引用完整。否则,你必须修复丢失的脚本引用。

(逐物体变化的光滑度)

为了保持GPU实例化,我们必须将smoothness变量移至实例化缓冲区。

并使用UNITY_ACCESS_INSTANCED_PROP宏检索它。

2 反射环境

镜面高光表示光源的直接反射。但是,光(直接和间接)都可以来自各个方向。我们无法实时跟踪所有这些反射,因此我们将对包含环境照明的立方体贴图进行采样。

2.1 采样环境

默认环境是skybox。Unity通过unity_SpecCube0在着色器中将其变为可用。这是一个立方体贴图纹理资源,我们可以通过TEXTURECUBE宏以及samplerunity_SpecCube0采样器状态进行定义。在Lighting.hlsl中定义这些参数以及其他变量和资源,因为我们如何获取环境数据的细节与照明计算无关。

再次在Lit.hlsl中,以表面为参数定义SampleEnvironment函数。它将按照“渲染8,反射”中所述的相同方式对立方体贴图进行采样。首先,使用具有负视图方向和表面法线的反射函数来获取反射向量。然后调用PerceptualRoughnessToMipmapLevel来基于感知粗糙度找到正确的Mip级别。之后,我们可以使用SAMPLE_TEXTURECUBE_LOD宏对立方体贴图进行采样,并将结果用作最终颜色。

PerceptualRoughnessToMipmapLevel在ImageBasedLighting.hlsl核心RP库文件中定义。粗糙表面会产生模糊反射,我们可以通过选择适当的Mip级别来获得模糊反射。Unity生成特殊的Mipmap,以表示散射的反射。

要检查是否可行,请在LitPassFragment的末尾对环境进行采样,并将其用作最终颜色,以覆盖照明。

结果是统一的灰色,这意味着没有可用的立方体贴图。我们必须指示Unity绑定环境地图,这是通过在MyPipeline.Render的渲染器配置中设置RendererConfiguration.PerObjectReflectionProbes标志来完成的。因为此时我们还没有使用反射探针,所以所有对象最终都带有天空盒立方体贴图。

(采样天空盒)

2.2 调制反射

反射多少环境取决于表面的粗糙度。为此,以表面和环境颜色为参数,向Lighting.hlsl添加ReflectEnvironment函数。请注意,此函数并不关心环境颜色是从立方体贴图样本,或者统一值还是其他值衍生而来。

理想的漫反射器不会反射任何东西,因此结果始终为零。否则,将镜面反射颜色计入结果中。然后将其除以平方粗糙度+1。

通过此功能过滤采样的环境。

(调制反射)

2.3 菲涅尔

在掠射角处,大多数光被反射,并且所有表面都像镜子一样起作用。这称为菲涅耳反射。这实际上是根据表面法线和视图方向之间的角度增强镜面反射颜色。我们将使用一个减去法线和视图方向的饱和点积,并提高到四次方。核心RP库为此定义了一个方便的Pow4函数。使用结果将高光颜色插值为白色,然后将其分解为ReflectEnvironment中的环境颜色。

(菲涅尔反射)

但是粗糙度也会影响菲涅耳反射。表面越粗糙,效果越弱。将fresnelStrength字段添加到表面以跟踪此情况。我们将简单地使其等于平滑度。

现在提高菲涅耳强度,而不是始终保持最大强度。

(调制菲涅尔反射)

最后,将环境反射添加到直接照明中,而不是替换它。

(反射添加到直接照明)

2.4 金属表面

固定的单色镜面反射镜0.04适用于介电材质,但不适用于金属。纯金属仅反射光,但会改变其颜色。要指示某物是否为金属,请添加另一个着色器属性。再次使用范围为0-1的滑块,这样就可以表示由电介质和金属混合而成的材质。

(金属度滑块)

我们也将立即将METALAL属性添加到InstancedMaterialProperties中。

(逐物体的金属度)

添加着色器实例属性。

并在平滑之前将其传递给LitPassFragment中的LitSurface。

将相应的参数添加到GetLitSurface,并为LitSurface提供一个字段以存储其反射率。如果是完美的扩散器,则始终为零。

对于金属,提供的颜色控制镜面反射而不是漫反射。由于金属不是二进制的,因此可以使用它在非金属的0.04和金属的颜色之间插入镜面反射颜色。在那之后,反射率将简单地等于金属,除了我们使用0.04作为最小值。因此,根据金属从0.04插值到1。最后,反射率增加了菲涅耳强度,最大为1。

(一半 VS 全部 金属度)

3 非同一的缩放值

在继续之前,让我们重新考虑所有对象具有统一比例的假设。该限制适用于简单的场景,但是要构建具有简单形状的更复杂的场景,将它们拉伸会很有用,这会导致缩放比例不一致。如果现在这样做,最终将导致着色不正确,如渲染4,第一束光中所述。

(拉伸的球体下 不正确的着色)

3.1 移除假设条件

为了使阴影正确,无论使用何种缩放比例,我们都必须在着色器中摆脱假设一致的缩放编译指示。

如果比例尺不均匀,则必须使用对象的wold-to-object矩阵正确转换法线向量。因此,除了unity_ObjectToWorld外,我们还需要UnityPerDraw缓冲区中的unity_WorldToObject。

除此之外,Unity的实例化代码希望通过UNITY_MATRIX_I_M宏将其定义为UNITY_MATRIX_M的反函数。

在LitPassVertex中转换法线向量时,我们必须交换矩阵,逆转乘法顺序,并对结果进行归一化。但是,仅在不采用统一缩放比例的情况下才需要这样做。如果确实启用该选项,则将定义UNITY_ASSUME_UNIFORM_SCALING,并且仍然可以使用更便宜的方法。

(拉伸的球体 正确的着色)

4 反射探针

仅当没有其他反射探头可用时,才将skybox用于环境反射。你可以通过GameObject/ Light / Reflection Probe将一个添加到场景中。默认情况下,反射探针的“Type”设置为“Baked”,这意味着其立方体贴图由Unity编辑器渲染一次,并且仅显示标记为反射探针为静态的对象。如果更改了静态内容,它将更新。设置为“Realtime”时,它将显示整个场景。何时渲染立方体贴图取决于“Refresh Mode”和“Time Slicing ”设置。在编辑模式下,场景变化时,实时反射探针并不总是刷新。有关更多详细信息,请参见渲染8,反射。

(反射探针设置为实时渲染)

反射探针仅在有东西要反射时才有用,因此将它们放在其他物体附近的场景中。你可以将它们放置在一个对象中,只要该对象使用剔除背面的材质即可。这样,你可以获得该对象的最准确的反射。

(场景中间有一个反射探针)

Unity在渲染立方体贴图面时会使用我们的管道,尽管这不会在帧调试器中显示。但可以通过记录“Render”中使用的摄像机类型,在MyPipeline中对此进行验证。默认情况下,立方体贴图在需要时渲染一次。这意味着反射面最终会比环境图中的预期要暗,因为它们自己依赖于环境图。你可以通过照明设置增加反射量。例如,2的反射值意味着所有立方体贴图都将正常渲染,但随后会使用先前用于环境映射的结果再次渲染它们。

(2次反射值)

4.1 盒投影

默认情况下,由立方体贴图表示的光被视为来自无限远的地方。这不适用于附近的表面。盒映射可用于使小区域的反射更准确。Unity的轻量级渲染管道不执行此操作,但我们将使用与Unity的Legacy渲染管道相匹配的“渲染8,反射”中描述的方法来支持盒映射。

将探针盒的最小和最大边界及其位置的变量添加到UnityPerDraw缓冲区。

直接从其他教程中复制BoxProjection函数。

使用该函数在SampleEnvironment中查找调整后的样本坐标。

为反射探针启用“盒投影”,并调整其盒边界,使其最匹配其反射的内容。

(盒投影)

4.2 探针混合

反射探针经过一些调整后可以产生不错的结果,但仅适用于合理接近探针位置的物体。否则,除了反射未对齐之外,对象最终有可能反射自己。如果错误太明显,则必须使用更多探针。

(用两个探针替代1个)

每个对象使用哪种反射探针由其盒控制。选择覆盖对象的最接近或最重要的探针。如果该对象未包含在任何探针盒中,它将使用天空盒。但这会导致从一个探针到下一个探针的艰难过渡。可以通过在探针之间进行混合来缓解这种情况,可以针对每个对象进行配置。最多可以将两种探针以这种方式混合。

为了支持混合,我们必须为第二个探针添加另一组变量。

除了第二个立方体贴图纹理外,我们还可以为两者使用相同的采样器状态。

再次,我们从其他教程中复制该方法。

(混合探针)

4.3 HDR解码

现在,我们支持反射探针,但前提是它们的纹理包含未编码的光数据。通常是这种情况,但是当烘焙的贴图经过HDR编码或探针的强度发生变化时,情况并非如此。为了支持这一点,我们可以依赖在ImageBasedLighting.hlsl核心RP库文件中定义的DecodeHDREnvironment。

每个探测器都有HDR解码指令,为此我们必须添加变量。

然后,我们可以解码立方体贴图样本。

(双倍强度)

请注意,当使用多次反射时,增加探头的强度会产生巨大的变化,因为每次反射都会使光线增强。

5 透明表面

我们通过回顾半透明的表面来总结。在上一教程中,我们增加了对淡入淡出表面的支持。淡出表面的整个颜色,也包括反射。如果你想使所有物体淡化,那效果还不错,但是它不适用于水晶或玻璃等材质。

(淡入淡出反射)

5.1 预乘Alpha

玻璃通常几乎是完全透明的,但仍会反射光。为了表示这一点,我们只需要将不透明度应用于漫反射光照。我们通过将Alpha用作漫反射颜色来实现。因此,我们预乘alpha而不是在完成所有光照后应用它,而不是使用常规片段混合。之后,我们根据反射率提高Alpha值,以使反射替换表面后面的任何东西。向Lighting.hlsl添加一个函数来相应地调整表面和Alpha。

如果定义了_PREMULTIPLY_ALPHA着色器关键字,则在LitPassFragment中获取表面后调用它。

添加切换着色器属性以控制关键字。

为了使这项工作有效,我们必须将源混合模式设置为一种,而不是source-alpha。

(开启预乘alpha)

5.2 预设

让我们向LitShaderGUI添加用于透明材质的预设。为它提供一个属性来设置_PREMULTIPLY_ALPHA关键字以及随附的着色器属性。

到目前为止,在所有预设方法中将其设置为false。

复制两个淡入淡出预设方法并进行调整,以使它们配置透明材质。因此PremultiplyAlpha变为true,SrcBlend变为BlendMode.One。

最后一步是调用OnGUI中的方法以及其他方法。

(新的透明预设)

下一章,全局光照。

往期推荐:

Unity可编程渲染管线系列(六)透明度(裁剪与淡化 Clipping and Fading)

Unity可编程渲染管线系列(五)方向阴影(级联贴图 Cascaded Maps)

Unity可编程渲染管线系列(四)聚光灯阴影(阴影贴图)

Unity可编程渲染管线系列(三)光照(单通道 正向渲染)

欢迎扫描二维码,查看更多精彩内容。点击 阅读原文 可以跳转原教程。

本文翻译自 Jasper Flick的系列教程

原文地址:

https://catlikecoding.com/unity/tutorials

Unity可编程渲染管线系列(七)反射(镜面和环境)相关推荐

  1. Unity可编程渲染管线系列(六)透明度(裁剪与淡化 Clipping and Fading)

    目录 1 Alpha裁剪 1.1 Alpha贴图 1.2 纹理化 1.3 丢弃片段 1.4 裁剪阴影 1.5 双面渲染 1.6 给背面翻转法线 1.7 可选的裁剪 1.8 Alpha-Test渲染队列 ...

  2. Unity可编程渲染管线系列(四)聚光灯阴影(阴影贴图)

    目录 1 一个带有阴影的聚光灯 1.1 阴影贴图 1.2 阴影命令缓冲区 1.3 设置 渲染目标 1.4 配置视图和投影矩阵 1.5 渲染阴影投射器 2 阴影投射器通道 2.1 阴影包含文件 2.2 ...

  3. Unity可编程渲染管线系列教程(1):自定义渲染管线

    前言     Jasper Flick<Unity可编程渲染管线>系列教程之:自定义渲染管线.该教程分享了用户如何在Unity引擎从头构建简易的渲染管线.原文链接可见该博客末尾. 目录 创 ...

  4. Unity可编程渲染管线系列(一)自定义管线(控制渲染)

    本文重点: 1.创建管线资产和实例 2.剔除.过滤.排序.渲染 3.保持内存干净 4.提供良好的编辑体验 这是涵盖Unity可编写脚本的渲染管线的教程系列的第一部分.本教程假定您首先阅读了Unity基 ...

  5. Unity可编程渲染管线系列(十二)图像质量(MSAA和HDR)

    目录 1 渲染比例 1.1 向下缩放 1.2 渲染到缩放后的纹理 1.3 向上缩放 2 MSAA 2.1 配置 2.2 多采样渲染纹理 2.3 解析纹理贴图 2.4 无深度解析 2.5 Depth-O ...

  6. unity烘培单个物体_Unity可编程渲染管线(SRP)教程:二、自定义着色器

    本文翻译自Catlike Coding,原作者:Jasper Flick. 本文经原作者授权,转载请说明出处. 原文链接在下: https://catlikecoding.com/unity/tuto ...

  7. Unity SRP自定义渲染管线 -- 4.Spotlight Shadows

    英文原文:https://catlikecoding.com/unity/tutorials/scriptable-render-pipeline/spotlight-shadows/ 渲染并且读取纹 ...

  8. 可编程渲染管线12 图像质量

    这是Unity可编程渲染管线的第十二章,在本章中,我们将通过调整渲染比例.应用MSAA .HDR缓冲配合tone mapping等方式来提升画面质量. 该教程基于Unity2018.4.6f1. 1 ...

  9. 可编程渲染管线4 聚光灯阴影

    原文:https://catlikecoding.com/unity/tutorials/scriptable-render-pipeline/spotlight-shadows/ 读取并渲染纹理 从 ...

最新文章

  1. Centos中文输入法安装以及切换
  2. cron计划任务使用
  3. 东北农业大学大学计算机基础作业答案,大学计算机基础实践教学改革的研究
  4. 趣文:如果编程语言是车
  5. 风机桨叶故障诊断(二) 获取图像几何主方向
  6. maven 镜像_Maven(一)
  7. 一文入门基于三维数据的深度学习
  8. 关于 vmware虚拟机的一些问题及解决办法备忘
  9. (二)生成深度伪造的方法
  10. 3说明书_怎么才能做好产品说明书翻译?知行翻译公司总结了3点
  11. Cardboard开发教程:使用Unity制作Cardboard全景图片浏览器
  12. 矩阵分解(matrix factorization)
  13. 索引法则--字符串不加单引号会导致索引失效
  14. LINUX内核-等待队列
  15. linux安装中文输入法
  16. 图片完整检查linux,Linux 下的免费图片查看器
  17. 清除docker镜像缓存
  18. Git小乌龟(TortoiseGit) 简单提交代码到github
  19. 使用Java将图片转成Base64编码,并压缩至40k
  20. 基于Matlab的暗通道先验、Retinex去雾图像增强研究

热门文章

  1. 【转载】SQL注入进阶
  2. BAT级别划分和KPI考核等消息
  3. 孩子该不该学编程?学编程有用吗?
  4. markdown无法显示图片的问题
  5. Dynamics CRM命令栏定制基础知识及手动编辑customization.xml实例
  6. html多张图片无缝滚动播放,jQuery实现的多张图无缝滚动效果【测试可用】
  7. mysql identity sqlserver_mysql和sqlserver的区别
  8. connectbot 1.8.2 下载from github
  9. 云主机1元简直就不是骗人的,大家不要上当受骗了呢
  10. YOLO v5 实现目标检测(参考数据集自制数据集)