画布 - 如何使用中心的光源绘制点的网格?

时间:2013-08-09 13:10:41

标签: javascript canvas

我认为这是一个常见的问题,但我在画布上显示点有一些问题。我想知道的第一件事是如何绘制像this这样的点(请缩放它)。 第二件事是,如何在这个点的网格的每个元素上绘制阴影,光源位于中心。

目前我所拥有的here

我的代码部分:

context.fillStyle = "#ccc";

context.shadowColor = '#e92772';
context.shadowOffsetX = 15;
context.shadowOffsetY = 15;

while (--e >= 1) {
    x -= z;
    if(x < 0) {
        x = z*w;
        y -= z;
    }
    context.moveTo(x, y);
    context.fillRect( x, y, 1, 1 );
    outs = a[e];
}

另外,我尝试使用“context.arc();”,但我认为“context.fillRect();”更容易。还有一个时刻,当我使用“while(--e&gt; = 0)”代替“while(--e&gt; = 1)”时,我还有两个点,在顶部。为什么呢?

如果你知道一些文章或教程,你会给我链接吗?优选地,不使用框架。感谢。

1 个答案:

答案 0 :(得分:2)

您可以使用一些三角函数来模拟光源的3D点。

<强> HERE IS AN ONLINE DEMO

这是你可以做到的一种方式,当然还有其他方式(这是第一个想到的):

  • 在主画布上绘制带有一些点的网格
  • 将径向渐变渲染到离屏画布
  • 更改合成模式,以便在已存在的像素上绘制任何内容
  • 计算与光源的距离和角度,并将点绘制到每个网格点偏移角度/ dist。

以下是演示中的一些代码。

用点绘制网格

我们跳过一个网格点,因为我们稍后会用渐变点填充每个点,否则会在相邻点上绘制。

/// draw a grid of dots:
for (y = 0; y < ez.width; y += gridSize * 2) {
    for (x = 0; x < ez.height; x += gridSize * 2) {
        ctx.beginPath();
        ctx.arc(x + offset, y + offset, radius, 0, arcStop);
        ctx.closePath();
        ctx.fill();
    }
}

创建一个灯光“反射”

将渐变点准备到离屏画布(dctx = dot-context)。我正在使用easyCanvas进行设置并给我一个已经计算出中心点的离屏画布,但当然也可以手动设置:

grd = dctx.createRadialGradient(dot.centerX, dot.centerY, 0,
                                dot.centerX, dot.centerY, gridSize);
grd.addColorStop(0, '#fff');
grd.addColorStop(0.2, '#777'); // thighten up
grd.addColorStop(1, '#000');

dctx.fillStyle = grd;
dctx.fillRect(0, 0, gridSize, gridSize);

做数学

然后我们进行所有的计算和抵消:

/// change composition mode
ctx.globalCompositeOperation = 'source-atop';

/// calc angle and distance to light source and draw each
/// dot gradient offset in relation to this
for (y = 0; y < ez.width; y += gridSize) {
    for (x = 0; x < ez.height; x += gridSize) {

        /// angle
        angle = Math.atan2(lightY - y, lightX - x);
        //if (angle < 0) angle += 2;

        /// distance
        dx = lightX - x;
        dy = lightY - y;
        dist = Math.sqrt(dx * dx + dy * dy);

        /// map distance to our max offset
        od = dist / maxLength * maxOffset * 2;
        if (od > maxOffset * 2) od = maxOffset * 2;

        /// now get new x and y position based on angle and offset
        offsetX = x + od * Math.cos(angle) - maxOffset * 0.5;
        offsetY = y + od * Math.sin(angle) - maxOffset * 0.5;

        /// draw the gradient dot at offset
        ctx.drawImage(dot.canvas, x + offsetX, y + offsetY);
    }
}

<强>影

对于阴影,您只需在使用合成模式destination-over时反转偏移,这将在外部绘制已经绘制的像素:

/// Shadow, same as offsetting light, but in opposite
/// direction and with a different composite mode
ctx.globalCompositeOperation = 'destination-over';

for (y = 0; y < ez.width; y += gridSize) {
    for (x = 0; x < ez.height; x += gridSize) {

        /// angle
        angle = Math.atan2(lightY - y, lightX - x);
        //if (angle < 0) angle += 2;

        /// distance
        dx = lightX - x;
        dy = lightY - y;
        dist = Math.sqrt(dx * dx + dy * dy);

        /// map distance to our max offset
        od = dist / maxLength * maxOffset * 2;
        if (od > maxOffset * 4) od = maxOffset * 4;

        /// now get new x and y position based on angle and offset
        offsetX = x - od * Math.cos(angle) + gridSize * 0.5;
        offsetY = y - od * Math.sin(angle) + gridSize * 0.5;

        ctx.beginPath();
        ctx.arc(x + offsetX, y + offsetY, radius, 0, arcStop);
        ctx.fill();

    }
}

这可以全部优化为单个循环对但是为了概述代码是分开的。

其他

在演示中,我添加了鼠标跟踪,因此鼠标成为光源,您可以在移动鼠标时看到点反射的变化。为了获得最佳性能,请使用Chrome。

为了满足您的需求,只需缩小我正在使用的值 - 或 - 绘制到一个大的屏幕外画布并使用drawImage将其缩小到主画布。