assignFinalMaterial method

void assignFinalMaterial(
  1. Object3D mesh
)

Assigns final material to a Mesh, Line, or Points instance. The instance already has a material (generated from the glTF material options alone) but reuse of the same glTF material may require multiple threejs materials to accomodate different primitive types, defines, etc. New materials will be created if necessary, and reused from a cache. @param {Object3D} mesh Mesh, Line, or Points instance.

Implementation

void assignFinalMaterial(Object3D mesh) {
  final geometry = mesh.geometry;
  Material material = mesh.material!;

  bool useVertexTangents = geometry?.attributes["tangent"] != null;
  bool useVertexColors = geometry?.attributes["color"] != null;
  bool useFlatShading = geometry?.attributes["normal"] == null;

  if (mesh is Points) {
    final cacheKey = 'PointsMaterial:${material.uuid}';

    PointsMaterial? pointsMaterial = cache.get(cacheKey);

    if (pointsMaterial == null) {
      pointsMaterial = PointsMaterial();
      pointsMaterial.copy(material);
      pointsMaterial.color.setFrom(material.color);
      pointsMaterial.map = material.map;
      pointsMaterial.sizeAttenuation = false; // glTF spec says points should be 1px

      cache.add(cacheKey, pointsMaterial);
    }

    material = pointsMaterial;
  }
  else if (mesh is Line) {
    final cacheKey = 'LineBasicMaterial:${material.uuid}';

    LineBasicMaterial? lineMaterial = cache.get(cacheKey);

    if (lineMaterial == null) {
      lineMaterial = LineBasicMaterial();
      lineMaterial.copy(material);
      lineMaterial.color.setFrom(material.color);

      cache.add(cacheKey, lineMaterial);
    }

    material = lineMaterial;
  }

  // Clone the material if it will be modified
  if (useVertexTangents || useVertexColors || useFlatShading) {
    String cacheKey = 'ClonedMaterial:${material.uuid}:';

    if (material.type == "GLTFSpecularGlossinessMaterial"){
      cacheKey += 'specular-glossiness:';
    }
    if (useVertexTangents) cacheKey += 'vertex-tangents:';
    if (useVertexColors) cacheKey += 'vertex-colors:';
    if (useFlatShading) cacheKey += 'flat-shading:';

    Material? cachedMaterial = cache.get(cacheKey);

    if (cachedMaterial == null) {
      cachedMaterial = material.clone();

      if (useVertexTangents) cachedMaterial.vertexTangents = true;
      if (useVertexColors) cachedMaterial.vertexColors = true;
      if (useFlatShading) cachedMaterial.flatShading = true;

      cache.add(cacheKey, cachedMaterial);

      associations[cachedMaterial] = associations[material];
    }

    material = cachedMaterial;
  }

  // workarounds for mesh and geometry

  if (material.aoMap != null &&
      geometry?.attributes["uv2"] == null &&
      geometry?.attributes["uv"] != null) {
    geometry?.setAttributeFromString('uv2', geometry.attributes["uv"]);
  }

  // https://github.com/mrdoob/three.js/issues/11438#issuecomment-507003995
  if (material.normalScale != null && !useVertexTangents) {
    material.normalScale!.y = -material.normalScale!.y;
  }

  if (material.clearcoatNormalScale != null && !useVertexTangents) {
    material.clearcoatNormalScale!.y = -material.clearcoatNormalScale!.y;
  }

  mesh.material = material;
}