typescript - WebGL2 getUniformLocation Android'de null döndürüyor
Bu konuda oldukça şaşkınım. Bir avuç uniformu olan bir fragment shader'ım var. Uniformların konumunu şöyle alıyorum:
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
}
Fragment shader’ım aşağıdaki gibidir:
#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);
}
Diğer tüm cihazlarda ve tarayıcılarda (Windows, Linux, Mac, iOS, Firefox, Safari, Chrome) bu kod çalışır ve uniform konumları doğru şekilde alınır.
Sadece Android'de (hem Firefox hem de Chrome), u_resolution ve u_pix_to_map null döndürüyor. Ayrıca, bunu API 34 çalıştıran bir Android emülatöründe çoğaltamıyorum. Bunu sadece Android 11 veya Android 12 çalıştıran fiziksel cihazlarda gördüm.
Uniformlar kesinlikle kullanılıyor, bu yüzden shader'dan optimize edilmemeliler.
Eğer bir kesme noktası shader derlendikten ve çalıştırıldıktan sonra ayarlanırsa:
this.gl.getActiveUniform(this.program, 0)
sonuç şudur:
WebGLActiveInfo {size: 1, type: 35664, name: 'u_resolution'}
Bu, derlenmiş shader’da bu uniform’un bulunduğunu bana söylüyor. Ancak, eğer hemen ardından bu uniform’u almaya çalışırsam:
this.gl.getUniformLocation(program, 'u_resolution')
sonuç null.
Ayrıca dikkat edilmesi gereken bir diğer nokta, herhangi bir hata görünmüyor:
this.gl.getError()
0
Bunu daha fazla nasıl hata ayıklayacağımı bilmiyorum, ama aklıma gelen tek olasılıklar şunlar:
- Android'de GLSL derleyicisi tarafından derlenmiş shader'dan uniform değişkenler yanlış şekilde kaldırılıyor
- Android'deki tek tip "paketleme"yi bozacak bir şey yaptım
- Android üzerinde Chrome ve/veya Firefox'ta başka bir hata var
Sorunun ne olduğunu biliyor musun, ya da bu sorunu teşhis etmek için atabileceğim birkaç ek adım var mı?