I try to follow example from webgl2fundamentals regarding transform feedback.
My goal is to create animation of vertex positions in a way that there are two programs:
- doing animation calculations each frame and writing output to a buffer
- doing drawing on screen using buffer with calculated values from 1st program.
I made this code snippet on codesandbox.
It seems that varying vPosition
from first program is not being feed to the second program. What am I doing wrong?
Is setup enough to handle this use case? I have one TFO and one VAO and one buffer. What would be best approach?
The output should look something like this:
here is the code:
const canvas = document.querySelector("canvas");
canvas.width = 500;
canvas.height = 500;
const gl = canvas.getContext("webgl2");
const genPointsVSGLSL = `#version 300 es
uniform float time;
in vec2 position;
out vec2 vPosition;
void main() {
vPosition = vec2(position * (sin(time) + 1.0));
}
`;
const genPointsFSGLSL = `#version 300 es
void main() {
discard;
}
`;
const drawVSGLSL = `#version 300 es
uniform float time;
in vec2 vPosition;
void main() {
gl_PointSize = 20.0;
gl_Position = vec4(vPosition, 0.0, 1.0);
}
`;
const drawFSGLSL = `#version 300 es
precision highp float;
out vec4 outColor;
void main() {
outColor = vec4(0.0, 0.0, 0.0, 1.0);
}
`;
function generatePoints(num) {
const arr = [];
for (let i = 0; i < num; i++) {
const u = i / num;
const a = u * Math.PI * 2.0;
arr.push(Math.cos(a) * 0.8, Math.sin(a) * 0.8);
}
return new Float32Array(arr);
}
const numPoints = 12;
let time = 0.0;
const createShader = function (gl, type, glsl) {
const shader = gl.createShader(type);
gl.shaderSource(shader, glsl);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
throw new Error(gl.getShaderInfoLog(shader));
}
return shader;
};
const createProgram = function (gl, vsGLSL, fsGLSL, outVaryings) {
const vs = createShader(gl, gl.VERTEX_SHADER, vsGLSL);
const fs = createShader(gl, gl.FRAGMENT_SHADER, fsGLSL);
const prg = gl.createProgram();
gl.attachShader(prg, vs);
gl.attachShader(prg, fs);
if (outVaryings) {
gl.transformFeedbackVaryings(prg, outVaryings, gl.SEPARATE_ATTRIBS);
}
gl.linkProgram(prg);
if (!gl.getProgramParameter(prg, gl.LINK_STATUS)) {
throw new Error(gl.getProgramInfoLog(prg));
}
return prg;
};
// gen prog
const genProg = createProgram(gl, genPointsVSGLSL, genPointsFSGLSL, [
"vPosition"
]);
gl.bindAttribLocation(genProg, 0, "position");
const timeLocGen = gl.getUniformLocation(genProg, "time");
const drawProg = createProgram(gl, drawVSGLSL, drawFSGLSL);
gl.bindAttribLocation(drawProg, 0, "vPosition");
const timeLocDraw = gl.getUniformLocation(drawProg, "time");
const dotVertexArray = gl.createVertexArray();
gl.bindVertexArray(dotVertexArray);
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// gl.bufferData(gl.ARRAY_BUFFER, numPoints * 2 * 4, gl.DYNAMIC_DRAW);
gl.bufferData(gl.ARRAY_BUFFER, generatePoints(12), gl.DYNAMIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(
0, // location
2, // size (components per iteration)
gl.FLOAT, // type of to get from buffer
false, // normalize
0, // stride (bytes to advance each iteration)
0 // offset (bytes from start of buffer)
);
gl.bindVertexArray(null);
const tf = gl.createTransformFeedback();
function loop() {
// update positions
gl.useProgram(genProg);
gl.enable(gl.RASTERIZER_DISCARD);
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, positionBuffer);
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
gl.beginTransformFeedback(gl.POINTS);
gl.uniform1f(timeLocGen, time);
gl.drawArrays(gl.POINTS, 0, numPoints);
gl.endTransformFeedback();
gl.disable(gl.RASTERIZER_DISCARD);
// draw vertices
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.bindVertexArray(dotVertexArray);
gl.useProgram(drawProg);
gl.uniform1f(timeLocDraw, time);
gl.drawArrays(gl.POINTS, 0, numPoints);
}
function animate() {
time += 0.01;
loop();
window.requestAnimationFrame(animate);
}
animate();
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<canvas></canvas>
<script src="src/index.js"></script>
</body>
</html>