1. Three.js 材质系统:类型对比与选择指南

1.1. 材质系统概览

材质类型总览.png

1.2. 详细材质对比表

基础材质对比.png

1.3. PBR材质对比

PBR材质对比.png

1.4. 风格化材质对比

风格化材质对比.png

1.5. 材质属性详细对比

1.5.1. 光照相关属性

光照相关属性.png

1.5.2. 纹理贴图支持

纹理贴图支持.png

1.5.3. 透明与混合

透明与混合.png

1.6. 材质选择决策指南

1.6.1. 决策流程图

javascript

class MaterialSelector {
  static selectMaterial(requirements) {
    const {
      needsLighting = true,
      needsReflections = false,
      performanceCritical = false,
      style = 'realistic',
      hasTextures = false,
      textureTypes = [],
      platform = 'desktop'
    } = requirements;

    // 决策逻辑
    if (!needsLighting) {
      return 'MeshBasicMaterial'; // 无光照需求
    }

    if (performanceCritical) {
      if (needsLighting && !needsReflections) {
        return 'MeshLambertMaterial'; // 性能优先
      }
      return 'MeshPhongMaterial'; // 平衡选择
    }

    if (style === 'cartoon') {
      return 'MeshToonMaterial'; // 卡通风格
    }

    if (style === 'matcap') {
      return 'MeshMatcapMaterial'; // 风格化
    }

    if (style === 'realistic') {
      if (platform === 'mobile' || performanceCritical) {
        return 'MeshStandardMaterial'; // 移动端或性能敏感
      }

      // 检查是否需要Physical的高级特性
      if (textureTypes.includes('clearcoat') || 
          textureTypes.includes('sheen') ||
          requirements.needsIridescence) {
        return 'MeshPhysicalMaterial'; // 需要高级PBR特性
      }

      return 'MeshStandardMaterial'; // 默认PBR
    }

    // 默认选择
    return 'MeshStandardMaterial';
  }

  // 示例使用
  static exampleSelections() {
    const scenarios = [
      {
        name: '移动端游戏',
        requirements: {
          needsLighting: true,
          performanceCritical: true,
          style: 'realistic',
          platform: 'mobile'
        },
        result: 'MeshStandardMaterial'
      },
      {
        name: '产品展示',
        requirements: {
          needsLighting: true,
          needsReflections: true,
          style: 'realistic',
          textureTypes: ['clearcoat', 'roughness'],
          platform: 'desktop'
        },
        result: 'MeshPhysicalMaterial'
      },
      {
        name: 'UI元素',
        requirements: {
          needsLighting: false,
          performanceCritical: true
        },
        result: 'MeshBasicMaterial'
      },
      {
        name: '卡通风格游戏',
        requirements: {
          needsLighting: true,
          style: 'cartoon',
          performanceCritical: false
        },
        result: 'MeshToonMaterial'
      }
    ];

    return scenarios;
  }
}

1.6.2. 常见场景推荐

常见场景推荐.png

1.6.3. 性能优化指南

javascript

class MaterialOptimizer {
  // 根据平台优化材质
  static optimizeForPlatform(material, platform) {
    const optimizedMaterial = material.clone();

    switch(platform) {
      case 'mobile':
        // 移动端优化
        optimizedMaterial.precision = 'mediump';
        optimizedMaterial.vertexColors = false;

        if (optimizedMaterial instanceof THREE.MeshStandardMaterial) {
          optimizedMaterial.envMapIntensity = 0.5;
          optimizedMaterial.roughness = 0.8; // 降低计算
        }
        break;

      case 'desktop':
        // 桌面端可以启用更多特性
        if (optimizedMaterial instanceof THREE.MeshPhysicalMaterial) {
          optimizedMaterial.clearcoat = 1.0;
          optimizedMaterial.clearcoatRoughness = 0.1;
        }
        break;

      case 'vr':
        // VR需要保持高帧率
        optimizedMaterial.precision = 'highp';
        optimizedMaterial.dithering = true; // 减少色带
        break;
    }

    return optimizedMaterial;
  }

