提问人:user3722952 提问时间:9/28/2023 更新时间:11/16/2023 访问量:90
WebGL2 getUniformLocation 在 Android 上返回 null
WebGL2 getUniformLocation returns null on Android
问:
我对此感到非常困惑。我有一个带有少量制服的片段着色器。我正在获取制服的位置,如下所示:
this.gl.useProgram(this.program)
// Get uniform locations
for (const uniform of [
'u_resolution',
'u_data_resolution',
'u_pix_to_map',
'u_gps_to_data',
'u_data',
'u_colormap',
'u_product_min',
'u_product_max',
'u_product_cutoff',
'u_alpha',
'u_no_data',
]) {
const loc = this.gl.getUniformLocation(this.program, uniform)
if (loc === null) {
throw Error(`could not get location for uniform ${uniform}`)
}
this.uniformLocations[uniform] = loc
}
我的片段着色器如下:
#version 300 es
precision mediump float;
const float E = 2.71828182845904523536028747135266250;
const float PI = 3.14159265358979323846264338327950288;
const float RADIUS = 6378137.0;
const float HALF_SIZE = PI * RADIUS;
uniform vec2 u_resolution;
uniform vec2 u_data_resolution;
uniform mat3 u_pix_to_map;
uniform mat3 u_gps_to_data;
uniform sampler2D u_data;
uniform sampler2D u_colormap;
uniform float u_product_min;
uniform float u_product_max;
uniform float u_product_cutoff;
uniform float u_alpha;
uniform float u_no_data;
out vec4 fragColor;
vec2 apply(mat3 transform, vec2 coordinate) {
float x = (transform[0][0] * coordinate.x) + (transform[0][1] * coordinate.y) + transform[0][2];
float y = (transform[1][0] * coordinate.x) + (transform[1][1] * coordinate.y) + transform[1][2];
return vec2(x, y);
}
vec2 mapToGPS(vec2 coordinate) {
return vec2(
(180.0 * coordinate.x) / HALF_SIZE,
(360.0 * atan(exp(coordinate.y / RADIUS))) / PI - 90.0
);
}
vec2 screenSpaceToCanvasSpace(vec2 coordinate, vec2 resolution) {
return vec2(
coordinate.x,
-1.0 * (coordinate.y - resolution.y)
);
}
float getDataValue(vec2 coords) {
return texture(u_data, vec2(coords.x / u_data_resolution.x, coords.y / u_data_resolution.y)).x;
}
float bilerp(float x, float y, float x1, float x2, float y1, float y2, float z11, float z12, float z21, float z22) {
// Sometimes the floor and ceiling values are too close to each other; if this is the case, just return the average.
if (abs(x2 - x1) < 0.00001 || abs(y2 - y1) < 0.00001) {
return (z11 + z12 + z21 + z22) / 4.0;
}
float zxy1 = (( (x2 - x) / (x2 - x1) ) * z11) + (( (x - x1) / (x2 - x1) ) * z21);
float zxy2 = (( (x2 - x) / (x2 - x1) ) * z12) + (( (x - x1) / (x2 - x1) ) * z22);
return (( (y2 - y) / (y2 - y1) ) * zxy1) + (( (y - y1) / (y2 - y1) ) * zxy2);
}
float normalizeValue(float value) {
return (value - u_product_min) / (u_product_max - u_product_min);
}
vec3 getColor(float normalizedValue) {
return texture(u_colormap, vec2(normalizedValue, 0.5)).rgb;
}
void main() {
vec2 adjustedCoords = screenSpaceToCanvasSpace(gl_FragCoord.xy, u_resolution);
vec2 mapCoords = apply(u_pix_to_map, adjustedCoords);
vec2 gpsCoords = mapToGPS(mapCoords);
vec2 dataCoords = apply(u_gps_to_data, gpsCoords);
if (dataCoords.x < 0.0 || dataCoords.x > u_data_resolution.x || dataCoords.y < 0.0 || dataCoords.y > u_data_resolution.y) {
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
return;
}
float x1 = floor(dataCoords.x);
float x2 = ceil(dataCoords.x);
float y1 = floor(dataCoords.y);
float y2 = ceil(dataCoords.y);
float z11 = getDataValue(vec2(x1, y1));
float z12 = getDataValue(vec2(x1, y2));
float z21 = getDataValue(vec2(x2, y1));
float z22 = getDataValue(vec2(x2, y2));
if (abs(z11 - u_no_data) < 0.01) {
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
return;
}
if (abs(z12 - u_no_data) < 0.01) {
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
return;
}
if (abs(z21 - u_no_data) < 0.01) {
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
return;
}
if (abs(z22 - u_no_data) < 0.01) {
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
return;
}
float value = bilerp(dataCoords.x, dataCoords.y, x1, x2, y1, y2, z11, z12, z21, z22);
float normalizedValue = normalizeValue(value);
vec3 color = getColor(normalizedValue);
float normalizedCutoff = normalizeValue(u_product_cutoff);
float alpha = u_alpha;
if (normalizedValue < normalizedCutoff) {
alpha -= (u_alpha * ((normalizedCutoff - normalizedValue) / normalizedCutoff));
}
fragColor = vec4(color, alpha);
}
在所有其他设备和浏览器(Windows、Linux、Mac、iOS、Firefox、Safari、Chrome)上,此代码可以正常工作,并且可以正确获取统一位置。
仅在 Android(Firefox 和 Chrome)上,并返回 null。另外值得注意的是,我无法在运行 API 34 的 Android 模拟器中重现这一点。我只在运行 Android 11 或 Android 12 的物理设备上看到过这种情况。u_resolution
u_pix_to_map
制服肯定是用到的,所以它们不应该在着色器之外进行优化。
如果在编译并运行着色器后设置断点:
this.gl.getActiveUniform(this.program, 0)
结果是:
WebGLActiveInfo {size: 1, type: 35664, name: 'u_resolution'}
这告诉我,这种统一存在于编译的着色器中。但是,如果我试图在之后立即获得那套制服:
this.gl.getUniformLocation(program, 'u_resolution')
结果是 。null
另外值得注意的是,似乎没有错误:
this.gl.getError()
0
我不确定如何进一步调试,但我能想到的唯一可能性是:
- Android 上的 GLSL 编译器错误地从编译的着色器中删除了均匀
- 我做了一些事情来打破 Android 上的制服“包装”
- Android 上的 Chrome 和/或 Firefox 中还有其他一些错误
知道问题是什么,或者甚至只是我可以采取一些进一步的步骤来调试这个问题吗?
答: 暂无答案
评论