第45节:分布式渲染:Web Workers多线程渲染优化 - 教程

第45节:分布式渲染:Web Workers多线程渲染优化

概述

随着Web应用复杂度的增加,单线程渲染已成为性能瓶颈。分布式渲染通过Web Workers将计算任务分发到多个线程,充分利用多核CPU优势,显著提升渲染性能。
在这里插入图片描述

分布式渲染架构:

主线程
任务调度器
几何处理Worker
物理计算Worker
光照计算Worker
后期处理Worker
顶点处理
几何变换
LOD计算
碰撞检测
物理模拟
约束求解
阴影计算
光照烘焙
全局光照
效果合成
色调映射
抗锯齿
结果收集器
最终渲染

核心原理

Web Workers通信模式

通信模式适用场景优点缺点
Transferable Objects大数据传输零拷贝,高性能数据所有权转移
SharedArrayBuffer多线程共享数据真正共享内存需要同步机制
MessageChannel双向通信灵活,支持多通道序列化开销
BroadcastChannel广播通信一对多通信所有Worker都能接收

任务分割策略

// 任务分割配置
class TaskScheduler {
static createRenderTasks(scene, camera, renderer, workerCount) {
const tasks = [];
const objects = scene.getVisibleObjects(camera);
const objectsPerWorker = Math.ceil(objects.length / workerCount);
for (let i = 0; i < workerCount; i++) {
const start = i * objectsPerWorker;
const end = Math.min(start + objectsPerWorker, objects.length);
const workerObjects = objects.slice(start, end);
tasks.push({
workerId: i,
objects: workerObjects,
camera: camera.clone(),
viewport: this.calculateViewport(i, workerCount),
dependencies: this.calculateDependencies(i, workerCount)
});
}
return tasks;
}
static calculateViewport(workerIndex, totalWorkers) {
const width = 1.0 / totalWorkers;
const x = workerIndex * width;
return { x, y: 0, width, height: 1.0 };
}
}

完整代码实现

分布式渲染系统