  // 性能分级配置
  static getPerformanceProfile(level) {
    const profiles = {
      low: {
        material: 'MeshLambertMaterial',
        textures: {
          maxSize: 512,
          mipmaps: false,
          anisotropic: 1
        },
        shadows: false,
        antialias: false
      },
      medium: {
        material: 'MeshPhongMaterial',
        textures: {
          maxSize: 1024,
          mipmaps: true,
          anisotropic: 2
        },
        shadows: true,
        antialias: false
      },
      high: {
        material: 'MeshStandardMaterial',
        textures: {
          maxSize: 2048,
          mipmaps: true,
          anisotropic: 4
        },
        shadows: true,
        antialias: true
      },
      ultra: {
        material: 'MeshPhysicalMaterial',
        textures: {
          maxSize: 4096,
          mipmaps: true,
          anisotropic: 16
        },
        shadows: true,
        antialias: true,
        postprocessing: true
      }
    };

    return profiles[level] || profiles.medium;
  }
}

1.7. 材质实例与配置示例

javascript

const MaterialTemplates = {
  // 基础材质 - UI元素
  basicUI: new THREE.MeshBasicMaterial({
    color: 0xffffff,
    transparent: true,
    opacity: 0.9,
    side: THREE.DoubleSide
  }),

  // Lambert - 性能优先的3D物体
  lambertPerformance: new THREE.MeshLambertMaterial({
    color: 0x808080,
    emissive: 0x000000,
    emissiveIntensity: 0.5,
    flatShading: false  // 设为true可提升性能但质量降低
  }),

  // Phong - 塑料/光滑表面
  phongPlastic: new THREE.MeshPhongMaterial({
    color: 0xffffff,
    specular: 0x111111,
    shininess: 30,
    reflectivity: 0.5,
    combine: THREE.MixOperation
  }),

  // Standard - 通用PBR
  standardGeneric: new THREE.MeshStandardMaterial({
    color: 0xffffff,
    metalness: 0.0,     // 0=非金属, 1=金属
    roughness: 0.5,     // 0=光滑, 1=粗糙
    envMapIntensity: 1.0,
    aoMapIntensity: 1.0
  }),

  // Standard - 金属材质
  standardMetal: new THREE.MeshStandardMaterial({
    color: 0xcccccc,
    metalness: 0.9,
    roughness: 0.1,
    envMapIntensity: 2.0
  }),

  // Physical - 汽车漆
  physicalCarPaint: new THREE.MeshPhysicalMaterial({
    color: 0xff0000,
    metalness: 0.0,
    roughness: 0.1,
    clearcoat: 1.0,
    clearcoatRoughness: 0.0,
    sheen: 0.5,
    sheenColor: 0xff0000,
    sheenRoughness: 0.1
  }),

  // Physical - 清漆木材
  physicalVarnishedWood: new THREE.MeshPhysicalMaterial({
    color: 0x8b4513,
    metalness: 0.0,
    roughness: 0.7,
    clearcoat: 0.3,
    clearcoatRoughness: 0.2,
    anisotropy: 0.8,
    anisotropyRotation: Math.PI / 4
  }),

  // Toon - 卡通风格
  toonCartoon: new THREE.MeshToonMaterial({
    color: 0x00aaff,
    gradientMap: this.createGradientTexture(),
    shininess: 100,
    specular: 0x444444
  }),

  // Matcap - 风格化
  matcapStylized: new THREE.MeshMatcapMaterial({
    matcap: this.loadMatcapTexture('metal'),
    color: 0xffffff
  }),

  // 透明玻璃
  transparentGlass: new THREE.MeshPhysicalMaterial({
    color: 0xffffff,
    metalness: 0.0,
    roughness: 0.0,
    transmission: 0.9,      // 透光率
    thickness: 0.5,         // 玻璃厚度
    ior: 1.5,               // 折射率
    specularIntensity: 1.0,
    specularColor: 0xffffff
  })
};

1.7.1. 纹理配置最佳实践

javascript

