OpenGL ES高斯模糊Shader在Mali GPU异常其他平台正常问题咨询
Mali GPU高斯模糊失效问题解决方案
问题根因
你遇到的适配问题核心来源于Mali GPU对OpenGL ES精度规范的严格实现,和Adreno、PowerVR的宽松兼容逻辑存在差异,具体问题点如下:
- 循环计数器
i/j、模糊半径intensity使用了lowp精度修饰符:OpenGL ES规范中lowp浮点数的可表示范围最高为±2.0,完全无法覆盖你设置的15的循环上限,在Mali GPU上循环实际仅执行3次(i=0/1/2)就提前终止,仅采样了中心附近极小范围的像素,因此没有模糊效果。 - 高斯核未做归一化:你当前计算的所有高斯权重累加和小于1,最终输出的像素值整体偏低,就是图像偏暗的直接原因。
resolution参数使用lowp精度:分辨率倒数的数值通常极小,lowp仅有的8位精度会导致采样偏移量计算出现严重误差。
修复方案
1. 修正精度修饰符
- 将所有大于2的数值变量(循环计数器i/j、intensity、width_hal)的精度改为
mediump - 将
resolution参数的精度改为mediump
2. 高斯权重归一化
在循环外预计算权重累加和,最终输出时除以累加值,修正图像偏暗问题
3. 可选优化:拆分一维高斯模糊
将15x15的二维模糊拆分为两次1x15的横向/纵向一维模糊,性能可提升5~10倍,同时减少循环内的计算误差
修正后的着色器代码
varying highp vec2 textureCoordinate; uniform sampler2D inputImageTexture; uniform mediump vec2 resolution; // 修正参数精度 void main() { mediump vec2 uv = textureCoordinate; mediump float intensity = 15.0; // 修正半径精度 mediump float width_hal = float(int(intensity/2.0)); mediump float red = 0.0; mediump float green = 0.0; mediump float blue = 0.0; mediump float weight_sum = 0.0; // 权重累加和用于归一化 // 循环变量改用mediump精度 for (mediump float i = 0.0; i < intensity; i=i+1.0){ for (mediump float j = 0.0; j < intensity; j = j+1.0){ mediump float x_offset = i - intensity / 2.0; mediump float y_offset = j - intensity / 2.0; mediump float guas_value = 1.0 / (2.0 * 3.14159 * 16.0) * exp(-(x_offset*x_offset + y_offset*y_offset)/32.0); weight_sum += guas_value; mediump float x_axis = uv.x + (x_offset * resolution.x * 1.5); mediump float y_axis = uv.y + (y_offset * resolution.y * 1.5); lowp vec3 color = texture2D(inputImageTexture, vec2(x_axis, y_axis)).rgb; red += color.r * guas_value; green += color.g * guas_value; blue += color.b * guas_value; } } // 归一化修正偏暗问题 red /= weight_sum; green /= weight_sum; blue /= weight_sum; gl_FragColor = vec4(red, green, blue, 1.0); }
内容的提问来源于stack exchange,提问作者Syed Muhammad Akbar
相关产品推荐
相关产品推荐

