如何在Three.js中传递超过255的像素分割ID至自定义着色器?
解决分割ID超过255无法传递的方案
方案1:使用高精度单通道纹理
直接替换纹理存储格式为16位无符号整数或32位浮点数,能支持更大范围的分割ID,步骤如下:
16位无符号整数(支持最大65535的ID)
修改纹理数据填充逻辑:
// 单通道16位,数组长度等于像素总数 var imageData = new Uint16Array(persDatas[threshold].length); for (var x = 0; x < persDatas[threshold].length; x++) { var segID = persDatas[threshold][x]; // 直接存储原始ID,确保≤65535 imageData[x] = segID; } // 创建指定格式的DataTexture var texture = new THREE.DataTexture( imageData, 4104, 1856, THREE.RedFormat, // 单通道存储 THREE.UnsignedShortType // 16位无符号整数类型 ); texture.needsUpdate = true; persTextures[threshold] = texture; uniforms.persTexture.value = texture;修改着色器采样逻辑:
采样得到的是0-1的浮点数,乘以65535还原原始ID:float segID = texture(persTexture, vPosition.xy).r * 65535.0;
32位浮点数(支持超大范围ID)
若ID超过65535,可改用Float32格式:
var imageData = new Float32Array(persDatas[threshold].length); for (var x = 0; x < persDatas[threshold].length; x++) { imageData[x] = persDatas[threshold][x]; // 直接存储原始ID } var texture = new THREE.DataTexture( imageData, 4104, 1856, THREE.RedFormat, THREE.FloatType );
着色器中直接读取即可:
float segID = texture(persTexture, vPosition.xy).r;
方案2:多通道拆分编码(兼容Uint8纹理)
如果必须保留Uint8格式,可将ID拆分为高8位和低8位,分别存入R、G通道,组合后支持最大65535的ID:
修改数据填充逻辑:
var imageData = new Uint8Array(4 * persDatas[threshold].length); for (var x = 0; x < persDatas[threshold].length; x++) { var segID = persDatas[threshold][x]; // 拆分高8位和低8位 var lowByte = segID & 0xFF; var highByte = (segID >> 8) & 0xFF; imageData[x * 4] = lowByte; imageData[x * 4 + 1] = highByte; imageData[x * 4 + 2] = 0; imageData[x * 4 + 3] = 255; } var texture = new THREE.DataTexture(imageData, 4104, 1856); texture.needsUpdate = true; persTextures[threshold] = texture; uniforms.persTexture.value = texture;修改着色器采样逻辑:
合并两个通道的值还原原始ID:vec4 color = texture(persTexture, vPosition.xy); float segID = color.r * 255.0 + color.g * 255.0 * 256.0;
方案3:使用存储缓冲区(适合特定场景)
若分割ID与顶点一一对应而非屏幕像素,可考虑用BufferAttribute存储ID数组,通过顶点缓冲区传递。但对于屏幕空间每个像素对应ID的场景,纹理仍是更高效的选择。
内容的提问来源于stack exchange,提问作者Pravin Poudel
相关产品推荐
相关产品推荐

