Last active
September 27, 2019 04:55
-
-
Save 1chandu/58c2f58b95a1975120b373eb57bfea9a to your computer and use it in GitHub Desktop.
Rendering to 1X1 Target (WebGL1)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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