Reputation: 23
How does WebGL write data to a transform-feedback output when doing instanced drawing? Particularly, how does it decide on what index of the transform-feedback-buffer to write to when using instanced drawing?
Consider the following example:
offset
attributeoffset
attribute should be updated for each draw via transform feedbackHere's some pseudo-code (full code available here):
Vertex shader:
#version 300 es
in vec2 rectVertex;
in vec2 offset;
out vec2 newOffset;
void main() {
gl_Position = vec4(rectVertex + offset, 0, 1);
newOffset = offset + vec2(0.02);
}
Fragment shader:
#version 300 es
precision mediump float;
out vec4 fragColor;
void main() {
fragColor = vec4(1, 0, 0, 1);
}
JS:
const program = createProgram(vertexShader, fragmentShader, ['newOffset']);
const rectBuffer = createBuffer(rectData.flat()); // 6*2 entries
const offsetBuffer1 = createBuffer(offsetData.flat()); // 100*2 entries
const offsetBuffer2 = createBuffer(offsetData.flat()); // 100*2 entries
const vao1 = createVao(
{
rectVertex: { buffer: rectBuffer, nrInstances: 0 },
offset: { buffer: offsetBuffer1, nrInstances: 1 },
},
program
);
const tf1 = createTf({
newOffset: offsetBuffer2,
});
const vao2 = createVao(
{
rectVertex: { buffer: rectBuffer, nrInstances: 0 },
offset: { buffer: offsetBuffer2, nrInstances: 1 },
},
program
);
const tf2 = createTf({
newOffset: offsetBuffer1,
});
drawInstanced({ program, vao: vao1, tf: tf1, nrInstances });
drawInstanced({ program, vao: vao2, tf: tf2, nrInstances });
Chrome gives me a helpful error:
[.WebGL-0x11c00521400] GL_INVALID_OPERATION: Not enough space in bound transform feedback buffers.
I'm not quite sure... but here's my best guess, written in python pseudo-code:
import numpy as np
nrInstances = 5
nrVertices = 3
positionBuffer = {
"data": np.array([[0,1], [2,3], [4,5], [5,6], [6,7]], dtype=np.float32),
"nrInstances": 1
}
# transform feedback output
positionNewBuffer = {
"data": np.array([[0, 0]] * nrInstances * nrVertices, dtype=np.float32),
}
# my understanding of how webgl fetches data from instanced
# and non-instanced attributes:
def getDataIn(i, v, buffer):
index = 0
if "nrInstances" in buffer:
# https://registry.khronos.org/OpenGL/specs/es/3.0/es_spec_3.0.pdf#nameddest=subsection.2.9
# If an enabled vertex attribute array is instanced (it has a non-zero
# divisor), the element that is transferred to the GL, for
# all vertices, is given by:
# floor(instance / divisor)
index = int(i / buffer["nrInstances"]) # independent of v!
# non-instanced: same vertices used for all instances
else:
index = v # independent of i!
data = buffer["data"][index]
return data
# my understanding of how webgl places data in a transform-feedback buffer:
def setDataOut(value, i, v, buffer):
# https://registry.khronos.org/OpenGL/specs/es/3.0/es_spec_3.0.pdf#nameddest=subsection.2.15.2
# not sure how this is implemented when doing instanced drawing,
# but here's my guess:
indexOut = i * nrVertices + v
buffer["data"][indexOut] = value
# draw call:
for i in range(nrInstances):
for v in range(nrVertices):
valPos = getDataIn(i, v, positionBuffer)
newVal = valPos + 0.02
setDataOut(newVal, i, v, positionNewBuffer)
The problem here is this:
While webgl expects the input-attribute position
to have a buffer with nrInstances * 2
elements, it requires the output-transform-feedback buffer to have nrInstances * nrVertices * 2
elements.
Is my suspicion correct? Is there a way to configure transform feedback in such a way that I can still combine transform feedback with instanced drawing?
Upvotes: 0
Views: 84