Shading with GPU accelerated math
by Richard
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/gpu.js/1.10.4/gpu.min.js"></script>
<div class="images">
<img id="img" crossorigin width="400" src="//cdn.shopify.com/s/files/1/0654/9053/products/untitled-untitled-IMG_7342_e1143013-eda0-4fc8-a813-a030c32bdcf3_grande.jpg?v=1525821958">
</div>
<br>
<label>Custom Image
<input type="file" id="pic">
</label>
<br>
<label>
Spaces
<input type="range" step="1" value="4" min="2" max="10" id="spaces">
<span id="spaces-value"></span>
</label>
<br>
<label>
Line Exponentiality
<input type="range" step="0.1" value="1.4" min="1" max="3" id="exp">
<span id="exp-value"></span>
</label>
<br>
<label>
K
<input type="range" step="0.1" value="30" min="10" max="200" id="k">
<span id="k-value"></span>
</label>
<br>
<label>
Function
<select id="function">
<option value="1">Vertical</option>
<option value="2">Diagonal</option>
<option value="3">Circular</option>
<option value="4">Wave</option>
</select>
</label>
JavaScript
const gpu = new GPU();
const image = document.getElementById('img');
function lum(r, g, b) {
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
gpu.addFunction(lum);
function verticalLine(x) {
return x;
}
gpu.addFunction(verticalLine);
function diagonalLine(x, y) {
return x + y;
}
gpu.addFunction(diagonalLine);
function reverseDiagonalLine(x, y) {
return y - x;
}
gpu.addFunction(reverseDiagonalLine);
function circleLine(x, y) {
return Math.round(Math.sqrt(x * x + y * y));
}
gpu.addFunction(circleLine);
function waveLine(x, y) {
return Math.round(y / this.constants.k * Math.cos(x / this.constants.k));
}
gpu.addFunction(waveLine);
function shade(img) {
// Get position
const x = this.thread.x;
const y = this.thread.y;
// Get pixel
const p = img[y][x];
// Get luminace
const l = lum(p[0], p[1], p[2])
// Threshold color
const space = l * this.constants.spaces;
// Exponentially space out lines
const lineSpacing = Math.round(Math.pow(space, this.constants.exp));
// Default color
this.color(1, 1, 1);
// Apply function
let f = 1;
if (this.constants.func === 1) {
f = verticalLine(x);
} else if (this.constants.func === 2) {
f = diagonalLine(x, y);
} else if (this.constants.func === 3) {
f = circleLine(x, y);
} else {
f = waveLine(x, y);
}
if (f % lineSpacing === 0) {
this.color(0, 0, 0);
}
}
let first = true;
function update() {
const render = gpu.createKernel(shade)
.setGraphical(true)
.setOutput([image.width, image.height])
.setConstants({
spaces: parseInt(document.getElementById('spaces').value),
exp: parseFloat(document.getElementById('exp').value),
k: parseFloat(document.getElementById('k').value),
func: parseFloat(document.getElementById('function').value),
})
document.getElementById('spaces-value').innerHTML = document.getElementById('spaces').value
document.getElementById('exp-value').innerHTML = document.getElementById('exp').value
...