Google Filament 源码学习(四):Material System (三) - 材质格式 (mat)

目录

  • Filament Materials Guide
    • Introduction
  • Material definitions
    • Format (材质定义的格式)
      • Differences with JSON
      • Example
    • Material block
      • General
      • Vertex and attributes
      • Blending and transparency
      • Rasterization
      • Lighting
      • Anti-aliasing
      • Shading
    • Vertex block
      • Material vertex inputs
      • Fragment block
        • prepareMaterial function
      • Material fragment inputs
      • Custom surface shading
        • Shading data structure
        • Light data structure
  • 总结

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;
          }
      }
      
  • 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 阴影且对象是阴影接收者时使用
    • 示例
      • 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.0y
      • 设置为 false 时,将禁用翻转,并按原样读取 UV
      • flipUV : false
  • 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 部分。
    • 示例如下

      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);
          }
      }
      
  • vertexDomain

    • Type:string
    • Value:object, world, view, device. 默认为 object
    • Description
      • 定义渲染网格的域 [domain (或坐标空间)]。域会影响顶点着色器中顶点的变换方式。可能的域包括:
        • Object
          • 顶点在对象(或模型)坐标空间-(局部坐标系)中定义。顶点使用渲染对象的变换矩阵进行变换
        • World
          • 顶点在世界坐标空间中定义。顶点不会使用渲染对象的变换矩阵进行变换。
        • View
          • 顶点在视图(或眼睛、或相机)坐标空间中定义。顶点不会使用渲染对象的变换矩阵进行变换。
        • Device
          • 顶点在 normalized device(或 clip)坐标空间中定义。顶点不会使用渲染对象的变换矩阵进行变换。
      • 示例
        material {
            vertexDomain : device
        }
        
  • 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 部分。
    • 实例
      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 相乘,并将结果添加到材质的计算颜色中。
      • 示例
        material {
            postLightingBlending : add
        }
        
  • 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组合使用,可以获得更好的效果。
      • 示例
        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,
        }
        
  • refractionType
    • Type:string
    • Value:solid, thin,默认为 solid
    • Description
      • 当设置为除了 none 之外的值时才有效。refractionType 定义所使用的折射模型。
        • solid 用于实心物体,如水晶球,冰块或雕塑。
          • 在 solid 模式下,所有折射对象都假定是与入射点相切,并且半径为 thickness 的球体。
        • thin 用于薄物体,如窗户,装饰球或肥皂泡。
          • 在 thin 模式下,假定所有折射物体都是 flat (平坦)、 thin 的,并且厚度为 thickness。
    • 示例
      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)
    • 示例
      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 通道。
        • 可以在不透明对象上启用透明阴影,使它们与原本被认为是不透明的折射/透射物体兼容。
    • 示例
      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 材质系统框架代码的基础。

你可能感兴趣的:(Filament,学习,材质)