class TextureConfiguration {
  // 根据材质类型配置纹理
  static configureTextures(material, textureConfig) {
    const {
      colorMap,
      normalMap,
      roughnessMap,
      metalnessMap,
      aoMap,
      emissiveMap,
      displacementMap
    } = textureConfig;

    // 公共纹理设置
    const applyTextureSettings = (texture) => {
      if (!texture) return;

      texture.wrapS = THREE.RepeatWrapping;
      texture.wrapT = THREE.RepeatWrapping;
      texture.anisotropy = 4; // 各向异性过滤
      texture.minFilter = THREE.LinearMipmapLinearFilter;
      texture.magFilter = THREE.LinearFilter;

      texture.needsUpdate = true;
    };

    // 应用纹理到材质
    if (colorMap) {
      material.map = colorMap;
      applyTextureSettings(colorMap);
    }

    if (normalMap && material.normalMap !== undefined) {
      material.normalMap = normalMap;
      material.normalScale = new THREE.Vector2(1, 1);
      applyTextureSettings(normalMap);
    }

    if (roughnessMap && material.roughnessMap !== undefined) {
      material.roughnessMap = roughnessMap;
      applyTextureSettings(roughnessMap);
    }

    if (metalnessMap && material.metalnessMap !== undefined) {
      material.metalnessMap = metalnessMap;
      applyTextureSettings(metalnessMap);
    }

    if (aoMap && material.aoMap !== undefined) {
      material.aoMap = aoMap;
      applyTextureSettings(aoMap);
    }

    if (emissiveMap && material.emissiveMap !== undefined) {
      material.emissiveMap = emissiveMap;
      material.emissiveIntensity = 1.0;
      applyTextureSettings(emissiveMap);
    }

    if (displacementMap && material.displacementMap !== undefined) {
      material.displacementMap = displacementMap;
      material.displacementScale = 0.1;
      applyTextureSettings(displacementMap);
    }

    return material;
  }

  // 纹理压缩建议
  static getTextureCompressionSettings(platform) {
    const settings = {
      desktop: {
        format: THREE.RGBAFormat,
        type: THREE.UnsignedByteType,
        compression: THREE.NoCompression,
        maxSize: 4096
      },
      mobile: {
        format: THREE.RGBAFormat,
        type: THREE.HalfFloatType,
        compression: THREE.CompressedTexture,
        maxSize: 2048
      },
      webgl1: {
        format: THREE.RGBFormat, // 减少内存
        type: THREE.UnsignedByteType,
        compression: THREE.NoCompression,
        maxSize: 1024
      }
    };

    return settings[platform] || settings.desktop;
  }
}

1.8. 性能与内存管理

1.8.1. 材质性能评分

材质性能评分.png

1.8.2. 材质池与重用

javascript

class MaterialPool {
  constructor() {
    this.pool = new Map();
    this.stats = {
      created: 0,
      reused: 0,
      active: 0
    };
  }

  // 获取或创建材质
  getMaterial(config) {
    const key = this.generateKey(config);

    if (this.pool.has(key)) {
      this.stats.reused++;
      return this.pool.get(key);
    }

    // 创建新材质
    const material = this.createMaterial(config);
    this.pool.set(key, material);
    this.stats.created++;
    this.stats.active++;

    return material;
  }

  // 生成材质配置的唯一键
  generateKey(config) {
    return JSON.stringify({
      type: config.type,
      color: config.color?.getHex(),
      map: config.map?.uuid,
      metalness: config.metalness,
      roughness: config.roughness,
      transparent: config.transparent
    });
  }

  // 创建材质实例
  createMaterial(config) {
    switch(config.type) {
      case 'basic':
        return new THREE.MeshBasicMaterial(config);
      case 'lambert':
        return new THREE.MeshLambertMaterial(config);
      case 'phong':
        return new THREE.MeshPhongMaterial(config);
      case 'standard':
        return new THREE.MeshStandardMaterial(config);
      case 'physical':
        return new THREE.MeshPhysicalMaterial(config);
      default:
        return new THREE.MeshStandardMaterial(config);
    }
  }

  // 清理未使用的材质
  cleanup(unusedTimeout = 60000) { // 60秒
    const now = Date.now();

    for (const [key, material] of this.pool.entries()) {
      if (material.userData.lastUsed && 
          now - material.userData.lastUsed > unusedTimeout) {

        material.dispose();
        this.pool.delete(key);
        this.stats.active--;
      }
    }
  }

