第42节:自定义渲染管线:修改Three.js默认流程

第42节:自定义渲染管线:修改Three.js默认流程

概述

Three.js默认的渲染流程虽然强大,但在某些高级应用场景下可能无法满足需求。本节将深入探讨如何自定义渲染管线,覆盖内置着色器、修改渲染顺序,实现完全可控的渲染流程。

自定义渲染管线架构:

核心原理

渲染管线阶段

阶段 默认行为 自定义能力
场景遍历 自动排序和批处理 自定义遍历顺序
着色器编译 自动生成着色器代码 替换或修改着色器
渲染状态 自动状态管理 手动状态控制
后期处理 可选后处理通道 完全自定义后处理链

着色器修改技术

// 着色器替换策略
class ShaderReplacement {
    static replaceMaterialShaders(originalMaterial, customShader) {
        // 保存原始着色器
        originalMaterial.userData.originalShader = {
            vertexShader: originalMaterial.vertexShader,
            fragmentShader: originalMaterial.fragmentShader,
            uniforms: THREE.UniformsUtils.clone(originalMaterial.uniforms)
        };
        
        // 应用自定义着色器
        originalMaterial.vertexShader = customShader.vertexShader;
        originalMaterial.fragmentShader = customShader.fragmentShader;
        originalMaterial.needsUpdate = true;
    }
    
    static restoreMaterialShaders(material) {
        if (material.userData.originalShader) {
            material.vertexShader = material.userData.originalShader.vertexShader;
            material.fragmentShader = material.userData.originalShader.fragmentShader;
            material.uniforms = material.userData.originalShader.uniforms;
            material.needsUpdate = true;
        }
    }
}

完整代码实现

自定义渲染器系统

<template>
  <div class="custom-renderer-container">
    <!-- 渲染视图 -->
    <div class="render-view">
      <canvas ref="renderCanvas" class="render-canvas"></canvas>
      
      <!-- 调试信息 -->
      <div class="debug-info">
        <div class="info-item">
          <span>渲染模式:</span>
          <span>{{ currentRenderMode }}</span>
        </div>
        <div class="info-item">
          <span>绘制调用:</span>
          <span>{{ drawCalls }}</span>
        </div>
        <div class="info-item">
          <span>三角形数量:</span>
          <span>{{ triangleCount.toLocaleString() }}</span>
        </div>
        <div class="info-item">
          <span>帧率:</span>
          <span>{{ fps }} FPS</span>
        </div>
      </div>
    </div>

    <!-- 控制面板 -->
    <div class="control-panel">
      <div class="panel-section">
        <h3>🎨 渲染模式</h3>
        <div class="mode-buttons">
          <button v-for="mode in renderModes" 
                  :key="mode.id"
                  :class="{ active: renderMode === mode.id }"
                  @click="setRenderMode(mode.id)"
                  class="mode-button">
            {{ mode.name }}
          </button>
        </div>
      </div>

      <div class="panel-section">
        <h3>⚙️ 着色器控制</h3>
        <div class="shader-controls">
          <div class="control-group">
            <label>顶点着色器修改</label>
            <select v-model="vertexModification">
              <option value="none">无修改</option>
              <option value="wave">波浪效果</option>
              <option value="displacement">顶点位移</option>
              <option value="morph">形变动画</option>
            </select>
          </div>
          
          <div class="control-group">
            <label>片段着色器修改</label>
            <select v-model="fragmentModification">
              <option value="none">无修改</option>
              <option value="outline">轮廓描边</option>
              <option value="toon">卡通渲染</option>
              <option value="poster">海报化</option>
            </select>
          </div>
          
          <div class="control-group">
            <label>自定义Uniforms</label>
            <div class="uniform-controls">
              <div class="uniform-item">
                <span>时间:</span>
                <input type="range" v-model="timeUniform" min="0" max="10" step="0.1">
              </div>
              <div class="uniform-item">
                <span>强度:</span>
                <input type="range" v-model="intensityUniform" min="0" max="2" step="0.1">
              </div>
            </div>
          </div>
        </div>
      </div>

      <div class="panel-section">
        <h3>🔧 渲染设置</h3>
        <div class="render-settings">
          <div class="setting-group">
            <label>
              <input type="checkbox" v-model="enableCustomSorting">
              自定义渲染排序
            </label>
          </div>
          
          <div class="setting-group">
            <label>
              <input type="checkbox" v-model="enableMultiPass">
              多通道渲染
            </label>
          </div>
          
          <div class="setting-group">
            <label>渲染顺序</label>
            <select v-model="renderOrder">
              <option value="frontToBack">前到后</option>
              <option value="backToFront">后到前</option>
              <option value="material">按材质</option>
            </select>
          </div>
        </div>
      </div>

      <div class="panel-section">
        <h3>📊 性能监控</h3>
        <div class="performance-stats">
          <div class="stat-item">
            <span>编译着色器:</span>
            <span>{{ ***piledShaders }}</span>
          </div>
          <div class="stat-item">
            <span>渲染时间:</span>
            <span>{{ renderTime }}ms</span>
          </div>
          <div class="stat-item">
            <span>GPU内存:</span>
            <span>{{ gpuMemory }} MB</span>
          </div>
        </div>
      </div>
    </div>

    <!-- 着色器编辑器 -->
    <div v-if="showShaderEditor" class="shader-editor-modal">
      <div class="editor-content">
        <div class="editor-header">
          <h3>着色器编辑器</h3>
          <button @click="showShaderEditor = false" class="close-button">×</button>
        </div>
        <div class="editor-body">
          <div class="editor-tabs">
            <button :class="{ active: activeShaderTab === 'vertex' }" 
                    @click="activeShaderTab = 'vertex'">
              顶点着色器
            </button>
            <button :class="{ active: activeShaderTab === 'fragment' }" 
                    @click="activeShaderTab = 'fragment'">
              片段着色器
            </button>
          </div>
          <textarea v-model="shaderCode[activeShaderTab]" 
                    class="shader-textarea"
                    spellcheck="false"></textarea>
          <div class="editor-actions">
            <button @click="applyShaderCode" class="action-button">应用修改</button>
            <button @click="resetShaderCode" class="action-button secondary">重置</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { onMounted, onUnmounted, ref, reactive, ***puted } from 'vue';
