Inverting colors within shape in Processing - processing

I want to draw shapes which invert the color of the pixels underneath them.
I know similar effects can be achieved in black and white using by setting the blendMode() to DIFFERENCE. However this does not work for colours.
I have also tried to use filter(INVERT) but this affects the whole canvas rather than specific areas.
Is there any way to efficiently achieve these aims in Processing, hopefully with built-in functionality?

I'm not seeing why blendMode does not work for this:
function setup() {
createCanvas(windowWidth, windowHeight);
rectMode(CENTER);
noStroke();
noLoop();
}
function draw() {
background(0);
translate(width / 2, height / 2);
push();
fill(0, 255, 0);
rect(0, 0, width * 0.6, height * 0.6);
pop();
push();
blendMode(DIFFERENCE);
fill(255);
ellipse(width * 0.3, height * 0.3, 100, 100);
pop();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>

Well you could probably do:
color col = get(x, y);
color colInv = color(255 - col.r, 255 - col.g, 255 - col.b, 255 - col.a);
Not sure if you can do 255 - col all at once. Also I'm not sure if this would actually work, but it should...
Also get(x, y) takes a while, so you can also do it with the pixel array The coding train has a nice video on the pixel array.

Related

How to draw a fading object trail? Without background manipulation

I have a simple ellipse, moving across the screen, is there any simple code I could implement to have this ellipse draw a trail behind it that has its alpha fade over time to a certain extent? I still want the trail visible in the end but less bright than the casting ellipse.
You could also do something like this:
let positions = [];
function draw(){
positions.push(mouseX);
positions.push(mouseY);
for(let i in positions){
let x = positions[i];
let y = positions[i + 1];
fill(255, 255 - i * 10); noStroke();
ellipse(mouseX, mouseY, x, y)
}
if(positions.length > 20){
positions.shift();
positions.shift();
}
}
Assuming the ellipse is the only thing being drawn then there is a simple solution which is to, instead of drawing a fully opaque background on each frame, draw a semi-transparent background:
function setup() {
createCanvas(windowWidth, windowHeight);
}
function draw() {
background(0, 35);
ellipse(mouseX, mouseY, 20, 20);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
However, there are some caveats, namely that for certain colors/transparency levels you will be left with permanent "ghost" of the trails due to some weird alpha blending math anomalies.

Natural Color Mixing in Processing

I am trying to naturally mix green tint on one photo (elephant) and red tint on another photo (ship) by placing the two opaque and tinted photos on top of one another. While both photos appear with equal prominence, when the program is run and both colors can be observed, the red tint (because it is the last tint applied) is more dominant and there is no discernable yellow color in the image no matter which tint is applied first. If anyone knows how to naturally mix colors in processing I would love to hear your advice. I also do not want to simply apply a yellow tint as the last tint. Thanks!
PImage elephant;
PImage ship;
void setup(){
size(695,473);
elephant = loadImage("elephantRider.png");
ship = loadImage("ship.jpg");
ship.filter(OPAQUE);
elephant.filter(OPAQUE);
}
void draw(){
background(255);
tint(0,255,0, 127);
image(elephant, 0,0);
tint(255,0,0,127);
image(ship, 0,0);
}
Think of Processing as painting. What you're doing now is a little bit like drawing one color to the screen, and then drawing another color on top of the first color.
Instead, what you want to do is mix the two colors together before you draw the result to the screen. Think of this as mixing two paints together to make a new color.
You can do this by taking the average of the two colors, something like this:
PImage img;
void setup() {
size(695, 473);
img = loadImage("image.jpg");
}
void draw() {
background(255);
//green
tint(0, 255, 0, 127);
image(img, width/2, height/2, 50, 50);
float blendedRed = (0 + 255) / 2;
float blendedGreen = (255 + 0) / 2;
float blendedBlue = (0 + 0) / 2;
// blended
tint(blendedRed, blendedGreen, blendedBlue, 127);
image(img, mouseX, mouseY, 50, 50);
}
This example is a little contrived because the averages are pretty trivial, but this approach should work for any color.
If you want something more advanced, note that color averaging is a pretty advanced topic. Googling "color averaging" is probably a good start.

P3D camera orientation

I've got a big sphere. There is a red dot that moves around the sphere. I want to follow that red dot as it moves around to sphere. So my camera has to move with the red dot. But there is a problem. Right now, what I'm experiencing is what is shown in exhibit B. I want my animation to realize the point of view shown in exhibit A.
Here is the code I have so far. I think it's pretty simple. I have 3 variables that control where my eye is, and I have 3 variables that control where the target is. The red dot is also located at the target position. I added 2 planes in x-y which helped me not get too confused as the thing was spinning.
Here is a fiddle:
https://jsfiddle.net/da8nza6y/
float radius = 1000;
float view_elevation = 1500;
float target_elevation = 300;
float x_eye;
float y_eye;
float z_eye;
float x_aim;
float y_aim;
float z_aim;
float h;
float theta;
void setup() {
size(600, 600, P3D);
theta = 0;
h = 30;
}
void draw() {
theta += 0.5;
theta = theta%360;
x_eye = (radius+view_elevation)*cos(theta*PI/180);
y_eye = 0;
z_eye = (radius+view_elevation)*sin(theta*PI/180);
x_aim = (radius+target_elevation)*cos((theta+h)*PI/180);
y_aim = 0;
z_aim = (radius+target_elevation)*sin((theta+h)*PI/180);
camera(x_eye, y_eye, z_eye, x_aim, y_aim, z_aim, 0, 0, -1);
background(255);
// the red dot
pushMatrix();
translate(x_aim, y_aim, z_aim);
fill(255, 0, 0, 120);
noStroke();
sphere(10);
popMatrix();
// the big sphere
noStroke();
fill(205, 230, 255);
lights();
sphere(radius);
// the orange plane
pushMatrix();
translate(0, 0, 10);
fill(255, 180, 0, 120);
rect(-2000, -2000, 4000, 4000);
popMatrix();
// the green plane
pushMatrix();
translate(0, 0, -10);
fill(0, 180, 0, 120);
rect(-2000, -2000, 4000, 4000);
popMatrix();
}
So the pickle is that, it seems like the moment the red dot (whose location in the x-z plane is given by the angle (theta+h) and distance (radius+target_elevation) from the origin) crosses the x-y plane, everything gets flipped upside-down and backwards.
Now, I have tried to control the last 3 variables in the camera() function but I'm getting confused. The documentation for the function is here:
https://processing.org/reference/camera_.html
Can anyone see a solution to this problem?
Also, I'm sure I could just rotate the sphere (which I can do) and not have these problems, but I'm sure where I'm going with this animation and I feel like there will be things to come that will be easier with this method. Though I could be mistaken.
I believe I've solved my own problem.
I've added the following lines in draw, before calling the camera() function:
if ((x_eye- x_aim) < 0) {
z_orientation = 1;
} else {
z_orientation = -1;
}
I noticed that it wasn't (theta+h) that was triggering the flip, but the relative positions of the view and target.
Here is an updated fiddle:
https://jsfiddle.net/da8nza6y/1/

Processing.js : how to draw() only parts of the canvas to reduce cpu usage

Right now I have an html page that renders 20 canvases each with its own instance of a processing.js script. To decrease CPU usage, I have mouseover/out events to loop()/noLoop() only the graph the mouse is hovering over.
But I need to take this even further. The canvas right now is 300x400 where there is a 300x300 space that needs to dynamically draw all the time but there's a rectangle with a legend that is the rest of the space which really doesn't need to be redrawn using the framerate() of the rest.
Does any know of a way to essentially specify to the draw() function which pixels to redraw?
I'm pretty sure a 100x300 blank area is not going to add significantly to the computations. But you can of course pass to draw something like:
if(frameCount==1) [draw legend code];
or using if(frameCount % 30 == 0)... for a continuous but less frequent rendering.
Edit:
void setup(){
size(400,400);
noStroke();
background(255);
}
void draw(){
fill(255,255,255,50);
rect(0, 150, width, height-150);
if(frameCount%50 == 1) {
fill(255);
rect(0, 0, width, 150);
fill(0);
text("frame " + frameCount, width/2, 75);
}
fill(255,0,0);
ellipse(random(0, width), random(150, height), 10, 10);
}

“Rotate” and “translate” in processing give me headaches

As a small homework to get into Processing, I had to write some code to get the following:
Using
public void setup() {
size(300,200);
noFill();
rect(100, 20, 40, 80);
ellipseMode(CENTER);
fill(#000000);
ellipse(width/2, height/2, 5,5);
noFill();
translate(width/2, height/2);
rotate(radians(65));
rect(-20, -40, 40, 80);
}
public void draw() {
}
this worked very good, so far. But I don’t like that I had to change the coordinates inside of the bottom rect instruction in order to get the rotation right. I know that by rotating you don’t rotate single elements but in fact the whole coordinate system.
What I don’t know is which values to put into the translate instruction to have the output be like in the picture above while also still using the same coordinates within the rect command.
The task is already done with the code I used, I just don’t like it too much. So this isn’t mere asking for somebody else doing my homework but pure interest.
EDIT: More generalised attempt of a question: How do I know which values to pit into translate before rotate to get whatever result I want? Is there a way to calculate them? For sure, it’s not just trying out, is it?
A lot of the confusion in processing is the coordinate system. In Processing the origin (0,0) is at the top left of the screen and only positive coordinates display on the screen. The very common workaround for this is to call:
translate(width/2, height/2);
at the beginning of your void draw() method. That way 0,0 is now at the center of the sketch, and any subsequent methods called such as rotate(radians(65)) will take action from the center of the sketch.
This is also good because sketches that use the P3D or OPENGL renderer often call translate to change the coordinate system into something that is easier to use. For example an object at 0,0 or 0,0,0 is at the center and it makes it easier to orbit the camera around the object or have the object rotate around its center.
another popular way of drawing objects would be to set the origin as above and instead of giving the coordinates of each object, i.e. rect(-100, -50, 50, 50) is to use popMatrix() and pushMatrix before a translate before drawing each object at 0,0 as illustrated below:
translate(width/2, height/2);
pushMatrix();
translate(-100, -50);
rect(0,0,50,50);
popMatrix();
This is a good approach to use in a 2d renderer if you think you might move to 3d renderer eventually, because you can easily replace rect() with box() or sphere() or create your own method or object that draws geometry assuming the origin is at 0,0.
If you replace the x and y coordinates with variables or iterate through an array in a for loop it becomes very easy to draw hundreds or thousands of shapes in either 2d or 3d with minimal effort and minimal rewriting of the code.
update: added clarification for the original poster, per their comment.
I have changed the problem slightly to show you how I would approach this. I am showing the translate / rotate method I described above using push and pop matrix. I am just guessing at the values, but if you want something pixel accurate you can take measurements in an image editing program like photoshop or preview.
translate(180, 150);
rect(0, 0, 180, 80);
translate(185, 170);
rotate(radians(65));
rect(0, 0, 180, 80);
translate(180, 250);
ellipse(0, 0, 8, 8);
Putting it all together with pushMatrix() and popMatrix().
void setup(){
size(400,400);
}
void draw(){
// rect1
noFill();
pushMatrix();
translate(180, 150);
rect(0, 0, 180, 80);
popMatrix();
// rect2
pushMatrix();
translate(185, 170);
rotate(radians(65));
rect(0, 0, 180, 80);
popMatrix();
// ellipse
fill(0);
pushMatrix();
translate(180, 250);
ellipse(0, 0, 8, 8);
popMatrix();
}
in my particular example, know how to translate and rotate to get the
result in the picture without changing the rectangle coordinates?
Well, you need to draw at origin to use rotate properly, so you are just dealing with the origin of the rect... As it is in your code, the default, the origin is the upper left corner, so you made an off set (from (0,0)) to draw it's centre, not the corner, at coordinate(0,0), then rotate by the middle. Well done. It is not coincidence that the values you found was minus half rect width(-20) and minus half rect height(-40). If you change to rectMode(CENTER) than you can just draw at (0,0). The same applies to translate, you can just translate to the desired point, the center of the screen, where there is the ellipse. What is done using half width and half height...
look:
public void setup() {
size(300, 200);
smooth();
ellipseMode(CENTER);
rectMode(CENTER);
noFill();
// here converting the coordinates to work with CENTER mode
//could have changed the rect mode just after this
// but i kept as an illustration
int rwidth = 40;
int rheight = 80;
int xpos = 100 + rwidth/2;
int ypos = height/2 - rheight/2 ;
rect(xpos, ypos, rwidth, rheight);
fill(#000000);
ellipse(width/2, height/2, 5, 5);
noFill();
pushMatrix();
translate(width/2, height/2);
//draw at origin gray
stroke(150);
rect(0, 0, 40, 80);
// then rotate
rotate(radians(65));
// draw again black
stroke(0);
rect(0, 0, 40, 80);
popMatrix();
// here using the cordinates calculated before as a translate value
// we draw at origin, but it appears at same place
stroke(230,230,100);
// a bit to the left...
translate(xpos-2, ypos-2);
rect(0, 0, 40, 80);
}
Rotation is aways applied to origin point (0,0), so you want to draw your axis for rotating at origin. Or move the coordinate system origin, to your axis. It is indeed confusing. When using transformations I tend to draw at origin always. Try this to see if it makes things more clear... or less :)
Also there is push/popMatrix() to control the scope of transformations...
public void setup() {
size(300, 380);
smooth();
}
public void draw() {
background(0);
stroke(255);
//use push/pop Matrix to control scope of translate and rotate
pushMatrix();
//move coordinates system origin to center of screen
translate(width/2, height/2);
// rotate with origin as axis
rotate(radians(mouseY));
//draw at origin (now temp moved to center of screen)
// white line
line(0, 0, 150, 0);
// here all coordinate system is back to normal
popMatrix();
//draw with normal system red line at origin
stroke(255, 0, 0);
line(0, 0, 150, 0);
//draw with normal system blue line at centre
stroke(0, 0, 255);
line(width/2, height/2, width/2 + 150, height/2);
}

Resources