绘制重叠的圆阿尔法窜 [英] Drawing overlapping circles with alpha channeling

查看:137
本文介绍了绘制重叠的圆阿尔法窜的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题已排序已经在这里找到答案:合并重叠的圆圈 <面积/ P>

我的问题是更具体的,但。我有一个任意数量的任意大小的圆圈内的其他任意大小的圆形,使目标式的影像:

此图像必须具有透明度一定量。透明度必须在整个形状相同。然后,还有这些形状可以重叠任意数量的,它需要是这样的:

透明度量必须保持不变,不管他们多么重叠。

我唯一能想到的拉这一关是要遍历在画布上的每一个像素,并计算出什么颜色的像素,应根据每个圆心的距离,但这个时间太长。我想圆圈为可拖动一样,所以这个需要是pretty的快。有没有更好的办法做到这一点? (对不起我那可怜的GIMP技能)

解决方案

这是可以做到的本身,而无需使用像素处理或任何库。

所提供的透明性是相同的所有的圈子是pretty的直线前进。

解决方案


上的一些随机的背景

顶圆

您需要做的是:

  • 分配离屏画布上,其中圆圈画成固体(不透明度)
  • 在画中的三个步骤的圈子。
  • 所有圈红色表面上的第一,那么所有的圆圈蓝面等。
  • 在透明的主(可见光)的画布设置全局alpha
  • 清除这两个画布
  • 在画离屏画布主画布

您圈子功能可以是这个样子:

 函数画圆(X,Y,R,步骤){

    ctx.beginPath();

    开关(步骤){
        情况下0://一步0,外圈红色
            ctx.fillStyle ='#F00;
            打破;

        案例1://步骤1,中圈蓝
            ctx.fillStyle ='#00F';
            R * = 0.67;
            打破;

        案例2://步骤2中,内圆绿色
            ctx.fillStyle ='#0f0;
            R * = 0.33;
            打破;
    }
    ctx.arc(X,Y,R,0,2 * Math.PI);
    ctx.fill();
}
 

该函数将 X 中心点以及半径。但除了它需要一个介于0和2,它决定表面被绘制的值。这将在接下来的步骤的重要

首先,我们可以定义一个数组保存所有我们要画的圆圈:

  VAR =欲订购[
    // XYR DX DY(最后两个动画只)
    [100,100,50,2,1],
    [200,200,50,-2,-3],
    [150,50,50,3,-1]
]。
 

在这里,您会拖他们,偏移x和y,然后重绘它们,但是对于演示的份上,我会为它们制作动画。

在我们得出我们设置了主画布(关闭屏幕保持固体)对全球阿尔法:

  mctx.globalAlpha = 0.7; //主画布
 

和动画循环:

 函数start(){

    //清晰的屏幕外的画布
    ctx.clearRect(0,0,W,H);

    //明确主画布
    mctx.clearRect(0,0,W,H);

    变种T = 0,I,C;

    //外部台阶环
    对于(; T&LT; 3;吨++){

        //画各界在当前步骤
        对于(i = 0; C =欲订购[我];我++){
            画圆(C [0],C [1],C [2],吨);
        }
    }

    //重新定位圈动画
    对于(i = 0; C =欲订购[我];我++){
        C [0] + = C [3]; ///增加增量为x
        C [1] + = C [4]; ///增加增量为y

        //反向增量,如果在边界处
        如果(C [0]℃,|| C [0]≥瓦特)C [3] = -c [3];
        如果(C [1]; 0 || C [1]≥H)C [4] = -c [4];
    }

    //绘制闭屏到主画布
    mctx.drawImage(ocanvas,0,0);

    //循环动画
    requestAnimationFrame(开始);
}
 

全球阿尔法可以重置为每个操作的情况下,你想画等元素在画布上 - 或者使用第二个屏幕上的画布举行的静态内容

演示

