11-mini版WebGLGeometries

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

1-WebGLGeometriesMini的代码

src\renderers\webgl\WebGLGeometriesMini.js

csharp 复制代码
/**
 * 几何体 GPU 数据管理:将 BufferGeometry 的各 attribute 同步到 WebGL buffer。
 */
function WebGLGeometriesMini( gl, attributes, bindingStates ) {
    const geometries = {};
​
    /** geometry 销毁时释放其关联的所有 VAO */
    function onGeometryDispose( event ) {
        const geometry = event.target;
        attributes.remove( geometry.index );
        for ( const name in geometry.attributes ) {
            attributes.remove( geometry.attributes[ name ] );
        }
        geometry.removeEventListener( 'dispose', onGeometryDispose );
        delete geometries[ geometry.id ];
        bindingStates.releaseStatesOfGeometry( geometry );
    }
    /** 获取 geometry ,如果 geometry 已注册,则直接返回原 geometry 引用,否则注册 geometry 并返回 */
    function get( geometry ) {
        if ( geometries[ geometry.id ] === true ) return geometry;
        geometry.addEventListener( 'dispose', onGeometryDispose );
        geometries[ geometry.id ] = true;
        return geometry;
    }
    /** 遍历 geometry 全部 attribute,按需创建或更新 GPU buffer 
     * geometry: BufferGeometry
    */
    function update( geometry ) {
        const geometryAttributes = geometry.attributes;
        for ( const name in geometryAttributes ) {
            attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );
        }
    }
    return {
        get: get,
        update: update,
    };
}
​
export { WebGLGeometriesMini };

2-WebGLGeometriesMini 的功能定位

WebGLGeometries 是处于 几何体对象 和 底层 WebGL buffer 管理 之间的中间层。,它是面向BufferGeometry 的服务者。

WebGLGeometries 本身不绑定 VAO、也不发起 draw,只负责以下事务:

  • 注册/追踪几何体。
  • 把顶点属性同步到 WebGL buffer。
  • 在 dispose 时释放资源。
  • 为线框模式生成专用索引。

WebGLGeometries 的整体定位:

scss 复制代码
Mesh / Line / Points
        ↓
WebGLObjects.update()     ← 每帧调用
        ↓
WebGLGeometries.get()     ← 注册 / 追踪 geometry
        ↓
WebGLGeometries.update()  ← 遍历 attributes,触发 GPU 上传
        ↓
WebGLAttributes.update()  ← 真正创建/更新 GPU buffer
        ↓
WebGLBindingStates        ← VAO 绑定

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

3-整体结构

php 复制代码
function WebGLGeometriesMini( gl, attributes, bindingStates ) {
    const geometries = {};
​
    /** geometry 销毁时释放其关联的所有 VAO */
    function onGeometryDispose( event ) {
        // ...
    }
    function get( geometry ) {
        // ...
    }
    function update( geometry ) {
        // ...
    }
    return {
        get: get,
        update: update,
    };
}

这是一个工厂函数(不是 class),闭包里维护一个 geometries 注册表,对外只暴露 get 和 update。

依赖 作用
gl WebGL2 上下文(当前 update 里主要用 gl.ARRAY_BUFFER)
attributes WebGLAttributesMini,管理每个 BufferAttribute ↔ GPU buffer
bindingStates WebGLBindingStatesMini,管理 VAO(顶点数组对象)

4-核心函数

1. get(geometry) --- 注册几何体

kotlin 复制代码
function get( geometry ) {
    if ( geometries[ geometry.id ] === true ) return geometry;
    geometry.addEventListener( 'dispose', onGeometryDispose );
    geometries[ geometry.id ] = true;
    return geometry;
}

作用:

  • 首次见到某个 BufferGeometry:监听它的 dispose 事件,并在 geometries 里用 geometry.id 标记为已注册。
  • 再次见到:直接返回,避免重复注册。

注意:geometries 存的是 true,不是 geometry 副本;真正对象仍是原来的 BufferGeometry。这个表只是「已追踪 ID 集合」。

完整版 WebGLGeometries.get(object, geometry) 还会做内存统计(info.memory.geometries++),Mini 版去掉了这部分。

2. update(geometry) --- 同步顶点属性到 GPU

查找、创建、缓存VAO。

ini 复制代码
function update( geometry ) {
    const geometryAttributes = geometry.attributes;
    for ( const name in geometryAttributes ) {
        attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );
    }
}

作用:遍历 geometry.attributes(如 position、normal),对每个 BufferAttribute 调用 WebGLAttributesMini.update():

  • 第一次:gl.createBuffer() + gl.bufferData() 上传完整数据
  • 之后:若 attribute.version 变了,用 gl.bufferSubData() 增量更新

