1

我试图在浏览器中渲染一个图像,它是这样构建的:

  • 一堆矩形每个都填充有径向渐变(理想情况下是高斯,但可以用几个停止点来近似)
  • 每个矩形在被放置到绘图区域之前都经过旋转和平移

  • 通过对矩形的所有强度求和来展平图像(并裁剪到绘图区域的尺寸)

  • 重新调整强度,使最高强度为 255,最低为 0(理想情况下,我也可以应用某种伽玛校正)

  • 最后绘制一个图像,其中每个像素的颜色取自 256 种颜色的调色板。

我不能用画布对象轻松做到这一点的原因是我需要在浮点数中工作,否则我会失去精度。我事先不知道最大强度和最小强度是多少,所以我不能只画透明矩形并希望最好。

有没有办法在 webgl 中做到这一点?如果是这样,我会怎么做?

4

1 回答 1

-1

您可以使用常规画布来执行此任务:

1)检查你的矩形的最小值/最大值,这样你就可以在该范围之外构建一个映射函数 double -> [0-255] 。

2)以“较轻”模式绘制矩形==添加组件值。

3)当几个矩形重叠时,您可能会出现饱和:如果是这样,则将映射范围加倍并转到 2)。
现在,如果您没有饱和度,只需调整范围以使用画布的整个 [0-255] 范围,您就完成了。

由于此算法使用getImageData,它可能无法在所有浏览器/设备上达到 60 fps。但桌面/Chrome 上超过 10fps 似乎完全有可能。

希望下面的代码能澄清我的描述:

//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 the scene using current mapping
        drawScene();
        // get the max int value from the canvas
        var max = getMax();
        if (max == 255) {
            // saturation ?? double the min-max interval
            globalMax = globalMin + 2 * (globalMax - globalMin);
        } else {
            // no sauration ? Just adjust the 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 that = 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;
    for (var i = 1; i < 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 = [];
    for (var i = 0; i < 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 all 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';
    for (var i = 0; i < rectCount; i++) {
        var thisRect = rects[i];
        thisRect.draw();
    }
    ctx.restore();
}


// get maximum value for r for this canvas 
//   ( == max r, g, b value for a gray-only drawing. )
function getMax() {
    var data = ctx.getImageData(0, 0, cv.width, cv.height).data;
    var max = 0;
    for (var i = 0; i < data.length; i += 4) {
        if (data[i] > max) max = data[i];
        if (max == 255) return 255;
    }
    return max;
}
<canvas id='cv' width = 400 height = 400></canvas>

于 2015-05-15T18:05:38.413 回答