如何制作双色渐变

问题描述 投票:0回答:1

How do I go about making a two-coloured border that fades with p5js?

我还是个新手,所以我基本上所做的是使用黑色两次,并在内边框上应用 alpha。虽然这样做了,但似乎没有连续性。

p5.js
1个回答
0
投票

在 p5.js 中制作渐变的最简单方法是使用循环,如下面的可运行堆栈片段所示。

鉴于您在问题中包含的图片,您似乎想在图像周围制作一个彩色边框,该边框会淡入图像背景中。 这里有四种不同的方法,按从最简单到最复杂的顺序排列。每种都有自己的优点和缺点,并且给人的视觉效果略有不同。不同方法的说明和比较请参考代码注释。

虽然这里的示例都显示矩形边框渐变,但您可以轻松使用

ellipse
或任何其他形状。通过调整循环中的迭代次数、绘制每个形状的不透明度以及同心形状之间的间距/重叠,您可以使用相同的基本代码实现许多不同的效果。

奖励:如果您想获得如下所示的渐变背景作为图像文件(例如PNG)而不是使用代码动态生成它,您可以拍摄画布的屏幕截图(如所述此处(适用于 Windows 10/11),然后在您选择的图像编辑器中打开它。

var canvasSize = 400;
var numberOfLayers = 25;

// Composing the gradients can be done in setup(), instead of inside the draw() function, because they only have to be rendered once instead of every frame. This makes your code more efficient and less resource-intensive.
function setup() {
  createCanvas(canvasSize, canvasSize);
  angleMode(DEGREES);
  background(255);
  rectMode(CORNER);
  stroke(100, 0, 100);
  fill(100, 0, 100);
  rect(canvasSize/2, 0, canvasSize/2, canvasSize/2);
  stroke(0, 80, 0);
  fill(0, 80, 0);
  rect(0, canvasSize/2, canvasSize/2, canvasSize/2);
  
  /** FIRST GRADIENT: black border fades into white background */
  /* 
    Border is composed of concentric black outline rectangles of decreasing opacity.
  
    This is a very simple method, but it comes with some disadvantages. With such finely spaced, thin rectangles, the gradient may display gappily on some screen resolutions. There also appear to be lighter "channels" extending diagonally into the gradient's corners.
  */
  var cornerX = 0;
  var cornerY = 0;
  strokeWeight(1);
  noFill();
  for (var i = 0; i < numberOfLayers; i++) {
    stroke(0, 0, 0, 255 - 10*i);
    rect(cornerX + i, cornerY + i, canvasSize/2 - 2*i, canvasSize/2 - 2*i);
  }
  
  /** SECOND GRADIENT: white overlay on purple background */
  /*
    Overlay is composed of concentric white rectangles all with the same opacity value, stacked until they reach fully opaque.
  
    Since the rectangles are filled instead of hollow, and stacked instead of side-by-side, this method produces a more reliably smooth gradient than does the first method above. However, it still displays the lighter diagonal "channels" at the corners.
  */
  noStroke();
  cornerX = canvasSize/2;
  fill(255, 255, 255, 40);
  for (i = 0; i < numberOfLayers; i++) {
    rect(cornerX + i, cornerY + i, canvasSize/2 - 2*i, canvasSize/2 - 2*i);
  }
  
  /** THIRD GRADIENT: white overlay on green background */
  /*
    Similar to the second gradient, but with two improvements:
    
    1 - Gives the stacked filled rectangles rounded corners (radius=5), eliminating the lighter "channel" artifacts which occurred with the previous methods.
    
    2 - Makes the opacity of each layer successively increase dependent on the loop variable, for a more gradual fade into the background color
  */
  cornerX = 0;
  cornerY = canvasSize/2;
  for (i = 0; i < numberOfLayers; i++) {
    fill(255, 255, 255, 8*i);
    rect(cornerX + i, cornerY + i, canvasSize/2 - 2*i, canvasSize/2 - 2*i, 5);
  }
  
  /** FOURTH GRADIENT: blue to red border on white background */
  /*
    This is the most complex version. Both the fill color and the opacity are dependent on the loop variable, so the gradient both changes color and fades into the background. After the end of the loop, one final white rectangle is drawn (with size and position determined by the final value of the loop variable) for a more crisp background boundary.
  */
  cornerX = canvasSize/2;
  fill(0, 0, 255);
  rect(cornerX, cornerY, canvasSize/2, canvasSize/2);
  for (i = 0; i < numberOfLayers; i++) {
    fill(12*i, 0, 255 - 12*i, 255 - 9*i);
    rect(cornerX + i, cornerY + i, canvasSize/2 - 2*i, canvasSize/2 - 2*i, 5);
    fill(255, 255, 255, 9*i);
    rect(cornerX + i, cornerY + i, canvasSize/2 - 2*i, canvasSize/2 - 2*i, 5);
  }
  fill(255);
  rect(cornerX + i, cornerY + i, canvasSize/2 - 2*i, canvasSize/2 - 2*i, 5);
}

var t = 0;
function draw() {
  t++;
  if (t >= 360) {
    t = 0;
  }
  // Draw bouncing circles, with white background rectangles behind them, to illustrate redrawing only the necessary parts of the design.
  for (var i = 0; i < 4; i++) {
    noStroke();
    fill(255);
    rect(canvasSize/4 - canvasSize/6 + canvasSize/2 * (i % 2), canvasSize/4 - canvasSize/6 + canvasSize/2 * (i < 2 ? i%2 : 1 - i%2), canvasSize/3, canvasSize/3, 5);
    strokeWeight(2);
    stroke(100);
    fill(200);
    ellipse(canvasSize/4 + canvasSize/2 * (i % 2), canvasSize/4 + canvasSize/2 * (i < 2 ? i%2 : 1 - i%2) - (canvasSize/20)*sin(t * (-1)**(i % 2) * (-1)**(i < 2 ? i%2 : 1 - i%2)), canvasSize/8, canvasSize/8);
  }
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.js"></script>

© www.soinside.com 2019 - 2024. All rights reserved.