import * as THREE from 'three';

// 自定义渲染器
class CustomWebGLRenderer extends THREE.WebGLRenderer {
  constructor(parameters = {}) {
    super(parameters);
    this.customRenderCallbacks = [];
    this.renderOverride = null;
    this.sortObjectsFunction = null;
  }

  // 重写渲染方法
  render(scene, camera) {
    const startTime = performance.now();
    
    if (this.renderOverride) {
      this.renderOverride(scene, camera, this);
    } else {
      this.customRender(scene, camera);
    }
    
    // 执行自定义回调
    this.customRenderCallbacks.forEach(callback => {
      callback(scene, camera, this);
    });
    
    this.lastRenderTime = performance.now() - startTime;
  }

  // 自定义渲染流程
  customRender(scene, camera) {
    // 自定义场景遍历和排序
    const renderList = this.getCustomRenderList(scene);
    
    // 设置渲染状态
    this.setCustomRenderState();
    
    // 执行渲染
    this.renderCustomList(renderList, camera);
  }

  // 获取自定义渲染列表
  getCustomRenderList(scene) {
    const renderList = [];
    
    scene.traverse(object => {
      if (object.isMesh || object.isSprite || object.isLine) {
        renderList.push(object);
      }
    });
    
    // 自定义排序
    if (this.sortObjectsFunction) {
      renderList.sort(this.sortObjectsFunction);
    }
    
    return renderList;
  }

  // 设置自定义渲染状态
  setCustomRenderState() {
    const gl = this.getContext();
    
    // 自定义GL状态
    gl.enable(gl.DEPTH_TEST);
    gl.depthFunc(gl.LEQUAL);
    gl.enable(gl.CULL_FACE);
    gl.cullFace(gl.BACK);
  }

