Nano Hash - криптовалюты, майнинг, программирование

Pixi.js - рисование прямоугольника с градиентной заливкой

Я использую графическую библиотеку 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. Как нарисовать прямоугольник с закругленными углами, который имеет постепенную непрозрачность, чтобы плавно переходить слева направо?



Ответы:


1

Похоже, что невозможно реализовать то, что вам нужно, с 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);

To:

var colorFromData = prepareColorData(0xFFFFFF, 1);
var colorToData = prepareColorData(0x000000, 0.2);
30.01.2018
  • Я написал ваш код, и он очень хорошо работает на моем компьютере, но некоторые из моих плееров видят линии (фон) между заливками. prnt.sc/py6kr9 prnt.sc/pyrvs8 Почему это происходит на некоторых устройствах и как это исправить? Вы можете посмотреть игру здесь: colonist.io 22.11.2019

  • 2

    Не полный ответ, но некоторая дополнительная информация

    1. # P2 #
      # P3 # # P4 #
      # P5 #
    2. Для постепенной непрозрачности может помочь альфа-маска.

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

    P.S Может быть, phaser.js может больше

    27.01.2018

    3

    Вы когда-нибудь догадывались об этом? Мне тоже не удалось найти решение в сети, поэтому я реализовал его сам с помощью фильтра. Взгляните: 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];
    }
    
    12.03.2018
  • Код на codepen не работает. Не могли бы вы взглянуть на это? 03.04.2019

  • 4

    Я создал плагин pixi для отображения векторных рисунков в Pixi. Основное ограничение заключается в том, что вам нужно сначала нарисовать прямоугольник в программе векторной графики Omber, поэтому вы необходимо заранее знать размер вашего прямоугольника (поскольку все является векторным, вы можете теоретически масштабировать элементы позже, но тогда закругленные углы будут немного неровными). Рабочий процесс аналогичен использованию спрайтов: 1. нарисуйте прямоугольники в Omber 2. экспортируйте их в gltf 3. загрузите файлы gltf в свою программу Pixi 4. разместите прямоугольники там, где вы хотите.

    Другая возможность состоит в том, что вы можете создать градиент как отдельный объект, а затем замаскировать его многоугольником. Вот пример . В этом примере я использую векторный рисунок для градиента, но поскольку градиенты не становятся размытыми при изменении размера, вы, вероятно, также можете использовать для этого спрайт. Я не уверен, что маски имеют хорошие характеристики, но если вам просто нужно несколько из них, то, вероятно, все в порядке.

    16.05.2018
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..