【Filament】材质系统

1 前言

​ 本文主要介绍 Filament 的材质系统,官方介绍详见 → Filament Materials Guide。材质系统中会涉及到一些空间和变换的知识点,可以参考:【Unity3D】空间和变换【Unity3D】Shader常量、变量、结构体、函数【OpenGL ES】MVP矩阵变换【OpenGL ES】透视变换原理

​ 需要注意的是,Unity 世界空间是左手坐标系,OpenGL 和 Filament 的世界空间是右手坐标系,Filament 的世界空间坐标轴如下。

红 +X, 绿 +Y, 蓝 +Z

​ 读者如果对 Filament 不太熟悉,请回顾以下内容。

2 材质结构

​ 材质的格式是一种松散地基于 JSON 的格式,Filament 官方称之为 JSONish 格式。在顶层,材质定义由 JSON 对象表示的 3 个不同块组成,如下。其中,vertex 块是可选的,必须包含 material 和 fragment 块。

cpp 复制代码
material {
    // 材质属性
}

vertex {
    // 顶点着色器(可选)
}

fragment {
    // 片元着色器
}

​ JSONish 格式具有以下特点。

  • JSON 格式为【"key" : value】;JSONish 格式为【key : value】,当字符串包含空格时,需要引号;
  • 允许使用单行 C++ 样式的注释;
  • key 区分大小写,value 不区分大小写。

2.1 材质属性(material)

​ 材质属性(material)中可以定义材质名(name)、外部参数(parameters)、顶点属性参数(requires)、光照模型(shadingModel)、混合模式(blending)等。

cpp 复制代码
material {
    name : "Textured material",
    parameters : [ // 外部参数
        {
           type : sampler2d,
           name : texture
        },
        {
           type : float,
           name : metallic
        },
        {
            type : float,
            name : roughness
        }
    ],
    requires : [ // 顶点属性
        uv0
    ],
    shadingModel : lit, // 光照模型
    blending : opaque // 混合模式
}
  • parameters:外部参数,纹理类型参数可以通过 materialParams_xxx 访问(如 materialParams_texture),其他类型参数可以通过 materialParams.xxx 访问(如 materialParams.metallic)。
  • requires:顶点属性参数,会参与光栅化,取值有:uv0、uv1、color、position、tangents、custom0 ~ custom。
  • shadingModel:光照模型,取值有 lit、subsurface、cloth、unlit、specularGlossiness,默认取 lit。
  • blending:混合模式,取值有:opaque、transparent、fade、add、multiply、screen、masked,默认取 opaque。

2.2 顶点着色器(vertex)

​ 顶点着色器(vertex)中可以对顶点的属性进行变换,如下。

cpp 复制代码
vertex {
    void materialVertex(inout MaterialVertexInputs material) {
        float3 p = getPosition().xyz;
        float3 u = mulMat4x4Float3(getViewFromClipMatrix(), p).xyz;
        material.eyeDirection.xyz = mulMat3x3Float3(getWorldFromViewMatrix(), u);
    }
}

2.3 片元着色器块(fragment)

​ 片元着色器(fragment)中可以计算光照模型所需的参数,如下。

cpp 复制代码
fragment {
    void material(inout MaterialInputs material) {
        prepareMaterial(material);
        material.baseColor = texture(materialParams_texture, getUV0());
        material.metallic = materialParams.metallic;
        material.roughness = materialParams.roughness;
    }
}

​ 其中,materialParams_texture、materialParams.metallic、materialParams.roughness 是材质属性中定义的外部参数。

3 输入结构

​ 顶点着色器的输入结构体如下。

cpp 复制代码
struct MaterialVertexInputs {
    float4 color;              // if the color attribute is required
    float2 uv0;                // if the uv0 attribute is required
    float2 uv1;                // if the uv1 attribute is required
    float3 worldNormal;        // only if the shading model is not unlit
    float4 worldPosition;      // always available (see note below about world-space)

    mat4   clipSpaceTransform; // default: identity, transforms the clip-space position, only available for `vertexDomain:device`

    // variable* names are replaced with actual names
    float4 variable0;          // if 1 or more variables is defined
    float4 variable1;          // if 2 or more variables is defined
    float4 variable2;          // if 3 or more variables is defined
    float4 variable3;          // if 4 or more variables is defined
};

​ 片元着色器的输入结构体如下。

cpp 复制代码
struct MaterialInputs {
    float4 baseColor;           // default: float4(1.0)
    float4 emissive;            // default: float4(0.0, 0.0, 0.0, 1.0)
    float4 postLightingColor;   // default: float4(0.0)

    // no other field is available with the unlit shading model
    float  roughness;           // default: 1.0
    float  metallic;            // default: 0.0, not available with cloth or specularGlossiness
    float  reflectance;         // default: 0.5, not available with cloth or specularGlossiness
    float  ambientOcclusion;    // default: 0.0

    // not available when the shading model is subsurface or cloth
    float3 sheenColor;          // default: float3(0.0)
    float  sheenRoughness;      // default: 0.0
    float  clearCoat;           // default: 1.0
    float  clearCoatRoughness;  // default: 0.0
    float3 clearCoatNormal;     // default: float3(0.0, 0.0, 1.0)
    float  anisotropy;          // default: 0.0
    float3 anisotropyDirection; // default: float3(1.0, 0.0, 0.0)

    // only available when the shading model is subsurface or refraction is enabled
    float  thickness;           // default: 0.5

    // only available when the shading model is subsurface
    float  subsurfacePower;     // default: 12.234
    float3 subsurfaceColor;     // default: float3(1.0)

    // only available when the shading model is cloth
    float3 sheenColor;          // default: sqrt(baseColor)
    float3 subsurfaceColor;     // default: float3(0.0)

    // only available when the shading model is specularGlossiness
    float3 specularColor;       // default: float3(0.0)
    float  glossiness;          // default: 0.0

    // not available when the shading model is unlit
    // must be set before calling prepareMaterial()
    float3 normal;              // default: float3(0.0, 0.0, 1.0)

