Pixi.js - 用渐变填充绘制矩形

5
我将使用Pixi.js v4图形库和JavaScript制作游戏。我知道我可以像下面这样绘制一个黑色的圆角矩形:
const rectangle = new pixi.Graphics();
rectangle.beginFill(0); // Color it black
rectangle.drawRoundedRect(
    0,
    0,
    100, // Make it 100x100
    100,
    5, // Make the rounded corners have a radius of 5
);
rectangle.endFill();
stage.addChild(rectangle);
  1. 我如何绘制一个从白色到黑色的渐变圆角矩形?

  2. 我如何绘制一个渐变透明度的圆角矩形,使其从左向右淡入?


对于使用 Pixi v5 的用户:https://pixijs.io/examples/#/textures/gradient-basic.js - Gman
4个回答

5
看起来,如果没有额外的代码,使用pixi.js无法实现您所需的内容,但我们可以进行一些魔法使其发生。这是我得到的结果: https://jsfiddle.net/exkf3zfo/21/ 底部颜色是纯红色,透明度为0.2。
我将整个过程分解为以下步骤:
  1. 绘制渐变
  2. 用圆形遮罩遮盖渐变
以下是代码本身:
var app = new PIXI.Application(800, 600, {
  antialias: true
});
document.body.appendChild(app.view);

// Functions

// param color is a number (e.g. 255)
// return value is a string (e.g. ff)
var prepareRGBChannelColor = function(channelColor) {
  var colorText = channelColor.toString(16);
  if (colorText.length < 2) {
    while (colorText.length < 2) {
      colorText = "0" + colorText;
    }
  }

  return colorText;
}

// Getting RGB channels from a number color
// param color is a number
// return an RGB channels object {red: number, green: number, blue: number}
var getRGBChannels = function(color) {
  var colorText = color.toString(16);
  if (colorText.length < 6) {
    while (colorText.length < 6) {
      colorText = "0" + colorText;
    }
  }

  var result = {
    red: parseInt(colorText.slice(0, 2), 16),
    green: parseInt(colorText.slice(2, 4), 16),
    blue: parseInt(colorText.slice(4, 6), 16)
  };
  return result;
}

// Preparaiton of a color data object
// param color is a number [0-255]
// param alpha is a number [0-1]
// return the color data object {color: number, alpha: number, channels: {red: number, green: number, blue: number}}
var prepareColorData = function(color, alpha) {
  return {
    color: color,
    alpha: alpha,
    channels: getRGBChannels(color)
  }
}

// Getting the color of a gradient for a very specific gradient coef
// param from is a color data object
// param to is a color data object
// return value is of the same type
var getColorOfGradient = function(from, to, coef) {
  if (!from.alpha && from.alpha !== 0) {
    from.alpha = 1;
  }
  if (!from.alpha && from.alpha !== 0) {
    to.alpha = 1;
  }

  var colorRed = Math.floor(from.channels.red + coef * (to.channels.red - from.channels.red));
  colorRed = Math.min(colorRed, 255);
  var colorGreen = Math.floor(from.channels.green + coef * (to.channels.green - from.channels.green));
  colorGreen = Math.min(colorGreen, 255);
  var colorBlue = Math.floor(from.channels.blue + coef * (to.channels.blue - from.channels.blue));
  colorBlue = Math.min(colorBlue, 255);

  var rgb = prepareRGBChannelColor(colorRed) + prepareRGBChannelColor(colorGreen) + prepareRGBChannelColor(colorBlue);

  return {
    color: parseInt(rgb, 16),
    alpha: from.alpha + coef * (to.alpha - from.alpha)
  };
}

var startTime = Date.now();
console.log("start: " + startTime);

// Drawing the gradient
//
var gradient = new PIXI.Graphics();
app.stage.addChild(gradient);
//
var rect = {
  width: 200,
  height: 200
};
var round = 20;
//
var colorFromData = prepareColorData(0xFF00FF, 1);
var colorToData = prepareColorData(0xFF0000, 0.2);
//
var stepCoef;
var stepColor;
var stepAlpha;
var stepsCount = 100;
var stepHeight = rect.height / stepsCount;
for (var stepIndex = 0; stepIndex < stepsCount; stepIndex++) {
  stepCoef = stepIndex / stepsCount;
  stepColor = getColorOfGradient(colorFromData, colorToData, stepCoef);

  gradient.beginFill(stepColor.color, stepColor.alpha);
  gradient.drawRect(
    0,
    rect.height * stepCoef,
    rect.width,
    stepHeight
  );
}

