html5 canvas - Compose an image with floating point layers in webgl -
i have trying render image in browser built this:
- a bunch of rectangles each filled radial gradient (ideally gaussian, can approximated few stopping points
each rectangle rotated , translated before being deposited on drawing area
the image flattened summing intensities of rectangles (and cropping drawing area's dimensions )
the intensity rescaled highest intensity 255 , lowest 0 (ideally can apply sort of gamma correction too)
finally image drawn color of each pixel taken palette of 256 colors.
the reason cannot canvas object need working in floating points or i'll lose precision. not know in advance maximum intensity , minimum intensity be, cannot merely draw transparent rectangles , hope best.
is there way in webgl? if so, how go it?
you can use regular canvas perform task :
1) check min/max of rects, can build mapping function double -> [0-255] out of range.
2) draw rects in 'lighter' mode == add component values.
3) might have saturation when several rects overlaps : if so, double mapping range , go 2).
if don't have saturation adjust range use full [0-255] range of canvas, , you're done.
since algorithm makes use of getimagedata
, might not reach 60 fps on browsers/devices. more 10fps on desktop/chrome seems possible.
hopefully code below clarify description :
//noprotect // boilerplate var cv = document.getelementbyid('cv'); var ctx = cv.getcontext('2d'); // rectangle collection var rectcount = 30; var rects = buildrandrects(rectcount); iteratetomax(); // -------------------------------------------- function iteratetomax() { var limit = 10; // loop protection // initialize min/max mapping based on rects min/max updatemapping(rects); // while (true) { // draw scene using current mapping drawscene(); // max int value canvas var max = getmax(); if (max == 255) { // saturation ?? double min-max interval globalmax = globalmin + 2 * (globalmax - globalmin); } else { // no sauration ? adjust min-max interval globalmax = globalmin + (max / 255) * (globalmax - globalmin); drawscene(); return; } limit--; if (limit <= 0) return; } } // -------------------------------------------- // -------------------------------------------- // oriented rectangle class. function rect(x, y, w, h, rotation, min, max) { this.min = min; this.max = max; this.draw = function () { ctx.save(); ctx.fillstyle = createradialgradient(min, max); ctx.translate(x, y); ctx.rotate(rotation); ctx.scale(w, h); ctx.fillrect(-1, -1, 2, 2); ctx.restore(); }; var = this; function createradialgradient(min, max) { var gd = ctx.createradialgradient(0, 0, 0, 0, 0, 1); var start = map(that.min); var end = map(that.max); gd.addcolorstop(0, 'rgb(' + start + ',' + start + ',' + start + ')'); gd.addcolorstop(1, 'rgb(' + end + ',' + end + ',' + end + ')'); return gd; } } // mapping : float value -> 0-255 value var globalmin = 0; var globalmax = 0; function map(value) { return 0 | (255 * (value - globalmin) / (globalmax - globalmin)); } // create initial mapping function updatemapping(rects) { globalmin = rects[0].min; globalmax = rects[0].max; (var = 1; < rects.length; i++) { var thisrect = rects[i]; if (thisrect.min < globalmin) globalmin = thisrect.min; if (thisrect.max > globalmax) globalmax = thisrect.max; } } // random rect collection function buildrandrects(rectcount) { var rects = []; (var = 0; < rectcount; i++) { var thismin = math.random() * 1000; var newrect = new rect(math.random() * 400, math.random() * 400, 10 + math.random() * 50, 10 + math.random() * 50, math.random() * 2 * math.pi, thismin, thismin + math.random() * 1000); rects.push(newrect); } return rects; } // draw rects in 'lighter' mode (=sum values) function drawscene() { ctx.save(); ctx.globalcompositeoperation = 'source-over'; ctx.clearrect(0, 0, cv.width, cv.height); ctx.globalcompositeoperation = 'lighter'; (var = 0; < rectcount; i++) { var thisrect = rects[i]; thisrect.draw(); } ctx.restore(); } // maximum value r canvas // ( == max r, g, b value gray-only drawing. ) function getmax() { var data = ctx.getimagedata(0, 0, cv.width, cv.height).data; var max = 0; (var = 0; < data.length; += 4) { if (data[i] > max) max = data[i]; if (max == 255) return 255; } return max; }
<canvas id='cv' width = 400 height = 400></canvas>
Comments
Post a Comment