let div = document.createElement('div'); document.body.appendChild( div ); div.style['font-size'] = '20pt'; function log( s ) { console.log( s ); let args = [...arguments].join(' '); div.innerHTML += args + '<br><br>'; }
// Output texture - output from the compute shader written to this texture // Copy this texutre to the 'canvas' - needs to be the same size as the output // canvas size const texture1 = device.createTexture({ size: [imgWidth, imgHeight, 1], format: "rgba8unorm", usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.STORAGE_BINDING });
var coords = vec2<f32>(f32(globalId.x), f32(globalId.y)); var uv = coords / vec2<f32>(imgWidth, imgHeight); // normalize coordinates to 0.0 - 1.0 range
// Neighborhood size for oil painting effect let radius: i32 = 4; // size of the neighborhood let intensityLevels: i32 = 32; // number of intensity levels for quantization
// Loop through the neighborhood for (var i = -radius; i <= radius; i++) { for (var j = -radius; j <= radius; j++) { var sampleCoords = vec2<i32>(i32(globalId.x) + i, i32(globalId.y) + j); if (sampleCoords.x >= 0 && sampleCoords.x < i32(imgWidth) && sampleCoords.y >= 0 && sampleCoords.y < i32(imgHeight) ) { var sampleUv = vec2<f32>(f32(sampleCoords.x) / imgWidth, f32(sampleCoords.y) / imgHeight); var sampleColor = textureLoad(myTexture0, sampleCoords, 0);
// Convert color to intensity var intensity = dot(sampleColor.rgb, vec3<f32>(0.299, 0.587, 0.114)); var intensityIndex = i32(intensity * f32(intensityLevels - 1)); intensityIndex = clamp(intensityIndex, 0, intensityLevels - 1);
// Accumulate color in histogram hist[intensityIndex] += sampleColor; intensityCount[intensityIndex] += 1; } } }
// Find the most frequent intensity var maxIndex:u32 = 0; var maxCount:u32 = 0; for (var k = 0; k < intensityLevels; k++) { if (intensityCount[k] > u32(maxCount) ) { maxCount = intensityCount[k]; maxIndex = u32(k); } }
// Average the colors in the most frequent intensity var finalColor = vec4<f32>(0.0); if (maxCount > 0) { finalColor = hist[maxIndex] / f32(maxCount); }
// Store the result in the output texture textureStore(myTexture1, vec2<i32>(globalId.xy), finalColor); } `;
• Try modifying the coefficients (modify the effect).
• Combine the oil effect with other image filtering techniques (sharpening/blurring/edge detection).