如何制作径向渐变'二维数组中的值?

时间:2014-06-24 15:35:17

标签: javascript arrays math matrix radial-gradients

让我们说我有一个二维数组,例如[7] [7],全部为零,如下:

0000000
0000000
0000000
0000000
0000000
0000000
0000000

我试图找出如何取任何数字范围(例如:0到3)并从中心创建一个径向渐变的排序,如下所示:

0000000
0011100
0122210
0123210
0122210
0011100
0000000

基本上,边应该始终是最低的值,并且数组的中心应该是最高的。控制强度'是非常棒的。中锋(更多的三分球,更快的下降),但我可能会想出那个部分。

我真的很难理解这样的事情背后的数学。我认为这将使用正弦波或其他东西来实现,但不知道从哪里开始或如何将其应用于2D数组值。

(注意 - 我真正想要做的是在HTML中创建DIV网格,然后使用Javascript设置每个元素的alpha,使得中心是最不透明的,边缘是最透明的。在此期间,使用像这样的简单圆形数字,我更容易理解。

3 个答案:

答案 0 :(得分:2)

这个帖子上唯一的答案对我来说并不是很令人满意,我最终自己搞清楚了,这是我用过的方法:

首先我创建了一个空值数组

var values = [];
for(var x = 0; x < 8; x++) {
    values[x] = [];
    for(var y = 0; y < 6; y++) {
        values[x].push(0);
    }
}

然后我决定使用渐变的中心坐标,我决定使用数组的中心。

var centerX = values.length / 2;
var centerY = values.length / 2;

然后我决定了我想要渐变的大小。我决定最佳半径为3(确保它不超过数组中最宽点的一半,否则它将不合适。)

var radius = 3;
var maxRadius = radius + 1;

我的计划是绘制一个圆,然后缩小半径并在其中画一个圆,直到半径为0,此时我无法再绘制,我会有一个倾斜的渐变。

要画一个圆圈,我需要弄清楚圆圈的坐标是什么。所以我查了一下,事实证明你可以使用这个等式来计算圆上坐标的位置:

x = centerX + radius * cos(angle)
y = centerY + radius * sin(angle)

因此,如果我们以角度0开始并递增它,直到它为360,我们就会有一个完整的圆圈。

function drawCircle(r) {
    while(angle < 360) {
        x = centerX + r * Math.cos(angle);
        y = centerY + r * Math.sin(angle);
        values[x][y] = maxRadius - r;
        angle += 1;
    }
}
drawCircle(radius);

这会将第一个圆圈放入我们的数组中。所以它现在看起来像这样:

[[0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0],
 [0, 0, 1, 1, 1, 0],
 [0, 1, 0, 0, 0, 1],
 [0, 1, 0, 0, 0, 1],
 [0, 1, 0, 0, 0, 1],
 [0, 0, 1, 1, 1, 0],
 [0, 0, 0, 0, 0, 0]]

现在我们只需要缩小半径以在其中绘制一个圆圈。虽然它确实在这个数组中画了一个正方形,但这只是因为它只是一个小例子,更大的例子看起来看起来更像一个圆圈,请看帖子底部的截图以获得更大的例子。

我编写了一个减少半径的循环,以便我们可以获得渐变效果。

while(radius > 0) {
    drawCircle(radius);
    angle = 0;
    radius --;
}

Et瞧。运行该循环,你会看到这样的东西:

[ [ 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 0, 0, 0, 0 ],
  [ 0, 0, 1, 1, 1, 0 ],
  [ 0, 1, 2, 2, 2, 1 ],
  [ 0, 1, 2, 3, 2, 1 ],
  [ 0, 1, 2, 2, 2, 1 ],
  [ 0, 0, 1, 1, 1, 0 ],
  [ 0, 0, 0, 0, 0, 0 ] ]

这是一个更大的例子:

Radial Gradient in an array

HTH

答案 1 :(得分:1)

一种可能性是进行高斯梯度。因为高斯函数是可分的,所以可以单独将它应用于x值和y值。

您可以在此页面上获取公式并在代码中实现它。 https://en.wikipedia.org/wiki/Gaussian_function#Two-dimensional_Gaussian_function

为此,x0和y0将是数组中心的索引(3,3)。您只需遍历数组并计算每个数组元素的链接函数的值。这将提供你的alpha因素。

最后,这只是一种梯度衰减函数。它是一条正常的曲线,所以它给你一个从最强烈到最低强度的愉快渐变。如果您想要一种不同类型的曲线,可以使用d = sqrt((x-x0)^2 + (y-y0)^2)模板与矩阵中心的距离来构建基于d的函数

答案 2 :(得分:1)

我已经在这里留下了一个答案,但是有一种不同的(更好的)方法来实现。

此解决方案假定数组的中心是渐变的源(最高点)。

前提是您要遍历数组中的每个项目,并使用Euclidean distance计算它到中间点的距离。

这实质上表明可以通过计算∆x 2 + ∆y ^ 2 的平方根来找到两点之间的距离。

这是9x9数组的实现:

var grid = []
var gridWidth = 9
var gridHeight = 9

var euclideanDistance = (point1, point2) => {
  return Math.sqrt(
    Math.abs(Math.pow(point1.x - point2.x, 2)) +
    Math.abs(Math.pow(point1.y - point2.y, 2))
  )
}

var centrePoint = {x: Math.floor(gridWidth / 2), y: Math.floor(gridHeight / 2)}

var furthestDistanceFromCentre = euclideanDistance(
  {x: 0, y: 0}, centrePoint
)

for (var x = 0; x < gridWidth; x++) {
  grid[x] = []
  for (var y = 0; y < gridHeight; y++) {
    grid[x][y] = Math.floor(
      furthestDistanceFromCentre - euclideanDistance(
        {x: x, y: y}, centrePoint
      )
    )
  }
}

以下是输出:

[0, 0, 1, 1, 1, 1, 1, 0, 0]
[0, 1, 2, 2, 2, 2, 2, 1, 0]
[1, 2, 2, 3, 3, 3, 2, 2, 1]
[1, 2, 3, 4, 4, 4, 3, 2, 1]
[1, 2, 3, 4, 5, 4, 3, 2, 1]
[1, 2, 3, 4, 4, 4, 3, 2, 1]
[1, 2, 2, 3, 3, 3, 2, 2, 1]
[0, 1, 2, 2, 2, 2, 2, 1, 0]
[0, 0, 1, 1, 1, 1, 1, 0, 0]

之所以如此有效,是因为您不会遗漏任何点,网格中的每个单元格都被考虑在内。如果您使用的是我发布的其他解决方案,可能到处都是空白,这不理想。

这将为您每次提供平滑,流畅的结果。

I wrote an article on a use case of this here.

这是圆技巧上的点生成的渐变:

Circle gradient

这是欧几里德距离技术生成的梯度:

Euclidean gradient