Created
March 8, 2022 22:19
-
-
Save lefuturiste/45eee83ebe76adcac32579a72f31113a to your computer and use it in GitHub Desktop.
This file contains hidden or 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 lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Voronoi Diagram with GPU</title> | |
</head> | |
<body> | |
<div> | |
<canvas id="glcanvas" width="512" height="512"> | |
</canvas> | |
</div> | |
<script id="vertex-shader" type="x-shader/x-vertex"> | |
attribute vec2 aVertexPosition; | |
varying vec2 uv; | |
void main() { | |
gl_Position = vec4(aVertexPosition.x, aVertexPosition.y, 0, 1.0); | |
uv = vec2(aVertexPosition.x, aVertexPosition.y); | |
} | |
</script> | |
<script id="fragment-shader" type="x-shader/x-fragment"> | |
#ifdef GL_ES | |
precision highp float; | |
#endif | |
#define POINTS_COUNT %POINTS_COUNT% | |
uniform sampler2D diagPointsTex; | |
uniform sampler2D diagColorsTex; | |
varying vec2 uv; | |
void main() { | |
int closest = -1; | |
float closestDistance = 0.0; | |
for (int i = 0; i < POINTS_COUNT; ++i) { | |
mediump vec4 _diagPoint = texture2D(diagPointsTex, vec2((float(i)/float(POINTS_COUNT)), 0)); | |
vec2 diagPoint = vec2(_diagPoint.x, _diagPoint.y); | |
float d = length( | |
diagPoint - uv | |
); | |
if (i == 0 || d < closestDistance) { | |
closest = i; | |
closestDistance = d; | |
} | |
if (d < 0.008) { | |
gl_FragColor = vec4(1, 1, 1, 1); | |
return; | |
} | |
} | |
gl_FragColor = texture2D(diagColorsTex, vec2((float(closest)/float(POINTS_COUNT)), 1)); | |
} | |
</script> | |
<script src="voronoi_webgl.js"> | |
</script> | |
</body> | |
</html> |
This file contains hidden or 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
let gl = null; | |
let glCanvas = null; | |
let aVertexPosition; | |
let uDiagPoints; | |
let uDiagPointsColors; | |
let vertexCount; | |
const vertexNumComponents = 2; | |
let numberOfPoints = 4; | |
const startup = (nb = null) => { | |
if (nb !== null) { | |
numberOfPoints = nb | |
} | |
glCanvas = document.getElementById("glcanvas"); | |
gl = glCanvas.getContext("webgl"); | |
const shaderSet = [ | |
{ type: gl.VERTEX_SHADER, id: "vertex-shader" }, | |
{ type: gl.FRAGMENT_SHADER, id: "fragment-shader" } | |
]; | |
shaderProgram = buildShaderProgram(shaderSet); | |
if (shaderProgram == -1) { | |
return | |
} | |
vertexBuffer = gl.createBuffer(); | |
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); | |
let vertexArray = new Float32Array([ -1,1, -1,-1, 1,-1, 1,1 ]); | |
gl.bufferData(gl.ARRAY_BUFFER, vertexArray, gl.STATIC_DRAW); | |
vertexCount = vertexArray.length / vertexNumComponents; | |
let baseColor = [0x39/255, 0x47/255, 0x20/255] | |
let pointsRaw = [] | |
let colorsRaw = [] | |
for (let i = 0; i < numberOfPoints; i++) { | |
pointsRaw.push((Math.random() > 0.5 ? 1 : -1)*Math.random()) | |
pointsRaw.push((Math.random() > 0.5 ? 1 : -1)*Math.random()) | |
pointsRaw.push(0) | |
pointsRaw.push(0) | |
colorsRaw.push(0.2+i*(0.8/numberOfPoints)) | |
colorsRaw.push(0) | |
colorsRaw.push(0) | |
colorsRaw.push(0.1+i*((1-0.1)/numberOfPoints)) | |
} | |
console.log(pointsRaw, colorsRaw) | |
gl.getExtension('OES_texture_float'); | |
let initTexture = (textureId, rawData, count) => { | |
// 3x1 pixel 1d texture | |
gl.activeTexture(textureId); | |
let tex = gl.createTexture(); | |
gl.bindTexture(gl.TEXTURE_2D, tex); | |
let data = new Float32Array(rawData) | |
gl.texImage2D( | |
gl.TEXTURE_2D, | |
0, gl.RGBA, | |
count, 1, | |
0, gl.RGBA, | |
gl.FLOAT, | |
data | |
); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_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); | |
} | |
initTexture(gl.TEXTURE0, pointsRaw, numberOfPoints) | |
initTexture(gl.TEXTURE1, colorsRaw, numberOfPoints) | |
animateScene(); | |
} | |
const buildShaderProgram = (shaderInfo) => { | |
let program = gl.createProgram(); | |
shaderInfo.forEach((desc) => { | |
let shader = compileShader(desc.id, desc.type); | |
if (shader == -1) { | |
return -1; | |
} | |
if (shader) { | |
gl.attachShader(program, shader); | |
} | |
}); | |
gl.linkProgram(program) | |
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { | |
console.error("Error linking shader program:", gl.getProgramInfoLog(program)); | |
return -1; | |
} | |
return program; | |
} | |
const compileShader = (id, type) => { | |
let code = document.getElementById(id).firstChild.nodeValue; | |
let shader = gl.createShader(type); | |
if (id == 'fragment-shader') { | |
code = code.replace('%POINTS_COUNT%', numberOfPoints) | |
} | |
gl.shaderSource(shader, code); | |
gl.compileShader(shader); | |
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { | |
console.error( | |
`Error compiling ${type === gl.VERTEX_SHADER ? "vertex" : "fragment"} shader:`, | |
gl.getShaderInfoLog(shader) | |
); | |
return -1; | |
} | |
return shader; | |
} | |
const animateScene = () => { | |
gl.viewport(0, 0, glCanvas.width, glCanvas.height); | |
gl.clearColor(0.8, 0.9, 1.0, 1.0); | |
gl.clear(gl.COLOR_BUFFER_BIT); | |
gl.useProgram(shaderProgram); | |
// gl.uniform1f(uScalingFactor, currentScale); | |
gl.uniform1f(gl.getUniformLocation(shaderProgram, "numberOfPoints"), numberOfPoints); | |
// gl.uniform2fv(uRotationVector, currentRotation); | |
//gl.uniform4fv(uGlobalColor, [0.1, 0.7, 0.2, 1.0]); | |
gl.uniform1i(gl.getUniformLocation(shaderProgram, "diagPointsTex"), 0); | |
gl.uniform1i(gl.getUniformLocation(shaderProgram, "diagColorsTex"), 1); | |
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); | |
aVertexPosition = gl.getAttribLocation(shaderProgram, "aVertexPosition"); | |
gl.vertexAttribPointer(aVertexPosition, vertexNumComponents, gl.FLOAT, false, 0, 0); | |
gl.enableVertexAttribArray(aVertexPosition); | |
gl.drawArrays(gl.TRIANGLE_FAN, 0, vertexCount); | |
} | |
window.addEventListener("load", () => { | |
startup() | |
}, false); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment