materialExtensionsFromJson function
The layers extensions names — a glTF material's own extensions
object, or the same shape in a .fmat or a .f3d — or null when it names
none of MaterialExtensions.gltfNames.
One reader for three formats, each passing its own texture: a glTF
texture info, a .fmat slot, a .f3d binding record. Only that differs;
the numbers, their names and their defaults are the extension's, so they
are spelled out once.
Textures the renderer does not draw are reported through warnings,
once each, with where naming the material.
Implementation
MaterialExtensions? materialExtensionsFromJson(
Map<String, Object?> extensions, {
required TextureBinding? Function(Object? info) texture,
List<String>? warnings,
String where = 'a material',
}) {
Map<String, Object?>? object(String name) => switch (extensions[name]) {
final Map<Object?, Object?> map => map.cast<String, Object?>(),
_ => null,
};
final ior = object('KHR_materials_ior');
final specular = object('KHR_materials_specular');
final clearcoat = object('KHR_materials_clearcoat');
final sheen = object('KHR_materials_sheen');
final anisotropy = object('KHR_materials_anisotropy');
final transmission = object('KHR_materials_transmission');
final volume = object('KHR_materials_volume');
final dispersion = object('KHR_materials_dispersion');
final iridescence = object('KHR_materials_iridescence');
if (ior == null &&
specular == null &&
clearcoat == null &&
sheen == null &&
anisotropy == null &&
transmission == null &&
volume == null &&
dispersion == null &&
iridescence == null) {
return null;
}
final read = MaterialExtensions(
ior: _number(ior?['ior'], 1.5),
specular: _number(specular?['specularFactor'], 1.0),
specularTexture: texture(specular?['specularTexture']),
specularColor: _vec3(specular?['specularColorFactor']),
specularColorTexture: texture(specular?['specularColorTexture']),
clearcoat: _number(clearcoat?['clearcoatFactor'], 0.0),
clearcoatTexture: texture(clearcoat?['clearcoatTexture']),
clearcoatRoughness: _number(clearcoat?['clearcoatRoughnessFactor'], 0.0),
clearcoatRoughnessTexture: texture(clearcoat?['clearcoatRoughnessTexture']),
clearcoatNormalTexture: texture(clearcoat?['clearcoatNormalTexture']),
clearcoatNormalScale: switch (clearcoat?['clearcoatNormalTexture']) {
{'scale': final num scale} => scale.toDouble(),
_ => 1.0,
},
sheenColor: switch (sheen?['sheenColorFactor']) {
final Object colour => _vec3(colour),
null => null,
},
sheenColorTexture: texture(sheen?['sheenColorTexture']),
sheenRoughness: _number(sheen?['sheenRoughnessFactor'], 0.0),
sheenRoughnessTexture: texture(sheen?['sheenRoughnessTexture']),
anisotropyStrength: _number(anisotropy?['anisotropyStrength'], 0.0),
anisotropyRotation: _number(anisotropy?['anisotropyRotation'], 0.0),
anisotropyTexture: texture(anisotropy?['anisotropyTexture']),
transmission: _number(transmission?['transmissionFactor'], 0.0),
transmissionTexture: texture(transmission?['transmissionTexture']),
thickness: _number(volume?['thicknessFactor'], 0.0),
thicknessTexture: texture(volume?['thicknessTexture']),
attenuationDistance: _number(
volume?['attenuationDistance'],
double.infinity,
),
attenuationColor: switch (volume?['attenuationColor']) {
final Object colour => _vec3(colour),
null => null,
},
dispersion: _number(dispersion?['dispersion'], 0.0),
iridescence: _number(iridescence?['iridescenceFactor'], 0.0),
iridescenceTexture: texture(iridescence?['iridescenceTexture']),
iridescenceIor: _number(iridescence?['iridescenceIor'], 1.3),
iridescenceThicknessMinimum: _number(
iridescence?['iridescenceThicknessMinimum'],
100.0,
),
iridescenceThicknessMaximum: _number(
iridescence?['iridescenceThicknessMaximum'],
400.0,
),
iridescenceThicknessTexture: texture(
iridescence?['iridescenceThicknessTexture'],
),
);
// The plan for 0.8: two packed maps and no more samplers, so these three
// are carried and not drawn. Said once per material rather than silently.
if (read.specularTexture != null || read.specularColorTexture != null) {
warnings?.add(
'$where: KHR_materials_specular\'s textures are kept for export and '
'not drawn; only its factors shade the surface.',
);
}
if (read.anisotropyTexture != null) {
warnings?.add(
'$where: KHR_materials_anisotropy\'s texture is kept for export and '
'not drawn; its strength and rotation shade the surface.',
);
}
if (read.iridescenceTexture != null ||
read.iridescenceThicknessTexture != null) {
warnings?.add(
'$where: KHR_materials_iridescence\'s textures are kept for export and '
'not drawn; the film is its factor strong and its maximum thick.',
);
}
if (read.clearcoatNormalTexture != null) {
warnings?.add(
'$where: the clear coat\'s normal map is kept for export and not '
'drawn; the coat is lit on the geometric normal.',
);
}
return read;
}