14-mini版WebGLPrograms

源码:github.com/buglas/thre...

1-WebGLProgramsMini 的代码

src\renderers\webgl\WebGLPrograms.js

ini 复制代码
import { WebGLProgramMini } from './WebGLProgramMini.js';
import { WebGLShaderCache } from './WebGLShaderCache.js';
import { ShaderLibMini } from '../shaders/ShaderLibMini.js';
import { UniformsUtils } from '../shaders/UniformsUtils.js';
​
/**
 * 着色器程序池:根据材质类型选择 shader 源码,编译/缓存 WebGLProgramMini。
 * 全局 programsMap 按 cacheKey 共享;每个 Material 另有独立的 programs Map。
 */
function WebGLProgramsMini( renderer ) {
    const programs = [];
    const programsMap = new Map();
    let precision = 'highp';
    // 内置材质类型 
    const shaderIDs = {
        MeshMiniMaterial: 'mini',
    };
    /** 收集编译 shader 所需的参数(源码、精度等)
     * material: Material
     */
    function getParameters( material ) {
        const shaderID = shaderIDs[ material.type ];
        const shader = ShaderLibMini[ shaderID ];
        let vertexShader = shader.vertexShader;
        let fragmentShader = shader.fragmentShader;
        const parameters = {
            shaderID: shaderID,
            shaderType: material.type,
            shaderName: material.name,
            vertexShader: vertexShader,
            fragmentShader: fragmentShader,
            precision: precision,
        };
        return parameters;
    }
    /** 获取用于缓冲 shader 的 cacheKey */
    function getProgramCacheKey( parameters ) {
        const array = [];
        array.push( parameters.shaderID );
        return array.join();
    }
    /** 获取在CPU中预定义的uniforms */
    function getUniforms( material ) {
        const shaderID = shaderIDs[ material.type ];
        const shader = ShaderLibMini[ shaderID ];
        let uniforms = UniformsUtils.clone( shader.uniforms );
        return uniforms;
    }
    /** 从programsMap 中获取program,如果获取不到,则创建新的program */
    function acquireProgram( parameters, cacheKey ) {
        let program = programsMap.get( cacheKey );
        if ( program !== undefined ) {
            ++ program.usedTimes;
        } else {
            program = new WebGLProgramMini( renderer, cacheKey, parameters );
            programs.push( program );
            programsMap.set( cacheKey, program );
        }
        return program;
    }
    return {
        getParameters: getParameters,
        getProgramCacheKey: getProgramCacheKey,
        getUniforms: getUniforms,
        acquireProgram: acquireProgram,
        programs: programs,
    };
}
​
export { WebGLProgramsMini };
​

2-WebGLProgramsMini 的功能定位

WebGLPrograms 是WebGL 渲染器中的 Shader program管理器。

WebGLPrograms 不负责编译 GLSL 本身(那是WebGLProgram 的事),而是负责:

  1. 根据材质、几何体、场景、灯光等收集参数。
  2. 生成缓存键(cache key),决定是否需要新建 Shader。
  3. 复用 / 释放 已编译的 WebGL Program。

WebGLRenderer.js 中,每次绘制前会调用 getProgram(),其核心流程就是:

scss 复制代码
材质 + 场景 + 物体 → getParameters() → getProgramCacheKey() → acquireProgram()

WebGLProgramsMini 亦是如此,只是具体功能做了删减。

WebGLProgramsMini 的核心职责:

  • 根据材质类型选出 GLSL 源码
  • 生成缓存 key
  • 克隆 uniform 默认值
  • 在全局池里 编译并复用 WebGLProgramMini 实例。

3-模块结构

WebGLProgramsMini 是一个 工厂函数(不是 class),接收 renderer,返回一组 API:

导出方法 作用
getParameters(material) 收集编译 shader 所需参数
getProgramCacheKey(parameters) 生成全局缓存 key
getUniforms(material) 获取材质 uniform 默认值
acquireProgram(parameters, cacheKey) 从全局池获取或新建 program
programs 所有已创建 program 的数组

4-代码详解

构造函数

ini 复制代码
function WebGLProgramsMini( renderer ) {
    const _customShaders = new WebGLShaderCache();
    const programs = [];
    const programsMap = new Map();
    let precision = 'highp';
    // 内置材质类型 → ShaderLibMini 中的 key
    const shaderIDs = {
        MeshMiniMaterial: 'mini',
    };
  • programsMap:全局 program 池,cacheKey → WebGLProgramMini
  • programs:所有 program 的列表(便于遍历/调试)
  • shaderIDs:材质类型到 ShaderLibMini 的映射;Mini 版目前只有 `MeshMiniMaterial → 'mini'
  • precision:精度,固定 'highp',会传给 WebGLProgramMini 生成 precision highp float;

getParameters(material)

收集编译 shader 所需的参数(源码、精度等)

ini 复制代码
function getParameters( material ) {
    const shaderID = shaderIDs[ material.type ];
    const shader = ShaderLibMini[ shaderID ];
    let vertexShader = shader.vertexShader;
    let fragmentShader = shader.fragmentShader;
    const parameters = {
        shaderID: shaderID,
        shaderType: material.type,
        shaderName: material.name,
        vertexShader: vertexShader,
        fragmentShader: fragmentShader,
        precision: precision,
    };
    return parameters;
}

内置 shader 定义在 ShaderLibMini.js

css 复制代码
const ShaderLibMini = {
    mini: {
        uniforms: {
            diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }
        },
        vertexShader: ShaderChunkMini.meshmini_vert,
        fragmentShader: ShaderChunkMini.meshmini_frag
    },

后续,parameters 中还会添加ShaderLibMini中预定义的uniforms。

getProgramCacheKey(parameters)

获取用于缓冲 shader 的 cacheKey。

c 复制代码
function getProgramCacheKey( parameters ) {
    const array = [];
    array.push( parameters.shaderID );
    return array.join();
}

Mini 版极简:cacheKey 就是 shaderID(例如 "mini")。

完整版 WebGLPrograms.js 的 key 会包含灯光、雾、贴图、宏定义等几十项;Mini 版只有一种内置 shader,不需要那些维度。

getUniforms(material)

获取在CPU中预定义的uniforms

ini 复制代码
function getUniforms( material ) {
    const shaderID = shaderIDs[ material.type ];
    const shader = ShaderLibMini[ shaderID ];
    let uniforms = UniformsUtils.clone( shader.uniforms );
    return uniforms;
}

这些 uniform 会存到getParameters() 获取的对象上,然后上传到 GPU。

acquireProgram(parameters, cacheKey)

从programsMap 中获取program,如果获取不到,则创建新的program。

ini 复制代码
function acquireProgram( parameters, cacheKey ) {
    let program = programsMap.get( cacheKey );
    if ( program !== undefined ) {
        ++ program.usedTimes;
    } else {
        program = new WebGLProgramMini( renderer, cacheKey, parameters );
        programs.push( program );
        programsMap.set( cacheKey, program );
    }
    return program;
}

相同 cacheKey 只编译一次,复用时 usedTimes++,为将来释放做准备。

与完整版 WebGLPrograms.js 的对比

维度 WebGLProgramsMini WebGLPrograms
材质类型 MeshMiniMaterial 十几种内置材质
getParameters 参数 只要 material 还要 lights、shadows、scene、object 等
cacheKey shaderID 灯光、贴图、宏、精度等大量因素

设计要点小结

  1. 职责分离:WebGLProgramsMini 管「选 shader + 缓存」;WebGLProgramMini 管「编译 + 链接 + uniform/attribute 查询」。
  2. 两级缓存:材质级避免重复查表;全局级避免重复编译(shader 编译成本高)。
  3. 可扩展:加新内置材质时,在 shaderIDsShaderLibMini 里各加一项即可;getProgramCacheKey 在 shader 变多时需要相应扩展。
相关推荐
GuWenyue14 小时前
不用第三方SDK!Vue3原生Fetch实现DeepSeek流式输出,90%前端都会踩的分片解析坑一次性解决
前端·人工智能·llm
独隅14 小时前
前端离线暂停更新策略:Service Worker 与 PWA 实战指南
前端
不如摸鱼去15 小时前
Wot UI 2.3.0 发布:二维码组件来了,Open Wot 与 wot-starter 同步更新
前端·ui·微信小程序·前端框架·uni-app
Cloud_bread15 小时前
从ReAct到自主闭环:Agentic Coding核心执行引擎的技术演进
前端·react.js·前端框架
cidy_9815 小时前
OptMem 使用教程
前端
杉氧15 小时前
用 Compose 挑战交互与动效天花板:ComposeCraftLab 开源实验室全解析
android·前端·kotlin
Canace15 小时前
AI 生成到 90% 突然断了:你的解决方案是?
前端·人工智能
TinssonTai16 小时前
Vite 8 版 Chrome 插件全家桶,popup/options/sidepanel 一次集齐
前端·vue.js
玉鸯16 小时前
让 Agent 面向用户:AG-UI 协议构建 Agent 前端
前端·python·agent
程序员黑豆16 小时前
鸿蒙应用开发 @Extend 装饰器使用教程
前端·harmonyos