// Applying a mask with round corners to the gradient
var roundMask = new PIXI.Graphics();
roundMask.beginFill(0x000000);
roundMask.drawRoundedRect(0, 0, rect.width, rect.height, round);
app.stage.addChild(roundMask);
gradient.mask = roundMask;

var endTime = Date.now();
console.log("end: " + endTime);
console.log("total: " + (endTime - startTime));

有趣的是,整个过程只需要大约2-5毫秒!
如果你想将渐变颜色更改为白色>黑色(如问题所述),只需更改下一个参数:
var colorFromData = prepareColorData(0xFF00FF, 1);
var colorToData = prepareColorData(0xFF0000, 0.2);

致:

var colorFromData = prepareColorData(0xFFFFFF, 1);
var colorToData = prepareColorData(0x000000, 0.2);

1
我已经运行了你的代码,它在我的电脑上非常好用,但是我的一些玩家在填充之间看到了线条(背景)。https://prnt.sc/py6kr9 https://prnt.sc/pyrvs8为什么会在某些设备上出现这种情况,如何解决?您可以在此处查看游戏:https://colonist.io/ - demiculus

4

这不是完整的答案,但是有些额外的信息

  1. 据我所知,你不能在PIXI.Graphics中使用渐变,即使对于精灵也需要额外的画布(canvas)

    只需将您想要的渐变绘制到画布(canvas)上: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createLinearGradient

    然后将该画布作为纹理(Texture)使用:Texture.fromCanvas(canvas);

    请参阅此文章

  2. 对于逐渐消失的效果,可以使用 Alpha Mask

    http://pixijs.io/examples/#/demos/alpha-mask.js

P.S 也许Phaser.js可以做更多


2
你解决了这个问题吗?我也找不到在线的解决方案,所以我使用了一个过滤器来自己实现。请查看:https://codepen.io/Lancer611/pen/KodabK
以下是一些 Pixi 代码:
function newGradientPoly(poly, fill, fillSize){
  var container = new PIXI.Sprite();
  app.stage.addChild(container);
  var shape = new PIXI.Graphics();
  shape.beginFill(0xffffff)
  .lineStyle(1, 0x333333)
  .drawPolygon(poly);
  var mask = new PIXI.Graphics();
  mask.beginFill(0xffffff, 1)
    .drawPolygon(poly);
  container.mask = mask;
  container.addChild(shape);
  var fshaderCode = document.getElementById("fragShader").innerHTML;
  fogShader = new PIXI.Filter(null,  fshaderCode);
  fogShader.uniforms.resolution = [width, height];
  fogShader.uniforms.segments = poly.slice();
  fogShader.uniforms.count = poly.length/2;
  fogShader.uniforms.gSize = fillSize;
  fogShader.uniforms.fill = fill;
  shape.filters=[fogShader];
}

Codepen上的代码无法工作。能否帮忙看一下? - NieMaszNic

0
我已经为Pixi创建了一个pixi插件,用于显示矢量图形。主要限制是您需要先在矢量艺术程序Omber中绘制矩形,因此您需要事先知道矩形的大小(由于一切都是基于矢量的,理论上您可以稍后缩放物体,但是圆角会变得有点不均匀)。工作流程类似于使用精灵:1. 在Omber中绘制矩形2. 将它们导出到gltf3. 在Pixi程序中加载gltf文件4. 将矩形定位到所需位置。
另一种可能性是您可以将渐变作为单独的对象创建,然后使用多边形对其进行遮罩。这里有一个示例。在该示例中,我使用矢量图形来制作渐变,但由于渐变在调整大小时不会变得模糊,因此您也可以使用精灵。我不确定遮罩的性能如何,但如果您只需要其中几个,那么它可能还可以。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接