Create a image-mask with p5js - javascript

Im trying to figure out if its possible to have a blank canvas and then place a image and have it masked by a random shape? That or use a png as mask.
Thank you
M

Yup it is possible and quite trivial with the mask() function on the p5.Image class (it's too bad they don't list this class member functions on the main page of the reference but if you use the search box you'll find these types of things).
Given the image:
And the mask PNG:
You can render the masked image like so:
let img;
let mask;
function preload() {
img = loadImage('https://www.paulwheeler.us/files/windows-95-desktop-background.jpg');
mask = loadImage('https://www.paulwheeler.us/files/Vase-Illusion.png');
}
function setup() {
createCanvas(windowWidth, windowHeight);
img.mask(mask);
noLoop();
}
function draw() {
image(img, 0, 0, height * (img.width / img.height), height)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>

Related

How to move ellipse filled with an image to mask similar background?

I am a super early user of coding from Italy.
I came up with an idea to promote a company logo on their website and I almost reached the goal so I am sharing this problem.
The idea is to obtain a sort of clipping mask effect when the mouse/cursor move on the image
I've made so far a code that does the work with a still ellipse.
When I set the position parameters of the ellipse as mouseX and mouseY the effect does not work if not just a bit of a glitch at the start.
How can I make it work as intended?
Here you can find the link of what I have now:
https://editor.p5js.org/francesco.ficini.designer/full/FLBuhggW-
Here the code:
let img;
let imgbg2;
let maskImage;
function preload() {
img = loadImage("NeroP.jpg");
imgbg2 = loadImage("RossoP.jpg");
}
function setup() {
createCanvas(400, 225);
img.mask(img);
}
function draw() {
background(imgbg2, 0, 0);
//Immages
image(imgbg2, 0, 0);
image(img,0,0);
// Ellipse Mask
maskImage = createGraphics(400, 225);
maskImage.ellipse(200, 100, 50, 50);
imgbg2.mask(maskImage);
image(imgbg2, 0, 0);
}
The thing about the p5.Image.mask function is that it modifies the image that is being masked. Which means that any pixels that are cleared by the mask are gone for good. So if you want to dynamically change the mask you will need to make a copy of the original and re-apply the modified mask any time it changes.
Additionally you will want to avoid creating images and graphics objects in your draw() function because this can result in excessive memory allocation. Instead create a single set of graphics/images and re-use them.
let img;
let imgbg2;
let maskImage;
let maskResult;
function preload() {
img = loadImage("https://www.paulwheeler.us/files/NeroP.jpeg");
imgbg2 = loadImage("https://www.paulwheeler.us/files/RossoP.jpeg");
}
function setup() {
createCanvas(400, 225);
// Create graphics and image buffers in setup
maskImage = createGraphics(imgbg2.width, imgbg2.height);
maskResult = createImage(imgbg2.width, imgbg2.height);
}
function mouseMoved() {
if (maskResult) {
maskImage.clear();
// Ellipse
maskImage.ellipse(mouseX, mouseY, 50, 50);
// Copy the original imgbg2 to the maskResult image
maskResult.copy(
imgbg2,
0, 0, imgbg2.width, imgbg2.height,
0, 0, imgbg2.width, imgbg2.height
);
// apply the mask to maskResult
maskResult.mask(maskImage);
}
}
function draw() {
//Immagini
image(img, 0, 0);
// draw the masked version of the image
image(maskResult, 0, 0);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>

How to Render a Single p5.js Sketch to Multiple Divs

I am trying to use a single p5 sketch in multiple divs.
Currently using below code below. I have tried using a class selector but it seems to only work with a parent method(doesn't work with getElementById for example.) As another workaround, I could not make this p5 sketch the background element in the body selector either. Thanks for the help!
let theShader;
function preload() {
theShader = loadShader('shader.vert', 'shader.frag');
}
function setup() {
pixelDensity(1);
let myCanvas = createCanvas(windowWidth, windowHeight, WEBGL);
myCanvas.parent('container1');
}
function draw() {
shader(theShader);
theShader.setUniform("u_resolution", [width, height]);
theShader.setUniform("u_time", millis() / 1000.0);
theShader.setUniform("u_mouse", [mouseX, map(mouseY, 0, height, height, 0)]);
rect(0.0, 0.0, 1.0, 1.0);
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
Not sure if it works like that. But you could try to create a canvas element instead of a div element. At the end of the day, a p5 sketch is also a canvas element.
And then you should be able to grab the new canvas:
let newCanvasCtx = newCanvas.getContext('2d');
and then call drawImage and pass in the p5 canvas:
newCanvasCtx.drawImage(p5Canvas, 0, 0);

How to draw a p5.js circle over an HTML image

I am loading an image into my web app using standard JS and HTML It just just a simple map and my goal is to draw on it using p5.js.
<div id="map">
<img src="Assets/MENA.jpg" class="image" width="1500" height="750">
</div>
function conflictMapMENA() {
this.name="MENA conflict map";
this.id="conflict-map"
this.draw = function() {
var map = document.createElement('img')
map.src = 'Assets/MENA.jpg'
gallery.selectVisual(map);
fill(255, 0, 0);
ellipse(30, 30, 10);
}
}
Inside this.draw = function(){}, I am invoking p5.js library's ellipse() and fill() functions to draw a red circle. This is what it looks like:
But when I try to adjust the coordinates to move the circle over the map, the circles go under it. Is there a way for me to have these two things cooperate without me having to draw the circle in pure JS?
Do you need the image to be in your actual HTML? If not, you can use the loadImage() and image() functions in p5.js:
let myImage;
function setup() {
createCanvas(400, 400);
myImage = loadImage("https://upload.wikimedia.org/wikipedia/commons/thumb/4/4b/Domestic_Cat_Demonstrating_Dilated_Slit_Pupils.jpg/220px-Domestic_Cat_Demonstrating_Dilated_Slit_Pupils.jpg");
}
function draw() {
image(myImage, 0, 0, width, height);
ellipse(width / 2, height / 2, 100, 100);
}
If you do need your image in your actual HTML, then you can use a combination of CSS and the parent() function to make the image overlap with your sketch:
<body>
<div id="my-canvas"
style="position:absolute;"></div>
<img style="width: 400px; height: 400px;"
src="path/to/image.png" />
<script src="sketch.js"></script>
</body>
function setup() {
const canvas = createCanvas(400, 400);
canvas.parent('my-canvas');
}
function draw() {
ellipse(width / 2, height / 2, 100, 100);
}
Just checked your doubt the background is overlapping the circle because of the depth u can give the depth of the circle greater than the backgroung

P5 SVG imageMode

I load my mapbox-Link like this and it works:
var mapimg;
function preload () {
mapimg = loadImage('mapbox-LINK');
}
function setup() {
createCanvas(1024,720);
translate(width /2, height / 2);
imageMode (CENTER);
image(mapimg, 0,0);
}
But when I change craeteCanvas() to craeteCanvas( , , SVG) it jumps away and behaves strange. I'm using zenozeng to render the .svg Canvas.
I think it is the imageMode(CENTER) that doesnt work in this enviroment. How can I center my Image again?
You are translating your canvas to center translate(width /2, height / 2); then drawing the image. If you want the image centered, just keep the canvas on its original (0,0), and default imageMode(CORNER)
var mapimg;
function preload () {
mapimg = loadImage('https://api.mapbox.com/styles/v1/foliran/cjnrcb1pm1vbw2rqkbw3o5uog/static/10.4209538,51.1657564,5/1024x720?access_token=pk.eyJ1IjoiZm9saXJhbiIsImEiOiJjam5yZXA0Z2gwNnlmM2twcDJrNnlxdHJkIn0.vSpVuibxadIaVGb4JiPn_w');
}
function setup() {
createCanvas(1024,720,SVG);
// translate(width /2, height / 2); //no need to translate
// imageMode (CORNER); //no need to imageMode, as it's default
image(mapimg, 0,9);
}
I'm not familiar with p5.js-svg but be careful with all the different implications of rendering using the p5.js canvas vs using this svg mode.

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

Categories

Resources