如何使用PIXI.js绘制透明轨迹?

How to draw transparent trails using PIXI.js?

我已经开始玩 PIXI.js 并尝试移植这个基本的 actionscript 3 片段:

import flash.display.Sprite;
import flash.events.Event;

var trails:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,true,0x00000000);//create a transparent bitmap to draw the trails into
var trailsFade:ColorTransform = new ColorTransform(1,1,1,0.25,0,0,0,1);//color transform: keep rgb the same(1,1,1), set alpha to 0.025 out of 1.0
var background:Bitmap = addChild(new Bitmap(trails,PixelSnapping.AUTO,true)) as Bitmap;//add the trails pixels/bitmap data into a Bitmap/display object at the bottom of the display list

var dot:Sprite = addChild(new Sprite()) as Sprite;
dot.graphics.lineStyle(3);
dot.graphics.drawCircle(-4, -4, 8);

addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
    dot.x = mouseX;
    dot.y = mouseY;
    //draw trails of the dot
    trails.draw(dot,dot.transform.concatenatedMatrix,trailsFade);//draw the dot into the bitmap data using the dot's transformation (x,y, rotation, scale)
}

它所做的是绘制一个圆并将它的快照放入 BitmapData 对象中,并且有一个 ColorMatrix 滤镜应用了一个小的 alpha/transparency 值。

我注意到 PIXI.js 有很多相似之处并且有一个 ColorMatrixFilter available, but I couldn't figure out what the equivalent of BitmapData.draw() is in PIXI.js. The closest thing I found is the RenderTexture demo

基于此,我尝试移植上面的 as3 代码:

