【问题标题】:How to draw transparent trails using PIXI.js?如何使用 PIXI.js 绘制透明轨迹?
【发布时间】:2016-09-23 04:41:35
【问题描述】:

我已经开始使用 PIXI.js 并尝试移植这个基本的 actionscript 3 sn-p:

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 对象中,并且应用了一个带有小 alpha/透明度值的 ColorMatrix 过滤器。

我注意到 PIXI.js 有很多相似之处,并且有一个 ColorMatrixFilter 可用,但我无法弄清楚 PIXI.js 中 BitmapData.draw() 的等价物是什么。我找到的最接近的是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>

如果您运行代码 sn-p,您会注意到圆圈留下了痕迹,这很好。但是我想控制这些路径的透明度。怎样才能做到这一点?

使用 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 的等价物是什么?理想情况下是高效且可扩展的(允许轻松跟踪数千个对象)?

【问题讨论】:

    标签: javascript pixi.js


    【解决方案1】:

    查看您的 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>

    【讨论】:

    • 谢谢(+1),第二个选项效果更好(刚刚测试了大约 100 个代理)。在渲染缓冲区时,您是否有任何处理这些警告的提示:[.CommandBufferContext]GL ERROR :GL_INVALID_OPERATION : glDrawElements: Source and destination textures of the draw are the same.
    • @GeorgeProfenza 代码缺少一行outputSprite.texture = renderTexture; 用于交换缓冲区。我已更新我的答案以修复该警告。
    【解决方案2】:

    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>

    【讨论】:

    • 感谢您的回答 (+1)。我确实尝试过(抱歉应该提到)。我正在寻找的是一种不需要为场景中的每个显示对象单独设置 alpha 的解决方案。
    • @GeorgeProfenza 你能更好地解释你想要达到的目标吗?如果您不想在每个显示对象上设置 alpha,则可以将其设置在原始 Graphics 对象上。或者,您可以将填充的alpha设置为beginFill的第二个参数dot.beginFill(0xFF9900, 0.25);
    • @Karmacon 这在一定程度上有效。我想用几千个代理做一个 boids 模拟,我尝试了图形方法,但它不能很好地扩展。在 gl 或像素中,可以通过使用低 alpha 缓冲区清除颜色来实现相同的效果(例如,绘制一个低透明度的矩形作为背景,其余的形状在顶部)。我不确定这是否清楚,我已经添加了更新
    猜你喜欢
    • 1970-01-01
    • 2020-08-26
    • 1970-01-01
    • 2014-03-26
    • 1970-01-01
    • 2017-01-18
    • 1970-01-01
    • 1970-01-01
    • 2013-04-09
    相关资源
    最近更新 更多