In P5js I want to overlay a shape to a video, but they don't share the same dom element.
Is there any way to do it?
Code test here: The video should be visible through the triangular contour that cuts the shape.
The code:
let video;
function preload() {
video = createVideo("video.mp4");
}
function setup() {
createCanvas(400, 300);
background("gray");
video.size(400,400);
video.loop();
var w = width * 0.7;
var h = height * 0.7;
translate((width/2) - (w/2), (height/2) - (h/2));
fill("lightgray");
noStroke();
beginShape();
vertex(0, 0);
vertex(w, 0);
vertex(w, h);
vertex(0, h);
beginContour();
vertex(w * 0.2, h * 0.4);
vertex(w * 0.5, h * 0.8);
vertex(w * 0.8, h * 0.4);
endContour();
endShape();
noLoop();
}
I see here that hiding the video and using image (i.e. image(video, 10, 10)) it is possible to draw a single frame. Alas I use noLoop() and in my case there would be no automatic refresh of the video in draw().
"The video should be visible through the triangular contour that cuts the shape."
Below is a result I got from a quick play-around with your code. Maybe it will be useful to you in some way (eg: gives new ideas on how to proceed).
The code's logic is to simply create 2 layers.
Bottom layer 1 is video and top layer 2 is triangle (the canvas).
Other ideas include maybe using BlendModes like Screen or Multiply:
example: canv.blendMode(SCREEN);
Where SCREEN makes whites transparent, and MULTIPLY makes blacks transparent).
The example testing code (makes two layers and also removed background("gray");)
let video; let canv;
function preload()
{ video = createVideo("video.mp4"); }
function setup()
{
translate(0, 0);
video.size(400,300);
video.style("z-index: 1"); //# is default in P5.JS
video.position(0, (width * 0.7) );
video.loop();
canv = createCanvas(400, 400);
canv.style("z-index: 2");
canv.position(0, 0); //# important to have a setting
//# Not needed ....
//background("gray");
var w = width * 1;
var h = height * 1;
translate((width/2) - (w/2), (height/2) - (h/2));
fill("lightgray");
noStroke();
beginShape();
vertex(0, 0);
vertex(w, 0);
vertex(w, h);
vertex(0, h);
beginContour();
vertex(w * 0.2, h * 0.4);
vertex(w * 0.5, h * 0.8);
vertex(w * 0.8, h * 0.4);
endContour();
endShape();
noLoop();
}
Related
I recently started using p5.js more and noticed that when I the textAlign() function to center text, it is offset higher than the coordinates I specify when calling text(). The amount it is offset seems to be constant between different font sizes, being approximately fontSize()/12 above the y-coordinate I entered.
An example of this can be seen at this p5.js sketch, showing the default centering on the left, and the text being offset by fontSize()/12 on the right, having it be properly centered at varying text sizes.
Is there a way I could fix this issue and have all text be aligned properly without having to specify in each call of text that I want the text to be shifted down the amount of pixels needed for it to be properly centered? Is there a way I can modify the text function to have this functionality built in?
(Edit: I was able to "solve" this issue by overwriting the default text function with my own code, though I don't know if this is very good practice. A link to the fix can be found here, with the fixed text alignment in black and the default p5.js alignment in green.)
This has to do with what you think of as the vertical "center" of the glyphs. From you example it is evident that you think of the "center" as the center line of the capital letters. However, by this metric all lower case letters would appear mostly below center and it also fails to take into account glyph descent (that is, the amount of certain lower case glyphs that appear below the font baseline).
Here is an example that I think clearly demonstrates how the various vertical positioning types work.
function setup() {
createCanvas(windowWidth, windowHeight);
noLoop();
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
redraw();
}
function draw() {
let w = width / 4;
push();
stroke('blue');
line(0, height / 2, width, height / 2);
pop();
drawText(0, 0, w, height, TOP);
drawText(w, 0, w, height, CENTER);
drawText(w * 2, 0, w, height, BASELINE);
drawText(w * 3, 0, w, height, BOTTOM);
}
const str = 'Age';
const size = 48;
function drawText(x, y, w, h, valign) {
push();
textSize(size);
textAlign(LEFT, valign);
let tw = textWidth(str);
let yOff = 0;
switch (valign) {
case TOP:
yOff = -size / 2;
break;
case BOTTOM:
yOff = size / 2;
break;
case BASELINE:
yOff = size / 2 - textDescent();
}
stroke('limegreen');
rectMode(CENTER);
noFill();
rect(x + w / 2, y + h / 2, tw, size);
translate(x + w / 2 - tw / 2, height / 2 + yOff);
stroke('red');
line(0, 0, tw, 0);
strokeWeight(4);
point(0, 0);
noStroke();
fill('black');
text(str, 0, 0);
pop();
}
body, html {
margin: 0;
padding: 0;
overflow: hidden;
}
<script src="https://cdn.jsdelivr.net/npm/p5#1.3.1/lib/p5.js"></script>
Im working of a program that has a circle moving around inside another bigger circle.
var offX;
function setup() {
createCanvas(400, 400);
offX = 0.00;
}
function draw() {
background(220);
var bigBoy = {
x: 200,
y: 200,
r: 150,
};
var smallBoy = {
x: noise(offX) * 400,
y: map(sin(offX),-1,1,10,380),
r: 10,
};
offX += 0.005;
ellipse(bigBoy.x,bigBoy.y,bigBoy.r * 2);
ellipse(smallBoy.x,smallBoy.y,smallBoy.r * 2);
var d = dist(bigBoy.x,bigBoy.y,smallBoy.x,smallBoy.y);
text(round(d,0),30,20);
//-------------------------------//
if(d > bigBoy.r - smallBoy.r){
//move away from / dont cross over bigBoy's diameter//
} else{
//crack on mate//
}
}
could anyone advise me how I would keep the smaller circle within the bigger circles diameter. I would need it to look natural, like the small circle has a force preventing it from leaving the bigger one?
Thanks in advance!
P
I'm using p5.js to draw a bottle shape (cylinder) and to put a string on that cylinder. Until now, I could only put the string horizontally and I'm trying to put my string vertically (as if you had to turn your head to be able to read)
I searched a lot and I tried with using rotate() and translate() functions, which are in the p5.js documentation.
let angle = 0;
function setup() {
createCanvas(600, 400, WEBGL);
graphics = createGraphics(200, 200);
graphics.background(255);
test = createGraphics(300, 100);
test.background(144, 214, 199);
test.fill(255);
test.textAlign(CENTER);
test.textSize(32);
test.text('QWERTY', 150, 50);
rotate(90);
}
function draw() {
background(255);
graphics.fill(255, 0, 255);
graphics.ellipse(mouseX, mouseY, 20);
ambientLight(100);
directionalLight(255, 255, 255, 0, 0, 1);
noStroke();
rotateY(angle * 0.1);
texture(test);
cylinder(50, 230);
angle += 0.07;
}
You can find the codepen on the link below:
https://codepen.io/smickael/pen/bPMEOP
You're so super close !
You simply need to rotate the PGraphics buffer you're drawing the text into, not the sketch itself, by 90 degrees (using radians (HALF_PI)).
Additionally it would help to translate after depending on how you want to align the text
let angle = 0;
function setup() {
createCanvas(600, 400, WEBGL);
graphics = createGraphics(200, 200);
graphics.background(255);
test = createGraphics(300, 100);
test.background(144, 214, 199);
// rotate the buffer by 90 degrees (remember rotate() works with radians)
test.rotate(radians(90));
// similar to passing 75,0 to text, but keeping transformations grouped for easy tweaking
test.translate(75,0);
test.fill(255);
test.textAlign(CENTER);
test.textSize(32);
test.text('QWERTY', 0, 0);
}
function draw() {
background(255);
graphics.fill(255, 0, 255);
graphics.ellipse(mouseX, mouseY, 20);
ambientLight(100);
directionalLight(255, 255, 255, 0, 0, 1);
noStroke();
rotateY(angle * 0.25);
texture(test);
cylinder(50, 230);
angle += 0.07;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js"></script>
I'm trying to use phaser with the web audio API but I can't figure out how to go from the sprites x, y, z and rotation values to a directional vector and up vector. How would I do this?
ctx.setPosition(sprite.x, sprite.y, sprite.z);
ctx.setOrientation(0,0,0,0,0,0);
ctx.setVelocity(0, 0, 0);
I'm pretty sure I worked it out, here's the code:
function updateWithSprite(sprite)
if (sprite.body) {
var rot = sprite.body.rotation + Math.PI / 2;
this.setPosition(sprite.body.x, body.y, 0);
this.setOrientation(Math.cos(rot), Math.sin(rot), 0);
this.setVelocity(sprite.body.velocity.x, sprite.body.velocity.y, sprite.body.velocity.z);
} else {
var rot = sprite.rotation + Math.PI / 2;
this.setPosition(sprite.x, sprite.y, 0);
this.setOrientation(Math.cos(rot), Math.sin(rot), 0);
this.setVelocity(0, 0, 0);
}
}
I`m new with canvas so thanks for your patience.
I wrote an engine that is creating 2 different layers in 2 canvas elements which are one over another. They contain some generated pictures, which aren`t important here.
I'm trying to create an effect which will display bottom layer when I move mouse over the top layer and click.
Something like this:
This is what I have tried so far:
To use transparency on canvas element and display bottom canvas (fast but not usable)
Re-create a clipping region.
Whenever I press the mouse I store current coordinates and re-render the canvas with updated clipping region
Updating clipping region is slow if I use stroke to create shadows + I`m not sure how to remove lines from it (see picture).
If I remove shadow effect, it works really fast, but I need to have it.
The only thing that comes on my mind how to speed this, is to save coordinates of every click, and then to re-calculate that into 1 shape and drop a shadow on it - I`ll still have lines, but it will be faster because there won`t be thousand of circles to draw...
Any help will be most appreciated!
You can take advantage of the browser's built in interpolation by using it as a pseudo low-pass filter, but first by painting it black:
Copy the top layer to the bottom layer
Set source-in comp. mode
Draw all black
Set source-in comp. mode
Scale down image to 25%
Scale the 25% region back up to 50% of original (or double of current)
Scale the now 50% region back up to 100% of original. It will be blurred.
Depending on how much blur you want you can add additional steps. That being said: blurred shadow is an intensive operation no matter how it is twisted and turned. One can make compromise to only render the shadow on mouse up for example (as in the demo below).
Example
Example using two layers. Top layer let you draw anything, bottom will show shadow version at the bottom later while drawing.
var ctx = document.getElementById("top").getContext("2d"),
bctx = document.getElementById("bottom").getContext("2d"),
bg = new Image(),
isDown = false;
bg.src = "http://i.imgur.com/R2naCpK.png";
ctx.fillStyle = "#27f";
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.globalCompositeOperation = "destination-out"; // "eraser"
ctx.canvas.onmousedown = function(e) {isDown = true};
window.onmousemove = function(e) {
if (!isDown) return;
var pos = getPos(ctx.canvas, e);
ctx.beginPath();
ctx.moveTo(pos.x + 10, pos.y);
ctx.arc(pos.x, pos.y, 10, 0, 2*Math.PI); // erase while drawing
ctx.fill();
};
window.onmouseup = function(e) {
if (isDown) {
isDown = false;
makeShadow();
}
};
function makeShadow(){
var w = bctx.canvas.width,
h = bctx.canvas.height,
offset = 7,
alpha = 0.75;
// reset alpha
bctx.globalAlpha = 1;
// normal comp mode to clear as it is faster than using "copy"
bctx.globalCompositeOperation = "source-over";
bctx.clearRect(0, 0, w, h);
// copy top-layer to bottom-layer
bctx.drawImage(ctx.canvas, 0, 0);
// comp. mode will only draw in to non-alpha pixels next
bctx.globalCompositeOperation = "source-in";
// black overlay
bctx.fillRect(0, 0, w, h);
// copy mode so we don't need an extra canvas
bctx.globalCompositeOperation = "copy";
// step 1: reduce to 50% (quality related - create more steps to increase blur/quality)
bctx.drawImage(bctx.canvas, 0, 0, w, h, 0, 0, w * 0.5, h * 0.5);
bctx.drawImage(bctx.canvas, 0, 0, w * 0.5, h * 0.5, 0, 0, w * 0.25, h * 0.25);
bctx.drawImage(bctx.canvas, 0, 0, w * 0.25, h * 0.25, 0, 0, w * 0.5, h * 0.5);
// shadow transparency
bctx.globalAlpha = alpha;
// step 2: draw back up to 100%, draw offset
bctx.drawImage(bctx.canvas, 0, 0, w * 0.5, h * 0.5, offset, offset, w, h);
// comp in background image
bctx.globalCompositeOperation = "destination-over";
bctx.drawImage(bg, 0, 0, w, h);
}
function getPos(canvas, e) {
var r = canvas.getBoundingClientRect();
return {x: e.clientX - r.left, y: e.clientY - r.top};
}
div {position:relative;border:1px solid #000;width:500px;height:500px}
canvas {position:absolute;left:0;top:0}
#bottom {background:#eee}
<div>
<canvas id="bottom" width=500 height=500></canvas>
<canvas id="top" width=500 height=500></canvas>
</div>