1. 纹理与几何体优化指南

1.1. 纹理优化策略

1.1.1. 纹理尺寸优化

javascript

// 使用合适尺寸的纹理
const textureLoader = new THREE.TextureLoader();
// 避免超大纹理 (4096x4096以上需谨慎)
const texture = textureLoader.load('texture.jpg', (tex) => {
    tex.needsUpdate = true;
    // 自动生成mipmaps
    tex.generateMipmaps = true;
    // 设置合适的过滤方式
    tex.minFilter = THREE.LinearMipmapLinearFilter;
    tex.magFilter = THREE.LinearFilter;
});

1.1.2. 纹理格式选择

javascript

// 根据需求选择格式
// WebP/AVIF - 现代浏览器,高压缩比
// JPEG - 照片类纹理
// PNG - 需要透明度
// Basis Universal - 跨平台压缩纹理

// 使用压缩纹理
const ktxLoader = new THREE.KTX2Loader();
ktxLoader.load('texture.ktx2', (texture) => {
    material.map = texture;
});

// 或使用Basis纹理
const basisLoader = new THREE.BasisTextureLoader();
basisLoader.load('texture.basis', (texture) => {
    material.map = texture;
});

1.1.3. 纹理图集(Atlas)

javascript

// 合并多个小纹理为一个大纹理
const atlasTexture = new THREE.TextureLoader().load('atlas.png');
// 在shader或UV坐标中定位子纹理
const material = new THREE.ShaderMaterial({
    uniforms: {
        atlas: { value: atlasTexture },
        uvOffset: { value: new THREE.Vector2(0, 0) },
        uvScale: { value: new THREE.Vector2(0.25, 0.25) }
    },
    vertexShader: `
        varying vec2 vUv;
        void main() {
            vUv = uv;
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        }
    `,
    fragmentShader: `
        uniform sampler2D atlas;
        uniform vec2 uvOffset;
        uniform vec2 uvScale;
        varying vec2 vUv;
        void main() {
            vec2 atlasUv = uvOffset + vUv * uvScale;
            gl_FragColor = texture2D(atlas, atlasUv);
        }
    `
});

1.1.4. Mipmapping与各向异性过滤

javascript

// 启用各向异性过滤(提升斜角纹理质量)
texture.anisotropy = renderer.capabilities.getMaxAnisotropy();

// Mipmapping设置
texture.minFilter = THREE.LinearMipmapLinearFilter; // 质量最好
texture.magFilter = THREE.LinearFilter;

1.2. 几何体优化策略

1.2.1. 顶点数优化

javascript

// 使用BufferGeometry代替Geometry
const geometry = new THREE.BufferGeometry();

// 合并几何体减少draw calls
const geometries = [geom1, geom2, geom3];
const mergedGeometry = THREE.BufferGeometryUtils.mergeBufferGeometries(geometries);

// 使用LOD(细节层次)
const lod = new THREE.LOD();
const highDetail = new THREE.Mesh(highDetailGeometry, material);
const lowDetail = new THREE.Mesh(lowDetailGeometry, material);

lod.addLevel(highDetail, 0);
lod.addLevel(lowDetail, 50); // 50单位距离切换
scene.add(lod);

1.2.2. 索引化几何体

javascript

// 使用索引减少重复顶点
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([...]);
const indices = new Uint16Array([...]); // 或Uint32Array

geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
geometry.setIndex(new THREE.BufferAttribute(indices, 1));

// 计算法线(如果需要)
geometry.computeVertexNormals();

1.2.3. 实例化渲染

javascript

// 大量相同几何体使用实例化
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const instanceCount = 1000;
const mesh = new THREE.InstancedMesh(geometry, material, instanceCount);

// 设置每个实例的变换矩阵
const matrix = new THREE.Matrix4();
for (let i = 0; i < instanceCount; i++) {
    matrix.setPosition(
        Math.random() * 100 - 50,
        Math.random() * 100 - 50,
        Math.random() * 100 - 50
    );
    mesh.setMatrixAt(i, matrix);
}
mesh.instanceMatrix.needsUpdate = true;

1.2.4. 几何体简化

javascript

// 使用简化算法减少面数
import { SimplifyModifier } from 'three/examples/jsm/modifiers/SimplifyModifier';

const modifier = new SimplifyModifier();
const simplifiedGeometry = modifier.modify(originalGeometry, count); // 目标面数

1.3. 内存与性能优化

1.4. 纹理内存管理

javascript

// 纹理回收
function disposeTexture(texture) {
    texture.dispose();
    texture.image = null;
}

// 按需加载/卸载纹理
class TextureManager {
    constructor() {
        this.cache = new Map();
        this.maxCacheSize = 10;
    }

    loadTexture(url) {
        if (this.cache.has(url)) {
            return this.cache.get(url);
        }

        const texture = new THREE.TextureLoader().load(url);
        this.cache.set(url, texture);

        // LRU缓存清理
        if (this.cache.size > this.maxCacheSize) {
            const firstKey = this.cache.keys().next().value;
            this.cache.get(firstKey).dispose();
            this.cache.delete(firstKey);
        }

        return texture;
    }
}

1.4.1. 几何体内存管理

javascript

// 清理几何体
function disposeGeometry(geometry) {
    geometry.dispose();
    geometry.attributes = null;
    geometry.index = null;
}

// 使用BufferGeometry池
class GeometryPool {
    constructor() {
        this.pool = new Map();
    }

    getGeometry(type, params) {
        const key = `${type}_${JSON.stringify(params)}`;
        if (!this.pool.has(key)) {
            this.pool.set(key, this.createGeometry(type, params));
        }
        return this.pool.get(key).clone();
    }
}

1.4.2. GPU内存优化

javascript

// 使用压缩纹理格式
renderer.textureFormat = THREE.RGBFormat; // 或RGBAFormat
renderer.textureEncoding = THREE.sRGBEncoding;

// 调整纹理精度
renderer.precision = 'mediump'; // 或 'highp'

// 使用顶点压缩
const packedGeometry = new THREE.BufferGeometry();
// 使用半浮点数存储位置
const positions = new Uint16Array(vertexCount * 3);
// 使用8位无符号整数存储颜色/法线
const colors = new Uint8Array(vertexCount * 3);

1.5. 实用工具与库

1.5.1. 性能监控

javascript

import Stats from 'three/examples/jsm/libs/stats.module';

const stats = new Stats();
document.body.appendChild(stats.dom);

function animate() {
    stats.begin();
    // 渲染场景
    stats.end();
    requestAnimationFrame(animate);
}

1.5.2. 纹理工具

javascript

// 纹理大小检查
function checkTextureSize(texture, maxSize = 2048) {
    if (texture.image) {
        const width = texture.image.width || texture.image.videoWidth;
        const height = texture.image.height || texture.image.videoHeight;

        if (width > maxSize || height > maxSize) {
            console.warn(`Texture too large: ${width}x${height}`);
            return false;
        }
    }
    return true;
}

// 纹理自动降级
function loadAdaptiveTexture(url, quality = 'high') {
    const suffixes = {
        high: '',
        medium: '_medium',
        low: '_low'
    };
    const suffix = suffixes[quality] || '';
    const adaptedUrl = url.replace(/(\.\w+)$/, `${suffix}$1`);

    return new Promise((resolve, reject) => {
        new THREE.TextureLoader().load(adaptedUrl, resolve, undefined, reject);
    });
}

1.6. 最佳实践总结

  1. 纹理方面

  2. 几何体方面

  3. 内存管理

  4. 性能调优

通过实施这些优化策略,可以显著提升Three.js应用的性能,特别是在处理复杂场景和大量对象时。