web-dev-qa-db-ja.com

インデックス式は定数でなければなりません-WebGL / GLSLエラー

非定数intをインデックスとして使用して、フラグメントシェーダーの配列にアクセスできません。とにかくここではあまり意味がないので式を削除しましたが、私のコードは現在のピクセルに基づいてtileIDを計算し、それを使用して色を決定することを目的としています。

これが私のコードです:

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);

どうやらGLSLはこれを気に入らず、エラーが発生します:

'[]':インデックス式は定数でなければなりません

誰かが私がこれを修正する方法を知っていますか?ありがとう。

17
Joey Morani

背景として-GLSLはCによく似ていますが、コンパイルが少し異なります。物事は非常に展開されており、条件は並行して実行され、最後に切り替えられる可能性があります。ハードウェアによって異なります...

ループインデックスまたは定数を使用して、配列にインデックスを付けることができます。ループ内の割り当ては問題ありませんが、tileIDによるアクセスは問題ありません。

WebGLシェーダー言語はGLESからのものであり、文書化されています

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

付録のセクション5では、次のことについて説明しています。

Indexing of Arrays, Vectors and Matrices
Definition:
constant-index-expressions are a superset of constant-expressions. Constant-index-expressions can include loop indices as defined in Appendix A section 4.
The following are constant-index-expressions:
• Constant expressions
• Loop indices as defined in section 4
• Expressions composed of both of the above
When used as an index, a constant-index-expression must have integral type.

お役に立てば幸いです。


ああ、それを修正することに関しては、上記の正確な例では...事前計算とインデックスではなく、tileIDから計算できるように見えます。

または、好きな配列を事前に計算して、テクスチャとして渡します。もちろん、テクスチャは好きなようにインデックスを付けることができます。

フロートをシェーダーに渡すために使用するjavascriptヘルパーメソッドは次のとおりです。

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;
}

Gl.NEARESTの使用に注意してください。そうすれば、値が「ぼやけ」ることはありません。次に、gl.drawXxx呼び出しの前に、次のように設定できます。

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);

そしてシェーダーで(フラグメントまたは頂点を信じています;以前のいくつかのwebglは頂点テクスチャをサポートしていませんでした...)

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

したがって、0から1の範囲内で、テクスチャとしての配列のサイズに合わせて適切にインデックスを付ける必要があります。各値/ピクセルの中央からサンプリングしてみてください。同様に、配列の幅が2つの値の場合、0.25と0.75のインデックスを付けます。

それがその要点です!

13
david van brink

OS X10.11.6のSafari9.1.2でテスト済み

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);
}
5
asdf

整数変数を使用してテクスチャの配列からn番目のテクスチャを取得しようとしたため、このエラーが発生しました。

// 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);
}

解決策は、テクスチャのインデックス作成を一連の条件に分割することでした。

// 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);
  } 
}
2
duhaime