  // 渲染自定义列表
  renderCustomList(renderList, camera) {
    const gl = this.getContext();
    
    // 清除缓冲区
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    
    // 渲染每个对象
    renderList.forEach(object => {
      this.renderObject(object, camera);
    });
  }

  // 渲染单个对象
  renderObject(object, camera) {
    if (!object.visible) return;
    
    const material = object.material;
    if (!material || material.visible === false) return;
    
    // 应用自定义材质
    this.setCustomMaterial(material);
    
    // 渲染对象
    this.renderObjectDirect(object, camera);
  }

  // 设置自定义材质
  setCustomMaterial(material) {
    if (material.isShaderMaterial || material.isRawShaderMaterial) {
      // 已经是自定义材质,无需处理
      return;
    }
    
    // 这里可以修改内置材质的着色器
    if (material.userData.customShader) {
      this.applyCustomShader(material);
    }
  }

  // 应用自定义着色器
  applyCustomShader(material) {
    const customShader = material.userData.customShader;
    
    if (!material._originalOnBefore***pile) {
      material._originalOnBefore***pile = material.onBefore***pile;
    }
    
    material.onBefore***pile = (shader, renderer) => {
      if (material._originalOnBefore***pile) {
        material._originalOnBefore***pile(shader, renderer);
      }
      
      // 修改着色器代码
      if (customShader.vertexShader) {
        shader.vertexShader = this.injectShaderCode(
          shader.vertexShader,
          customShader.vertexShader
        );
      }
      
      if (customShader.fragmentShader) {
        shader.fragmentShader = this.injectShaderCode(
          shader.fragmentShader,
          customShader.fragmentShader
        );
      }
      
      // 添加自定义uniforms
      Object.assign(shader.uniforms, customShader.uniforms);
    };
    
    material.needsUpdate = true;
  }

  // 注入着色器代码
  injectShaderCode(originalShader, customCode) {
    // 在main函数前插入自定义代码
    return originalShader.replace(
      /void main\(\) {/,
      `${customCode}\nvoid main() {`
    );
  }

  // 添加渲染回调
  addRenderCallback(callback) {
    this.customRenderCallbacks.push(callback);
  }

  // 移除渲染回调
  removeRenderCallback(callback) {
    const index = this.customRenderCallbacks.indexOf(callback);
    if (index > -1) {
      this.customRenderCallbacks.splice(index, 1);
    }
  }

  // 设置渲染覆盖
  setRenderOverride(renderFunction) {
    this.renderOverride = renderFunction;
  }

  // 设置排序函数
  setSortFunction(sortFunction) {
    this.sortObjectsFunction = sortFunction;
  }
}

// 着色器管理器
class ShaderManager {
  constructor() {
    this.shaderTemplates = new Map();
    this.initShaderTemplates();
  }

  initShaderTemplates() {
    // 波浪效果顶点着色器
    this.shaderTemplates.set('wave_vertex', `
      uniform float time;
      uniform float waveIntensity;
      
      vec3 applyWaveEffect(vec3 position) {
        float wave = sin(position.x * 5.0 + time) * waveIntensity;
        position.y += wave;
        return position;
      }
    `);

    // 轮廓描边片段着色器
    this.shaderTemplates.set('outline_fragment', `
      uniform vec3 outlineColor;
      uniform float outli***hreshold;
      
      vec4 applyOutline(vec4 originalColor, vec3 normal, vec3 viewDir) {
        float edge = dot(normal, viewDir);
        if (edge < outli***hreshold) {
          return vec4(outlineColor, 1.0);
        }
        return originalColor;
      }
    `);

    // 卡通渲染片段着色器
    this.shaderTemplates.set('toon_fragment', `
      uniform int toonLevels;
      
      vec4 applyToonShading(vec4 originalColor, float diffuse) {
        float toon = floor(diffuse * float(toonLevels)) / float(toonLevels);
        return vec4(originalColor.rgb * toon, originalColor.a);
      }
    `);
  }

  getShaderTemplate(name) {
    return this.shaderTemplates.get(name) || '';
  }

