520x780 是俺07年刚进大学时的一个互动装置作品,基于Flash as2.0,当时的头像拼贴是预先做好,而后根据鼠标事件相应,出现对应的大头像。整个过程完全在FP 的二维舞台中完成。贴一些当时的效果图。
这个作品是从07年11月21日开始创作,而后在08年年初,俺在Visual Complexity 上看到了Firstborn 和Microsoft 合作的互动作品Operation Smile,发现主题和呈现效果的撞车。同时也被Operation Smile 的演示效果完完全全惊艳到,这也是俺第一次了解到Processing 的存在。
而后言归正传,昨天下午,由于大学童鞋询问我关于当时520x780 的制作方法,俺头脑一热,就用Processing 把这个作品重置了,当然这还只是个Demo,直接拿来当时拍摄的头几张素材照片就用上了。出来的视觉效果和Operation Smile 还真是略有相似,这也是让人挺尴尬的一件事。Anyway,开放一下Demo 的源码。运行效果大家可以上OpenP5 社区观看。
//Raven Kwok | 郭锐文
//the-moor.blogbus.com
//weibo.com/ravenkwok
//vimeo.com/ravenkwok
float xmouse,ymouse;
float xoffset,yoffset;
float rxoffset,ryoffset;
Grid grid;
void setup(){
size(800,600,P3D);
frameRate(30);
background(0);
imageMode(CENTER);
xoffset = width/2;
yoffset = height/2;
grid = new Grid(50,50);
}
void draw(){
xmouse = mouseX - xoffset;
ymouse = mouseY - yoffset;
rxoffset = lerp(rxoffset,xmouse/30,0.1);
ryoffset = lerp(ryoffset,ymouse/30,0.1);
background(0);
translate(xoffset,yoffset,-2000);
rotateY(radians(rxoffset));
rotateX(radians(ryoffset));
grid.update();
grid.display();
}
void keyPressed(){
if(keyCode == RIGHT){
grid.targetPortraitIndex = (grid.targetPortraitIndex+1)%grid.portraitsAmount;
}
}
class Grid {
Cell [][] cells;
int rows, cols;
float cellsize;
PImage [] portraits;
int portraitsAmount;
int targetPortraitIndex;
Grid(int rows, int cols) {
this.rows = rows;
this.cols = cols;
cells = new Cell[this.rows][this.cols];
portraitsAmount = 12;
portraits = new PImage[portraitsAmount];
for (int i=0;i<portraitsAmount;i++) {
portraits[i] = loadImage(i+".jpg");
}
cellsize = portraits[0].width;
for (int i=0;i<rows;i++) {
for (int j=0;j<cols;j++) {
int randomPortrait = floor(random(8));
float xoffset = -cols/2*cellsize+j*cellsize;
float yoffset = -rows/2*cellsize+i*cellsize;
cells[i][j] = new Cell(portraits[randomPortrait],xoffset,yoffset);
}
}
targetPortraitIndex = 0;
}
void display(){
for (int i=0;i<rows;i++) {
for (int j=0;j<cols;j++) {
cells[i][j].display();
}
}
}
void update(){
for (int i=0;i<rows;i++) {
for (int j=0;j<cols;j++) {
float zoffset = brightness(portraits[targetPortraitIndex].pixels[j+i*portraits[targetPortraitIndex].width])*2;
cells[i][j].update(zoffset,portraits[targetPortraitIndex].pixels[j+i*portraits[targetPortraitIndex].width]);
}
}
}
}
class Cell{
PImage bitmap;
float xoffset,yoffset;
float zoffset,zoffsetTarget;
float r,g,b;
Cell(PImage bitmap, float xoffset, float yoffset){
this.bitmap = bitmap;
this.xoffset = xoffset;
this.yoffset = yoffset;
zoffset = 0;
}
void display(){
pushMatrix();
translate(xoffset,yoffset,zoffset);
tint(r,g,b);
image(bitmap,0,0);
popMatrix();
}
void update(float zoffsetTarget,color cellColor){
this.zoffsetTarget = zoffsetTarget;
zoffset = lerp(zoffset,zoffsetTarget,0.1);
r = lerp(r,red(cellColor),0.1);
g = lerp(g,green(cellColor),0.1);
b = lerp(b,blue(cellColor),0.1);
}
}