//Drawing machine #14 0.1///Alejandro González///60rpm.tv///Dominio Púbico/////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//Esta es el primer prototipo de una herramienta de dibujo que intenta emular el trazo de un carboncillo.//
//Para conseguir ese efecto, he usado un enjambre de partículas que siguen al ratón,///////////////////////
//añadiendo un poco de ruido Perlin y un poco de azar, para darle organicidad al trazo.////////////////////
//Está pensada para ser usada con una tablet, por lo que reconoce la presión y por lo que se puede borrar//
//usando la goma del lápiz. ///////////////////////////////////////////////////////////////////////////////
//Otra interacción: //
// · 'e' para borrar la pantalla //
// · 'h' para ocultar la ventana de control //
// · 'u' para mostrar la ventana de control //
//Parámetros: //
// · 'N': número de partículas //
// · 'D': diámetro de distribución //
// · 'F': factor de influencia del ruido (a mayor valor, un trazo más rudo) //
// · 'P': para ajustar la presión de la tableta //
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//This is a charcoal drawing machine, using a swarm of particles that act//////////////////////////////////
//as pencils. In order to emulate human pulse, I´ve used perlin noise and some randomness//////////////////
//to give an organic feeling to the stroke. It´s intended to be used on tablets////////////////////////////
//Other interaction: //
// · 'e' to clean the screen //
// · 'h' to hide the control window //
// · 'u' to show the control window //
//Parameters: //
// · 'N': number of particles //
// · 'D': distribution diameter //
// · 'F': influence of noise in movement (a bigger value, a rougher stroke) //
// · 'P': to adjust tablet pressure //
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
boolean
drawing=false, //estamos dibujando?//are we drawing?
first=true; //necesitamos crear un nuevo enjambre?//do we need to launch a new swarm?
int
n=150, //número de partículas inicial//inital number of particles
kind, //ver abajo//see below
bg=1, //color del fondo//background color
sh=0; //tono principal del pincel//stroke main hue
float
d=25f, //máximo diámetro inicial del enjambre//initial value for maximum diameter
f=.005, //factor inicial para el Perlin que define el movimiento//initial value for the perlin noise that shifts the movement of the swarm
p=.3; //factor para ajustar la presión de la tableta//value to adjust the pressure value coming from the tablet
PencilSwarm swarm; //nuestro enjambre//this swarm composes our pen
void setup(){
size(900,450,P2D);
cursor(CROSS);
colorMode(RGB,1);
smooth();
background(bg);
noStroke();
cp5setup();
}
void draw(){
if(drawing){
//este método --getPenKind-- nos devuelve un int con el tipo de herramienta que estamos usando: 1--ratón · 2--lápiz · 3--goma//
//this method --getPenKind-- returns an int that represents the current drawing tool: 1--mouse · 2--pen · 3--eraser//
kind=tablet.getPenKind();
//este otro --getPressure-- devuelve el valor de presión en un flotante normalizado (0-1)//
//and this one --getPressure-- returns the pressure of the pen as a normalized float value (0-1)//
swarm.allDraw(mouseX,mouseY,tablet.getPressure());
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////General
import codeanticode.protablet.*;
Tablet tablet;
void mousePressed(){
swarm= new PencilSwarm(n,d,f,mouseX,mouseY);
noCursor();
}
void mouseDragged(){
drawing=true;
}
void mouseReleased(){
drawing=false;
cursor(CROSS);
}
void keyPressed(){
switch(key){
case('h'):
cP5.window("dm_14").hide();
break;
case('u'):
cP5.window("dm_14").show();
break;
case('e'):
background(bg);
break;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////GUI
import controlP5.*; ControlP5 cP5;
Slider[] s=new Slider[4];
ControlWindow cW;
void cp5setup(){
tablet= new Tablet(this);
cP5= new ControlP5(this);
//
cP5.setColorBackground(#dddddd); //color de fondo de los deslizadores
cP5.setColorForeground(#aaaaaa); //color frontal de los deslizadores
cP5.setColorActive(#555555); //color activo de los deslizadores
cP5.setColorLabel(#555555); //color de las etiquetas
//
int
sliderHeight=100,
sliderWidth=5,
offset=25;
//
cW=cP5.addControlWindow("dm_14",100,100,(s.length+2)*offset,sliderHeight+(2*offset));
cW.setBackground(#ffffff);
//
s[0] = cP5.addSlider("D",10,100,d, offset,offset,sliderWidth,sliderHeight); //D de Diámetro // D of Diameter
s[1] = cP5.addSlider("N",10,300,n,2*offset,offset,sliderWidth,sliderHeight); //N de Número // N of Number of particles
s[2] = cP5.addSlider("F",.001,.025,f,3*offset,offset,sliderWidth,sliderHeight); //F de Factor de ruido // F of noise Factor
s[3] = cP5.addSlider("P",.05,.6,p,4*offset,offset,sliderWidth,sliderHeight); //F de Factor de ruido // F of noise Factor
//
for (int i=0;i<s.length;i++) s[i].setWindow(cW);
}
//Métodos asociados a los deslizadores//Slider associated methods//
void D(float newD){
d= newD;
}
void N(float newNumber){
n= int(newNumber);
}
void F(float newFactor){
f= newFactor;
}
void P(float newPressureFactor){
p= newPressureFactor;
}
//Esquema de clases: una clase matriz PencilSwarm, con una matriz de objetos Pincel, internos a la anterior.//
//Class scheme: a mother class called PencilSwarm, with an array of Pencil objects, internal to the former////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
class PencilSwarm {
int sC; //color del trazo//stroke color
PVector or; //coordenadas del punto donde hemos creado el enjambre//coordinates of the point where we have created the swarm
Pencil[] pencils; //conjunto de los pinceles// the list of pencils
float
noiseFactor, //parameter F
maxD, //parameter D
c, //this parameter will be used on the noise formula
penPressure; //...
//Constructor//
PencilSwarm(int n,float maxD,float noiseFactor,float birthX,float birthY){
this.maxD=maxD;
this.noiseFactor=noiseFactor;
or=new PVector(birthX,birthY);
pencils=new Pencil[n];
for (int i=0;++i<pencils.length;){
pencils[i]=new Pencil();
}
}
void allDraw(int mX,int mY,float pressure){
sC=sh;
if(kind==1){penPressure=p*.2;} else{penPressure=pressure*p; if(kind==3) sC=bg;}
stroke(color(sC,penPressure));
for (int i=0;++i<pencils.length;){
pencils[i].update(mX,mY);
pencils[i].drip();
}
}
class Pencil {
PVector l,s;
Pencil(){
l=new PVector(or.x+(maxD*random(1)),or.y+(maxD*random(1)));
s=new PVector(0,0);
}
//Éste es el método encargado de crear el movimiento.
//Le pasamos al método las coordenadas del ratón, al que siguen las partículas
//Posteriormente le damos organicidad al movimiento salpimentando con un poco de azar y otro poco de ruido
void update(float targetX,float targetY){
//swarm follows mouse
PVector target=new PVector(targetX,targetY);
s=PVector.sub(target,l);
//add motion an organic feeling
s.mult(random(.3,.5));
s.x+=(noise(l.x*noiseFactor,l.y*noiseFactor,c)-.5) *maxD;
s.y+=(noise(l.x*noiseFactor,l.y*noiseFactor,c+=.5)-.5)*maxD;
//
l.add(s);
}
void drip(){
point(l.x,l.y);
}
}
}
A drawing tool intended to be used with a graphic tablet in order to get some kind of charcoal drawings (although it´s possible to use the mouse only).
Interaction:
· e: to clean the screen
· h: to hide the control window
· u: to unhide the control window
Parameters:
· n: number of particles
· d: distribution diameter
· f: noise factor (a bigger value a rougher stroke)
· p: to adjust tablet pressure
It´s better to use it offline because the pen works much better (i.e. offline you can create shadows with short gestures)