在后面的章节里我们会按照WebGLRenderer的initGLContext() 方法里的初始化顺序,简化其中的关键模块,我们会忽略一些与绘制纯色三角形无关的模块。
src\renderers\WebGLRenderer.js
ini
function initGLContext() {
extensions = new WebGLExtensions( _gl );
extensions.init();
utils = new WebGLUtils( _gl, extensions );
capabilities = new WebGLCapabilities( _gl, extensions, parameters, utils );
state = new WebGLState( _gl, extensions );
if ( capabilities.reversedDepthBuffer && reversedDepthBuffer ) {
state.buffers.depth.setReversed( true );
}
info = new WebGLInfo( _gl );
properties = new WebGLProperties();
textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
environments = new WebGLEnvironments( _this );
attributes = new WebGLAttributes( _gl );
bindingStates = new WebGLBindingStates( _gl, attributes );
geometries = new WebGLGeometries( _gl, attributes, info, bindingStates );
objects = new WebGLObjects( _gl, geometries, attributes, bindingStates, info );
morphtargets = new WebGLMorphtargets( _gl, capabilities, textures );
clipping = new WebGLClipping( properties );
programCache = new WebGLPrograms( _this, environments, extensions, capabilities, bindingStates, clipping );
materials = new WebGLMaterials( _this, properties );
renderLists = new WebGLRenderLists();
renderStates = new WebGLRenderStates( extensions );
background = new WebGLBackground( _this, environments, state, objects, _alpha, premultipliedAlpha );
shadowMap = new WebGLShadowMap( _this, objects, capabilities );
uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state );
bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info );
indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info );
接下来我们先说WebGLState,我会参考它新建一个src\renderers\webgl\WebGLStateMini.js文件。
src\renderers\WebGLRendererMini.js
javascript
import { Vector4 } from '../../math/Vector4.js';
/**
* GL 固定功能状态的最小封装。
* Mini 版仅包含 clearColor、useProgram、viewport,不含深度/混合/裁剪等。
*/
function WebGLStateMini( gl ) {
// 颜色缓冲区,如果当前颜色与传入颜色相同,则不进行操作
function ColorBuffer() {
const color = new Vector4();
const currentColorClear = new Vector4( 0, 0, 0, 0 );
return {
setClear: function ( r, g, b, a ) {
color.set( r, g, b, a );
if ( currentColorClear.equals( color ) === false ) {
gl.clearColor( r, g, b, a );
currentColorClear.copy( color );
}
},
};
}
// 颜色缓冲区实例
const colorBuffer = new ColorBuffer();
// 当前程序
let currentProgram = null;
// 设置颜色缓冲区清除颜色
colorBuffer.setClear( 0, 0, 0, 1 );
// 当前视口
const currentViewport = new Vector4()
// 使用着色器程序,如果当前程序与传入程序相同,则不进行操作
function useProgram( program ) {
if ( currentProgram !== program ) {
gl.useProgram( program );
currentProgram = program;
return true;
}
return false;
}
// 设置视口,如果当前视口与传入视口相同,则不进行操作
function viewport( viewport ) {
if ( currentViewport.equals( viewport ) === false ) {
gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
currentViewport.copy( viewport );
}
}
return {
buffers: {
color: colorBuffer,
},
useProgram: useProgram,
viewport: viewport,
};
}
export { WebGLStateMini };
1-WebGLState 的定位与职责
WebGLState 是 WebGL 的「全局状态」管理器,它可以设置背景色、视口、useProgram 等。
WebGL 有很多「全局状态」:当前 shader、视口、清除颜色、深度测试、混合模式等。
Three.js 不直接到处调用 gl.xxx,而是通过 State 层 统一管理,主要目的是:
- 封装 WebGL 原生 API
- 避免重复设置相同状态(减少 CPU → GPU 调用)
Mini 版只保留三条最基础的状态:
| 功能 | GL API | 用途 |
|---|---|---|
| 清屏颜色 | gl.clearColor |
背景/清屏 |
| 着色器程序 | gl.useProgram |
切换 shader |
| 视口 | gl.viewport |
画布绘制区域 |
2-WebGLStateMini 代码详解
1. 工厂函数
javascript
function WebGLStateMini( gl ) {
接收 WebGL2 上下文 gl,闭包保存当前状态,返回对外 API。
2. ColorBuffer --- 清屏颜色缓存
scss
function ColorBuffer() {
const color = new Vector4();
const currentColorClear = new Vector4( 0, 0, 0, 0 );
return {
setClear: function ( r, g, b, a ) {
color.set( r, g, b, a );
if ( currentColorClear.equals( color ) === false ) {
gl.clearColor( r, g, b, a );
currentColorClear.copy( color );
}
},
};
}
currentColorClear记录上次传给 GL 的清除色- 新颜色与上次相同 → 跳过
gl.clearColor - 初始化时设为
(0, 0, 0, 1)黑色不透明
3. useProgram --- 着色器程序缓存
ini
function useProgram( program ) {
if ( currentProgram !== program ) {
gl.useProgram( program );
currentProgram = program;
return true;
}
return false;
}
- 同一 program 不重复
useProgram - 切换时返回
true,未切换返回false(完整版上层可据此决定是否重绑 uniform)
在 WebGLRendererMini.setProgram 中会调用useProgram :
ini
state.useProgram( program.program );
4. viewport --- 视口设置
scss
// 设置视口,如果当前视口与传入视口相同,则不进行操作
function viewport( viewport ) {
if ( currentViewport.equals( viewport ) === false ) {
gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
currentViewport.copy( viewport );
}
}
viewport 的概念是在画布中确定一个矩形区域,webgl 会只在这个区域中绘画。
5. 对外接口
css
return {
buffers: {
color: colorBuffer,
},
useProgram: useProgram,
viewport: viewport,
};
总结
WebGLStateMini 可以在 JavaScript 侧缓存当前 GL 状态,只在变化时才调用底层 API,避免重复设置。
下一章我们会说mini版的WebGLProperties。