VAR演示=的document.getElementById(演示); 变种W = demo.width,H = demo.height; VAR ocanvas = document.createElement方法('画布'); ocanvas.width = W; ocanvas.height = H; 变种CTX = ocanvas.getContext('二维'); 变种mctx = demo.getContext('二维'); VAR IMG = document.createElement方法(IMG) img.onload =启动; img.src ='http://i.imgur.com/CHPdL2y.png'; ///关键这一切 mctx.globalAlpha = 0.7; VAR =欲订购[     // X Y - [R DX DY     [100,100,50,2,1.5],     [200,200,70,-2,-3],     [150,50,50,3,-1],     [150,50,30,4,4],     [150,50,20,-3,-2],     [100,100,55,2.5,2.5],     [200,200,75,-1,-2.5],     [150,50,45,3.5,-2]     [150,50,35,5,2]     [150,50,25,-1.2,-5] ]。 功能画圆(X,Y,R,步骤){     ctx.beginPath();     开关(步骤){         情况下0:             ctx.fillStyle ='#F00;             打破;         情况1:             ctx.fillStyle ='#00F';             R * = 0.67;             打破;         案例2:             ctx.fillStyle ='#0f0;             R * = 0.33;             打破;     }     ctx.arc(X,Y,R,0,2 * Math.PI);     ctx.fill(); } 函数的start(){          ctx.clearRect(0,0,W,H);     mctx.clearRect(0,0,W,H);     变种I = 0,T,C;     对于(T = 0; T&LT; 3;吨++){         对于(i = 0; C =欲订购[我];我++){             画圆(C [0],C [1],C [2],吨);         }     }     对于(i = 0; C =欲订购[我];我++){         C [0] + = C [3];         C [1] + = C [4];         如果(C [0]℃,|| C [0]≥瓦特)C [3] = -c [3];         如果(C [1]; 0 || C [1]≥H)C [4] = -c [4];     }          mctx.drawImage(ocanvas,0,0);     requestAnimationFrame(开始); }

