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

时间:2018-01-21 19:37:47

标签: javascript gradient pixi.js pixijs

我正在使用Pixi.js v4 graphics library与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)如何绘制渐变不透明的圆角矩形,使其从左向右淡入?

4 个答案:

答案 0 :(得分:4)

不是完整答案,而是一些额外信息

1)据我所知,你不能为PIXI.Graphics使用渐变,即使对于你需要额外画布的精灵也是如此

  

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

     

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

看:http://www.html5gamedevs.com/topic/25691-gradients-in-pixi4/

2)对于渐进的不透明度 Alpha Mask 可以提供帮助

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

P.S也许phaser.js可以做得更多

答案 1 :(得分:3)

看起来似乎不可能在没有附加代码的情况下用pixi.js实现你需要的东西,但我们可以做一些魔术来实现它。这是我得到的结果:https://jsfiddle.net/exkf3zfo/21/

底色为纯红色,0.2 alpha。

我会将整个过程分成以下几个步骤:

  1. 绘制渐变
  2. 使用圆形遮罩遮挡渐变
  3. 以下是代码本身:

    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毫秒!

    如果您不想将渐变的颜色更改为白色&gt;黑色(如问题中所述),只需更改下一个参数:

    var colorFromData = prepareColorData(0xFF00FF, 1); var colorToData = prepareColorData(0xFF0000, 0.2);

    要:

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

答案 2 :(得分: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];
}

答案 3 :(得分:0)

我创建了一个pixi plugin用于在Pixi中显示矢量绘图。主要的限制是你需要首先在矢量艺术程序Omber中绘制矩形,所以你需要事先知道矩形的大小(因为一切都是基于矢量的,理论上你可以稍后缩放,但是然后圆角会变得有点不均匀)。工作流程类似于使用精灵:1。在Omber中绘制矩形2.将它们导出到gltf 3.在你的Pixi程序中加载gltf文件4.将矩形放在你想要的位置。

另一种可能性是您可以将渐变创建为单独的对象,然后可以使用多边形将其遮罩。这是一个example。在这个例子中,我使用了渐变的矢量绘图,但由于渐变时渐变不会变得模糊,所以你也可以使用精灵。我不确定面具是否具有良好的性能,但如果你只是需要它们中的一些,那么它可能很好。