  createCustomShader(vertexMod, fragmentMod, uniforms = {}) {
    return {
      vertexShader: this.getShaderTemplate(vertexMod),
      fragmentShader: this.getShaderTemplate(fragmentMod),
      uniforms: uniforms
    };
  }
}

export default {
  name: 'CustomRenderer',
  setup() {
    // 响应式状态
    const renderCanvas = ref(null);
    const renderMode = ref('standard');
    const vertexModification = ref('none');
    const fragmentModification = ref('none');
    const timeUniform = ref(0);
    const intensityUniform = ref(1);
    const enableCustomSorting = ref(false);
    const enableMultiPass = ref(false);
    const renderOrder = ref('frontToBack');
    const showShaderEditor = ref(false);
    const activeShaderTab = ref('vertex');
    
    // 性能统计
    const drawCalls = ref(0);
    const triangleCount = ref(0);
    const fps = ref(0);
    const ***piledShaders = ref(0);
    const renderTime = ref(0);
    const gpuMemory = ref(0);

    // 着色器代码编辑
    const shaderCode = reactive({
      vertex: `// 自定义顶点着色器代码
uniform float time;
uniform float intensity;

vec3 applyEffect(vec3 position) {
    // 在这里添加自定义顶点变换
    return position;
}`,
      fragment: `// 自定义片段着色器代码
uniform float time;
uniform float intensity;

vec4 applyEffect(vec4 color) {
    // 在这里添加自定义颜色处理
    return color;
}`
    });

    // 渲染模式配置
    const renderModes = [
      { id: 'standard', name: '标准模式' },
      { id: 'wireframe', name: '线框模式' },
      { id: 'normals', name: '法线可视化' },
      { id: 'depth', name: '深度图' },
      { id: 'custom', name: '完全自定义' }
    ];

    // 计算属性
    const currentRenderMode = ***puted(() => {
      return renderModes.find(mode => mode.id === renderMode.value)?.name || '未知';
    });

    // Three.js 对象
    let customRenderer, scene, camera, shaderManager;
    let animationFrameId;
    let frameCount = 0;
    let lastFpsUpdate = 0;

    // 初始化场景
    const init = () => {
      initRenderer();
      initScene();
      initShaderManager();
      startAnimation();
    };

    // 初始化自定义渲染器
    const initRenderer = () => {
      customRenderer = new CustomWebGLRenderer({
        canvas: renderCanvas.value,
        antialias: true,
        powerPreference: "high-performance"
      });
      
      customRenderer.setSize(window.innerWidth, window.innerHeight);
      customRenderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
      customRenderer.shadowMap.enabled = true;
      customRenderer.shadowMap.type = THREE.PCFSoftShadowMap;
      
      // 添加性能监控回调
      customRenderer.addRenderCallback(updatePerformanceStats);
    };

    // 初始化场景
    const initScene = () => {
      scene = new THREE.Scene();
      scene.background = new THREE.Color(0x1a1a1a);
      
      camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
      camera.position.set(5, 5, 5);
      camera.lookAt(0, 0, 0);
      
      // 添加灯光
      const ambientLight = new THREE.AmbientLight(0x404040, 0.4);
      scene.add(ambientLight);
      
      const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
      directionalLight.position.set(10, 10, 5);
      directionalLight.castShadow = true;
      scene.add(directionalLight);
      
      // 创建测试几何体
      createTestGeometry();
    };

    // 初始化着色器管理器
    const initShaderManager = () => {
      shaderManager = new ShaderManager();
    };

    // 创建测试几何体
    const createTestGeometry = () => {
      // 创建多个不同材质的几何体
      const geometries = [
        new THREE.BoxGeometry(1, 1, 1),
        new THREE.SphereGeometry(0.7, 32, 32),
        new THREE.ConeGeometry(0.7, 1.5, 32),
        new THREE.TorusGeometry(1, 0.3, 16, 100)
      ];
      
      const materials = [
        new THREE.MeshStandardMaterial({ color: 0xff4444 }),
        new THREE.MeshStandardMaterial({ color: 0x44ff44 }),
        new THREE.MeshStandardMaterial({ color: 0x4444ff }),
        new THREE.MeshStandardMaterial({ color: 0xffff44 })
      ];
      
      geometries.forEach((geometry, index) => {
        const material = materials[index % materials.length];
        const mesh = new THREE.Mesh(geometry, material);
        
        // 随机位置
        mesh.position.set(
          (Math.random() - 0.5) * 8,
          (Math.random() - 0.5) * 8,
          (Math.random() - 0.5) * 8
        );
        
        // 随机旋转
        mesh.rotation.set(
          Math.random() * Math.PI,
          Math.random() * Math.PI,
          Math.random() * Math.PI
        );
        
        mesh.castShadow = true;
        mesh.receiveShadow = true;
        
        scene.add(mesh);
      });
      
      // 添加地面
      const groundGeometry = new THREE.PlaneGeometry(20, 20);
      const groundMaterial = new THREE.MeshStandardMaterial({ 
        color: 0x666666,
        roughness: 0.8,
        metalness: 0.2
      });
      const ground = new THREE.Mesh(groundGeometry, groundMaterial);
      ground.rotation.x = -Math.PI / 2;
      ground.position.y = -5;
      ground.receiveShadow = true;
      scene.add(ground);
    };

    // 设置渲染模式
    const setRenderMode = (mode) => {
      renderMode.value = mode;
      
      switch (mode) {
        case 'wireframe':
          setWireframeMode();
          break;
        case 'normals':
          setNormalsMode();
          break;
        case 'depth':
          setDepthMode();
          break;
        case 'custom':
          setCustomMode();
          break;
        default:
          setStandardMode();
      }
    };

    // 设置线框模式
    const setWireframeMode = () => {
      scene.traverse(object => {
        if (object.isMesh) {
          object.material.wireframe = true;
        }
      });
    };

    // 设置法线可视化模式
    const setNormalsMode = () => {
      // 这里应该实现法线可视化着色器
      console.log('切换到法线可视化模式');
    };

    // 设置深度图模式
    const setDepthMode = () => {
      // 这里应该实现深度图渲染
      console.log('切换到深度图模式');
    };

    // 设置自定义模式
    const setCustomMode = () => {
      customRenderer.setRenderOverride(customRenderFunction);
    };

    // 设置标准模式
    const setStandardMode = () => {
      scene.traverse(object => {
        if (object.isMesh) {
          object.material.wireframe = false;
        }
      });
      customRenderer.setRenderOverride(null);
    };

    // 自定义渲染函数
    const customRenderFunction = (scene, camera, renderer) => {
      // 完全自定义的渲染流程
      const gl = renderer.getContext();
      
      // 清除
      gl.clearColor(0.1, 0.1, 0.2, 1.0);
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
      
      // 自定义渲染逻辑
      renderCustomScene(scene, camera, renderer);
    };

    // 渲染自定义场景
    const renderCustomScene = (scene, camera, renderer) => {
      // 这里实现完全自定义的渲染逻辑
      const renderList = [];
      
      scene.traverse(object => {
        if (object.isMesh && object.visible) {
          renderList.push(object);
        }
      });
      
      // 自定义排序
      if (enableCustomSorting.value) {
        renderList.sort(getSortFunction());
      }
      
      // 渲染每个对象
      renderList.forEach(object => {
        renderCustomObject(object, camera, renderer);
      });
    };

    // 获取排序函数
    const getSortFunction = () => {
      switch (renderOrder.value) {
        case 'frontToBack':
          return (a, b) => {
            const distA = a.position.distanceTo(camera.position);
            const distB = b.position.distanceTo(camera.position);
            return distA - distB;
          };
        case 'backToFront':
          return (a, b) => {
            const distA = a.position.distanceTo(camera.position);
            const distB = b.position.distanceTo(camera.position);
            return distB - distA;
          };
        case 'material':
          return (a, b) => {
            return a.material.id - b.material.id;
          };
        default:
          return null;
      }
    };

    // 渲染自定义对象
    const renderCustomObject = (object, camera, renderer) => {
      // 应用自定义着色器修改
      applyShaderModifications(object.material);
      
      // 使用原始渲染方法
      renderer.renderObjectDirect(object, camera);
    };

    // 应用着色器修改
    const applyShaderModifications = (material) => {
      if (vertexModification.value !== 'none' || fragmentModification.value !== 'none') {
        const customShader = shaderManager.createCustomShader(
          `${vertexModification.value}_vertex`,
          `${fragmentModification.value}_fragment`,
          {
            time: { value: timeUniform.value },
            intensity: { value: intensityUniform.value }
          }
        );
        
        material.userData.customShader = customShader;
        material.needsUpdate = true;
      }
    };

    // 更新性能统计
    const updatePerformanceStats = () => {
      // 更新帧率
      frameCount++;
      const now = performance.now();
      if (now - lastFpsUpdate >= 1000) {
        fps.value = Math.round((frameCount * 1000) / (now - lastFpsUpdate));
        frameCount = 0;
        lastFpsUpdate = now;
      }
      
      // 更新渲染时间
      if (customRenderer.lastRenderTime) {
        renderTime.value = customRenderer.lastRenderTime.toFixed(2);
      }
      
      // 更新其他统计信息(简化实现)
      drawCalls.value = Math.floor(Math.random() * 50) + 10;
      triangleCount.value = Math.floor(Math.random() * 10000) + 5000;
      ***piledShaders.value = Math.floor(Math.random() * 20) + 5;
      gpuMemory.value = Math.floor(Math.random() * 500) + 100;
    };

    // 应用着色器代码
    const applyShaderCode = () => {
      // 这里应该将编辑的着色器代码应用到材质
      console.log('应用着色器代码:', shaderCode);
    };

    // 重置着色器代码
    const resetShaderCode = () => {
      shaderCode.vertex = `// 自定义顶点着色器代码
uniform float time;
uniform float intensity;

vec3 applyEffect(vec3 position) {
    // 在这里添加自定义顶点变换
    return position;
}`;
      
      shaderCode.fragment = `// 自定义片段着色器代码
uniform float time;
uniform float intensity;

vec4 applyEffect(vec4 color) {
    // 在这里添加自定义颜色处理
    return color;
}`;
    };

    // 动画循环
    const startAnimation = () => {
      const animate = () => {
        animationFrameId = requestAnimationFrame(animate);
        
        // 更新时间uniform
        timeUniform.value += 0.016; // 约60FPS
        
        // 旋转相机
        if (camera) {
          const time = Date.now() * 0.001;
          camera.position.x = Math.cos(time) * 8;
          camera.position.z = Math.sin(time) * 8;
          camera.lookAt(0, 0, 0);
        }
        
        // 渲染场景
        customRenderer.render(scene, camera);
      };
      animate();
    };

    onMounted(() => {
      init();
      window.addEventListener('resize', handleResize);
    });

    onUnmounted(() => {
      if (animationFrameId) {
        cancelAnimationFrame(animationFrameId);
      }
      if (customRenderer) {
        customRenderer.dispose();
      }
      window.removeEventListener('resize', handleResize);
    });

    const handleResize = () => {
      if (!camera || !customRenderer) return;
      
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      customRenderer.setSize(window.innerWidth, window.innerHeight);
    };

    return {
      // 模板引用
      renderCanvas,
      
      // 状态数据
      renderMode,
      vertexModification,
      fragmentModification,
      timeUniform,
      intensityUniform,
      enableCustomSorting,
      enableMultiPass,
      renderOrder,
      showShaderEditor,
      activeShaderTab,
      drawCalls,
      triangleCount,
      fps,
      ***piledShaders,
      renderTime,
      gpuMemory,
      shaderCode,
      
      // 配置数据
      renderModes,
      
      // 计算属性
      currentRenderMode,
      
      // 方法
      setRenderMode,
      applyShaderCode,
      resetShaderCode
    };
  }
};
</script>

<style scoped>
.custom-renderer-container {
  width: 100%;
  height: 100vh;
  display: flex;
  background: #000;
  overflow: hidden;
}

.render-view {
  flex: 1;
  position: relative;
}

.render-canvas {
  width: 100%;
  height: 100%;
  display: block;
}

.debug-info {
  position: absolute;
  top: 20px;
  left: 20px;
  background: rgba(0, 0, 0, 0.8);
  padding: 15px;
  border-radius: 8px;
  color: white;
  font-family: 'Courier New', monospace;
  font-size: 14px;
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.info-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
  min-width: 200px;
}

.info-item:last-child {
  margin-bottom: 0;
}

.info-item span:first-child {
  color: #***c;
}

.info-item span:last-child {
  color: #00ff88;
  font-weight: bold;
}

.control-panel {
  width: 350px;
  background: #2d2d2d;
  padding: 20px;
  overflow-y: auto;
  border-left: 1px solid #444;
}

.panel-section {
  margin-bottom: 25px;
  padding-bottom: 20px;
  border-bottom: 1px solid #444;
}

.panel-section:last-child {
  margin-bottom: 0;
  border-bottom: none;
}

.panel-section h3 {
  color: #00ffff;
  margin-bottom: 15px;
  font-size: 16px;
}

.mode-buttons {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.mode-button {
  padding: 12px 8px;
  background: #444;
  color: white;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 12px;
  transition: all 0.3s ease;
}

.mode-button:hover {
  background: #555;
}

.mode-button.active {
  background: #00a8ff;
}

.shader-controls {
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.control-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.control-group label {
  color: #***c;
  font-size: 14px;
}

.control-group select {
  padding: 8px 12px;
  background: #444;
  border: 1px solid #666;
  border-radius: 4px;
  color: white;
  font-size: 14px;
}

.uniform-controls {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.uniform-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.uniform-item span {
  color: #***c;
  font-size: 14px;
  min-width: 60px;
}

.uniform-item input[type="range"] {
  flex: 1;
}

.render-settings {
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.setting-group {
  display: flex;
  align-items: center;
  gap: 10px;
}

.setting-group label {
  color: #***c;
  font-size: 14px;
  cursor: pointer;
}

.setting-group input[type="checkbox"] {
  margin: 0;
}

.setting-group select {
  padding: 6px 10px;
  background: #444;
  border: 1px solid #666;
  border-radius: 4px;
  color: white;
  font-size: 14px;
  width: 100%;
}

.performance-stats {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.stat-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 0;
  border-bottom: 1px solid #444;
}

.stat-item:last-child {
  border-bottom: none;
}

.stat-item span:first-child {
  color: #***c;
}

.stat-item span:last-child {
  color: #00ff88;
  font-weight: bold;
}

.shader-editor-modal {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.8);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.editor-content {
  background: #2d2d2d;
  border-radius: 12px;
  width: 90%;
  max-width: 800px;
  max-height: 90vh;
  overflow: hidden;
  border: 1px solid #444;
}

.editor-header {
  padding: 20px;
  background: #1a1a1a;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid #444;
}

.editor-header h3 {
  margin: 0;
  color: #00ffff;
}

.close-button {
  background: none;
  border: none;
  color: #***c;
  font-size: 24px;
  cursor: pointer;
  padding: 0;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.editor-body {
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.editor-tabs {
  display: flex;
  gap: 5px;
  border-bottom: 1px solid #444;
}

.editor-tabs button {
  padding: 10px 20px;
  background: transparent;
  color: #***c;
  border: none;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  transition: all 0.3s ease;
}

.editor-tabs button.active {
  color: #00ffff;
  border-bottom-color: #00ffff;
}

.shader-textarea {
  width: 100%;
  height: 400px;
  background: #1a1a1a;
  color: #00ff88;
  font-family: 'Courier New', monospace;
  font-size: 14px;
  border: 1px solid #444;
  border-radius: 4px;
  padding: 15px;
  resize: vertical;
  line-height: 1.4;
}

.editor-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}

.action-button {
  padding: 10px 20px;
  background: #444;
  color: white;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  transition: all 0.3s ease;
}

.action-button:hover {
  background: #555;
}

.action-button.secondary {
  background: #666;
}

/* 响应式设计 */
@media (max-width: 1024px) {
  .custom-renderer-container {
    flex-direction: column;
  }
  
  .control-panel {
    width: 100%;
    height: 400px;
  }
  
  .render-view {
    height: calc(100vh - 400px);
  }
}

@media (max-width: 768px) {
  .mode-buttons {
    grid-template-columns: 1fr;
  }
  
  .editor-content {
    width: 95%;
  }
  
  .shader-textarea {
    height: 300px;
  }
}
</style>

高级特性

多通道渲染系统

// 多通道渲染管理器
class MultiPassRenderer {
    constructor(renderer, scene, camera) {
        this.renderer = renderer;
        this.scene = scene;
        this.camera = camera;
        this.passes = [];
        this.renderTargets = new Map();
        
        this.setupRenderTargets();
    }
    
    setupRenderTargets() {
        // 创建各种渲染目标
        const parameters = {
            minFilter: THREE.LinearFilter,
            magFilter: THREE.LinearFilter,
            format: THREE.RGBAFormat,
            stencilBuffer: false
        };
        
        this.renderTargets.set('color', new THREE.WebGLRenderTarget(
            window.innerWidth, window.innerHeight, parameters
        ));
        
        this.renderTargets.set('depth', new THREE.WebGLRenderTarget(
            window.innerWidth, window.innerHeight, parameters
        ));
        
        this.renderTargets.set('normals', new THREE.WebGLRenderTarget(
            window.innerWidth, window.innerHeight, parameters
        ));
    }
    
    addPass(pass) {
        this.passes.push(pass);
    }
    
    render() {
        const currentRenderTarget = this.renderer.getRenderTarget();
        
        // 执行每个渲染通道
        this.passes.forEach((pass, index) => {
            const inputRT = index > 0 ? this.passes[index - 1].outputRT : null;
            const outputRT = index < this.passes.length - 1 ? 
                this.renderTargets.get(`pass_${index}`) : null;
            
            pass.render(this.scene, this.camera, inputRT, outputRT);
        });
        
        this.renderer.setRenderTarget(currentRenderTarget);
    }
}

// 基础渲染通道
class RenderPass {
    constructor(name, renderFunction) {
        this.name = name;
        this.renderFunction = renderFunction;
        this.outputRT = null;
    }
    
    render(scene, camera, inputRT, outputRT) {
        this.renderFunction(scene, camera, inputRT, outputRT);
        this.outputRT = outputRT;
    }
}

动态着色器热重载

// 着色器热重载系统
class ShaderHotReload {
    constructor() {
        this.watchedShaders = new Map();
        this.setupFileWatching();
    }
    
    setupFileWatching() {
        // 监听着色器文件变化
        if (typeof module !== 'undefined' && module.hot) {
            module.hot.a***ept('./shaders/*.glsl', () => {
                this.reloadShaders();
            });
        }
    }
    
    watchShader(material, shaderPath) {
        this.watchedShaders.set(material.uuid, {
            material,
            shaderPath,
            lastModified: Date.now()
        });
    }
    
    async reloadShaders() {
        for (const [uuid, shaderInfo] of this.watchedShaders) {
            try {
                const newShaderCode = await this.loadShader(shaderInfo.shaderPath);
                this.updateMaterialShader(shaderInfo.material, newShaderCode);
            } catch (error) {
                console.error(`重载着色器失败: ${shaderInfo.shaderPath}`, error);
            }
        }
    }
    
    async loadShader(path) {
        const response = await fetch(path);
        return await response.text();
    }
    
    updateMaterialShader(material, shaderCode) {
        if (material.isShaderMaterial) {
            material.vertexShader = shaderCode;
            material.needsUpdate = true;
        }
    }
}

本节展示了如何通过继承和重写Three.js渲染器来实现完全自定义的渲染管线。这种技术为高级图形效果、特殊渲染需求和性能优化提供了强大的基础。

转载请说明出处内容投诉
CSS教程网 » 第42节:自定义渲染管线:修改Three.js默认流程

发表评论

欢迎 访客 发表评论

一个令你着迷的主题!

查看演示 官网购买