﻿ coding « Coding, Sounds and Colors | A blog about algorithmic experiments in music and visual art. Sort of.

## Ribbons

posted by on 2019.04.06, under openFrameworks
06:

Who doesn’t like ribbons? I know that I do, and that I always found them fascinating. There are tons of ways one can make ribbons which are dynamic, i.e. they interact with the user in some ways. For this simple code, I used openFrameworks, since I wanted to work with reacting meshes and 3D graphics. The idea is pretty simple: you basically add pair of vertices to the mesh by first having one of the vertex’s position follow the mouse position, and compute the position at the other end as the “head” of an orthogonal vector. Wait, what?! It sounds complicated, but it really isn’t. The interesting thing in the code is that there is a variable, namely N, which bounds the total number of vertices: otherwise, after a while you will find yourself with a HUGE mesh, the framerate will drop considerably, and you’ll think your life is miserable. So, let’s avoid that!
Here is the code

ofApp.h:

#pragma once

#include "ofMain.h"

class ofApp : public ofBaseApp{

public:
void setup();
void update();
void draw();
ofMesh mesh;
float t;
float theta;
ofVec2f pos;
ofLight light;
ofMaterial material;

void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void mouseEntered(int x, int y);
void mouseExited(int x, int y);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);

};

ofApp.cpp

#include "ofApp.h"

#define N  1000
//--------------------------------------------------------------
void ofApp::setup(){
ofBackground(ofColor::lightGray);
ofToggleFullscreen();
ofHideCursor();

mesh.setMode(OF_PRIMITIVE_TRIANGLE_STRIP);
pos = ofVec2f(ofRandom(-ofGetWidth() * 0.5, ofGetWidth() * 0.5), ofRandom(-ofGetHeight() * 0.5, ofGetHeight() * 0.5));

ofEnableDepthTest();
ofEnableLighting();

material.setDiffuseColor(ofColor::white);
material.setAmbientColor(ofColor::white);

material.setShininess(128);
}

//--------------------------------------------------------------
void ofApp::update(){
t += 10;
theta += ofRandom(0.0, 0.01);

ofVec2f target = ofVec2f(ofGetMouseX() - ofGetWidth() * 0.5, ofGetMouseY() - ofGetHeight() * 0.5);
ofVec2f  dir = target - pos;
float m = dir.length();
dir.normalize();
dir = dir.getScaled(20);
pos = pos + dir;
ofVec2f ort = ofVec2f(-pos.y, pos.x);
ort.normalize();
ort = ort.getScaled(20 + (m * (0.3 + 0.2 * sin(theta * 2 * PI))));

int n = mesh.getNumVertices();
if (n < N) {
float c = 1;
ofVec3f v0 = ofVec3f(pos.x, pos.y, t * c);
ofVec3f v1 = ofVec3f(pos.x + ort.x, pos.y + ort.y, t * c);
}
else {
mesh.removeVertex(0);
mesh.removeVertex(0);
}

}

//--------------------------------------------------------------
void ofApp::draw(){
ofBackground(ofColor::lightGray);
light.enable();
material.setDiffuseColor(ofColor(255 * sin(theta * 0.04 * 2 * PI), 102, 102));
material.setAmbientColor(ofColor(255 * sin(theta * 0.04 * 2 * PI), 12, 102));
ofPushMatrix();
ofTranslate(ofGetWidth() * 0.5, ofGetHeight() * 0.5, -t);
material.begin();
mesh.draw();
material.end();
ofPopMatrix();
light.disable();
}

It should look this.

Exercise: implements normals in the mesh above.