如何在GLSL中高效查询给定RGB值是否属于预存颜色列表
原大数组方案不可行的原因
你尝试的16777216长度的bool数组方案从硬件限制层面就无法实现:GLSL shader的可用内存非常有限,单个数组占用空间超过几十KB就可能触发编译/运行错误,16M大小的数组远远超出了所有GPU的shader内存限制,且GLSL不允许在全局作用域对数组做单元素赋值,所有const数组必须在定义时完成初始化。
最优兼容方案:排序+二分查找
这个方案不需要复杂的预处理,兼容性拉满,性能相比原遍历方案提升40倍以上,仅需最多9次循环即可完成查询:
- 预处理阶段(CPU端完成):将你的384个RGB值用你写的
rgbHash函数转换为24位整数,然后将这384个整数从小到大排序,得到排序后的整数列表。 - GLSL代码实现:
// 替换为你CPU端预处理好的排序后的384个哈希值 const int sortedRgbHash[384] = int[384]( 1234, 2345, 3456, /* 其余值按排序结果填充 */ ); int rgbHash(int r, int g, int b) { return (r << 16) | (g << 8) | b; } bool cExists(int r, int g, int b) { int target = rgbHash(r, g, b); int low = 0; int high = 383; while (low <= high) { int mid = (low + high) / 2; if (sortedRgbHash[mid] == target) { return true; } else if (sortedRgbHash[mid] < target) { low = mid + 1; } else { high = mid - 1; } } return false; }
极致性能方案:1D纹理实现O(1)查询
如果你的运行环境支持GLSL 300 es及以上/桌面GLSL 130及以上,可以用1D纹理实现无循环的O(1)查询:
- 预处理阶段(CPU端完成):创建一张长度为512的R8_UNORM格式1D纹理,对384个RGB值计算最小完美哈希映射到0-383的索引,对应纹理位置的值设为255,其余位置设为0。最小完美哈希的生成可以用现成的工具完成,384个元素的生成成本极低。
- GLSL代码实现:
uniform sampler1D u_RgbLookup; // 替换为你生成的最小完美哈希函数 int minimalPerfectHash(int r, int g, int b) { // 示例逻辑,实际由CPU端生成的哈希规则替换 return ((r * 123 + g * 456 + b * 789) % 512); } bool cExists(int r, int g, int b) { int idx = minimalPerfectHash(r, g, b); float val = texture(u_RgbLookup, float(idx) / 512.0).r; return val > 0.5; }
注意事项
如果传入的RGB是归一化的0-1浮点值,转换为整数时需要用int(round(r * 255.0))处理,避免浮点精度误差导致匹配失败。
内容的提问来源于stack exchange,提问作者Benny F.
相关产品推荐
相关产品推荐

