3

I am trying to do instancing in WebGL 2. I want to use the built-in variable gl_InstanceID to index into a uniform float array.

I get the following error:

glDrawElementsInstancedANGLE: attempt to draw with all attributes having non-zero divisors

Is the only instancing allowed in WebGL 2 instancing with vertex attributes (instanced arrays)?

Also, is the spec the only definitive place to find out about these capabilities?

gman
  • 100,619
  • 31
  • 269
  • 393
Startec
  • 12,496
  • 23
  • 93
  • 160
  • Hi @Startec did you manage to use `gl_InstanceID` inside your WebGL2.0 vertex shader in the end? My shader is refusing to compile if I include `id = gl_InstanceID;` for example, where `int id;` is defined at the top. –  Jun 16 '20 at 07:54
  • 1
    works for me: https://jsfiddle.net/greggman/fvwuoxhp/ – gman Jun 16 '20 at 07:55
  • @gman I'm using expo-gl with React Native, so maybe expo-gl doesn't support it, but I thought it should because it's a WebGL2.0 implementation. Confused. –  Jun 16 '20 at 07:58
  • You need to be using `#version 300 es` shaders – gman Jun 16 '20 at 07:59
  • @gman Yeah, but the shader won't compile with `#version 300 es` at the top. –  Jun 16 '20 at 08:00
  • You should ask a new question and make a **minimal repo** in a [snippet](https://stackoverflow.blog/2014/09/16/introducing-runnable-javascript-css-and-html-code-snippets/) – gman Jun 16 '20 at 08:02

1 Answers1

5

Based on the bug report below it looks like this issue was fixed. Here's a small working example

function main() {
  const gl = document.querySelector('canvas').getContext('webgl2');
  if (!gl) {
    return alert('need webgl2');
  }
  const vs = `#version 300 es
  void main() {
    float angle = float(gl_InstanceID) / 10.0 * 2.0 * radians(180.0);
    float radius = float(gl_VertexID + 1) / 4.0 * 0.8;
    gl_Position = vec4(vec2(sin(angle), cos(angle)) * radius, 0, 1);
    gl_PointSize = mix(5.0, 20.0, float(gl_VertexID) / 3.0);
  }
  `;

  const fs = `#version 300 es
  precision highp float;
  out vec4 foo;
  void main() {
    foo = vec4(1, 0, 0, 1);
  }
  `;
  
  const prg = twgl.createProgram(gl, [vs, fs]);
  gl.useProgram(prg);
  gl.drawArraysInstanced(gl.POINTS, 0, 4, 10);
}

main();
<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>

--- old answer ---

The spec says it's based on the OpenGL ES 3.0 spec

The remaining sections of this document are intended to be read in conjunction with the OpenGL ES 3.0 specification (3.0.4 at the time of this writing, available from the Khronos OpenGL ES API Registry). Unless otherwise specified, the behavior of each method is defined by the OpenGL ES 3.0 specification. This specification may diverge from OpenGL ES 3.0 in order to ensure interoperability or security, often defining areas that OpenGL ES 3.0 leaves implementation-defined. These differences are summarized in the Differences Between WebGL and OpenGL ES 3.0 section.

Unfortunately it looks like they forgot to specify that at least one attribute must have a non-zero divisor which is different from OpenGL ES 3.0. I filed a bug

The part that needs to be added is

INVALID_OPERATION is generated by DrawArraysInstanced or DrawElementsInstanced if there is not at least one enabled vertex attribute array that has a divisor of zero and is bound to an active generic attribute value in the program used for the draw command.

gman
  • 100,619
  • 31
  • 269
  • 393
  • 1
    Awesome. You go far beyond just answering the question. Also, I watched [this](https://www.youtube.com/watch?v=rfQ8rKGTVlg) today. Several years old and still full of good information. Good presenter! – Startec Jun 09 '17 at 03:59