如何将MediaPipe的WebGL纹理共享到自定义WebGL程序中?
我当前使用MediaPipe对视频流进行分割以提取背景(用于模糊处理),通过OffscreenCanvas让MediaPipe在GPU上完成计算,整体流程正常。现在我尝试将MediaPipe程序中的confidenceMask纹理导入到自己的模糊混合程序中,但绑定纹理并赋值给uniform时,出现错误:WebGL: INVALID_OPERATION: uniform1i: location is not from the associated program。相关代码如下:
const glCanvas = new OffscreenCanvas(width, height); const segmenter = ImageSegmenter.createFromOptions(video, { baseOptions: { modelAssetPath: QualitySettings.segmentationModel, delegate: 'GPU', }, canvas: glCanvas, runningMode: 'VIDEO', outputConfidenceMasks: true, }); //... segmenter.segmentForVideo(videoEl, startTimeMs, result => { //... gl.useProgram(myProgram); //... const mask = result.confidenceMasks[0].getAsWebGLTexture(); const maskLocation = gl.getUniformLocation(program, 'u_mask'); gl.activeTexture(gl.TEXTURE3); gl.bindTexture(gl.TEXTURE_2D, mask); gl.uniform1i(maskLocation, 3); // ❌ 抛出"location is not from the associated program"错误 });
请问如何将该纹理从MediaPipe程序转移到自定义程序?若无法实现,应如何正确使用getAsWebGLTexture方法?
1. 修复Uniform位置匹配错误
你代码里的核心错误是:当前激活的着色器程序是myProgram,但获取Uniform位置时用了另一个无关的program变量,导致拿到的Uniform位置不属于当前激活的程序,触发了WebGL的校验规则。
修改这一行即可解决当前报错:
const maskLocation = gl.getUniformLocation(myProgram, 'u_mask');
确保getUniformLocation的第一个参数是你当前激活的myProgram。
2. 确保纹理与自定义程序共用同一WebGL上下文
你已经将自己创建的OffscreenCanvas传给了MediaPipe的配置,这意味着MediaPipe会在这个Canvas对应的WebGL上下文中创建纹理。只要你的自定义模糊程序也使用同一个上下文(即通过glCanvas.getContext('webgl')获取的上下文),就能直接绑定和使用这个纹理,不需要额外的“转移”操作。
如果你的自定义程序用的是另一个WebGL上下文(比如页面上的可见Canvas),则无法直接跨上下文使用纹理,此时需要将MediaPipe的纹理内容复制到你自己的上下文纹理中:
- 在MediaPipe的上下文里,将纹理绑定到帧缓冲,调用
readPixels读取像素数据 - 在自己的上下文里,创建新纹理并调用
texImage2D上传读取到的像素数据
不过这种方式会损失GPU加速的优势,建议尽量避免跨上下文操作。
3. 正确使用getAsWebGLTexture的注意事项
- 不要修改MediaPipe纹理的参数:该纹理是MediaPipe内部管理的资源,修改纹理过滤方式、包裹模式等可能导致MediaPipe后续处理出错。
- 纹理格式匹配:MediaPipe返回的置信度掩码纹理通常是单通道格式,确保你的自定义着色器中对
u_mask的采样逻辑匹配该格式(比如用texture2D(u_mask, uv).r获取掩码值)。 - 资源释放(可选):如果你的处理流程不需要保留该纹理,可以在使用完后调用
gl.deleteTexture(mask)释放资源,但要注意MediaPipe是否会复用该纹理对象,避免提前释放导致异常。
内容的提问来源于stack exchange,提问作者atomrc

