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 的事),而是负责:
- 根据材质、几何体、场景、灯光等收集参数。
- 生成缓存键(cache key),决定是否需要新建 Shader。
- 复用 / 释放 已编译的 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 → WebGLProgramMiniprograms:所有 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 |
灯光、贴图、宏、精度等大量因素 |
设计要点小结
- 职责分离:
WebGLProgramsMini管「选 shader + 缓存」;WebGLProgramMini管「编译 + 链接 + uniform/attribute 查询」。 - 两级缓存:材质级避免重复查表;全局级避免重复编译(shader 编译成本高)。
- 可扩展:加新内置材质时,在
shaderIDs和ShaderLibMini里各加一项即可;getProgramCacheKey在 shader 变多时需要相应扩展。