var renderer = PIXI.autoDetectRenderer(640, 480);
 document.body.appendChild(renderer.view);

 var stage = new PIXI.Container();
 
 var dot = new PIXI.Graphics();
 dot.beginFill(0xFF9900);
 dot.drawCircle(-8,-8,16);
 dot.endFill();
 stage.addChild(dot);

 var renderTexture = new PIXI.RenderTexture(renderer, renderer.width, renderer.height);
 var renderTexture2 = new PIXI.RenderTexture(renderer, renderer.width, renderer.height);
 var currentTexture = renderTexture;

 var outputSprite = new PIXI.Sprite(currentTexture);
 stage.addChild(outputSprite);


 animate();

 function animate() {
  var a = Date.now() * 0.001;
  dot.x = renderer.width * 0.5 + (Math.cos(a) * 200);
  dot.y = renderer.height * 0.5 + (Math.sin(a) * 200);

  // swap the buffers ...
     var temp = renderTexture;
     renderTexture = renderTexture2;
     renderTexture2 = temp;

     renderTexture2.render(stage, null, false);

     renderer.render(stage);
     requestAnimationFrame( animate );
 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/3.0.11/pixi.min.js"></script>

如果您 运行 代码片段,您会注意到圆圈留下痕迹,这很好。但是我想控制这些路径的透明度。如何实现这一目标?

使用 PIXI.js 绘制透明轨迹的最佳方法是什么?

(此外,我在控制台中收到此警告:

[.CommandBufferContext]GL ERROR :GL_INVALID_OPERATION : glDrawElements: Source 

和绘制的目标纹理相同。

如何补救?)

更新

为了说明,这里是使用 p5.js 的相同想法:

function setup() {
  createCanvas(400,300);
  noStroke();
}

function draw() {
  //transparent rectangle
  fill(0,10);
  rect(0,0,width,height);
  //shape that will leave trails because buffer isn't cleared completely
  fill(255);
  ellipse(mouseX,mouseY,30,30);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.0/p5.min.js"></script>

我认为我可以使用 ColorMatrixFilter 实现此目的,但我找不到详尽的文档(因为它的参数与 as3 ColorMatrixFilter 不同)。接下来我将尝试使用 GLSL 着色器作为 CustomFilter。 使用 PIXI.js 的等价物是什么?理想情况下是高效且可扩展的东西(允许轻松跟踪数千个对象)?

PIXI.Graphics 对象有一个 "alpha" 属性。通过添加

你的点可以是透明的
dot.alpha = 0.25; // this is the value in the as3 script you shared

这是它的样子:

var renderer = PIXI.autoDetectRenderer(640, 480);
 document.body.appendChild(renderer.view);

 var stage = new PIXI.Container();
 
 var dot = new PIXI.Graphics();
 dot.beginFill(0xFF9900);
 dot.drawCircle(-8,-8,16);
 dot.endFill();
 stage.addChild(dot);

 var renderTexture = new PIXI.RenderTexture(renderer, renderer.width, renderer.height);
 var renderTexture2 = new PIXI.RenderTexture(renderer, renderer.width, renderer.height);
 var currentTexture = renderTexture;

 var outputSprite = new PIXI.Sprite(currentTexture);
 stage.addChild(outputSprite);


 animate();

 function animate() {
  var a = Date.now() * 0.001;
  dot.x = renderer.width * 0.5 + (Math.cos(a) * 200);
  dot.y = renderer.height * 0.5 + (Math.sin(a) * 200);
  dot.alpha = 0.25;
  // swap the buffers ...
     var temp = renderTexture;
     renderTexture = renderTexture2;
     renderTexture2 = temp;

     renderTexture2.render(stage, null, false);

     renderer.render(stage);
     requestAnimationFrame( animate );
 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/3.0.11/pixi.min.js"></script>

查看您的 p5 示例,您可以使用 PIXI 使用单个 Graphics 对象获得相同的结果。不确定这对数千个对象的处理效果如何,但我不认为 p5 的表现会更好,因为它做同样的事情。

var renderer = PIXI.autoDetectRenderer(640, 480);
document.body.appendChild(renderer.view);

var stage = new PIXI.Container();
 
var graphics = new PIXI.Graphics();
stage.addChild(graphics);

animate();

function animate() {
 var a = Date.now() * 0.001;

 var x = renderer.width * 0.5 + (Math.cos(a) * 200);
    var y = renderer.height * 0.5 + (Math.sin(a) * 200);

        //Draw a circle
 graphics.beginFill(0xFF9900);
 graphics.drawCircle(x-8, y-8, 16);
 graphics.endFill();

        //Draw background
 graphics.beginFill(0, 0.1);
 graphics.drawRect(0, 0, renderer.width, renderer.height);
 graphics.endFill();

   renderer.render(stage);
 requestAnimationFrame( animate );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/3.0.11/pixi.min.js"></script>


另一种方法是将其与使用 RenderTextures 的示例结合起来。对于 1000 个对象,这可能 运行 更快。

var renderer = PIXI.autoDetectRenderer(640, 480);
document.body.appendChild(renderer.view);

var stage = new PIXI.Container();

var renderTexture = new PIXI.RenderTexture(renderer, renderer.width, renderer.height);
var renderTexture2 = new PIXI.RenderTexture(renderer, renderer.width, renderer.height);
var outputSprite = new PIXI.Sprite(renderTexture);
stage.addChild(outputSprite);

var dot = new PIXI.Graphics();
dot.beginFill(0xFF9900);
dot.drawCircle(-8,-8,16);
dot.endFill();
dot.cacheAsBitmap = true;
stage.addChild(dot);

var bg = new PIXI.Graphics();
bg.beginFill(0, 0.1);
bg.drawRect(0, 0, renderer.width, renderer.height);
bg.endFill();
bg.cacheAsBitmap = true;
stage.addChild(bg);

animate();
function animate() {
    requestAnimationFrame( animate );

    var a = Date.now() * 0.001;
    dot.x = renderer.width * 0.5 + (Math.cos(a) * 200);
    dot.y = renderer.height * 0.5 + (Math.sin(a) * 200);

    // swap the buffers ...
    var temp = renderTexture;
    renderTexture = renderTexture2;
    renderTexture2 = temp;
    outputSprite.texture = renderTexture;

    renderTexture2.render(stage, null, false);
    renderer.render(stage);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/3.0.11/pixi.min.js"></script>