体{     保证金:0;     背景:URL(HTTP://coolstuffiknow.files.word$p$pss.com/2012/04/6320cool20perspective20pic.jpg)不重复; }

&LT;帆布ID =演示WIDTH =500HEIGHT =333 &GT;&LT; /帆布&GT;

This question has sort of been answered here: Combined area of overlapping circles

My problem is more specific though. I have an arbitrary number of arbitrarily sized circles inside other arbitrarily sized circles, to make a target-like image:

This image must have some amount of transparency. The transparency must be the same throughout the entire shape. Then, there's an arbitrary number of these shapes that can overlap, and it needs to look like this:

The transparency amount must stay the same no matter how much they overlap.

The only thing I can think of to pull this off is to iterate through every pixel on the canvas and calculate what color the pixel should be based on its distance from the center of each circle, but this takes too long. I want the circles to be draggable as well, so this needs to be pretty fast. Is there a better way to do this? (Sorry about my poor GIMP skills)

解决方案

It is possible to do natively without using pixel manipulation or any library.

Provided the transparency is the same for all the circles it is pretty straight forward.

Solution


Circles on top of some random background

What you need to do is to:

  • Allocate an off-screen canvas where circles are drawn as solids (no transparency)
  • Draw the circles in three steps.
  • All the circles' red surface first, then all the circles' blue surface and so on.
  • Set global alpha for transparency for main (visible) canvas
  • Clear both canvases
  • Draw off-screen canvas to main canvas

Your circle function can look something like this:

function drawCircle(x, y, r, step) {

    ctx.beginPath();

    switch (step) {
        case 0:  // step 0, outer circle red
            ctx.fillStyle = '#f00';
            break;

        case 1:  // step 1, middle circle blue
            ctx.fillStyle = '#00f';
            r *= 0.67;
            break;

        case 2:  // step 2, inner circle green
            ctx.fillStyle = '#0f0';
            r *= 0.33;
            break;
    }
    ctx.arc(x, y, r, 0, 2 * Math.PI);
    ctx.fill();
}

The function takes the x and y center point as well as radius. But in addition it takes a step value between 0 and 2 which determines which surface is being drawn. This will be important in the next steps.

First we can define an array holding all the circles we want to draw:

var circs = [
    //x   y    r   dx dy (the last two for animation only)
    [100, 100, 50, 2, 1],
    [200, 200, 50, -2, -3],
    [150, 50, 50, 3, -1]
];

From here you would drag them, offset x and y and then redraw them, but for demo's sake I'll animate them.

Before we draw we set the global alpha on the main canvas (the off-screen is kept solid):

mctx.globalAlpha = 0.7;  // main canvas

And the animation loop:

function start() {

    // clear off-screen canvas
    ctx.clearRect(0,0, w, h);

    // clear main canvas
    mctx.clearRect(0,0, w, h);

    var t = 0, i, c;

    // outer step loop
    for(; t < 3; t++) {

        // draw all circles at current step
        for(i = 0; c = circs[i]; i++) {
            drawCircle(c[0], c[1], c[2], t);
        }
    }

    // re-position circles for animation
    for(i = 0;c = circs[i]; i++) {
        c[0] += c[3];  /// add delta to x
        c[1] += c[4];  /// add delta to y

        // reverse deltas if at boundaries
        if (c[0] < 0 || c[0] > w) c[3] = -c[3];
        if (c[1] < 0 || c[1] > h) c[4] = -c[4];
    }

    // draw off-screen to main canvas        
    mctx.drawImage(ocanvas, 0, 0);

    // loop animation
    requestAnimationFrame(start);
}

The global alpha can be reset for each operation in case you want to draw other elements to the canvas - or use a second on-screen canvas to hold static content.

Demo

var demo = document.getElementById("demo");
var w = demo.width, h = demo.height;

var ocanvas = document.createElement('canvas');
ocanvas.width = w;
ocanvas.height = h;

var ctx = ocanvas.getContext('2d');
var mctx = demo.getContext('2d');
var img = document.createElement('img')
img.onload = start;
img.src = 'http://i.imgur.com/CHPdL2y.png';

/// key to it all
mctx.globalAlpha = 0.7;

var circs = [
    //x   y    r   dx   dy
    [100, 100, 50,  2  ,  1.5],
    [200, 200, 70, -2  , -3],
    [150,  50, 50,  3  , -1],
    [150,  50, 30,  4  ,  4],
    [150,  50, 20, -3  , -2],
    [100, 100, 55,  2.5,  2.5],
    [200, 200, 75, -1  , -2.5],
    [150,  50, 45,  3.5, -2],
    [150,  50, 35,  5  ,  2],
    [150,  50, 25, -1.2, -5]
];

function drawCircle(x, y, r, step) {

    ctx.beginPath();

    switch (step) {
        case 0:
            ctx.fillStyle = '#f00';
            break;
        case 1:
            ctx.fillStyle = '#00f';
            r *= 0.67;
            break;
        case 2:
            ctx.fillStyle = '#0f0';
            r *= 0.33;
            break;
    }
    ctx.arc(x, y, r, 0, 2 * Math.PI);
    ctx.fill();
}

function start() {
    
    ctx.clearRect(0, 0, w, h);
    mctx.clearRect(0, 0, w, h);

    var i = 0, t, c;
    for(t = 0; t < 3; t++) {
        for(i = 0; c = circs[i]; i++) {
            drawCircle(c[0], c[1], c[2], t);
        }
    }

    for(i = 0;c = circs[i]; i++) {
        c[0] += c[3];
        c[1] += c[4];
        if (c[0] < 0 || c[0] > w) c[3] = -c[3];
        if (c[1] < 0 || c[1] > h) c[4] = -c[4];
    }
    
    mctx.drawImage(ocanvas, 0, 0);
    requestAnimationFrame(start);
}

body {
    margin:0;
    background:url(http://coolstuffiknow.files.wordpress.com/2012/04/6320cool20perspective20pic.jpg) no-repeat;
}

<canvas id="demo" width="500" height="333"></canvas>

这篇关于绘制重叠的圆阿尔法窜的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