Index expression must be constant - WebGL/GLSL error

匿名 (未验证) 提交于 2019-12-03 03:05:02

问题:

I'm having trouble accessing an array in a fragment shader using a non-constant int as the index. I've removed the formula as it wouldn't make much sense here anyway, but my code is meant to calculate the tileID based on the current pixel and use that to determine the color.

Here's my code:

int tileID = <Insert formula here>;  vec3 colorTest;  int arrayTest[1024]; for (int x = 0; x < 1024; x++) {     if (x == 1) arrayTest[x] = 1;     else arrayTest[x] = 2; }  if (arrayTest[tileID] == 1) colorTest = vec3(0.0, 1.0, 0.0); else if (arrayTest[tileID] == 2) colorTest = vec3(1.0, 0.0, 0.0); else colorTest = vec3(0.0, 0.0, 0.0); 

Apparently GLSL doesn't like this and I get the error:

'[]' : Index expression must be constant

Does anyone know how I would fix this? Thanks.

回答1:

As background -- GLSL looks a lot like C, but compiles a bit different. Things are very unrolled, and conditionals may be executed in parallel and switched at the end, that sort of thing. Depends on the hardware...

You can use loop indices or constants to index into arrays. The assignment in your loop is ok, but the access by tileID isn't.

WebGL Shader language is from GLES, documented

http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf

The Appendix, section 5, discusses:

Hope that helps!


Oh, as for fixing it, in the exact example above... looks like you could compute from tileID rather than precompute and index.

Or, precompute whatever array you like, and pass it in as a texture. A texture, of course, can be indexed however you like.

Here's a javascript helper method I use, to pass floats down to the shaders:

function glSetupStuff() { ... ... if(!gl.getExtension("OES_texture_float"))   // <<-- enables RGBA float values, handy!     alert("cant pass in floats, use 8-bit values instead."); ... }  /*  * Pass in an array of rgba floats,  * for example: var data = new Float32Array([0.1,0.2,0.3,1,  .5,.5,1.0,1]);  */ function textureFromFloats(gl,width,height,float32Array)  { var oldActive = gl.getParameter(gl.ACTIVE_TEXTURE); gl.activeTexture(gl.TEXTURE15); // working register 31, thanks.  var texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture);  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,                  width, height, 0,                  gl.RGBA, gl.FLOAT, float32Array);  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.bindTexture(gl.TEXTURE_2D, null);  gl.activeTexture(oldActive);  return texture; } 

Note the use of gl.NEAREST, so it doesn't "blur" your values! Then you can set it up before the gl.drawXxx call, with something like

textureUnit = 3;  // from 0 to 15 is ok gl.activeTexture(gl.TEXTURE0 + textureUnit); gl.bindTexture(gl.TEXTURE_2D, texture);  var z = gl.getUniformLocation(prog, "uSampler"); gl.uniform1i(z, textureUnit); 

And in the shader (I believe fragment or vertex; some earlier webgl's didn't support vertex textures...)

uniform sampler2D uSampler; ... vec4 value = texture2D(uSampler, vec2(xValueBetween0And1,yValueBetween0And1)); 

So, you have to index appropriately for the array-as-texture size, within range of 0 to 1. Try to sample from the middle of each value/pixel. Like, if the array is 2 values wide, index by 0.25 and 0.75.

That's the gist of it!



回答2:

Tested in Safari 9.1.2 on OS X 10.11.6

uniform float data[32];  float getData(int id) {     for (int i=0; i<32; i++) {         if (i == id) return data[i];     } }  void main(void) {     float f = getData(yourVariable); } 


回答3:

I hit this error because I was attempting to use an integer variable to take the nth texture from an array of textures:

// this doesn't compile!  varying vec2 vUv; // uv coords varying float vTexture; // texture index in array of textures  uniform sampler2D textures[3]; // identify that there are 3 textures  void main() {   int textureIndex = int(floor(vTexture));   gl_FragColor = texture2D(textures[textureIndex], vUv); } 

The solution was to break out the texture indexing into a sequence of conditionals:

// this compiles!  varying vec2 vUv; // uv coords varying float vTexture; // texture index in array of textures  uniform sampler2D textures[3]; // identify that there are 3 textures  void main() {   int textureIndex = int(floor(vTexture));   if (textureIndex == 0) {     gl_FragColor = texture2D(textures[0], vUv);   } else if (textureIndex == 1) {     gl_FragColor = texture2D(textures[1], vUv);   } else if (textureIndex == 2) {     gl_FragColor = texture2D(textures[2], vUv);   }  } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!