<script>
import { onMounted, onUnmounted, ref, reactive, computed } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Worker管理器
class WorkerManager {
  constructor() {
    this.workers = new Map();
    this.taskQueue = new Map();
    this.results = new Map();
    this.workerScripts = new Map();
    this.setupWorkerScripts();
  }
  setupWorkerScripts() {
    // 注册不同类型的Worker
    this.workerScripts.set('geometry', this.createGeometryWorkerScript());
    this.workerScripts.set('lighting', this.createLightingWorkerScript());
    this.workerScripts.set('physics', this.createPhysicsWorkerScript());
    this.workerScripts.set('postprocess', this.createPostProcessWorkerScript());
  }
  // 初始化Workers
  async initializeWorkers(count, types = ['geometry', 'lighting', 'physics', 'postprocess']) {
    this.terminateAllWorkers();
    const cpuCores = navigator.hardwareConcurrency || 4;
    const actualCount = count === 'auto' ? Math.min(cpuCores, types.length) : parseInt(count);
    for (let i = 0; i < actualCount; i++) {
      const workerType = types[i % types.length];
      const worker = await this.createWorker(workerType, i);
      this.workers.set(worker.id, worker);
    }
    return Array.from(this.workers.values());
  }
  // 创建Worker
  createWorker(type, id) {
    return new Promise((resolve) => {
      const blob = new Blob([this.workerScripts.get(type)], { type: 'application/javascript' });
      const workerUrl = URL.createObjectURL(blob);
      const worker = new Worker(workerUrl);
      worker.id = `worker_${type}_${id}`;
      worker.type = type;
      worker.status = 'idle';
      worker.tasksCompleted = 0;
      // 设置消息处理器
      worker.onmessage = (event) => {
        this.handleWorkerMessage(worker, event);
      };
      worker.onerror = (error) => {
        console.error(`Worker ${worker.id} 错误:`, error);
        worker.status = 'error';
      };
      resolve(worker);
    });
  }
  // 处理Worker消息
  handleWorkerMessage(worker, event) {
    const { type, taskId, result, error, performance } = event.data;
    switch (type) {
      case 'ready':
        worker.status = 'ready';
        break;
      case 'task_complete':
        worker.status = 'idle';
        worker.tasksCompleted++;
        this.results.set(taskId, result);
        this.taskQueue.delete(taskId);
        // 触发任务完成回调
        if (this.onTaskComplete) {
          this.onTaskComplete(taskId, result, performance);
        }
        break;
      case 'error':
        worker.status = 'error';
        console.error(`Worker ${worker.id} 任务错误:`, error);
        break;
    }
  }
  // 分配任务
  assignTask(workerId, task) {
    const worker = this.workers.get(workerId);
    if (!worker || worker.status !== 'idle') return false;
    worker.status = 'working';
    const taskId = this.generateTaskId();
    this.taskQueue.set(taskId, {
      workerId,
      task,
      startTime: performance.now()
    });
    // 使用Transferable Objects优化大数据传输
    const transferables = this.prepareTransferableObjects(task);
    worker.postMessage({
      type: 'execute_task',
      taskId,
      task
    }, transferables);
    return taskId;
  }
  // 准备可传输对象
  prepareTransferableObjects(task) {
    const transferables = [];
    if (task.geometryData && task.geometryData.vertices) {
      transferables.push(task.geometryData.vertices.buffer);
    }
    if (task.textureData) {
      transferables.push(task.textureData.buffer);
    }
    return transferables;
  }
  // 智能任务调度
  scheduleTask(task) {
    // 找到最适合的Worker
    const suitableWorkers = this.findSuitableWorkers(task.type);
    if (suitableWorkers.length === 0) return null;
    // 选择负载最低的Worker
    const bestWorker = suitableWorkers.reduce((prev, current) =>
      prev.load < current.load ? prev : current
    );
    return this.assignTask(bestWorker.id, task);
  }
  // 查找合适的Worker
  findSuitableWorkers(taskType) {
    return Array.from(this.workers.values()).filter(worker =>
      worker.status === 'idle' &&
      (worker.type === taskType || worker.type === 'general')
    );
  }
  generateTaskId() {
    return `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }
  // 终止所有Worker
  terminateAllWorkers() {
    for (const worker of this.workers.values()) {
      worker.terminate();
    }
    this.workers.clear();
    this.taskQueue.clear();
    this.results.clear();
  }
  // 创建Worker脚本
  createGeometryWorkerScript() {
    return `
      importScripts('https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js');
      let scene, camera;
      const geometries = new Map();
      self.onmessage = function(event) {
        const { type, taskId, task } = event.data;
        switch (type) {
          case 'execute_task':
            handleGeometryTask(taskId, task);
            break;
        }
      };
      function handleGeometryTask(taskId, task) {
        const startTime = performance.now();
        try {
          // 处理几何数据
          const result = processGeometryData(task.geometryData, task.operations);
          const processingTime = performance.now() - startTime;
          self.postMessage({
            type: 'task_complete',
            taskId,
            result,
            performance: {
              processingTime,
              memory: getMemoryUsage()
            }
          });
        } catch (error) {
          self.postMessage({
            type: 'error',
            taskId,
            error: error.message
          });
        }
      }
      function processGeometryData(geometryData, operations) {
        // 创建BufferGeometry
        const geometry = new THREE.BufferGeometry();
        if (geometryData.vertices) {
          const vertices = new Float32Array(geometryData.vertices);
          geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
        }
        if (geometryData.normals) {
          const normals = new Float32Array(geometryData.normals);
          geometry.setAttribute('normal', new THREE.BufferAttribute(normals, 3));
        }
        // 应用几何操作
        if (operations.transform) {
          applyTransform(geometry, operations.transform);
        }
        if (operations.lod) {
          applyLOD(geometry, operations.lod);
        }
        // 计算边界体积
        geometry.computeBoundingSphere();
        geometry.computeBoundingBox();
        return {
          geometry: serializeGeometry(geometry),
          bounds: {
            boundingSphere: geometry.boundingSphere,
            boundingBox: geometry.boundingBox
          }
        };
      }
      function serializeGeometry(geometry) {
        // 简化几何体序列化
        const attributes = {};
        for (const [name, attribute] of Object.entries(geometry.attributes)) {
          attributes[name] = {
            array: attribute.array,
            itemSize: attribute.itemSize,
            normalized: attribute.normalized
          };
        }
        return {
          attributes,
          index: geometry.index ? geometry.index.array : null
        };
      }
      function getMemoryUsage() {
        return performance.memory ? (performance.memory.usedJSHeapSize / 1048576).toFixed(1) : 0;
      }
      // 通知主线程Worker已就绪
      self.postMessage({ type: 'ready' });
    `;
  }
  createLightingWorkerScript() {
    return `
      // 光照计算Worker实现
      self.onmessage = function(event) {
        const { type, taskId, task } = event.data;
        if (type === 'execute_task') {
          handleLightingTask(taskId, task);
        }
      };
      function handleLightingTask(taskId, task) {
        // 光照计算逻辑
        const result = calculateLighting(task.sceneData, task.lights, task.materials);
        self.postMessage({
          type: 'task_complete',
          taskId,
          result
        });
      }
      function calculateLighting(sceneData, lights, materials) {
        // 简化光照计算
        return {
          lightingData: new Float32Array(sceneData.vertexCount * 3),
          shadows: new Uint8Array(sceneData.vertexCount)
        };
      }
    `;
  }
  createPhysicsWorkerScript() {
    return `
      // 物理计算Worker实现
      importScripts('https://cdn.jsdelivr.net/npm/ammo.js@1.0.0/builds/ammo.wasm.js');
      let physicsWorld;
      self.onmessage = async function(event) {
        const { type, taskId, task } = event.data;
        if (type === 'execute_task') {
          await handlePhysicsTask(taskId, task);
        }
      };
      async function handlePhysicsTask(taskId, task) {
        if (!physicsWorld) {
          await initPhysics();
        }
        // 物理模拟逻辑
        const result = simulatePhysics(task.bodies, task.constraints, task.deltaTime);
        self.postMessage({
          type: 'task_complete',
          taskId,
          result
        });
      }
      async function initPhysics() {
        // 初始化物理引擎
        // 简化实现
      }
    `;
  }
  createPostProcessWorkerScript() {
    return `
      // 后期处理Worker实现
      self.onmessage = function(event) {
        const { type, taskId, task } = event.data;
        if (type === 'execute_task') {
          handlePostProcessTask(taskId, task);
        }
      };
      function handlePostProcessTask(taskId, task) {
        const result = applyPostProcessing(
          task.imageData,
          task.effects,
          task.parameters
        );
        self.postMessage({
          type: 'task_complete',
          taskId,
          result
        }, [result.buffer]); // 传输结果缓冲区
      }
      function applyPostProcessing(imageData, effects, parameters) {
        // 后期处理效果应用
        const processedData = new Uint8ClampedArray(imageData.data);
        effects.forEach(effect => {
          switch (effect) {
            case 'bloom':
              applyBloom(processedData, parameters);
              break;
            case 'ssao':
              applySSAO(processedData, parameters);
              break;
            case 'colorGrading':
              applyColorGrading(processedData, parameters);
              break;
          }
        });
        return processedData;
      }
    `;
  }
}
// 分布式渲染器
class DistributedRenderer {
  constructor(mainRenderer, workerManager) {
    this.mainRenderer = mainRenderer;
    this.workerManager = workerManager;
    this.renderTasks = new Map();
    this.partialResults = new Map();
    this.setupWorkerCallbacks();
  }
  setupWorkerCallbacks() {
    this.workerManager.onTaskComplete = (taskId, result, performance) => {
      this.handleTaskResult(taskId, result, performance);
    };
  }
  // 分布式渲染
  async renderDistributed(scene, camera) {
    const startTime = performance.now();
    // 分割渲染任务
    const tasks = this.splitRenderTasks(scene, camera);
    const taskPromises = [];
    // 分配任务给Workers
    for (const task of tasks) {
      const taskId = this.workerManager.scheduleTask(task);
      if (taskId) {
        taskPromises.push(this.waitForTask(taskId));
      }
    }
    // 等待所有任务完成
    await Promise.all(taskPromises);
    // 合成最终结果
    const finalResult = this.composeResults();
    const renderTime = performance.now() - startTime;
    return { finalResult, renderTime, taskCount: tasks.length };
  }
  // 分割渲染任务
  splitRenderTasks(scene, camera) {
    const tasks = [];
    const visibleObjects = this.getVisibleObjects(scene, camera);
    const workerCount = this.workerManager.workers.size;
    // 基于空间分割任务
    if (this.taskStrategy === 'spatial') {
      const spatialTasks = this.createSpatialTasks(scene, camera, workerCount);
      tasks.push(...spatialTasks);
    }
    // 基于物体分割任务
    else if (this.taskStrategy === 'object') {
      const objectTasks = this.createObjectTasks(visibleObjects, workerCount);
      tasks.push(...objectTasks);
    }
    return tasks;
  }
  // 创建空间分割任务
  createSpatialTasks(scene, camera, workerCount) {
    const tasks = [];
    const frustum = new THREE.Frustum();
    const projectionMatrix = new THREE.Matrix4().multiplyMatrices(
      camera.projectionMatrix, camera.matrixWorldInverse
    );
    frustum.setFromProjectionMatrix(projectionMatrix);
    // 将视锥体分割为多个子区域
    for (let i = 0; i < workerCount; i++) {
      const subFrustum = this.createSubFrustum(frustum, i, workerCount);
      const taskObjects = this.getObjectsInFrustum(scene, subFrustum);
      tasks.push({
        type: 'render',
        workerType: 'geometry',
        objects: taskObjects,
        camera: this.cloneCamera(camera),
        viewport: this.calculateViewport(i, workerCount),
        frustum: subFrustum
      });
    }
    return tasks;
  }
  // 处理任务结果
  handleTaskResult(taskId, result, performance) {
    this.partialResults.set(taskId, result);
    // 记录性能数据
    this.performanceStats.push({
      taskId,
      workerId: this.workerManager.taskQueue.get(taskId)?.workerId,
      ...performance
    });
  }
  // 等待任务完成
  waitForTask(taskId) {
    return new Promise((resolve) => {
      const checkResult = () => {
        if (this.partialResults.has(taskId)) {
          resolve(this.partialResults.get(taskId));
        } else {
          setTimeout(checkResult, 1);
        }
      };
      checkResult();
    });
  }
  // 合成结果
  composeResults() {
    const finalCanvas = document.createElement('canvas');
    const context = finalCanvas.getContext('2d');
    finalCanvas.width = this.mainRenderer.domElement.width;
    finalCanvas.height = this.mainRenderer.domElement.height;
    // 合并所有部分渲染结果
    for (const [taskId, result] of this.partialResults) {
      if (result.imageData) {
        this.mergeImageData(context, result.imageData, result.viewport);
      }
    }
    this.partialResults.clear();
    return finalCanvas;
  }
  mergeImageData(context, imageData, viewport) {
    const tempCanvas = document.createElement('canvas');
    const tempContext = tempCanvas.getContext('2d');
    tempCanvas.width = imageData.width;
    tempCanvas.height = imageData.height;
    tempContext.putImageData(imageData, 0, 0);
    context.drawImage(
      tempCanvas,
      viewport.x * context.canvas.width,
      viewport.y * context.canvas.height,
      viewport.width * context.canvas.width,
      viewport.height * context.canvas.height
    );
  }
}
export default {
  name: 'DistributedRendering',
  setup() {
    // 响应式状态
    const mainCanvas = ref(null);
    const workerCount = ref('4');
    const taskStrategy = ref('spatial');
    const communicationMode = ref('transferable');
    const enableGeometryWorker = ref(true);
    const enableLightingWorker = ref(true);
    const enablePhysicsWorker = ref(false);
    const enablePostProcessingWorker = ref(false);
    const taskGranularity = ref(5);
    const dynamicLoadBalancing = ref(true);
    const balanceFrequency = ref(30);
    const loadThreshold = ref(80);
    const sceneComplexity = ref('medium');
    const renderMode = ref('multi');
    const showCommunicationMonitor = ref(false);
    // Worker状态
    const workerStatus = ref([]);
    const workersRunning = ref(false);
    // 性能统计
    const mainFPS = ref(0);
    const workerFPS = ref(0);
    const communicationOverhead = ref(0);
    const speedupRatio = ref(1);
    // 通信日志
    const communicationLogs = ref([]);
    // Three.js 和 Worker 对象
    let renderer, scene, camera, controls;
    let workerManager, distributedRenderer;
    let animationFrameId;
    let frameCount = 0;
    let lastFpsUpdate = 0;
    // 初始化
    const init = async () => {
      await initRenderer();
      initScene();
      await initWorkers();
      startAnimationLoop();
    };
    // 初始化渲染器
    const initRenderer = () => {
      renderer = new THREE.WebGLRenderer({
        canvas: mainCanvas.value,
        antialias: true,
        powerPreference: "high-performance"
      });
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    };
    // 初始化场景
    const initScene = () => {
      scene = new THREE.Scene();
      scene.background = new THREE.Color(0x1a1a2e);
      camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
      camera.position.set(0, 10, 20);
      controls = new OrbitControls(camera, renderer.domElement);
      controls.enableDamping = true;
      // 照明
      const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
      scene.add(ambientLight);
      const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
      directionalLight.position.set(50, 50, 25);
      scene.add(directionalLight);
      // 创建测试场景
      createTestScene();
    };
    // 初始化Workers
    const initWorkers = async () => {
      workerManager = new WorkerManager();
      const workerTypes = [];
      if (enableGeometryWorker.value) workerTypes.push('geometry');
      if (enableLightingWorker.value) workerTypes.push('lighting');
      if (enablePhysicsWorker.value) workerTypes.push('physics');
      if (enablePostProcessingWorker.value) workerTypes.push('postprocess');
      const workers = await workerManager.initializeWorkers(workerCount.value, workerTypes);
      // 初始化Worker状态监控
      updateWorkerStatus(workers);
      distributedRenderer = new DistributedRenderer(renderer, workerManager);
    };
    // 重新初始化Workers
    const reinitializeWorkers = async () => {
      await initWorkers();
    };
    // 创建测试场景
    const createTestScene = () => {
      // 创建地面
      const groundGeometry = new THREE.PlaneGeometry(50, 50);
      const groundMaterial = new THREE.MeshStandardMaterial({ color: 0x3a3a3a });
      const ground = new THREE.Mesh(groundGeometry, groundMaterial);
      ground.rotation.x = -Math.PI / 2;
      ground.receiveShadow = true;
      scene.add(ground);
      // 根据复杂度创建物体
      const objectCount = getObjectCount(sceneComplexity.value);
      for (let i = 0; i < objectCount; i++) {
        const object = createRandomObject();
        scene.add(object);
      }
    };
    // 获取物体数量
    const getObjectCount = (complexity) => {
      const counts = {
        low: 1000,
        medium: 10000,
        high: 100000
      };
      return counts[complexity] || 1000;
    };
    // 创建随机物体
    const createRandomObject = () => {
      const geometries = [
        () => new THREE.BoxGeometry(1, 1, 1),
        () => new THREE.SphereGeometry(0.5, 8, 6),
        () => new THREE.ConeGeometry(0.5, 1, 8)
      ];
      const geometry = geometries[Math.floor(Math.random() * geometries.length)]();
      const material = new THREE.MeshStandardMaterial({
        color: new THREE.Color().setHSL(Math.random(), 0.7, 0.5)
      });
      const mesh = new THREE.Mesh(geometry, material);
      mesh.position.set(
        (Math.random() - 0.5) * 40,
        Math.random() * 10 + 1,
        (Math.random() - 0.5) * 40
      );
      mesh.rotation.set(
        Math.random() * Math.PI,
        Math.random() * Math.PI,
        Math.random() * Math.PI
      );
      mesh.castShadow = true;
      return mesh;
    };
    // 更新Worker状态
    const updateWorkerStatus = (workers) => {
      workerStatus.value = workers.map(worker => ({
        id: worker.id,
        name: worker.id,
        status: worker.status,
        indicator: getStatusIndicator(worker.status),
        tasksCompleted: worker.tasksCompleted,
        memory: (Math.random() * 50 + 10).toFixed(1), // 模拟内存使用
        load: Math.floor(Math.random() * 100) // 模拟负载
      }));
    };
    // 获取状态指示器
    const getStatusIndicator = (status) => {
      const indicators = {
        ready: '',
        working: '',
        idle: '⚪',
        error: ''
      };
      return indicators[status] || '⚪';
    };
    // 启动Workers
    const startWorkers = () => {
      workersRunning.value = true;
      // 实际实现中会开始分配任务
    };
    // 停止Workers
    const stopWorkers = () => {
      workersRunning.value = false;
      workerManager.terminateAllWorkers();
    };
    // 重置场景
    const resetScene = () => {
      // 清理场景并重新创建
      while (scene.children.length > 0) {
        const child = scene.children[0];
        if (child.isMesh) {
          child.geometry.dispose();
          child.material.dispose();
        }
        scene.remove(child);
      }
      createTestScene();
    };
    // 切换渲染模式
    const toggleRenderMode = () => {
      // 实现渲染模式切换逻辑
    };
    // 更新场景
    const updateScene = () => {
      resetScene();
    };
    // 动画循环
    const startAnimationLoop = () => {
      const animate = () => {
        animationFrameId = requestAnimationFrame(animate);
        // 更新控制
        controls.update();
        // 性能统计
        updatePerformanceStats();
        // 渲染
        if (renderMode.value === 'multi' && workersRunning.value) {
          // 分布式渲染
          renderDistributed();
        } else {
          // 单线程渲染
          renderer.render(scene, camera);
        }
      };
      animate();
    };
    // 分布式渲染
    const renderDistributed = async () => {
      const result = await distributedRenderer.renderDistributed(scene, camera);
      // 使用Worker渲染结果
      if (result.finalResult) {
        const context = renderer.getContext();
        context.drawImage(result.finalResult, 0, 0);
      }
    };
    // 更新性能统计
    const updatePerformanceStats = () => {
      frameCount++;
      const now = performance.now();
      if (now - lastFpsUpdate >= 1000) {
        mainFPS.value = Math.round((frameCount * 1000) / (now - lastFpsUpdate));
        frameCount = 0;
        lastFpsUpdate = now;
      }
      // 模拟Worker性能数据
      workerFPS.value = Math.round(mainFPS.value * 0.8 + Math.random() * 10);
      communicationOverhead.value = (Math.random() * 2).toFixed(1);
      speedupRatio.value = (workerFPS.value / mainFPS.value).toFixed(1);
    };
    onMounted(() => {
      init();
      window.addEventListener('resize', handleResize);
    });
    onUnmounted(() => {
      if (animationFrameId) {
        cancelAnimationFrame(animationFrameId);
      }
      if (workerManager) {
        workerManager.terminateAllWorkers();
      }
      if (renderer) {
        renderer.dispose();
      }
      window.removeEventListener('resize', handleResize);
    });
    const handleResize = () => {
      if (!camera || !renderer) return;
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
posted @ 2025-12-17 19:34  clnchanpin  阅读(53)  评论(0)    收藏  举报