129
edits
(15 intermediate revisions by 2 users not shown) | |||
Line 13: | Line 13: | ||
== '''Design''' | Interaction with Screen == | == '''Design''' | Interaction with Screen == | ||
The user will see a representative image of him on the screen, many fine lines around on it. The thin lines are a kind of metaphor of the complex relationships in the society. <br> | The user will see a representative image of him on the screen, many fine lines around on it. The thin lines are a kind of metaphor of the complex relationships in the society. <br> | ||
[[File:Diagram_2.jpg|thumb|left|300px|Original Diagram]] | [[File:Diagram_2.jpg|thumb|left|300px|Original Diagram]] | ||
Line 30: | Line 28: | ||
[[File:Mess.jpg|thumb|left|300px|Mess with all the relationships]] | [[File:Mess.jpg|thumb|left|300px|Mess with all the relationships]] | ||
<br style="clear:both;"> | <br style="clear:both;"> | ||
== '''Design''' | Interaction with Objects == | == '''Design''' | Interaction with Objects == | ||
Line 62: | Line 58: | ||
== '''Installation''' == | == '''Installation''' == | ||
'''Interaction with Screen''' | |||
At the beginning of the installation, we decided to replace those colorful fine lines with a 3D Chinese knot, which is designed with one line and very expressive in shape. On the other hand, a complex knot could also become a metaphor to describe a human being with complex relationships in his/her life. | At the beginning of the installation, we decided to replace those colorful fine lines with a 3D Chinese knot, which is designed with one line and very expressive in shape. On the other hand, a complex knot could also become a metaphor to describe a human being with complex relationships in his/her life. | ||
Line 75: | Line 73: | ||
<br style="clear:both;"> | <br style="clear:both;"> | ||
== | The user is captured by the tracking system in real-time, and the related data of his/her movement will be sent to the Processing which control the play of the animation we made. | ||
[[File:ChineseKnotDemo.jpg|thumb|left|500px|Chinese knot demo]] | |||
<br style="clear:both;"> | |||
Here is the code running in Processing: | |||
Main Tab: | |||
<source lang="Java" line start= "1"> | |||
import netP5.*; | |||
import oscP5.*; | |||
import processing.video.*; | |||
OscP5 osc; | |||
NetAddress remote; | |||
Movie myMovie; | |||
int localport = 12000; | |||
int remoteport = 1065; | |||
boolean debug = true; | |||
Sphere sphere1; | |||
String skeleton1 = "LiQianqian"; | |||
String bone1 = "Root"; | |||
String bone2 = "LeftHand"; | |||
String bone3 = "RightHand"; | |||
int depth; | |||
void setup() { | |||
frameRate(60); | |||
background(0); | |||
myMovie = new Movie(this, "Chinese Knot_Final.mov"); | |||
fullScreen(P3D); | |||
sphere1 = new Sphere(1); | |||
depth = width; | |||
osc = new OscP5(this, localport); | |||
remote = new NetAddress("kosmos.medien.uni-weimar.de", remoteport); | |||
setPort(localport); | |||
plugBone(sphere1, skeleton1, bone1); | |||
plugBone(sphere1, skeleton1, bone2); | |||
plugBone(sphere1, skeleton1, bone3); | |||
refreshSubscriptions(); | |||
} | |||
void refreshSubscriptions() { | |||
subscribeBone(skeleton1, bone1); | |||
subscribeBone(skeleton1, bone2); | |||
subscribeBone(skeleton1, bone3); | |||
} | |||
void movieEvent(Movie m) { | |||
m.read(); | |||
} | |||
void draw() { | |||
sphere1.draw(); | |||
if (frameCount % 10 == 0) { | |||
refreshSubscriptions(); | |||
} | |||
} | |||
void oscEvent(OscMessage msg) { | |||
if(debug) { | |||
print("### received an osc message."); | |||
print(" addrpattern: "+msg.addrPattern()); | |||
println(" typetag: "+msg.typetag()); | |||
} | |||
} | |||
void plugBone(Object target, String skeleton, String bone) { | |||
String path = "/" + skeleton + "/blender/" + bone + "/vector"; | |||
osc.plug(target, "update" + bone, path); | |||
} | |||
void setPort(int port) { | |||
OscMessage msg = new OscMessage("/configure/port"); | |||
msg.add(port); | |||
osc.send(msg, remote); | |||
} | |||
void subscribeBone(String skeletonId, String bone) { | |||
OscMessage msg = new OscMessage("/subscribe/" + skeletonId + "/blender/" + bone + "/vector"); | |||
msg.add(50.0); | |||
msg.add(0.0); | |||
msg.add(100.0); | |||
osc.send(msg, remote); | |||
} | |||
</source> | |||
Sphere Tab: | |||
<source lang="Java" line start= "10"> | |||
class Sphere { | |||
float x, y, z; | |||
float x1, y1, z1; | |||
float x2, y2, z2; | |||
float x3, y3, x4, y4; | |||
float a, b, cc; | |||
float a1, b1, cc1; | |||
float a2, b2, cc2; | |||
float a3, b3, a4, b4; | |||
float d, e, f; | |||
float d1, e1, f1; | |||
float d2, e2, f2; | |||
float d3, e3, d4, e4; | |||
float speedChange, speedChange1, VideoSpeed; | |||
int play; | |||
color c; | |||
int getLength() { | |||
return int(myMovie.duration() * myMovie.frameRate); | |||
} | |||
int getFrame() { | |||
return ceil(myMovie.time() * 60) - 1; | |||
} | |||
int newFrame = 0; | |||
Sphere( color c) { | |||
this.c = c; | |||
} | |||
void draw() { | |||
image(myMovie, 0, 0, width, height); | |||
if(speedChange > 0.3 && getFrame() < 599){ | |||
play = 1; | |||
myMovie.play(); | |||
} | |||
else { | |||
play = -1; | |||
myMovie.play(); | |||
} | |||
if(getFrame() < 0) myMovie.play(); | |||
float newSpeed = map(speedChange1, 0, 150, 0*play, 2*play); | |||
myMovie.speed(newSpeed); | |||
fill(255); | |||
x4 = abs(x2 - x3); | |||
y4 = abs(y2 - y3); | |||
speedChange = abs(x4 - y4); | |||
println(speedChange); | |||
text("Root Speed: " + nfc(speedChange, 2) + "X", 10, 30); | |||
x3 = x2; | |||
y3 = y2; | |||
speedChange1 = dist(a, b, cc, d, e, f); | |||
text("Hand Distance: " + nfc(speedChange1, 2), 10, 50); | |||
VideoSpeed = speedChange1*play; | |||
text("VideoSpeed: " + nfc(VideoSpeed, 2) + "X", 10, 70); | |||
text(getFrame() + " / " + (getLength() - 1), 10, 90); | |||
} | |||
public void updateRoot(float x, float y, float z) { | |||
this.x = map(x, 0, 100, -width/2, width/2); | |||
this.y = map(y, -100, 100, -height/2, height/2); | |||
this.z = map(z, 0, 100, 0, depth); | |||
x2 = abs(x - x1); | |||
y2 = abs(y - y1); | |||
z2 = abs(z - z1); | |||
x1 = this.x; | |||
y1 = this.y; | |||
z1 = this.z; | |||
} | |||
public void updateLeftHand(float a, float b, float cc) { | |||
this.a = map(a, 0, 100, -width/2, width/2); | |||
this.b = map(b, -100, 100, -height/2, height/2); | |||
this.cc = map(cc, 0, 100, 0, depth); | |||
a2 = abs(a - a1); | |||
b2 = abs(b - b1); | |||
cc2 = abs(cc - cc1); | |||
a1 = this.a; | |||
b1 = this.b; | |||
cc1 = this.cc; | |||
} | |||
public void updateRightHand(float d, float e, float f) { | |||
this.d = map(d, 0, 100, -width/2, width/2); | |||
this.e = map(e, -100, 100, -height/2, height/2); | |||
this.f = map(f, 0, 100, 0, depth); | |||
d2 = abs(d - d1); | |||
e2 = abs(e - e1); | |||
f2 = abs(f - f1); | |||
d1 = this.d; | |||
e1 = this.e; | |||
f1 = this.f; | |||
} | |||
} | |||
</source> | |||
'''Interaction with Objects''' | |||
We finally decided to use the photocell sensor and vibration motor to build a plumb line. Each line is wrapped with red wools and tied as a handle. The sensor and motor are connected to the Arduino Uno which is running on a laptop. | |||
Here is the code running in Arduino: | |||
<source lang="Java" line start= "1"> | |||
int photocellPin = 0; // the cell and 10K pulldown are connected to A0 | |||
int photocellPin1 = 1; // the cell and 10K pulldown are connected to A1 | |||
int photocellReading, photocellReading1; // the analog reading from the sensor divider | |||
void setup() { // We'll send debugging information via the Serial monitor | |||
Serial.begin(9600); | |||
pinMode(3, OUTPUT); | |||
pinMode(5, OUTPUT); | |||
} | |||
void loop(void) { | |||
photocellReading = analogRead(photocellPin); | |||
photocellReading1 = analogRead(photocellPin1); | |||
if(photocellReading < 400 && photocellReading1 < 400 ){ | |||
digitalWrite(3, HIGH); | |||
digitalWrite(5, HIGH); | |||
delay(100); | |||
} | |||
else { | |||
digitalWrite(3, LOW); | |||
digitalWrite(5, LOW); | |||
delay(100); | |||
} | |||
Serial.print("Analog reading1 = "); | |||
Serial.println(photocellReading); // the raw analog reading1 | |||
Serial.print("Analog reading2 = "); | |||
Serial.println(photocellReading1); // the raw analog reading2 | |||
Serial.println(" "); | |||
delay(10); | |||
} | |||
</source> | |||
== '''Demonstration''' == | |||
{{#ev:youtube|https://www.youtube.com/watch?v=Ns1VKddXT_w|1000|left|Wool's World|frame}} | |||
<br style="clear:both;"> | |||
== '''Summary''' == | |||
On the 16th of July, Wool's World exhibited in Digital Lab. We played the PPT about the introduction of Wool's World on the video wall when we arranged the exhibition. The red object handles and all the plumb lines with different length hung from the top. The mystic box covered by black wool felt with knitted woolen lines set in the center of the platform. It's glad that all the participants had a good experience when they tried the object handles, especially felt the vibration of the handles. For sure, if we can do more interactive handles, it will be more interested for lots of people. <br> | |||
It was a pity that the Captury didn't work well that day because of the update. We could only show the screen interaction part with play back video of the Captury and the live capture video shot before to explain to every participant. If it work, the interactivity will definitely be more meaningful and interesting. | |||
[[File:Summary01.jpg|thumb|left|1000px|Wool's World]] | |||
[[File:Summary02.jpg|thumb|left|450px|Plumb Line]] | |||
[[File:Summary03.jpg|thumb|right|450px|Mystic Box]] | |||
[[File:Summary04.jpg|thumb|left|450px|Summary]] | |||
[[File:Summary05.jpg|thumb|right|450px|Summary]] | |||
<br style="clear:both;"> | |||
== '''Conclusion''' == | == '''Conclusion''' == |
edits