  // 获取性能统计
  getStats() {
    return {
      ...this.stats,
      poolSize: this.pool.size,
      memoryEstimate: this.estimateMemoryUsage()
    };
  }

  estimateMemoryUsage() {
    let total = 0;
    for (const material of this.pool.values()) {
      // 粗略估算,实际会更复杂
      total += 1024; // 每个材质约1KB基础开销

      if (material.map) total += 1024 * 10; // 纹理额外开销
      if (material.normalMap) total += 1024 * 10;
      // 其他纹理...
    }

    return `${(total / 1024).toFixed(1)} KB`;
  }
}

1.9. 调试与问题排查

1.9.1. 常见材质问题与解决方案

常见材质问题与解决方案.png

1.10. 材质调试工具

javascript

class MaterialDebugger {
  constructor(mesh) {
    this.mesh = mesh;
    this.originalMaterial = mesh.material;
    this.debugModes = new Map();

    this.initDebugModes();
  }

  initDebugModes() {
    // 法线可视化
    this.debugModes.set('normal', new THREE.MeshNormalMaterial());

    // 线框模式
    this.debugModes.set('wireframe', new THREE.MeshBasicMaterial({
      wireframe: true,
      color: 0x00ff00
    }));

    // UV可视化
    this.debugModes.set('uv', new THREE.MeshBasicMaterial({
      map: this.createUVTexture(),
      side: THREE.DoubleSide
    }));

    // 深度可视化
    this.debugModes.set('depth', new THREE.MeshDepthMaterial());

    // 面索引可视化
    this.debugModes.set('face', this.createFaceIndexMaterial());
  }

  setDebugMode(mode) {
    if (mode === 'off') {
      this.mesh.material = this.originalMaterial;
    } else if (this.debugModes.has(mode)) {
      this.mesh.material = this.debugModes.get(mode);
    }
  }

  createUVTexture() {
    const canvas = document.createElement('canvas');
    canvas.width = 256;
    canvas.height = 256;
    const ctx = canvas.getContext('2d');

    // 绘制UV网格
    ctx.strokeStyle = '#ff0000';
    ctx.lineWidth = 2;

    for (let i = 0; i <= 10; i++) {
      const pos = i * 25.6;
      ctx.beginPath();
      ctx.moveTo(pos, 0);
      ctx.lineTo(pos, 256);
      ctx.stroke();

      ctx.beginPath();
      ctx.moveTo(0, pos);
      ctx.lineTo(256, pos);
      ctx.stroke();
    }

    const texture = new THREE.CanvasTexture(canvas);
    return texture;
  }

  // 分析材质性能
  analyzePerformance() {
    const material = this.mesh.material;
    const analysis = {
      type: material.type,
      textureCount: 0,
      shaderComplexity: 'low',
      memoryEstimate: 'unknown'
    };

    // 计算纹理数量
    const textureProperties = [
      'map', 'normalMap', 'roughnessMap', 'metalnessMap',
      'aoMap', 'emissiveMap', 'displacementMap', 'envMap'
    ];

    analysis.textureCount = textureProperties.filter(
      prop => material[prop]
    ).length;

    // 评估着色器复杂度
    if (material instanceof THREE.MeshBasicMaterial) {
      analysis.shaderComplexity = 'very low';
    } else if (material instanceof THREE.MeshLambertMaterial) {
      analysis.shaderComplexity = 'low';
    } else if (material instanceof THREE.MeshPhongMaterial) {
      analysis.shaderComplexity = 'medium';
    } else if (material instanceof THREE.MeshStandardMaterial) {
      analysis.shaderComplexity = 'high';
    } else if (material instanceof THREE.MeshPhysicalMaterial) {
      analysis.shaderComplexity = 'very high';
    }

    return analysis;
  }
}

1.11. 未来趋势与建议

1.11.1. 材质技术发展

材质技术发展.png

1.11.2.  项目中的材质策略

  1. 早期开发

  2. 中期优化

  3. 后期完善

  4. 维护阶段

1.11.3. 学习路径建议

  1. 初学者

  2. 中级开发者

  3. 高级开发者

这个综合指南应该能帮助你在不同场景下做出合适的材质选择。记住最重要的原则是:根据实际需求平衡视觉效果和性能开销