Mini 版只处理 geometry.attributes,不处理 geometry.index(索引 buffer)。

3. onGeometryDispose(event) --- 销毁清理

ini 复制代码
function onGeometryDispose( event ) {
    const geometry = event.target;
    attributes.remove( geometry.index );
    for ( const name in geometry.attributes ) {
        attributes.remove( geometry.attributes[ name ] );
    }
    geometry.removeEventListener( 'dispose', onGeometryDispose );
    delete geometries[ geometry.id ];
    bindingStates.releaseStatesOfGeometry( geometry );
}

当用户调用 geometry.dispose() 时触发,做三件事:

1.删 GPU buffer:index + 所有 attributes 对应的 WebGL buffer。

attributes.remove() 方法在src\renderers\webgl\WebGLAttributesMini.js 中:

scss 复制代码
function remove( attribute ) {
    const data = buffers.get( attribute );
    if ( data ) {
        gl.deleteBuffer( data.buffer );
        buffers.delete( attribute );
    }
}

2.注销追踪:从 geometries 表移除,并移除 dispose 监听。

3.释放 VAO:bindingStates.releaseStatesOfGeometry() 删除该 geometry 关联的所有 VAO

bindingStates.releaseStatesOfGeometry() 方法在src\renderers\webgl\WebGLBindingStatesMini.js 中:

ini 复制代码
function releaseStatesOfGeometry( geometry ) {
    const geometryMap = bindingStates[ geometry.id ];
    if ( geometryMap === undefined ) return;
    for ( const programId in geometryMap ) {
        const state = geometryMap[ programId ];
        if ( state !== undefined ) {
            if ( currentState === state ) {
                currentState = null;
            }
            gl.deleteVertexArray( state.object );
        }
    }
    delete bindingStates[ geometry.id ];
}

这是典型的 Three.js 资源生命周期模式:创建时注册监听,销毁时统一释放 GPU 资源,避免泄漏。

5-与完整版 WebGLGeometries.js 的对比

功能 完整版 Mini 版
注册 / dispose 清理 ✅ ✅
更新 attributes ✅ ✅
内存统计 info.memory ✅ ❌
Wireframe 索引属性 ✅ ❌
InstancedBufferGeometry ✅ ❌
Morph targets 等 ✅ ❌

Mini 版保留了「BufferGeometry → GPU buffer → VAO → draw」的主链路,去掉了线框、实例化、内存统计等扩展能力。

设计要点总结

  1. 职责分离:

    • WebGLGeometriesMini 管理 BufferGeometry;
    • VBO 在 WebGLAttributesMini;
    • VAO 在 WebGLBindingStatesMini。
  2. 按 ID 追踪:用 geometry.id 做注册表,同一 geometry 多次渲染不会重复注册。

  3. 惰性上传:update() 每帧都会调,但 WebGLAttributesMini 只在 attribute.version 变化时才真正 bufferSubData。

  4. dispose 联动:geometry 销毁时,buffer 和 VAO 一起释放,保证 GPU 资源不泄漏。

相关推荐
沧沧凉凉6 小时前
一段需求、零素材,Claude Code 派了 33 个代理给我做了个 3D 动作游戏
游戏·ai编程·three.js
福兮说7 小时前
设计稿是 #4A7C6F,页面量出来是 #4B7C6F:HEX、HSL、透明度、canvas 来回转的七个坑
前端·javascript·css·canvas
郑州光合科技余经理8 小时前
海外版外卖加盟:总站与分站配送规则怎么分开管
java·开发语言·前端·后端·uni-app·php·ai编程
小呆呆6668 小时前
副业搞起来,小说,漫画,漫剧的成本优化思路
前端·后端·面试
Dovis(誓平步青云)8 小时前
浇水提醒刚弹出又消失,植物状态别只存一个百分比
开发语言·前端·javascript·pdf·ecmascript·电脑
码艺-Alimjan9 小时前
Vben Admin 新增维吾尔语 Vben-Modal的关键坑之一
前端·javascript·vue.js
可乐鸡翅yeah_10 小时前
hls.js 手动自定义 http 请求 loader,修改请求头实战
开发语言·前端·javascript·网络协议·http·ecmascript·m3u8在线
IT_陈寒10 小时前
Vite静态资源导入这个坑我帮你们踩过了
前端·人工智能·后端
广州华水科技10 小时前
大坝安全监测解决方案:单北斗GNSS形变监测系统应用与维护
前端
yivifu11 小时前
中文古籍电子书注释集成
前端·javascript·python·beautifulsoup·epub