Filament Materials Guide
Introduction
材质第三部分学习使用 Filament 进行材质制作的方法(.mat文件编写方法),这部分已经开始涉及材质框架了,需要重点掌握。本章还是以笔记为主。学习文档来源于官方文档:
- https://github.com/google/filament/tree/main/docs/Materials.html
Material definitions
- 材质定义是描述材质所需的所有信息的文本文件:
- Name (名称)
- User parameters (参数)
- Material model (材质模型)
- Required attributes (必须属性)
- Interpolants (called variables) (变量)
- Raster state (blending mode, etc.) (光栅化状态,混合模式)
- Shader code (fragment shader, optionally vertex shader) (shader 代码)
Format (材质定义的格式)
-
材质定义的格式是一种松散地基于JSON的格式,称之为JSONish。在顶层,材质定义由 JSON 对象表示的3个不同块组成:
material { // material properties } vertex { // vertex shader, optional } fragment { // fragment shader }
-
最小可行材质的定义必须包含 material 和 fragment 块。vertex 块是可选项。
Differences with JSON
- 在 JSON 中,对象由键/值对组成。JSON 对具有以下语法:
"key" : value
- JSONish 可以不带双引号,因为 Filament 使用 variant 存储变量
key : value
- 当字符串包含空格时,这时需要引号
- vertex 和 fragment 块包含未转义、未引用的 GLSL 代码,这些代码在 JSON 中无效。
- 允许使用单行C++样式的注释
- key 区分大小写
- value 不区分大小写
Example
material {
//材质名称
name : "Textured material",
//参数
parameters : [
{
type : sampler2d,
name : texture
},
{
type : float,
name : metallic
},
{
type : float,
name : roughness
}
],
//需要使用的特性
requires : [
uv0
],
//材质模型
shadingModel : lit,
//混合模式
blending : opaque
}
//shader 代码
fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor = texture(materialParams_texture, getUV0());
material.metallic = materialParams.metallic;
material.roughness = materialParams.roughness;
}
}
Material block
- Material block 是必需要定义的块,其中包含所有非着色器(non-shader)数据的属性对。
General
- name
- Type:string
- Value: 任何字符串。如果名称包含空格,则需要双引号
- 示例
- name : stone
- name : “Wet pavement”
- 示例
- shadingModel
- Type:string
- Value: lit, subsurface, cloth, unlit, specularGlossiness(弃),默认为 lit
- parameters
- 每个 entry 都是一个具有属性 name 和 type 的对象,两者均为 string 类型。name 必须是有效的 GLSL 标识符。entry 可选的precision 字段,用于设置变量精度,可以是默认值(平台(platform)的最佳精度,通常 desktop 为 high ,在移动设备上为 medium),low,medium,high。type 必须是下列之一
- bool
- bool2
- bool3
- bool4
- float
- float2
- float3
- float4
- int
- int2
- int3
- int4
- uint
- uint2
- uint3
- uint4
- float3×3
- float4×4
- sampler2d
- samplerExternal : 外部纹理(特定平台)
- samplerCubemap
- Samplers 类型还可以指定一种格式,该格式可以是 int 或 float(默认为 float)。
- Arrays
- parameter 可以通过在类型名称后追加 [size] 来定义数组,其中 size 是正整数。例如:float[9] 声明一个由九个浮点数组成的数组。
- 注意:
- 目前不支持 samplers 数组。
- 在设计自己的引擎时需要支持矩阵 和 Arrays
- Description
- 这些参数在运行时由 Filament 的材质 API 进行设置。着色器访问参数因参数类型而异
- Samplers types
- 以 materialParams_ 为前缀的参数名称。例如,materialParams_myTexture。
- Other types
- 作为 materialParams 的结构体中的成员变量。例如,materialParams.myColor
- 示例如下
material { parameters : [ { type : float4, name : albedo }, { type : sampler2d, format : float, precision : high, name : roughness }, { type : float2, name : metallicReflectance } ], requires : [ uv0 ], shadingModel : lit, } fragment { void material(inout MaterialInputs material) { prepareMaterial(material); material.baseColor = materialParams.albedo; material.roughness = texture(materialParams_roughness, getUV0()); material.metallic = materialParams.metallicReflectance.x; material.reflectance = materialParams.metallicReflectance.y; } }
- 每个 entry 都是一个具有属性 name 和 type 的对象,两者均为 string 类型。name 必须是有效的 GLSL 标识符。entry 可选的precision 字段,用于设置变量精度,可以是默认值(平台(platform)的最佳精度,通常 desktop 为 high ,在移动设备上为 medium),low,medium,high。type 必须是下列之一
- variantFilter
- Type:string 数组
- Value: dynamicLighting、directionalLighting、shadowReceiver、skinning
- 其中一个或多个
- Description
- 用于指定应用程序不需要的 shader variants 列表。在代码生成阶段会跳过这些 shader variants,从而减小材质的整体大小。
- 注意:某些 variants 可能会被自动过滤掉。
- 例如,在编译 unlit 材质时,所有与光照相关的 variant (directionalLighting 等)都会被过滤掉。
- 请谨慎使用 variants 筛选器,筛选出运行时所需的 variants 可能会导致崩溃。
- variants 说明
- directionalLighting
- 当场景中存在定向光时使用
- dynamicLighting
- 当场景中存在非定向光源(point、spot等)时使用
- shadowReceiver
- 当对象可以接收阴影时使用
- skinning
- 在使用 GPU 蒙皮对渲染对象进行动画处理时使用
- fog
- 在将全局 fog 应用于场景时使用
- vsm
- 在启用 VSM 阴影且对象是阴影接收者时使用
- directionalLighting
- 示例
variantFilter : [ skinning ]
- flipUV
- Type:boolean
- Value: true or false. 默认为 true
- Description
- 设置为 true(默认值)时,当读取材质的 vertex shader 时,UV 属性的 Y 坐标将被翻转。
- 翻转等价于 y = 1.0 − y y = 1.0 - y y=1.0−y。
- 设置为 false 时,将禁用翻转,并按原样读取 UV
flipUV : false
- 设置为 true(默认值)时,当读取材质的 vertex shader 时,UV 属性的 Y 坐标将被翻转。
- quality
- Type:string
- Value:low, normal, high, default. 默认值为 default.
- Description
- 设置材质的 parameters 的全局精度。
- low
- 启用优化可能会略微影响正确性,并且在移动平台上默认为 low。
- normal
- 不影响正确性,在其他方面类似于 low。
- high
- 启用了可能会对性能产生负面影响的精度设置
- default
- 是桌面平台上的默认设置。
Vertex and attributes
-
requires
-
Type:string 数组
-
Value:uv0, uv1, color, position, tangents
-
Description
- 列出材质所需的 vertex 属性。
- position 属性始终是必需的,不需要指定。
- 在选取任何不是 unlit 的着色模型时,将自动设置 tangents 属性。
- 有关如何从着色器访问这些属性的详细信息,请参阅本文档的 shaders 部分。
- 列出材质所需的 vertex 属性。
-
示例如下
material { parameters : [ { type : sampler2d, name : texture }, ], requires : [ uv0 ], shadingModel : lit, } fragment { void material(inout MaterialInputs material) { prepareMaterial(material); material.baseColor = texture(materialParams_texture, getUV0()); } }
-
-
variables
- Type:string 数组
- Value:最多 4 个字符串,每个字符串必须是有效的 GLSL 标识。
- Description
- 定义由材质的顶点着色器输出的 interpolants [插值对象](或 variables 变量)。数组的每个 entry 都是定义的插值对象的名称。片元着色器中的全名是带有variable_ prefix的插值对象的名称。
- 例如,声明了一个名为eyeDirection的变量,则可以使用variable_eyeDirection在片元着色器中访问它。
- 在顶点着色器中,插值对象名称只是 MaterialVertexInputs 结构体(示例中为 material.eyeDirection)的成员。着色器中的每个插值对象类型为 float4 (vec4)。
- 实例
material { name : Skybox, parameters : [ { type : samplerCubemap, name : skybox } ], variables : [ eyeDirection ], vertexDomain : device, depthWrite : false, shadingModel : unlit } fragment { void material(inout MaterialInputs material) { prepareMaterial(material); float3 sky = texture(materialParams_skybox, variable_eyeDirection.xyz).rgb; material.baseColor = vec4(sky, 1.0); } } vertex { void materialVertex(inout MaterialVertexInputs material) { float3 p = getPosition().xyz; float3 u = mulMat4x4Float3(getViewFromClipMatrix(), p).xyz; material.eyeDirection.xyz = mulMat3x3Float3(getWorldFromViewMatrix(), u); } }
- 定义由材质的顶点着色器输出的 interpolants [插值对象](或 variables 变量)。数组的每个 entry 都是定义的插值对象的名称。片元着色器中的全名是带有variable_ prefix的插值对象的名称。
-
vertexDomain
- Type:string
- Value:object, world, view, device. 默认为 object
- Description
- 定义渲染网格的域 [domain (或坐标空间)]。域会影响顶点着色器中顶点的变换方式。可能的域包括:
- Object
- 顶点在对象(或模型)坐标空间-(局部坐标系)中定义。顶点使用渲染对象的变换矩阵进行变换
- World
- 顶点在世界坐标空间中定义。顶点不会使用渲染对象的变换矩阵进行变换。
- View
- 顶点在视图(或眼睛、或相机)坐标空间中定义。顶点不会使用渲染对象的变换矩阵进行变换。
- Device
- 顶点在 normalized device(或 clip)坐标空间中定义。顶点不会使用渲染对象的变换矩阵进行变换。
- Object
- 示例
material { vertexDomain : device }
- 定义渲染网格的域 [domain (或坐标空间)]。域会影响顶点着色器中顶点的变换方式。可能的域包括:
-
interpolation
- Type:string
- Value: smooth, flat. 默认为 smooth
- Description
- 定义如何在顶点之间进行插值(或 variables)。当此属性设置为 smooth 时,执行透视校正插值(perspective correct interpolation)。设置为 flat 时,不执行插值,并且给定三角形内的所有片元都将以相同的方式着色。
- 示例
material { interpolation : flat }
Blending and transparency
- blending
- Type:string
- Value: opaque, transparent, fade, add, masked, multiply, screen. 默认为 opaque
- Description
- 定义如何将渲染对象与渲染目标的内容混合。可能的混合模式包括:
- Opaque
- 混合被禁用,材质输出的 Alpha 通道将被忽略。
- Transparent
- 启用混合,材质的输出与渲染器目标进行 alpha 合成,使用 Porter-Duff 的 source over 规则。此混合模式假定 pre-multiplied Alpha
- Fade
- 行为类似 transparent ,但透明度也适用于 specular lighting。在 transparent 模式下,材质的 alpha 值仅适用于 diffuse lighting。此混合模式对于淡入和淡出光照对象 (fade lit objects) 非常有用。
- Add
- 启用混合。材质的输出将添加到渲染器目标的内容中。
- Multiply
- 启用混合。 材质的输出将与渲染目标的内容相乘,使内容变暗(darkening)。
- Screen
- 启用混合。实际上,与 Multiply 相反,渲染目标的内容被变亮(brightened)。
- Masked
- 启用混合。此混合模式启用 Alpha masking。材质输出的 alpha 通道定义片元是否被丢弃。有关详细信息,请参maskThreshold 部分。
- Opaque
- 定义如何将渲染对象与渲染目标的内容混合。可能的混合模式包括:
- 实例
material { blending : transparent }
- postLightingBlending
- Type:string
- Value:opaque, transparent, add. 默认为 transparent
- Description
- 定义 postLightingColor 材质属性如何与光照计算结果混合。可能的混合模式包括:
- Opaque
- 混合被禁用,材质将直接输出 postLightingColor 。
- Transparent
- 启用混合。材质的计算颜色使用波特·达夫(Porter Duff)的 source over 规则与 postLightingColor 进行alpha混合。此混合模式假定 pre-multiplied Alpha。
- Add
- 启用混合。材质的计算颜色将添加到 postLightingColor 中。
- Multiply
- 启用混合。材质的计算颜色与 postLightingColor 相乘
- Screen
- 启用混合。材质的计算颜色反转(反色)后与 postLightingColor 相乘,并将结果添加到材质的计算颜色中。
- Opaque
- 示例
material { postLightingBlending : add }
- 定义 postLightingColor 材质属性如何与光照计算结果混合。可能的混合模式包括:
- transparency
- Type:string
- Value:default, twoPassesOneSide or twoPassesTwoSides. 默认为 default
- Description
- 控制透明对象的渲染方式。仅当混合模式不是 opaque 且 refractionMode 为 none 时才有效。这些方法都不能准确地渲染凹陷几何(concave geometry)图形,但在实践中,效果也能满足需要。
- 三种可能的 transparency 模式是:
- default
- 透明对象正常渲染,遵循 culling 模式等。
- twoPassesOneSide
- 透明对象首先在深度缓冲区(depth buffer)中渲染,然后再次在颜色缓冲区(color buffer)中渲染,遵循 culling 模式。这实际上只渲染了透明对象的一半
- twoPassesTwoSides
- 透明对象在颜色缓冲区中渲染两次:首先是其背面,然后是正面。此模式渲染双面,同时减少或消除排序问题,twoPassesTwoSides 可以与 doubleSided组合使用,可以获得更好的效果。
- default
- 示例
material { transparency : twoPassesOneSide }
- maskThreshold
- Type:number
- Value:0.0 和 1.0 之间的值,默认为 0.4
- Description
- 当混合模式为 masked 时,设置片元不会被丢弃的最小 alpha 值。如果混合模式不是 masked,则忽略此值。该值可用于控 alpha-masked 的外观。
- 示例
material { blending : masked, maskThreshold : 0.5 }
- refractionMode
- Type:string
- Value:none, cubemap, screenspace,默认为 none
- Description
- 当设置为除了 none 之外的值时,激活折射。
- cubemap 仅使用 IBL cubemap 作为折射源,这样效率高。因为不会折射场景对象,只有编码在立方体贴图的远方环境用作折射计算。例如,该模式适用于对象查看器 (object viewer)。
- screenspace 将采用更高级的屏幕空间折射算法,该算法允许折射场景中的不透明对象。
- cubemap 模式下,假定折射光线从对象中心出现,thickness 参数仅用于计算吸收,但对折射本身没有影响。
- screenspace 模式下,折射光线在离开折射介质时被假定平行于视图方向。
- 示例
material { refractionMode : cubemap, }
- 当设置为除了 none 之外的值时,激活折射。
- refractionType
- Type:string
- Value:solid, thin,默认为 solid
- Description
- 当设置为除了 none 之外的值时才有效。refractionType 定义所使用的折射模型。
- solid 用于实心物体,如水晶球,冰块或雕塑。
- 在 solid 模式下,所有折射对象都假定是与入射点相切,并且半径为 thickness 的球体。
- thin 用于薄物体,如窗户,装饰球或肥皂泡。
- 在 thin 模式下,假定所有折射物体都是 flat (平坦)、 thin 的,并且厚度为 thickness。
- solid 用于实心物体,如水晶球,冰块或雕塑。
- 当设置为除了 none 之外的值时才有效。refractionType 定义所使用的折射模型。
- 示例
material { refractionMode : cubemap, refractionType : thin, }
Rasterization
- culling
- Type:string
- Value:one, front, back, frontAndBack,默认为 back
- Description
- 定义应剔除哪些三角形:none、front-facing 三角形、back-facing 三角形或全部。
- 示例
material { culling : none }
- colorWrite
- Type:boolean
- Value:true or false,默认为 true
- Description
- 启用或禁用对 color buffer 的写入。
- 示例
material { colorWrite : false }
- depthWrite
- Type:boolean
- Value:true or false,对于不透明材质,默认值为 true,对于透明材质,默认值为 false。
- Description
- 启用或禁用对 depth buffer 的写入。
- 示例
material { depthWrite : false }
- depthCulling
- Type:boolean
- Value:true or false,默认值为 true
- Description
- 启用或禁用深度测试。禁用深度测试后,使用此材质渲染的对象将始终显示在其他不透明对象的顶部。
- 示例
material { depthCulling : false }
- doubleSided
- Type:boolean
- Value:true or false,默认值为 false
- Description
- 支持在运行时切换双面渲染及其功能。
- 设置为 true 时,culling 将自动设置为 none
- 如果三角形是 back-facing 的,则三角形的法线被翻转为front-facing
- 当显式设置为 false 时,这允许在运行时切换双面性(double-sidedness)
- 设置为 true 时,culling 将自动设置为 none
- 支持在运行时切换双面渲染及其功能。
- 示例
material { doubleSided : true }
Lighting
- shadowMultiplier
- Type:boolean
- Value:true or false,默认值为 false
- Description
- 仅在 unlit 着色模型中可用。
- 如果启用此属性,则材质计算的最终颜色将乘以阴影因子(或 visibility)。
- 允许创建透明的阴影接收对象(例如AR中不可见的地平面)。
- 仅支持定向光源阴影。
- 示例
material { name : "Invisible shadow plane", shadingModel : unlit, shadowMultiplier : true, blending : transparent } fragment { void material(inout MaterialInputs material) { prepareMaterial(material); // baseColor defines the color and opacity of the final shadow material.baseColor = vec4(0.0, 0.0, 0.0, 0.7); } }
- transparentShadow
- Type:boolean
- Value:true or false,默认值为 false
- Description
- 在当前材质上启用透明阴影。启用此功能后,Filament 将使用抖动(dither)模式模拟透明阴影:
- 它们在启用 variance shadow maps(VSM) 和模糊(blurring)的情况下效果最佳。
- 阴影的不透明度直接来自材质的 baseColor 属性的 alpha 通道。
- 可以在不透明对象上启用透明阴影,使它们与原本被认为是不透明的折射/透射物体兼容。
- 在当前材质上启用透明阴影。启用此功能后,Filament 将使用抖动(dither)模式模拟透明阴影:
- 示例
material { name : "Clear plastic with stickers", transparentShadow : true, blending : transparent, // ... } fragment { void material(inout MaterialInputs material) { prepareMaterial(material); material.baseColor = texture(materialParams_baseColor, getUV0()); } }
- clearCoatIorChange
- Type:boolean
- Value:true or false,默认值为 true
- Description
- 添加 clear coat layer 时,将考虑折射率(IOR)的变化,以修改 base layer 的镜面反射颜色。
- 这会使 baseColor 变暗。禁用此效果后,不修改 baseColor。
- 示例
material { clearCoatIorChange : false }
- multiBounceAmbientOcclusion
- Type:boolean
- Value:true or false, 在移动设备上默认为 false,在桌面应用程序上为 true
- Description
- 将AO应用于 image-based lighting 时,Multi-bounce AO 会考虑相互反射(interreflection)。
- 开启此功能可避免过度变暗( over-darkening)的遮挡区域。它还考虑了物体表面的颜色以生成 colored ambient occlusion。
- 示例
material { multiBounceAmbientOcclusion : true }
- specularAmbientOcclusion
- Type:string
- Value:none, simple or bentNormals,
- 在移动设备上默认为 none
- 在桌面应用程序上默认为 simple 。
- 出于兼容性原因,可设置为 true 和 false,分别对应为 simple 和 none
- Description
- Static ambient occlusion maps 和 dynamic ambient occlusion (SSAO, etc.)适用于漫反射间接光照。
- 设置为 none 时,将从表面粗糙度(surface roughnes)派生一个新的 AO 项,并将其应用于镜面反射间接光照。该效果有助于消除不需要的镜面反射。
- 当设置为 simple 时,Filament 使用一种廉价但近似的方法来计算镜面反射环境 AO。
- 如果设置为 bentNormals,则 Filament 将使用更准确但更昂贵的方法
- 示例
material { specularAmbientOcclusion : simple }
Anti-aliasing
-
specularAntiAliasing
- Type:boolean
- Value:true or false, 默认为 false
- Description
- 减少镜面反射锯齿,并在对象离开相机时保留镜面反射高光的形状。
- 这种抗锯齿解决方案对 glossy 材质(低粗糙度)特别有效,但会增加材质渲染的成本。
- 可以使用另外两个属性来控制抗锯齿效果的强度:
- specularAntiAliasingVariance
- specularAntiAliasingThreshold。
- 示例
material { specularAntiAliasing : true }
-
specularAntiAliasingVariance
- Type:float
- Value:0.0 到 1.0 之间的值, 默认为 0.15
- Description
- 当应用 specular anti-aliasing 时, 设置 filter kernel 的屏幕空间变化。较高的值将增加滤波的效果,但可能会增加不需要滤波区域的粗糙程度。
- 示例
material { specularAntiAliasingVariance : 0.2 }
-
specularAntiAliasingThreshold
- Type:float
- Value:0.0 到 1.0 之间的值, 默认为 0.2
- Description
- 设置 clamping 阈值,用于在应用 specular anti-aliasing 抑制估计误差。设置为 0 时,将禁用 specular anti-aliasing。
- 示例
material { specularAntiAliasingThreshold : 0.1 }
Shading
- customSurfaceShading
- Type:bool
- Value:true or false, 默认为 false
- Description
- 设置为 true 时启用 custom surface shading。启用 surface shading 后,片元着色器必须提供一个额外的函数,该函数将为场景中可能影响当前片元的每个光源调用。详情在下面 Custom surface shading 小节
- 示例
material { customSurfaceShading : true }
Vertex block
- vertex block 是可选项,可用于控制材质的 vertex shading 阶段。vertex block 必须包含有效的 ESSL 3.0 代码(OpenGL ES 3.0 中支持的 GLSL 版本)。可以在 vertex block 内创建多个自定义函数,但必须要声明 materialVertex 函数:
- 示例
vertex { void materialVertex(inout MaterialVertexInputs material) { // vertex shading code } }
- 示例
- 该函数将在运行时由 shading system 自动调用,并使用 MaterialVertexInputs 结构体读取和修改材质属性。
- 可以使用 MaterialVertexInputs 结构体中的变量进行计算,也可以修改该结构体中变量的值。例如,下面 vertex blocks 设置为随时间推移修改顶点的颜色和 UV 坐标:
- 示例
material { requires : [uv0, color] } vertex { void materialVertex(inout MaterialVertexInputs material) { material.color *= sin(getUserTime().x); material.uv0 *= sin(getUserTime().x); } }
- 示例
- vertex shading code 还可以使用 Filament 列出的所有公共 API。(下节会总结 Filament 的API)
Material vertex inputs
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
// 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
};
- worldPosition
- 为了获得良好的精度,顶点着色器中的worldPosition坐标会根据摄影机位置进行移动。要获得真实的世界空间位置,可以将当前世界坐标加上getWorldOffset()。
- UV attributes
- 默认情况下,材质的顶点着色器将翻转当前网格的 UV 属性的 Y 坐标:material.uv0 = vec2(mesh_uv0.x, 1.0 - mesh_uv0.y)。可以使用 flipUV 属性并将其设置为 false 来控制翻转。
Fragment block
- fragment block 用于控制材质的 fragment shading 阶段。vertex block 必须包含有效的 ESSL 3.0 代码(OpenGL ES 3.0 中支持的 GLSL 版本)。可以在 fragment block 内创建多个自定义函数,但必须要声明 material 函数:
- 示例
fragment { void material(inout MaterialInputs material) { prepareMaterial(material); // fragment shading code } }
- 示例
- 该函数将在运行时由 shading system 自动调用,并使用 MaterialInputs 结构体读取和修改材质属性。
- 全局 material() 函数的目标是计算特定于所选着色模型的材质属性。例如,使用 standard lit shading model 创建有光泽的红色金属
fragment { void material(inout MaterialInputs material) { prepareMaterial(material); material.baseColor.rgb = vec3(1.0, 0.0, 0.0); material.metallic = 1.0; material.roughness = 0.0; } }
prepareMaterial function
-
注意,在退出 material() 函数之前,必须调用 prepareMaterial(material)。
- 设置材质模型的内部状态。Fragment APIs 小节中(下节总结)描述的某些 API(例如 shading_normal)只能在调用 prepareMaterial(material) 后才能访问。
-
注意,normal 属性仅在调用 prepareMaterial() 之前修改时才会有影响。
-
下面示例着色器正确修改了normal 属性,以实现具有凹凸贴图的光滑红色塑料。
fragment { void material(inout MaterialInputs material) { // fetch the normal in tangent space vec3 normal = texture(materialParams_normalMap, getUV0()).xyz; material.normal = normal * 2.0 - 1.0; // prepare the material prepareMaterial(material); // from now on, shading_normal, etc. can be accessed material.baseColor.rgb = vec3(1.0, 0.0, 0.0); material.metallic = 0.0; material.roughness = 1.0; } }
Material fragment inputs
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"
}
Custom surface shading
- 当 customSurfaceShading 在 material block 中设置为 true 时, fragment block 必须声明并实现 surfaceShading 函数
fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
// prepare material inputs
}
vec3 surfaceShading(
const MaterialInputs materialInputs,
const ShadingData shadingData,
const LightData lightData
) {
return vec3(1.0); // output of custom lighting
}
}
- 对于场景中可能影响当前片元的每个光源(定向光、点光源或spot ),将调用该函数。surfaceShading 有如下三个参数
- MaterialInputs
- ShadingData
- 保存利用 MaterialInputs 参数进行计算得到结果的结构体
- LightData
- 包含特定于当前光照计算使用参数的结构
- surfaceShading 函数必须以线性 sRGB 格式返回 RGB 颜色。Alpha 混合和 Alpha masking 在此函数之外处理,因此必须忽略。
- About shadowed fragments
- 即使已知片元完全处于当前光线的阴影中(lightData.NdotL <= 0.0 或 lightData.visibility < = 0.0),也会调用 surfaceShading 函数。这为 surfaceShading 功能提供了更大的灵活性,因为它提供了一种简单的方法来处理 constant ambient lighting。
- Shading models
- Custom surface shading 仅适用于 lit 模型。使用任何其他模型都会报错。
Shading data structure
struct ShadingData {
// The material's diffuse color, as derived from baseColor and metallic.
// This color is pre-multiplied by alpha and in the linear sRGB color space.
vec3 diffuseColor;
// The material's specular color, as derived from baseColor and metallic.
// This color is pre-multiplied by alpha and in the linear sRGB color space.
vec3 f0;
// The perceptual roughness is the roughness value set in MaterialInputs,
// with extra processing:
// - Clamped to safe values
// - Filtered if specularAntiAliasing is enabled
// This value is between 0.0 and 1.0.
float perceptualRoughness;
// The roughness value expected by BRDFs. This value is the square of
// perceptualRoughness. This value is between 0.0 and 1.0.
float roughness;
};
Light data structure
struct LightData {
// The color (.rgb) and pre-exposed intensity (.w) of the light.
// The color is an RGB value in the linear sRGB color space.
// The pre-exposed intensity is the intensity of the light multiplied by
// the camera's exposure value.
vec4 colorIntensity;
// The normalized light vector, in world space (direction from the
// current fragment's position to the light).
vec3 l;
// The dot product of the shading normal (with normal mapping applied)
// and the light vector. This value is equal to the result of
// saturate(dot(getWorldSpaceNormal(), lightData.l)).
// This value is always between 0.0 and 1.0. When the value is <= 0.0,
// the current fragment is not visible from the light and lighting
// computations can be skipped.
float NdotL;
// The position of the light in world space.
vec3 worldPosition;
// Attenuation of the light based on the distance from the current
// fragment to the light in world space. This value between 0.0 and 1.0
// is computed differently for each type of light (it's always 1.0 for
// directional lights).
float attenuation;
// Visibility factor computed from shadow maps or other occlusion data
// specific to the light being evaluated. This value is between 0.0 and
// 1.0.
float visibility;
};
总结
本节主要做一下材质格式规范相关的笔记。主要是学习.mat文件的编写方式。这部分是 Filament 材质系统的关键。该部分需要反复去看,是想深入了解 Filament 材质系统框架代码的基础。