材质第三部分学习使用 Filament 进行材质制作的方法(.mat文件编写方法),这部分已经开始涉及材质框架了,需要重点掌握。本章还是以笔记为主。学习文档来源于官方文档:
材质定义的格式是一种松散地基于JSON的格式,称之为JSONish。在顶层,材质定义由 JSON 对象表示的3个不同块组成:
material {
// material properties
}
vertex {
// vertex shader, optional
}
fragment {
// fragment shader
}
最小可行材质的定义必须包含 material 和 fragment 块。vertex 块是可选项。
"key" : value
key : value
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 {
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 : [ skinning ]
flipUV : false
requires
Type:string 数组
Value:uv0, uv1, color, position, tangents
Description
示例如下
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
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
material {
vertexDomain : device
}
interpolation
material {
interpolation : flat
}
material {
blending : transparent
}
material {
postLightingBlending : add
}
material {
transparency : twoPassesOneSide
}
material {
blending : masked,
maskThreshold : 0.5
}
material {
refractionMode : cubemap,
}
material {
refractionMode : cubemap,
refractionType : thin,
}
material {
culling : none
}
material {
colorWrite : false
}
material {
depthWrite : false
}
material {
depthCulling : false
}
material {
doubleSided : true
}
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);
}
}
material {
name : "Clear plastic with stickers",
transparentShadow : true,
blending : transparent,
// ...
}
fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor = texture(materialParams_baseColor, getUV0());
}
}
material {
clearCoatIorChange : false
}
material {
multiBounceAmbientOcclusion : true
}
material {
specularAmbientOcclusion : simple
}
specularAntiAliasing
material {
specularAntiAliasing : true
}
specularAntiAliasingVariance
material {
specularAntiAliasingVariance : 0.2
}
specularAntiAliasingThreshold
material {
specularAntiAliasingThreshold : 0.1
}
material {
customSurfaceShading : true
}
vertex {
void materialVertex(inout MaterialVertexInputs material) {
// vertex shading code
}
}
material {
requires : [uv0, color]
}
vertex {
void materialVertex(inout MaterialVertexInputs material) {
material.color *= sin(getUserTime().x);
material.uv0 *= sin(getUserTime().x);
}
}
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
};
fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
// fragment shading code
}
}
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;
}
}
注意,在退出 material() 函数之前,必须调用 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;
}
}
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"
}
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
}
}
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;
};
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 材质系统框架代码的基础。