Skip to content

Instantly share code, notes, and snippets.

@1chandu
Last active September 27, 2019 04:55
Show Gist options
  • Save 1chandu/58c2f58b95a1975120b373eb57bfea9a to your computer and use it in GitHub Desktop.
Save 1chandu/58c2f58b95a1975120b373eb57bfea9a to your computer and use it in GitHub Desktop.
Rendering to 1X1 Target (WebGL1)
<!DOCTYPE html>
<html>
<script type="vertex" id="vs">
attribute float vertexID;
varying vec4 vColor;
void main(void) {
gl_Position = vec4(0., 0., 0., 1.); // Failed on windows chrome/firefox, passed on firefox with disable-angle
// gl_Position = vec4(-1., -1., 0., 1.); // Failed on widnows chrome/firefox, passed on firefox with disable-angle
// gl_Position = vec4(0.5, 0.5, 0., 1.); // Failed on widnows chrome/firefox, passed on firefox with disable-angle
vColor = vec4(1, 1, 1, vertexID);
}
</script>
<script type="fragment" id="fs">
precision highp float;
varying vec4 vColor;
void main(void) {
gl_FragColor = vColor;
}
</script>
<canvas id="webgl-canvas"></canvas>
<script>
/*
Setup a frame buffer with 1X1 texture, and render N points to the same pixel position.
Clear the render target with (0, 0, 0) and render (1, 1, 1) and peform readPixels to verify the value
*/
const WIDTH = 1;
const HEIGHT = 1;
const POINT_COUNT = 10;
const canvas = document.getElementById("webgl-canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const gl = canvas.getContext("webgl");
const width = WIDTH;
const height = HEIGHT;
// set up Program
const vsSource = document.getElementById("vs").text.trim();
const fsSource = document.getElementById("fs").text.trim();
const vs = gl.createShader(gl.VERTEX_SHADER);
const fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vs, vsSource);
gl.compileShader(vs);
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
let i, lines;
console.error(gl.getShaderInfoLog(vs));
lines = vsSource.split("\n");
for (i = 0; i < lines.length; ++i) {
console.error(`${i + 1}: ${lines[i]}`);
}
}
gl.shaderSource(fs, fsSource);
gl.compileShader(fs);
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
let i, lines;
console.error(gl.getShaderInfoLog(fs));
lines = vsSource.split("\n");
for (i = 0; i < lines.length; ++i) {
console.error(`${i + 1}: ${lines[i]}`);
}
}
const program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
gl.useProgram(program);
// set up Framebuffer to render to 1X1 texture
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.activeTexture(gl.TEXTURE0);
const colorTarget = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, colorTarget);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTarget, 0);
// GEOMETRY
// var ext = gl.getExtension("OES_vertex_array_object");
// let quadArray;
// if (!ext) {
// console.error('This test will fail, OES_vertex_array_object is not supported');
// } else {
// quadArray = ext.createVertexArrayOES();
// }
// const quadArray = gl.createVertexArrayOES();
// gl.bindVertexArray(quadArray);
const vertexIDBuffer = gl.createBuffer();
const vertexIDs = new Float32Array(POINT_COUNT).map((_, index) => index);
gl.bindBuffer(gl.ARRAY_BUFFER, vertexIDBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertexIDs, gl.STATIC_DRAW);
gl.vertexAttribPointer(0, 1, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(0);
gl.viewport(0, 0, width, height);
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.disable(gl.BLEND);
gl.disable(gl.DEPTH_TEST);
gl.drawArrays(gl.POINTS, 0, POINT_COUNT);
const data = new Uint8Array(4 * width * height);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, data);
let failed = false;
console.log('--- Testing Rendering to 1X1 Texture ---');
const expectedColor = [255, 255, 255]; // alpha value depends on which fragment rendered last not checking for it.
const EPSILON = 0.000001;
if (Math.abs(data[0] - expectedColor[0]) > EPSILON) {
console.log(`Red channel: expected ${expectedColor[0]} actual: ${data[0]}`);
failed = true;
}
if (Math.abs(data[1] - expectedColor[1]) > EPSILON) {
console.log(`Green channel: expected ${expectedColor[1]} actual: ${data[1]}`);
failed = true;
}
if (Math.abs(data[2] - expectedColor[2]) > EPSILON) {
console.log(`Blue channel: expected ${expectedColor[2]} actual: ${data[2]}`);
failed = true;
}
console.log(`Expected color : ${expectedColor.slice(0, 3)}`);
console.log(`Received color : ${data.slice(0, 3)}`);
if (failed) {
console.log('TEST FAILED');
} else {
console.log('TEST PASSED');
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment