JSFiddle - React, Tailwind, and code Playground
HTML
<canvas id="gl"></canvas>
<div id="info">
<b>Mesh volume via x-flux</b><br>
Hover over a triangle.<br><br>
<span class="red">Red</span> = positive contribution<br>
<span class="blue">Blue</span> = negative contribution
<div id="face">No triangle selected</div>
</div>
CSS
html, body {
margin: 0;
width: 100%;
height: 100%;
overflow: hidden;
background: #101216;
font-family: system-ui, sans-serif;
}
#gl {
width: 100%;
height: 100%;
display: block;
}
#info {
position: absolute;
top: 14px;
left: 14px;
padding: 12px 15px;
color: white;
background: rgba(0,0,0,.72);
border-radius: 8px;
font-size: 14px;
line-height: 1.45;
pointer-events: none;
}
#face {
margin-top: 12px;
font-family: monospace;
white-space: pre;
}
.red { color: #ff6666; }
.blue { color: #66aaff; }
JavaScript
"use strict";
const canvas = document.getElementById("gl");
const info = document.getElementById("face");
const gl = canvas.getContext("webgl", {
antialias: true,
alpha: false
});
if (!gl) throw new Error("WebGL not supported");
// ============================================================
// SHADERS
// ============================================================
function compileShader(type, source) {
const s = gl.createShader(type);
gl.shaderSource(s, source);
gl.compileShader(s);
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {
throw new Error(gl.getShaderInfoLog(s));
}
return s;
}
function createProgram(vsSource, fsSource) {
const p = gl.createProgram();
gl.attachShader(p, compileShader(gl.VERTEX_SHADER, vsSource));
gl.attachShader(p, compileShader(gl.FRAGMENT_SHADER, fsSource));
gl.linkProgram(p);
if (!gl.getProgramParameter(p, gl.LINK_STATUS)) {
throw new Error(gl.getProgramInfoLog(p));
}
return p;
}
const program = createProgram(
`
attribute vec3 position;
uniform mat4 matrix;
void main() {
gl_Position = matrix * vec4(position, 1.0);
}
`,
`
precision mediump float;
uniform vec4 color;
void main() {
gl_FragColor = color;
}
`
);
const aPosition = gl.getAttribLocation(program, "position");
const uMatrix = gl.getUniformLocation(program, "matrix");
const uColor = gl.getUniformLocation(program, "color");
gl.useProgram(program);
// ============================================================
// MATH
// ============================================================
const sub = (a,b) => [
a[0]-b[0],
a[1]-b[1],
a[2]-b[2]
];
const add = (a,b) => [
a[0]+b[0],
a[1]+b[1],
a[2]+b[2]
];
const mul = (a,s) => [
a[0]*s,
a[1]*s,
a[2]*s
];
const dot = (a,b) =>
a[0]*b[0] +
a[1]*b[1] +
a[2]*b[2];
const cross = (a,b) => [
a[1]*b[2] - a[2]*b[1],
a[2]*b[0] - a[0]*b[2],
a[0]*b[1] -...