const canvas = document.querySelector('canvas');
var gl = canvas.getContext('webgl2', {preserveDrawingBuffer: true});
// ___________shaders
// ___________vs and fs #1
const genPointsVSGLSL = `#version 300 es
in vec4 aPos;
void main(void) {
gl_PointSize = 20.0;
gl_Position = vec4( -0.01 + aPos.x , -0.01+aPos.y , aPos.zw);
}
`;
const genPointsFSGLSL = `#version 300 es
precision highp float;
out vec4 color;
void main() {
discard;
//color = vec4(0.5,0.5,0.0,1.0);
}
`;
// ___________vs and fs #2
const drawVSGLSL = `#version 300 es
in vec4 position;
void main() {
gl_PointSize = 20.0;
gl_Position = position;
}
`;
const drawFSGLSL = `#version 300 es
precision highp float;
out vec4 outColor;
void main() {
outColor = vec4( 255.0,0.0,0.0,1.0 );
}
`;
// create shaders and programs code
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.getProgramParameter(prg))
}
return prg
};
const genProg = createProgram(gl, genPointsVSGLSL, genPointsFSGLSL, ['gl_Position']);
const drawProg = createProgram(gl, drawVSGLSL, drawFSGLSL, ['gl_Position']);
// program1 location attribute
const positionLoc = gl.getAttribLocation( drawProg , 'position');
// program2 location attribute
const aPosLoc = gl.getAttribLocation( genProg , 'aPos');
var vertizes = [0.8,0,0,1, 0.8,0.5,0,1];
var indizes = vertizes.length/4;
// create buffers and transform feedback
var bufA = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, bufA)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array( vertizes ), gl.DYNAMIC_COPY)
var bufB = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, bufB)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array( vertizes ) , gl.DYNAMIC_COPY)
var transformFeedback = gl.createTransformFeedback()
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, transformFeedback)
// draw
function draw(){
gl.useProgram( genProg );
gl.clear(gl.COLOR_BUFFER_BIT);
// bind bufA to output of program#2
gl.bindBuffer(gl.ARRAY_BUFFER, bufA);
gl.enableVertexAttribArray( aPosLoc );
gl.vertexAttribPointer(aPosLoc, 4, gl.FLOAT, gl.FALSE, 0, 0)
// run movement calculation code, aka program#2 (calculate movement location and hide the results using RASTERIZER_DISCARD )
gl.enable(gl.RASTERIZER_DISCARD);
gl.drawArrays(gl.POINTS, 0, indizes);
gl.disable(gl.RASTERIZER_DISCARD);
gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, bufB);
// move dot using rendering code and the position calculated previously which is still stored in bufA
gl.useProgram( drawProg );
gl.bindBuffer( gl.ARRAY_BUFFER, bufA );
gl.enableVertexAttribArray( positionLoc );
gl.vertexAttribPointer( positionLoc , 4, gl.FLOAT, gl.FALSE, 0, 0);
gl.drawArrays(gl.POINTS, 0, indizes);
gl.useProgram( genProg );
// run transforma feedback
gl.beginTransformFeedback(gl.POINTS);
gl.drawArrays(gl.POINTS, 0, indizes);
gl.endTransformFeedback();
gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null);
// switch bufA and bufB in preperation for the next draw call
var t = bufA;
bufA = bufB;
bufB = t;
}
setInterval( draw , 100 );
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>