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 变多时需要相应扩展。
相关推荐
李伟_Li慢慢1 小时前
19-mini版WebGLRenderer
前端·three.js
李伟_Li慢慢1 小时前
10-mini版bindingStates
前端·three.js
李伟_Li慢慢1 小时前
08-BufferAttribute
前端·three.js
李伟_Li慢慢1 小时前
09-mini版WebGLAttributes
前端·three.js
李伟_Li慢慢2 小时前
11-mini版WebGLGeometries
前端·three.js
李伟_Li慢慢2 小时前
18-mini版WebGLRenderList
前端·three.js
李伟_Li慢慢2 小时前
15-mini版WebGLMaterials
前端·three.js
ji_shuke2 小时前
Vue3 前端批量打印 PDF/图片踩坑记:跨域、合并打印、对话框闪退与按钮一直 loading
前端·pdf·状态模式·pdf打印
李伟_Li慢慢2 小时前
06-mini版WebGLState
前端·three.js