themessup
themessup

Reputation: 192

Pixi.js renderer from p5.js canvas

I've been trying to write a script in Pixi that uses the canvas from a p5.js program as the entire "view" to apply a displacement filter on. I've already achieved this with a single image added as a sprite (see below), but I can't figure out how to interface with the output of p5.js and use it as a view with Pixi's autoDetectRenderer(). I've used p5's .parent() function to attach the canvas to a specific element but that doesn't seem to help. Ideally this would all end up existing in my #main-container div.

The next task would be to make sure this feed is coming in live, so animating elements from the p5.js program are constantly fed into Pixi and filtered.

Any help/pointers would be greatly appreciated!

HTML:

<!DOCTYPE html>
<html>

<head>
    <title>pixi.js + p5.js displacement filter</title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <script type="text/javascript" src="https://cdn.rawgit.com/GoodBoyDigital/pixi.js/v1.6.1/bin/pixi.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.15/p5.min.js"></script>
    <style>
        #main-container {
            position: relative;
            width: 300px;
            height: 300px;
            border: 1px solid red;
        }
    </style>
</head>

<body>
    <div id="main-container"></div>
    <script type="text/javascript" src="js/program.js"></script>
</body>

</html>

program.js:

// p5.js program

var theCanvas, width, height;

function setup() {
  width = document.getElementById('main-container').offsetWidth;
  height = document.getElementById('main-container').offsetHeight;
  theCanvas = createCanvas(width, height);
    rectMode(CENTER);
}

function draw() {
  background(0, 0, 255);
    translate(width/2, height/2);
    rotate(frameCount*0.01);
  fill(0, 255, 0);
  rect(0, 0, 100, 100);
}

// -_-_-_-_-_-_-_-_-_-_-_-_

// pixi.js

// Renderer
var renderer = PIXI.autoDetectRenderer(width, height);
document.body.appendChild(renderer.view);

// Stage
var stage = new PIXI.Stage(0xd92256);

// Container
var container = new PIXI.DisplayObjectContainer();
stage.addChild(container);

// Background
var bg = PIXI.Sprite.fromImage("https://i.imgur.com/3q3kNGh.png?1");
container.addChild(bg);

// Filter
var displacementTexture = PIXI.Texture.fromImage("http://i.imgur.com/2yYayZk.png");
var displacementFilter = new PIXI.DisplacementFilter(displacementTexture);

// Apply it
container.filters = [displacementFilter];

// Animate
requestAnimFrame(animate);

function animate() {
  var offset = 1;

  displacementFilter.offset.x += offset;
  displacementFilter.offset.y += offset;

  renderer.render(stage);
  requestAnimFrame(animate);
}

Thank you!

Upvotes: 1

Views: 1398

Answers (1)

WDSTEVE
WDSTEVE

Reputation: 11

I think the best best thing to do would be to take different approach to the problem, trying to connect P5 and Pixi is a lot work. I have tried using both libraries before and it went off the rails fast. What you are trying to do can be done with P5 or Pixi alone. The P5 only approach is what I know best so I will walk you though it.

The way that Pixi makes it filters is with webGL shaders, they are small programs the run on the GPU to manipulate images. They are written in a C like language called glsl. P5 has support for webGL shaders (filters) and so, we write our own displacement shader. I am not going to get into the glsl part here but I have made a demo with lots of comments here.

The first part of a shader is loading in the glsl code. Always do this in preload. As an alternative you can use with createShader and grave strings.

let displacementShader;

function preload() {
    displacementShader = loadShader("displacement.vert", "displacement.frag");
}

Next you create a WEBGL mode canvas, this is not like a normal canvas and is for 3d graphics and shaders. You still need somewhere for your 2d graphics so make a buffer to draw 2d graphics too.

let buffer;

function setup(){
    createCanvas(windowWidth, windowHeight, WEBGL);
    buffer = createGraphics(windowWidth, windowHeight);
}

Now that everything is set up, all you need to do is run the shader.

function draw(){
    buffer.circle(100, 100, 50, 50) // draw stuff to the buffer
    shader(displacementShader);
    // pass variables into the shader, it will need to buffer to distort it
    displacementShader.setUniform("buffer", buffer);
    rect(0, 0, width, height); // some geometry for the shader to draw on too
}

If you want to look at some examples of shader other that my demo there is a lovely Github repo for that. In my demo I also

Upvotes: 1

Related Questions