    // only available when refraction is enabled
    float transmission;         // default: 1.0
    float3 absorption;          // default float3(0.0, 0.0, 0.0)
    float ior;                  // default: 1.5
    float microThickness;       // default: 0.0, not available with refractionType "solid"
}

4 数据类型

Name GLSL type Description
bool2 bvec2 A vector of 2 booleans
bool3 bvec3 A vector of 3 booleans
bool4 bvec4 A vector of 4 booleans
int2 ivec2 A vector of 2 integers
int3 ivec3 A vector of 3 integers
int4 ivec4 A vector of 4 integers
uint2 uvec2 A vector of 2 unsigned integers
uint3 uvec3 A vector of 3 unsigned integers
uint4 uvec4 A vector of 4 unsigned integers
float2 float2 A vector of 2 floats
float3 float3 A vector of 3 floats
float4 float4 A vector of 4 floats
float4×4 mat4 A 4×4 float matrix
float3×3 mat3 A 3×3 float matrix

5 材质函数

5.1 Math

Name Type Description
PI float π
HALF_PI float π / 2
saturate(float x) float 将 x 约束在 0 ~ 1 之间
pow5(float x) float x ^ 5
sq(float x) float x ^ 2
max3(float3 v) float 获取向量中最大的分量
mulMat4×4Float3(float4×4 m, float3 v) float4 m * v
mulMat3×3Float3(float4×4 m, float3 v) float4 m * v

5.2 Matrices

Name Type Description
getViewFromWorldMatrix() float4×4 [世界空间->观察空间]的变换矩阵V
getWorldFromViewMatrix() float4×4 [观察空间->世界空间]的变换矩阵V'
getClipFromViewMatrix() float4×4 [观察空间->裁剪空间]的变换矩阵P
getViewFromClipMatrix() float4×4 [裁剪空间->观察空间]的变换矩阵P'
getClipFromWorldMatrix() float4×4 [世界空间->裁剪空间]的变换矩阵VP
getWorldFromClipMatrix() float4×4 [裁剪空间->世界空间]的变换矩阵(VP)'
getUserWorldFromWorldMatrix() float4×4 [世界空间->用户世界空间]的变换矩阵
getWorldFromModelMatrix() float4×4 [模型空间->世界空间]的变换矩阵M(Vertex only)
getWorldFromModelNormalMatrix() float3×3 [模型空间->世界空间]的法线变换矩阵(Vertex only)

5.3 Frame constants

Name Type Description
getResolution() float4 (width, height, 1 / width, 1 / height),单位:pixels
getWorldCameraPosition() float3 相机的世界空间坐标
getWorldOffset() float3 获取 api 级世界空间的位置(已弃用,使用 getUserWorldPosition 替代)
getTime() float 获取当前时间,范围:0 ~ 1,单位:s
getUserTime() float4 (time, (double)time - time, 0, 0)
getUserTimeMod(float m) float 获取当前时间,范围:0 ~ m,单位:s
getExposure() float 照相机的曝光度
getEV100() float 相机在 ISO 100 下的曝光度

5.4 Vertex only

Name Type Description
getPosition() float4 获取模型空间顶点坐标
getCustom0() to getCustom7() float4 获取模型的 Custom0 ~ Custom7 的值
getVertexIndex() int 获取顶点的索引

5.5 Fragment only

