web-dev-qa-db-ja.com

glDisableVertexAttribArray()を呼び出すことは重要ですか?

頂点属性配列を有効にする範囲は完全には明確ではありません。頂点属性の数が異なるいくつかの異なるシェーダープログラムがあります。 glEnableVertexAttribArray呼び出しは、シェーダープログラムに対してローカルですか、それともグローバルですか?

現時点では、シェーダープログラムを作成するときに頂点属性配列を有効にし、無効にしないようにしています。すべてが機能しているようですが、描画呼び出しの直前/直後に有効/無効にする必要があるようです。これに影響はありますか?

(私はWebGLにいるので、実際にはgl.enableVertexAttribArrayおよびgl.disableVertexAttribArray。また、オレンジ色の本OpenGL Shading Languageは、これらの呼び出しについてまったく情報を提供しないことにも注意してください。)

53
Grumdrig

有効になっている頂点属性配列の状態は、頂点配列オブジェクト(VAO)にバインドするか、グローバルにすることができます。

VAOを使用している場合は、属性配列がVAOにカプセル化されているため、属性配列をnot無効にする必要があります。

ただし、グローバル頂点属性配列が有効な状態の場合は、無効にする必要があります。有効にしたままの場合、OpenGLは無効なポインターにバインドされている可能性がある配列から読み取ろうとするため、ポインターがクライアントアドレスにある場合、プログラムがクラッシュする可能性があります。スペース、またはバインドされたVertex Bufferオブジェクトの制限を超えている場合はOpenGLエラーを発生させます。

42
datenwolf

WebGLはOpenGLと同じではありません。

WebGLでは、属性にアタッチされたバッファーがある限り、配列を有効にしたままにすることが明示的に許可され、(a)使用されている場合、描画呼び出しを満たすのに十分な大きさであるか、または(b)使用されていません。

OpenGL ES 2.0とは異なり、WebGLはクライアント側の配列を許可しません。

証明:

var gl = document.querySelector("canvas").getContext("webgl");
var m4 = twgl.m4;
var programInfo2Attribs = twgl.createProgramInfo(gl, ["vs-uses-2-attributes", "fs"]);
var programInfo1Attrib  = twgl.createProgramInfo(gl, ["vs-uses-1-attribute", "fs"]);

var arrays2Attribs = {
  position: [
    -1, -1, 0, 
    1, -1, 0, 
    -1, 1, 0, 
  ],
  color: [
    1,0,0,1,
    1,1,0,1,
    0,1,0,1,
  ],
};

var arrays1Attrib = {
  position: [
    -1, -1, 0, 
    1, -1, 0, 
    -1, 1, 0, 
    -1, 1, 0, 
    1, -1, 0, 
    1, 1, 0,
  ],
};


var bufferInfo2Attribs = twgl.createBufferInfoFromArrays(gl, arrays2Attribs);
var bufferInfo1Attrib  = twgl.createBufferInfoFromArrays(gl, arrays1Attrib);

var uniforms = {
  u_matrix: m4.scale(m4.translation([-0.5, 0, 0]), [0.25, 0.5, 0.5]),
};

gl.useProgram(programInfo2Attribs.program);
twgl.setBuffersAndAttributes(gl, programInfo2Attribs, bufferInfo2Attribs);
twgl.setUniforms(programInfo2Attribs, uniforms);
twgl.drawBufferInfo(gl, gl.TRIANGLES, bufferInfo2Attribs);

uniforms.u_matrix = m4.scale(m4.translation([0.5, 0, 0]), [0.25, 0.5, 0.5]);

gl.useProgram(programInfo1Attrib.program);
twgl.setBuffersAndAttributes(gl, programInfo1Attrib, bufferInfo1Attrib);
twgl.setUniforms(programInfo1Attrib, uniforms);
twgl.drawBufferInfo(gl, gl.TRIANGLES, bufferInfo1Attrib);
canvas { border: 1px solid black; }
<script src="https://twgljs.org/dist/twgl-full.min.js"></script>
<script id="vs-uses-2-attributes" type="not-js">
attribute vec4 position;
attribute vec4 color;
  
varying vec4 v_color;

uniform mat4 u_matrix;
  
void main() {
  gl_Position = u_matrix * position;
  v_color = color;
}
</script>
<script id="vs-uses-1-attribute" type="not-js">
attribute vec4 position;
  
varying vec4 v_color;
  
uniform mat4 u_matrix;
  
void main() {
  gl_Position = u_matrix * position;
  v_color = vec4(0,1,0,1);
}
</script>
<script id="fs" type="not-js">
precision mediump float;
varying vec4 v_color;

void main() {
  gl_FragColor = v_color;
}
</script>
<p>
1st it draws a triangle (3 vertices, 2 attributes)<br/>
2nd it draws a quad (6 vertices, 1 attribute)<br/>
It does NOT called gl.disableVertexAttrib so on the second draw call one of the attributes is still enabled. It is pointing to a buffer with only 3 vertices in it even though 6 vertices will be drawn. There are no errors.
</p>
<canvas></canvas>
14
gman

WebGLではyesを使用します。gl.disableVertexAttribArrayを呼び出すことが重要です。

Chromeから次の警告が出ていました。

WebGL: INVALID_OPERATION: drawElements: attribs not setup correctly

これは、プログラムが属性の最大数未満を使用するものに変更したときに発生していました。明らかに、解決策は描画する前に未使用の属性を無効にすることでした。

すべてのプログラムが同じ数の属性を使用している場合は、初期化時にgl.enableVertexAttribArrayを呼び出すことで問題を回避できる可能性があります。そうしないと、プログラムを変更するときにそれらを管理する必要があります。

4
Adria