- Week 1: Intern's Greetings!
- Week 2: Refining the MVP
- Week 3: Diving Into Shaders
- Week 4: From 2D to 3D
- Week 5: Back to Inspiration Images
- Week 6: Blended Approach
- Week 7: Restructuring the Project
- Week 8: Drawing Board
This week, I spent time planning a function that could be used to position objects in the room. For example, I might want to place two cubes around a plant, but they should never overlap with the plant or each other. When trying to understand this problem, I found this video by Daniel Shiffman very useful. That combined with pseudocode that Nikolai provided was the key to create some functions.
The pseudocode:
for (let i = 0; i < max; i++) {
outer: for (;;) {
let point = make_random_point();
for (let j = 0; j < i; j++) {
if (dist(locations[j], point) < limit) {
continue outer;
}
}
locations.push(point);
break;
}
}
We wanted to create arrays for the possible locations of objects, either around a circle or semicircle. There is a central object with some orbiting objects:
const locationsCircle = [];
const locationsHalfCircle = [];
function neighbour_location_circle({ cx, cy, cz, min, max, startAngle = 0, endAngle = 2 * Math.PI }) {
// distance from the object in the center
const distance = min + (max - min) * Math.random();
const angle = startAngle + (endAngle - startAngle) * Math.random();
return [cx + distance * Math.cos(angle), cy, cz + distance * Math.sin(angle)];
}
// how close to each other the orbiting objects can be
let limit = 6;
// number of positions to create
let numOfLoc = 3;
function dist(x1, x2, y1, y2) {
var a = x1 - x2;
var b = y1 - y2;
return Math.sqrt(a * a + b * b);
}
Creating positions for orbiting objects by using limit
and checking that they don't overlap:
for (let i = 0; i < numOfLoc; i++) {
outer: for (;;) {
let point = neighbour_location_circle({
cx: xLoc,
cy: yLoc,
cz: 5,
min: 15,
max: 25
});
for (let j = 0; j < i; j++) {
if (dist(locationsCircle[j][0], point[0], locationsCircle[j][2], point[2]) < limit) {
continue outer;
}
}
locationsCircle.push(point);
break;
}
}
// now we add spheres that orbit the box (as a circle)
for (let i = 0; i < numOfLoc; i++) {
const ballGeometry = new THREE.SphereGeometry(5, 5, 5);
const material = new THREE.MeshPhongMaterial({
color: 0xffffff,
emissive: 0x444444
});
const ball = new THREE.Mesh(ballGeometry, material);
ball.position.x = locationsCircle[i][0];
ball.position.y = locationsCircle[i][1];
ball.position.z = locationsCircle[i][2];
scene.add(ball);
}
For placing the objects in a semicircle (so that they don't end up inside a wall), we modify the start and end angle in the neighbour_location_circle
function:
for (let i = 0; i < numOfLoc; i++) {
outer: for (;;) {
let point = neighbour_location_circle({
cx: 45,
cy: 5,
cz: 5,
min: 15,
max: 25,
startAngle: Math.PI / 2,
endAngle: (3 / 2) * Math.PI
});
for (let j = 0; j < i; j++) {
if (dist(locationsCircle[j][0], point[0], locationsCircle[j][2], point[2]) < limit) {
continue outer;
}
}
locationsHalfCircle.push(point);
break;
}
}
Adding New Data Points
It was also time to make the room visuals a bit more advanced. One of the elements of the room is a big blob that floats in the middle – a bit like a brain inside a head. Luckily, when working on my own art project on my free time, I had bumped into this resource about deformations with Perlin noise.
This animated blob is based on a vertex shader and fragment shader, added with a texture image. It's a good example on how to use normals and materials in deformations. An interesting thing with textures is that they can add a whole other dimension to the visual: you can use any image as a texture, and the shape will then reflect that image, hinting at a space or object that exists outside the viewport.
Finally, I spent time on the Python side of the app, adding a bunch of new variables that are based on the NLP calculations. The values that client side receives are now:
avgTone
avgSubj
numOfMe
(number of "I" and "me" words)avgSentenceLength
numOfUnique
(number of unique words)interactionAmount
(number of @ tags)numOfNeg
(number of negative tweets)numOfPos
numOfNeutr
numOfAll
I always enjoy exploring how easily Python can handle data. For example, I was prepared for requiring multiple lines of code to extract all the @ tags from an account. Finally it was just:
interactions = re.findall(r'@[\w\.-]+',str(whole_text_sample))
numOfInteractions = len(interactions)