Name Type Description
getWorldTangentFrame() float3×3 世界空间列向量:tangent、bi-tangent、normal,如果材质没有计算凹凸贴图的切空间法线,或者材质不是各向异性的,那么在这个矩阵中只有法线是有效的。
getWorldPosition() float3 片元的世界空间坐标
getUserWorldPosition() float3 片元的用户世界空间坐标
getWorldViewVector() float3 世界空间下,片元指向相机的单位方向向量
getWorldNormalVector() float3 世界空间下,经凹凸映射后的片元的单位法线向量(必须在 prepareMaterial() 之后使用)
getWorldGeometricNormalVector() float3 世界空间下,凹凸映射前的片元的单位法线向量 (可以在 prepareMaterial() 之前使用)
getWorldReflectedVector() float3 view 向量关于法线的反向量(必须在 prepareMaterial() 之后使用)
getNormalizedViewportCoord() float3 标准化的用户视口位置(即 NDC 坐标标准化为 [0,1] 的位置,[1,0] 的深度,可以在prepareMaterial() 之前使用)。因为用户视口比实际的物理视口小,所以在物理视口的不可见区域中,这些坐标可以为负或大于 1。
getNdotV() float 获取法线向量与观察向量的点积,即:dot(normal, view),返回结果严格大于 0(必须在 prepareMaterial() 之后使用)
getColor() float4 获取片元经光栅化插值后的颜色(当 required 中包含 color 时才可用)
getUV0() float2 获取 uv0 纹理坐标(当 required 中包含 uv0 时才可用)
getUV1() float2 获取 uv1 纹理坐标(当 required 中包含 uv1 时才可用)
getMaskThreshold() float 获取遮罩阈值(当 blending 设置为 masked 才可用
inverseTonemap(float3) float3 将逆色调映射操作应用于指定的线性 sRGB 颜色并返回线性 sRGB 颜色。此操作可能是近似的,并且与 "Filmic" 色调映射操作一起使用效果最好
inverseTonemapSRGB(float3) float3 将逆色调映射操作应用于指定的非线性 sRGB 颜色并返回线性 sRGB 颜色。此操作可能是近似的,并且与 "Filmic" 色调映射操作一起使用效果最好
luminance(float3) float 计算指定的线性 sRGB 颜色的亮度
ycbcrToRgb(float, float2) float3 将亮度和 CbCr 对转换为 sRGB 颜色
uvToRenderTargetUV(float2) float2 转换 UV 坐标以允许从 RenderTarget 中采样

6 光照模型(Lighting model)

​ 在 material 块中,通过 shadingModel 属性配置光照模型,取值主要有:litsubsurfaceclothunlitspecularGlossiness,默认取 lit。

6.1 lit model

​ lit model 官方介绍见 → litmodel,可以配置的参数如下,材质取值可以参考 → [Material Properties.pdf](https://github.com/google/filament/blob/main/docs/Material Properties.pdf)。

Property Type Range Note Definition
baseColor float4 [0..1] Linear RGB 非金属表面的漫反射颜色和金属表面的镜面反射颜色
metallic float [0..1] 0 or 1 表面是非金属(0)还是金属(1)
roughness float [0..1] 材质表面的光滑(0)或粗糙(1)感,光滑的表面有尖锐的反射
reflectance float [0..1] Prefer values > 0.35 表面正入射菲涅耳反射率,控制了反射的强度
sheenColor float3 [0..1] Linear RGB 光泽层的强度
sheenRoughness float [0..1] 光泽层的平滑度或粗糙度
clearCoat float [0..1] 0 or 1 清漆图层的强度
clearCoatRoughness float [0..1] 可感知的清漆图层的平滑度或粗糙度
anisotropy float [−1..1] 当该值为正值时,各向异性在切线方向上 在正切或双切方向上各向异性的数量
anisotropyDirection float3 [0..1] Linear RGB,在切空间中编码方向向量 切线空间的局部曲面方向
ambientOcclusion float [0..1] 定义一个表面点可以接触到多少环境光,它是一个介于 0 和 1 之间的每像素阴影因子
normal float3 [0..1] Linear RGB,在切空间中编码方向向量 使用凹凸贴图(法线贴图)来扰动表面的细节法线。
bentNormal float3 [0..1] Linear RGB,在切空间中编码方向向量 指向平均不包含方向的法线,可以用来改善间接光照的质量
clearCoatNormal float3 [0..1] Linear RGB,在切空间中编码方向向量 使用凹凸贴图(法线贴图)来扰动清漆图层的细节法线
emissive float4 rgb=[0..n], a=[0..1] Linear RGB,alpha 编码曝光权重 额外的漫射反照率来模拟自发光表面(如霓虹灯等),这个属性在带有 bloom 通道的 HDR 管道中非常有用
postLightingColor float4 [0..1] Linear RGB 额外的颜色,可以与光照计算的结果混合,见 postLightingBlending
ior float [1..n] 可选,通常由反射率推断 折射率,折射物的折射率或作为反射率的替代品
transmission float [0..1] 定义了有多少电介质的漫射光通过物体传播,它定义了物体的透射率
absorption float3 [0..n] 折射率物体的吸收系数
microThickness float [0..n] 折射率物体的薄层厚度
thickness float [0..n] 折射物体的固体体积的厚度

6.1.1 baseColor

​ baseColor 有时也被称为 albedo(反射率,如:Unity),用于控制非金属(non-metals)表面的漫反射颜色和金属(metals)表面的镜面反射颜色。官方介绍见 → basecolor

普通非金属(non-metals)的 baseColor 取值

普通金属(metals)的 baseColor 取值

6.1.2 metallic

​ metallic 用于控制材质表面是非金属(或电介质,取值 0)还是金属(或导体,1),此属性应作为二进制值使用,设置为 0 或 1。当使用纹理时,metallic 的中间值只在不同类型的表面之间创建过渡时真正有用。官方介绍见 → metallic

​ 该属性可以极大地改变表面的外观,非金属表面有彩色漫反射和消色差镜面反射(反射光不变色);金属表面没有漫反射和彩色镜面反射(反射光呈现表面的颜色由 baseColor定义)。

metallic(金属度)从 0(左)到 1(右)变化

6.1.3 roughness

​ roughness 用于控制材质表面的光滑(0)或粗糙(1)感。当 roughness 设置为 0 时,表面非常光滑,具有很高的光泽。表面越粗糙,反射越"模糊"。这个属性在其他引擎和工具中通常被称为光泽度(glossiness),与粗糙度相反(roughness = 1 - glossiness)。官方介绍见 → roughness

非金属(non-metals)粗糙度(roughness)从 0(左)到 1(右)变化

金属(metals)粗糙度(roughness)从 0(左)到 1(右)变化

6.1.4 refraction

​ 当物体的折射(refraction)被启用时(使用折射类型 refractonType 为 thin 或 solid),粗糙度(roughness)属性也会影响折射。官方介绍见 → refraction

折射率(refraction)从 0(左)到 1(右)变化

6.1.5 reflectance

​ reflectance 用于控制材质的镜面反射强度和折射率(index of refraction,ior),它只影响非金属表面。该属性定义在 0 到 1 之间,表示反射率对应的重映射百分比。如:默认值 0.5 对应于 4% 的反射率。应避免低于 0.35 (2% 反射率) 的值,因为现实世界中没有任何材质具有如此低的反射率。官方介绍见 → reflectance

反射率(reflectance)从 0(左)到 1(右)变化

refraction 与 reflectance 的函数关系

​ 下表描述了各种材质可接受的反射率值(现实世界中没有任何材质的值低于 2%)。

Material Reflectance IOR Linear value
水(Water) 2% 1.33 0.35
布料(Fabric) 4% to 5.6% 1.5 to 1.62 0.5 to 0.59
常见液体(Common liquids) 2% to 4% 1.33 to 1.5 0.35 to 0.5
普通宝石(Common gemstones) 5% to 16% 1.58 to 2.33 0.56 to 1.0
塑料、玻璃(Plastics, glass) 4% to 5% 1.5 to 1.58 0.5 to 0.56
其他电介质材质(Other dielectric materials) 2% to 5% 1.33 to 1.58 0.35 to 0.56
眼睛(Eyes) 2.5% 1.38 0.39
皮肤(Skin) 2.8% 1.4 0.42
头发(Hair) 4.6% 1.55 0.54
牙齿(Teeth) 5.8% 1.63 0.6
默认值(Default value) 4% 1.5 0.5

​ 注意:反射率(reflectance)也定义了表面的折射率(index of refraction,ior)。定义此属性后,不需要定义 ior 属性。设置这些属性中的任何一个都将自动计算另一个属性。可以同时指定两者,在这种情况下,它们的值保持原样,这可能导致物理上不可能的材质,但是,出于艺术原因,这可能是可取的。

​ 反射率属性被设计为范围 0 ~ 1 的归一化属性,这使得它很容易从纹理定义。

6.1.6 sheenColor

​ sheenColor 用于控制由上述属性描述的基础层(base layer)之上的可选光泽层(sheen layer)的颜色外观和强度,如果有光泽层,光泽层总是位于清漆层(clear coat layer)之下。光泽层可以用来代表布料和织物材质。官方介绍见 → sheencolor

不同的光泽颜色(sheenColor

6.1.7 sheenRoughness

​ sheenRoughness 属性与 roughness 属性类似,但只适用于光泽层。官方介绍见 → sheenroughness

​ sheenRoughness 对粗糙金属的效果如下,在这张图中,基础层(base layer)是深蓝色,金属(metallic)设置为 0.0,粗糙度(roughness)设置为 1.0。

光泽层粗糙度(sheenRoughness)从 0(左)到 1(右)变化

6.1.8 clearCoat

​ 多层材质是相当常见的,特别是在基础层(base layer)上有一层薄薄的半透明层(translucent layer)的材质,如:汽车油漆、汽水罐、漆木和丙烯酸。

​ clearCoat(清漆)属性可用于描述具有两层的材质,它只适用于各向同性(isotropic)和电介质(dielectric,即非金属)材质。

碳纤维材质在标准材质模型(standard material model,左)和清漆材质模型(clear coat model,右)下的比较

​ clearCoat 属性用于控制清漆的强度,它应该被视为二进制值,设置为 0 或 1,中间值可以控制具有清漆的表面部分和不具有清漆的表面部分之间的过渡。官方介绍见 → clearcoat

清漆强度(clearCoat)从 0(左)到 1(右)变化

6.1.9 clearCoatRoughness

​ clearCoatRoughness 属性与 roughness 属性类似,但只适用于清漆图层(clear coat layer)。官方介绍见 → clearcoatroughness

清漆粗糙度(clearCoatRoughness)从 0(左)到 1(右)变化

6.1.10 anisotropy

​ 许多现实世界的材质,如磨砂金属(brushed metal),只能使用各向异性反射模型(anisotropic reflectance model)实现。可以使用各向异性(anisotropy)属性将材质从默认的各向同性模型(isotropic model)更改为各向异性模型(anisotropic model)。官方介绍见 → anisotropy

各向同性材质(isotropic material,左)和各向异性材质(anistropic material,右)的比较

各向异性(anisotropy)从 0(左)到 1(右)变化

正(左)负(右)各向异性值(anisotropy)比较

6.1.11 anisotropyDirection

​ anisotropyDirection 属性定义了给定顶点表面的方向,从而控制镜面高光的形状,它是一个 3 维向量,通常使用纹理编码切线空间中表面的局部方向。因为方向在切空间中,所以 Z 分量应该设为 0。官方介绍见 → anisotropydirection

使用方向图(direction map)渲染的各向异性金属(anisotropic metal)

specularAmbientOcclusiona 方向图

6.1.12 ambientOcclusion

​ ambientOcclusion 属性定义了多少环境光可以到达一个表面点。它是一个在 0(完全阴影)和 1(完全照亮)之间的每像素阴影因子。该属性仅影响漫射间接光照(基于图像的光照,image-based lighting),不影响定向光(directional lights)、点光源(point lights)和聚光灯(spot lights)等直接光照(direct lights),也不影响镜面光照(specular lighting)。官方介绍见 → ambientocclusion

无漫反射环境遮挡(左)和有漫反射环境遮挡(diffuse ambient occlusion,右)的材质对比

6.1.13 normal

​ normal 属性定义了曲面在给定点处的法线,通常使用法线纹理编码法线。法线是在切空间中提供的,这意味着 + Z 点在表面之外。normal 属性只影响基础图层(base layer),不影响清漆图层(clear coat layer)。官方介绍见 → normal

没有法线贴图(左)和有法线贴图(normal mapping,右)的材质对比

6.1.14 bentNormal

​ bentNormal 属性定义了曲面上一点的平均未包含方向(average unoccluded direction),它可以提高间接光照的精度,也可以提高镜面环境遮挡(specular ambient occlusion)的质量。bentNormal 可以极大提高具有各种空腔和凹区的资源的视觉保真度。官方介绍见 → bentnormal

使用和不使用 bentNormal 渲染的模型示例

6.1.15 clearCoatNormal

​ clearCoatNormal 属性定义了在给定点的清漆图层(clear coat layer)的法线。官方介绍见 → clearcoatnormal

具有清漆图层法线贴图和表面法线贴图的材质

6.1.16 emissive

​ emissive 属性可以用来模拟表面的自发光,它是一个 float4 类型变量,其中包含以尼特(nit)为单位的 RGB 强度以及曝光权重(在 alpha 通道中)。官方介绍见 → emissive

​ 如果用户更喜欢使用 EV(或光圈值,f-stops),可以通过将自发光颜色(emissive color)与 API filament::Exposure::luminance(ev) 的输出简单相乘。该 API 返回特定 EV 的尼特亮度。用户也可以使用以下公式自行进行这种转换,其中,L 为最终的尼特强度。

L = pow(2, (EV − 3))

​ alpha 通道中携带的曝光权重可用于撤消相机曝光(camera exposure),从而强制自发光表面绽放(bloom)。当曝光权重设置为 0 时,自发光强度不受相机曝光的影响。当权重设置为 1 时,强度将乘以相机曝光,就像对待任何常规光源一样。

6.1.17 postLightingColor

​ postLightingColor 可用于在光照计算之后修改表面颜色,此属性没有物理意义,仅存在于实现特定效果或帮助调试,它是一个 float4 类型变量,表示在线性空间中预乘的 RGB 颜色。官方介绍见 → post-lightingcolor

​ 根据 postLightingBlending 指定的混合模式,postLightingColor 可以与光照计算后的颜色进行混合。通过将 postLightingBlending 设置为 add,并提供一个 alpha 设置为 0 的 RGB 颜色,postLightingColor 可以用作更简单的自发光(emissive)属性。

6.1.18 ior

​ ior 属性仅影响非金属(non-metallic)表面,它可以控制材质的折射率(Index of refraction)和镜面反射强度(specular intensity)。ior 属性需要与折射(refraction)或透射(transmissive)材质一起使用,即 refractionMode 设置为 cubemap 或 screenspace。它也可以用于非折射(non-refractive)对象,作为设置反射率(reflectance)的替代方法。官方介绍见 → indexofrefraction

​ 材质的折射率(index of refraction 或 refractive index)是一个无单位的变量,描述了光在该材质中传播的速度,数值越高,光在介质中传播的速度越慢。对于渲染材质而言,折射率更为重要,它决定了光线进入材质时的弯曲路径,较高的折射率会使光线偏离初始路径更远。

​ 下表是一些常见材质的折射率(index of refraction)。

Material IOR
空气(Air) 1.0
水(Water) 1.33
常见液体(Common liquids) 1.33 to 1.5
普通宝石(Common gemstones) 1.58 to 2.33
塑料、玻璃(Plastics, glass) 1.5 to 1.58
其他电介质材质(Other dielectric materials) 1.33 to 1.58

​ 折射材质的外观将在很大程度上取决于材质的 refractionType 和 refractionMode 设置。当 refractionMode设 置为 cubemap 且 refractionType 设置为 solid 时,折射率(ior)从 1.0 到 1.5 变化时的效果见下图。

透射率(ior)从 1.0(左)到 1.5(右)变化

​ 下图显示了 refractionMode 设置为 screenspace 且 refractionType 设置为 solid 时,折射率(ior)为 1.0 的球体与折射率(ior)为 1.33 的球体的比较。

折射率(ior)为 1.0(左)和 1.33(右)的材质对比

​ 注意:ior 属性还定义了表面的反射率(reflectance)或镜面反射强度(specular intensity)。当定义了 ior 属性时,无需定义反射率(reflectance)属性。设置这两个属性中的任何一个都将自动计算另一个属性。可以同时指定两者,这种情况下它们的值将保持不变,这可能导致物理上不可能的材质,但出于艺术原因可能是可取的。

​ 折射材质(refractive materials)受到粗糙度(roughness)属性的影响。粗糙的材质会散射光线,产生一种扩散效果,可用于再现类似于磨砂玻璃、某些塑料等的"模糊"外观。

6.1.19 transmission

​ transmission 属性定义了透过折射材质的漫反射光(ratio of diffuse light)的比例。此属性仅影响 refractionMode 设置为 cubemap 或 screenspace 的材质。官方介绍见 → transmission

​ 当透射率(transmission)设置为 0 时,没有光线透过,表面的漫反射成分是 100% 可见的。当透射率(transmission)设置为 1 时,所有光线都透过,漫反射成分不再可见,只有镜面成分可见。

​ 对于折射率(ior)为 1.5、refractionMode 为 cubemap、refractionType 为 solid 的光滑介质,透射率(transmission)从 0 ~ 1 变化对应的效果如下。

透射率(transmission)从 0(左)到 1(右)变化

6.1.20 absorption

​ absorption 属性定义了透过材质传播的光的吸收系数,官方介绍见 → absorption

​ 下图显示了 absorption 对折射物体的影响,该物体的折射率(ior)为 1.5,基础颜色(baseColor)设置为白色。

无吸收(absorption)和有吸收的折射对象比较

​ 透过体积的透射率与光学深度成指数关系(可以用 microThickness 或 thickness 定义)。计算得到的颜色遵循以下公式:

​ 其中,distance 可以是 microThickness 或 thickness,即光在给定点通过材质的距离。如果没有指定 thickness/distance,计算得到的颜色将遵循以下公式:

​ 下图显示了吸收率对物体的影响效果。在该图中,厚度(thickness)为 4.5,折射率(ior)为 1.3。

吸收率(absorption)从 (0.0, 0.02, 0.14)(左)到 (0.0, 0.36, 2.3)(右)变化

​ 直接设置吸收率(absorption)可能不直观,因此 Filament 建议使用透射颜色(transmittance color)和"at distance" 计算 absorption。这两个参数允许设计师在体积中指定的距离处指定材质的精确颜色。absorption 的值可以通过以下方式计算:

​ 虽然这个计算可以在材质本身完成,但 Filament 建议尽可能在离线状态下进行。Filament 提供了一个专门用于此目的的 API,即Color::absorptionAtDistance()。

6.1.21 microThickness 和 thickness

​ microThickness 和 thickness 属性定义了折射物体(refracting object)材质的光学深度(optical depth)。当 refractionType 设置为 thin 时,使用 microThickness,当 refractionType 设置为 volume 时,使用 thickness。官方介绍见 → micro-thicknessandthickness

​ thickness 表示垂直方向上实体对象的厚度,为了获得令人满意的结果,这应该以每个片段为单位提供(例如:作为纹理),或者至少以每个顶点为单位提供。

​ microThickness 表示对象的薄层(壳)的厚度,通常可以提供为常量值。例如,半径为 1 米、厚度为 1 毫米的空心球的 thickness 为 1,microThickness 为 0.001。目前,当 refractionType 设置为 thin 时,不使用 thickness。这两个属性都提供了可能在将来使用的可能性。

​ 当设置吸收率(absorption)属性时,thickness 和 microThickness 都用于计算材质的透射颜色。在实体体积中,thickness 还将影响光线的折射方向。

​ 在 refractionMode 设置为 screenSpace 的实体体积中的 thickness 效果如下图所示。注意,thickness 值不仅改变吸收效果,还修改了折射光的方向。

thickness 从 0(左)到 2(右)变化

​ 下图展示了当 refractionType 设置为 solid 且设置吸收系数时,一个具有空间变化厚度的棱镜的外观。

厚度(thickness)从棱镜顶部的 0 到棱镜底部的 3 变化

6.2 subsurface model

​ subsurface model 官方介绍见 → subsurfacemodel,官方文档只留着标题,无内容介绍。

6.3 cloth model

​ cloth model 官方介绍见 → clothmodel,可以配置的参数如下。布料材质模型包括先前为标准材质模型定义的所有参数,除了金属度(metallic)和反射率(reflectance)。

Property Type Range Note Definition
sheenColor float3 [0..1] Linear RGB 高光色调创建双色高光布料(默认值:sqrt(baseColor))
subsurfaceColor float3 [0..1] Linear RGB 通过材质散射和吸收后的漫射色着色

​ 先前描述的所有材质模型都设计用于模拟密集表面,无论是在宏观还是微观层面上。然而,衣物和织物通常由松散连接的线组成,这些线吸收并散射入射光。与坚硬的表面相比,织物的特征是具有较大衰减的柔软镜面光泽和前向/后向散射引起的模糊照明。一些织物还表现出两种色调的镜面颜色(例如天鹅绒)。

​ 下图显示了标准材质模型(standard material model)无法捕捉牛仔布织物的外观。表面看起来刚性(几乎像塑料一样),更类似于防水布而不是衣物。该图示还显示了由吸收和散射引起的柔软镜面光泽对于再现布料外观的重要性。

使用标准模型(standard model,左)和布料模型(cloth model,右)渲染的牛仔布料比较

​ 天鹅绒是布料材质模型的一个有趣的用例。如下图,这种类型的织物由于前向和后向散射而表现出强烈的边缘照明。这些散射事件是由于纤维直立在织物表面引起的。当入射光来自与视线方向相反的方向时,纤维将前向散射光。同样,当入射光来自与视线方向相同的方向时,纤维将向后散射光。

展示了前向和后向散射的天鹅绒布料

​ 需要注意的是,仍然有一些类型的布料最好使用硬表面材质模型建模。例如,皮革、丝绸和缎面可以使用标准(standard)或各向异性(anisotropic)材质模型重新创建。

6.3.1 sheen color

​ sheenColor 属性可用于直接修改镜面反射(specular reflectance)。它提供了更好的对布料外观的控制,并使得能够创建两种色调的镜面材质。

无光泽(sheen,左)和 有光泽(右)效果对比

6.3.2 subsurfaceColor

​ subsurfaceColor 属性不是基于物理的,可以用于模拟在某些类型的布料中光的散射、部分吸收和重新发射。这对于创建更柔软的织物特别有用。

白色布料(左列)与具有棕色次表面散射的白色布料(右列)

6.4 unlit model

​ unlit model 官方介绍见 → unlitmodel,可以配置的参数如下。

Property Type Range Note Definition
baseColor float4 [0..1] Linear RGB 表面漫反射色
emissive float4 rgb=[0..n], a=[0..1] Linear RGB,alpha 编码曝光权重 额外的漫射颜色来模拟发射表面,该属性在带有 bloom pass 的 HDR 管道中非常有用
postLightingColor float4 [0..1] Linear RGB 额外的颜色与基色和发射色混合

6.5 specularGlossiness

​ specularGlossiness 官方介绍见 → specularglossiness,可以配置的参数如下。

Property Type Range Note Definition
baseColor float4 [0..1] Linear RGB 表面漫反射色
specularColor float3 [0..1] Linear RGB 高光色调(默认为黑色)
glossiness float [0..1] Inverse of roughness 光泽度(默认为 0)

7 混合和透明(Blending and transparency)

7.1 blending

​ 在 material 块中,通过 blending 属性配置混合模式,取值有:opaque、transparent、fade、add、multiply、screen、masked,默认取 opaque,官方介绍见 → blending

  • opaque:不透明模式,混合被禁用,材质输出的 alpha 通道被忽略。
  • transparent:透明模式,启用混合,材质输出的是与渲染目标通过 alpha 混合的,使用 Porter-Duff 的 source over 规则,这种混合模式假定预先乘以 alph。
  • fade:半透明模式,启用混合,表现透明效果,但透明度也应用到镜面反射光照,在 transparent 模式下,材质的 alpha 值只应用到漫射光照,fade 混合模式对于淡化被照亮的物体很有用。
  • add:叠加模式,启用混合,材质的输出被叠加到渲染目标的内容中。
  • multiply:累乘模式,启用混合,材质的输出与渲染目标的内容相乘,使内容变暗。
  • screen:屏幕模式,启用混合,与 multiply 的效果相反,渲染目标的内容会变亮。
  • masked:遮罩模式,禁用混合,这种混合模式启用 alpha 遮罩,材质输出的 alpha 通道定义了片元是否被丢弃。此外,ALPHA_TO_COVERAGE 对于非半透明视图是启用的,有关更多信息,请参阅 maskThreshold 部分。
cpp 复制代码
material {
    blending : opaque
}

7.2 postLightingBlending

​ postLightingColor 属性定义了如何将 postLightingColor 材质属性与光照计算结果混合,官方介绍见 → postlightingblending。取值主要有:opaque、transparent、add、Screen,默认取值:transparent。

cpp 复制代码
material {
    postLightingBlending : add
}

7.3 transparency

​ transparency 控制透明物体的渲染方式,它仅在混合模式不是 opaque 且 refractionMode 为 none 时有效,这些方法都不能准确地渲染凹形物体,但在实践中它们往往足够好,官方介绍见 → transparency。取值主要有:default、twoPassesOneSide、twoPassesTwoSides,默认取值:default。

  • default:透明物体正常呈现,遵循剔除模式。
  • twoPassesOneSide:透明物体首先在深度缓冲区中渲染,然后再在颜色缓冲区中渲染,遵循剔除模式,这实际上只呈现了透明物体的一半。
  • twoPassesTwoSides:透明物体在颜色缓冲区中渲染两次,第一次渲染背面,然后渲染正面,该模式允许渲染两面,同时减少或消除排序问题,twoPassesTwoSides 可以与 doubleSided 结合使用,效果更好。
cpp 复制代码
material {
    transparency : twoPassesOneSide
}

7.4 maskThreshold

​ 当混合模式设置为 masked 时,maskThreshold 用于控制片元不被丢弃的最小 alpha 值;当混合模式未被设置为 masked 时,maskThreshold 将被忽略,官方介绍见 → maskThreshold。取值为 0.0 ~ 1.0 之间的浮点数,默认取值:0.4。

cpp 复制代码
material {
    blending : masked,
    maskThreshold : 0.5
}

7.5 refractionMode

​ refractionMode 用于控制折射模式,官方介绍见 → refractionMode。取值主要有:none、cubemap、screenspace,默认取值:none。当 refractionMode 设置为非 none 时才激活折射。

​ cubemap 模式只使用 IBL cubemap 作为折射源,这是非常有效的,没有场景对象被折射,只有在 cubemap 中编码的远处环境被折射,该模式对于对象查看器来说是足够的。screenspace 模式采用更先进的屏幕空间折射算法,该算法允许场景中不透明的物体被折射。

​ 在 cubemap 模式中,假定折射光线从物体的中心发出,厚度参数仅用于计算吸收,而对折射本身没有影响。在 screenspace 模式中,假定折射光线在离开折射介质时平行于观看方向。

cpp 复制代码
material {
    refractionMode : cubemap,
}

7.6 refractionType

​ refractionType 用于设置折射模型,官方介绍见 → refractionType。取值主要有:solid、thin,默认取值:solid。当 refractionMode 设置为非 none 时 refractionType 才会生效。

​ solid 模型用于厚的物体,如水晶球、冰块或雕塑;thin 模型用于薄的物体,如窗户、装饰球或肥皂泡。

​ solid 模型假定所有的折射物体都是与入射点相切且半径厚度的球体。thin 模型假定所有的折射物体都是平面的、薄的、均匀厚度的。

cpp 复制代码
material {
    refractionMode : cubemap,
    refractionType : thin,
}

8 光栅化(Rasterization)

8.1 culling

​ culling 用于控制需要剔除哪些三角形,官方介绍见 → culling。取值主要有:none、front、back、frontAndBack,默认取值:back。

  • none:不剔除,渲染双面。
  • front:剔除正面三角形,渲染背面。
  • back:剔除背面三角形,渲染正面。
  • frontAndBack:正面和背面全部剔除。
cpp 复制代码
material {
    culling : none
}

8.2 colorWrite

​ colorWrite 用于控制开启 / 禁用写入颜色缓冲区,官方介绍见 → colorWrite。取值有:true、false,默认取值:true。

cpp 复制代码
material {
    colorWrite : false
}

8.3 depthWrite

​ depthWrite 用于控制开启 / 禁用写入深度缓冲区,官方介绍见 → depthWrite。取值有:true、false,不透明物体默认取值:true,透明物体默认取值:false。

cpp 复制代码
material {
    depthWrite : false
}

8.4 depthCulling

​ depthCulling 用于控制开启 / 禁用深度测试 ,官方介绍见 → depthCulling。取值有:true、false,默认取值:true。

​ 当深度测试被禁用时,用此材质渲染的物体将始终出现在其他不透明物体的前面。

cpp 复制代码
material {
    depthCulling : false
}

8.5 doubleSided

​ doubleSided 用于控制开启 / 禁用双面渲染,官方介绍见 → doubleSided。取值有:true、false,默认取值:false。当设置为 true 时,culling 自动设置为 none。

​ 如果三角形是面向背面的,则三角形的法线将翻转为面向正面。当显式设置为 false 时,这允许在运行时切换双面性。

cpp 复制代码
material {
    doubleSided : true
}

8.6 alphaToCoverage

​ alphaToCoverage 用于控制开启 / 禁用 alpha 覆盖,官方介绍见 → alphaToCoverage。取值有:true、false,默认取值:false。

​ 当覆盖的 alpha 被启用时,片元的覆盖是从它的 alpha 派生出来的。此属性仅在启用 MSAA 时才可用。注意:将混合模式设置为 masked 会自动启用 alpha 覆盖,如果不希望这样做,可以通过将 alpha 的覆盖设置为 false 来取消此行为。

cpp 复制代码
material {
    blending : masked,
    alphaToCoverage : false
}

9 光照属性(Lighting)

9.1 reflections

​ reflections 用于控制材质的镜面反射源,官方介绍见 → reflections。取值有:default、screenspace,默认取值:default。

​ 当 reflections 设置为 default 时,反射仅来自基于图像的光照(image-based lights,IBL);当此 reflections 设置为 screenspace 时,反射除了来自 IBL 之外,还来自屏幕空间的颜色缓冲区。

cpp 复制代码
material {
    reflections : screenspace
}

9.2 shadowMultiplier

​ shadowMultiplier 用于控制开启 / 禁用阴影,该属性仅在 unlit 光照模型下才可用,官方介绍见 → shadowMultiplier。取值有:true、false,默认取值:false。

​ 当 shadowMultiplier 设置为 true 时,材质计算的最终颜色需要乘以阴影因子(或可见性),它允许创建透明的且接收阴影投射的物体(如:AR 中不可见的地面),它仅接收直射光(directional lights)的阴影。

cpp 复制代码
material {
    shadingModel : unlit,
    shadowMultiplier : true,
    blending : transparent
}

9.3 transparentShadow

​ transparentShadow 用于控制开启 / 禁用透明阴影,官方介绍见 → transparentShadow。取值有:true、false,默认取值:false。

​ 当 shadowMultiplier 设置为 true 时,Filament 使用抖动模式(dithering pattern)模拟透明阴影,它们在方差阴影地图(VSM)和模糊启用时效果最好。阴影的不透明度直接来源于材质的 baseColor 属性的 alpha 通道,透明阴影可以在不透明的物体上启用,使它们与不透明的折射 / 透射物体兼容。

cpp 复制代码
material {
    transparentShadow : true,
    blending : transparent
}

fragment {
    void material(inout MaterialInputs material) {
        prepareMaterial(material);
        material.baseColor = texture(materialParams_baseColor, getUV0());
    }
}

使用透明阴影(transparentShadow)和半径为 4 的模糊 VSM 渲染的物体

9.4 clearCoatIorChange

​ clearCoatIorChange 用于控制开启 / 禁用清除折射率变化图层,官方介绍见 → clearCoatIorChange。取值有:true、false,默认取值:true。

​ 当 clearCoatIorChange 设置为 true 时,会添加一个清除图层,它考虑到折射率(IoR)的变化来修改底层的镜面颜色,这会使 baseColor 变暗。当此效果被禁用时,baseColor 保持不变。

cpp 复制代码
material {
    clearCoatIorChange : false
}

相同的带有清漆层的粗糙金属球,启用 clearCoatIorChange 渲染(左)和禁用(右)

9.5 multiBounceAmbientOcclusion

​ multiBounceAmbientOcclusion 用于控制开启 / 禁用多反弹环境遮挡,官方介绍见 → multiBounceAmbientOcclusion。取值有:true、false,默认取值:false。

​ 当将环境遮挡(ambient occlusion)应用于基于图像的光照(image-based lighting,IBL)时,多反弹环境遮挡(multi-bounce ambient occlusion)考虑了相互反射。开启此功能可避免遮挡区域过度变暗。它还考虑了表面颜色来生成彩色环境遮挡。

cpp 复制代码
material {
    multiBounceAmbientOcclusion : true
}

使用启用(左)和禁用(右)的多次反弹环境光遮蔽渲染的砖纹理

使用启用和禁用的多次反弹环境光遮蔽渲染的砖纹理

9.6 specularAmbientOcclusion

​ specularAmbientOcclusion 用于控制开启 / 禁用多反弹环境遮挡,官方介绍见 → multiBounceAmbientOcclusion。取值有:none、simple、 bentNormals,默认取值:none。

​ 静态环境遮挡贴图和动态环境遮挡贴图(SSAO 等)适用于漫射间接光照。当将此属性设置为非 none 时,一个新的环境遮挡项将从表面粗糙度中衍生出来,并应用于镜面间接光照。这种效果有助于消除不需要的镜面反射。当这个值设置为 simple 时,Filament 使用一种便宜但近似的方法来计算高光环境遮挡项。如果将此值设置为 bentNormals, Filament 将使用更精确但更昂贵的方法。

cpp 复制代码
material {
    specularAmbientOcclusion : simple
}

开启和关闭时的镜面环境光遮蔽比较(效果在水管下尤其明显)

10 抗锯齿(Anti-aliasing)

10.1 specularAntiAliasing

​ specularAntiAliasing 用于控制开启 / 禁用镜面抗锯齿,官方介绍见 → specularAntiAliasing。取值有:true、false,默认取值:false。

​ 当一个对象远离相机,开启抗锯齿可用减少镜面锯齿,并保留镜面高光的形状。这种抗锯齿方案对光滑材质(低粗糙度)特别有效,但增加了渲染成本。抗锯齿效果的强度可以使用另外两个属性来控制:specularAntiAliasingVariance 和 specularAntiAliasingThreshold。

cpp 复制代码
material {
    specularAntiAliasing : true
}

10.2 specularAntiAliasingVariance

​ specularAntiAliasingVariance 用于设置应用镜面抗锯齿时使用的过滤器内核的屏幕空间方差,官方介绍见 → specularAntiAliasingVariance。取值类型是 float 型,取值范围是 0 ~ 1,默认取值:0.15。

​ 较高的 specularAntiAliasingVariance 值将增加过滤器的效果,但可能增加不需要的区域的粗糙度。

cpp 复制代码
material {
    specularAntiAliasingVariance : 0.2
}

10.3 specularAntiAliasingThreshold

​ specularAntiAliasingThreshold 用于设置应用镜面抗锯齿时抑制估计误差的夹持阈值(clamping threshold),官方介绍见 → specularAntiAliasingThreshold。取值类型是 float 型,取值范围是 0 ~ 1,默认取值:0.2。

​ 当设置为 0 时,镜面抗锯齿被禁用。

cpp 复制代码
material {
    specularAntiAliasingThreshold : 0.1
}

11 颜色处理(Handling colors)

11.1 Linear colors

​ 线性颜色空间的介绍见 → 【Unity3D】伽马校正,Filament 在线性颜色空间中使用 RGB 颜色,官方介绍见 → linearcolors

​ 如果颜色数据来自纹理,请确保使用 sRGB 纹理,以从 sRGB 自动进行硬件转换为线性。如果颜色数据作为材质的参数传递,可以通过在每个颜色通道上运行以下算法将其从 sRGB 转换为线性。

cpp 复制代码
float sRGB_to_linear(float color) {
	return color <= 0.04045 ? color / 12.92 : pow((color + 0.055) / 1.055, 2.4);
}

​ 可以使用以下两个更便宜但不太准确的方法。

cpp 复制代码
// Cheaper
linearColor = pow(color, 2.2);
// Cheapest
linearColor = color * color;

11.2 Pre-multiplied alpha

​ 如果一种颜色的 RGB 分量都乘以 alpha 通道,那么它使用了预乘 alpha,官方介绍见 → pre-multipliedalpha

cpp 复制代码
// Compute pre-multiplied color
color.rgb *= color.a;

​ 如果颜色是从纹理中取样的,可以简单地确保纹理数据在上传时进行了预乘。在 Android 上,从 Bitmap 上传的任何纹理默认都会进行预乘。

​ 声明:本文转自【Filament】材质系统

相关推荐
鲁元1 个月前
Laravel Filament 如何配置多语言支持
php·laravel·filament·多语言支持
little_fat_sheep8 个月前
【Filament】基于物理的光照(PBR)
filament
little_fat_sheep9 个月前
【Filament】立方体贴图(6张图)
filament
little_fat_sheep9 个月前
【Filament】绘制圆形
filament
little_fat_sheep9 个月前
【Filament】Filament环境搭建
filament
little_fat_sheep1 年前
【Filament】纹理贴图
贴图·filament
破竹151 年前
Filament引擎分析--command抽象设备API
filament
番茄蛋饭25块半1 年前
Filament 如何自定义登录页面
laravel·filament