材质系统总览

    EffectAsset 是由用户书写的着色流程描述文件, 详细结构及书写指南可以参考.
    这里主要介绍引擎读取 EffectAsset 资源的流程:

    在编辑器导入 EffectAsset 时, 会对用户书写的内容做一次预处理, 替换 GL 字符串为管线内常量, 提取 shader 信息, 转换 shader 版本等.
    还以 builtin-unlit.effect 为例, 编译输出的 EffectAsset 结构大致是这样的:

    这里的信息量不小,但大多数时候这些细节都不需要普通开发者关心,重要的是:
    对任意目标平台,所有着色必要的基础信息已经全部都在这里提前准备好,以保证跨平台和最高的运行效率,
    同时在最后构建时会针对当前平台剔除所有冗余的信息,以保证最好的空间利用率。

    Material 资源可以看成是 EffectAsset 在场景中的资源实例, 它本身的可配置参数有:

    • effectAsset 或 effectName: effect 资源引用, 使用哪个 EffectAsset 所描述的流程进行渲染? (必备)
    • technique: 使用 EffectAsset 中的第几个 technique? (默认为 0 号)
    • defines: 宏定义列表, 需要开启哪些宏定义? (默认全部关闭)
    • states: 管线状态重载列表, 对渲染管线状态 (深度模板透明混合等) 有哪些重载? (默认与 effect 声明一致)
    1. effectName: 'pipeline/skybox',
    2. defines: { USE_RGBE_CUBEMAP: true }
    3. });

    有了这些信息后, Material 就可以被正确初始化(标志是生成渲染使用的 Pass 对象数组), 用于具体模型的渲染了.

    1. mat.setProperty('cubeMap', someCubeMap);

    这些属性都是在材质资源对象本身内部生效, 还并不涉及场景.

    Material 通过挂载到 RenderableComponent 上与场景连接, 所有需要设定材质的 Component (ModelComponent, SkinningModelComponent等) 都继承自它.

    根据子模型的数量, RenderableComponent 也可以引用多个 Material 资源:

    1. comp.setMaterial(mat, 1); // 赋给第二个 submodel

    同一个 Material 也可挂载到任意多个 RenderableComponent 上, 一般在编辑器中通过拖拽的方式即可自动赋值.
    而当场景中的某个模型的 Material 需要特化的设置, 会在从 RenderableComponent 获取 Material 时自动做拷贝实例化, 创建对应的 MaterialInstance,从而实现独立的定制.

    1. const comp2 = someNode2.getComponent(ModelComponent);
    2. const mat2 = comp2.material; // 拷贝实例化, mat2 是一个 MaterialInstance,接下来对 `mat2` 的修改只会影响 `comp2` 的模型

    Material 与 MaterialInstance 的最大区别在于,MaterialInstance 从开始就永久地挂载在唯一的 RenderableComponent 上,只会对这个模型生效,而 Material 则无此限制。

    特别地, 如果只是希望修改 defines 或 states, 我们提供更高效的直接设置接口, 只需提供相对当前值的重载即可:

    1. mat2.overridePipelineStates({ rasterizerState: { cullMode: GFXCullMode.NONE } });

    但注意,这些接口只能对 MaterialInstance 实例调用,而不能对 Material 资源调用。

    每帧动态更新 uniform 值是非常常见的需求, 在类似这种需要更高效接口的情景下, 可以手动调用对应 pass 的接口:

    1. const pass = mat2.passes[0];
    2. const hColor = pass.getHandle('albedo');
    3. const color = new Color('#dadada');
    4. // 每帧更新时:

    编辑器内置了几种常见类型的材质,无光照的 unlit、基于物理光照的 standard、skybox、粒子、sprite 等;
    这里列一下最常用的 standard 各项参数的意义和用法:

    MacroInfo
    USE_BATCHING是否启用动态合批?
    USE_SKINNING是否启用顶点蒙皮? 对蒙皮模型必须启用
    ANIMATION_BAKED是否使用预烘焙的蒙皮动画?
    ROUGHNESS_CHANNEL指定粗糙度的数据来源通道,默认为 r 通道
    METALLIC_CHANNEL指定金属度的数据来源通道,默认为 g 通道
    AO_CHANNEL指定 AO 的数据来源通道,默认为 b 通道
    HAS_SECOND_UV是否存在第二套 UV?
    ALBEDO_UV指定采样漫反射贴图使用的 uv,默认为第一套
    EMISSIVE_UV指定采样自发光贴图使用的 uv,默认为第一套
    ALPHA_TEST_CHANNEL指定透明测试的测试通道
    USE_VERTEX_COLOR如果启用,顶点色会与漫反射项相乘
    USE_ALPHA_TEST是否开启透明测试(镂空效果)?
    USE_ALBEDO_MAP是否使用漫反射贴图?
    USE_NORMAL_MAP是否使用法线贴图?
    USE_PBR_MAP是否使用 PBR 材质参数贴图?
    USE_EMISSIVE_MAP是否使用自发光贴图?