[work 63] Ribbon – gradation –

[work 63] Ribbon – gradation –

Movie

Source code

about

  • 線分の軌跡を描く
  • 線分は以下のように描く
    • 複数のアームを接続する
    • それぞれのアームは、接続部を中心に回転させる
    • 先端のアーム部分が使用する線分となる
  • アームの不透明度をだんだん下げる

file

  • 上部にあるファイル名が表示されているボタンを押すと、表示されるファイルが切り替わります
  • 別ウィンドウ表示したい時や行番号などが無いRawMode表示したい時は、コード内右上のボタンを押してください(ボタンはマウスオーバーすると表示されます)
#include "ofMain.h"
#include "ofApp.h"

//================================
int main( ){

    // 4K:4096x2160
    // 2K:2048x1080
    // FullHD:1920x1080
    // HD:1440x1080
    // HD720p:1280x720
    // DVD:720x480
    // setup the GL context
    ofSetupOpenGL(1280, 720, OF_WINDOW);

	// this kicks off the running of my app
	// can be OF_WINDOW or OF_FULLSCREEN
	// pass in width and height too:
	ofRunApp( new ofApp());

}
#pragma once

#include "ofMain.h"

#include "Ribbon.hpp"


class ofApp : public ofBaseApp{
public:
    ofApp();
    ~ofApp();
    
    void setup();
    void update();
    void draw();
    
    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);
    
private:
    std::vector<std::shared_ptr<Ribbon>> ribbons;
};
#include "ofApp.h"


ofApp::ofApp(){
    
}

ofApp::~ofApp(){
    
}

//--------------------------------------------------------------
void ofApp::setup(){
    double fps = 30;
    
    
    ofSetFrameRate(fps);
    ofBackground(255);
    ofSetBackgroundAuto(true);
    ofSetVerticalSync(true);
    
    ofRectangle drawArea = ofRectangle(290, 10, 700, 700);
    int maxRow = 3;
    int maxCol = 3;
    
    for (int i = 0; i < maxCol; i++) {
        float w = (drawArea.getWidth() / maxCol);
        float x = drawArea.getLeft() + (w * i) + (w / 2);
        for (int j = 0; j < maxRow; j++) {
            float h = (drawArea.getHeight() / maxRow);
            float y = drawArea.getTop() + (h * j) + (h / 2);
            
            ribbons.push_back(make_shared<Ribbon>(ofVec2f(x, y)));
        }
    }
    
    for (shared_ptr<Ribbon> r : ribbons) {
        r->setup();
    }
}

//--------------------------------------------------------------
void ofApp::update(){
    for (shared_ptr<Ribbon> r : ribbons) {
        r->update();
    }
}

//--------------------------------------------------------------
void ofApp::draw(){
    for (shared_ptr<Ribbon> r : ribbons) {
        r->display();
    }
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
    if (key == 's') {
        ofImage img;
        img.grabScreen(0, 0, ofGetWidth(), ofGetHeight());
        img.save("screenshot.png");
    } else if (key == 'r') {
        for (shared_ptr<Ribbon> r : ribbons) {
            r->reset();
        }
    }
}
#ifndef Ribbon_hpp
#define Ribbon_hpp

#include <stdio.h>
#include "ofMain.h"

#include "Trochoid.hpp"

class Ribbon {
public:
    Ribbon(ofVec2f c);
    ~Ribbon();
    void setup();
    void update();
    void display();
    void reset();
    
private:
    std::shared_ptr<Trochoid> trochoid;
    std::vector<ofVec2f> locations;
    ofColor color;
    ofVec2f center;
    
    std::shared_ptr<ofFbo> fbo;
};
#endif /* Ribbon_hpp */
#include "Ribbon.hpp"


Ribbon::Ribbon(ofVec2f c)
{
    center = c;
}


Ribbon::~Ribbon()
{
    
}


void Ribbon::setup()
{
    trochoid = make_shared<Trochoid>(center, 2, false);
    trochoid->setup();
    
    fbo = make_shared<ofFbo>();
    fbo->allocate(ofGetWidth(), ofGetHeight(), GL_RGBA, 4);
    fbo->begin();
    ofClear(0);
    fbo->end();
    
    color = ofColor(ofRandom(255), ofRandom(255), ofRandom(255), 255);
}


void Ribbon::update()
{
    locations.clear();
    trochoid->update();
    trochoid->getLocations(locations);
    
    auto itr = locations.rbegin();
    ofVec2f end = *itr;
    ofVec2f start = *(itr + 1);
    
    ofEnableBlendMode(OF_BLENDMODE_ALPHA);
    fbo->begin();
    ofNoFill();
    ofSetLineWidth(1);
    ofSetColor(color);
    ofDrawLine(start, end);
    fbo->end();
    
    if (ofGetFrameNum() % 5 == 0) {
        color.a *= 0.999;
    }
}


void Ribbon::display()
{
    fbo->draw(0, 0);
}


void Ribbon::reset()
{
    fbo = nullptr;
    trochoid = nullptr;
    
    setup();
}

#ifndef Trochoid_hpp
#define Trochoid_hpp

#include <stdio.h>
#include "ofMain.h"


class Trochoid {
public:
    Trochoid(ofVec2f org, int dim, bool dec);
    ~Trochoid();
    void setup();
    void update();
    void display();
    void getLocations(std::vector<ofVec2f> &loc);
    ofVec2f getPoint();
private:
    Trochoid();
    
    ofVec2f origin;
    ofVec2f point;
    ofMesh locus;
    std::vector<float> angle;       // radian
    std::vector<float> angleVelocity;
    std::vector<int> direction;
    std::vector<float> decay;
    std::vector<float> amplitude;
    std::vector<ofVec2f> location;
    bool isDecay;
    int dimension;
};
#endif /* Trochoid_hpp */
#include "Trochoid.hpp"



Trochoid::Trochoid(ofVec2f org, int dim, bool dec)
{
    origin = org;
    dimension = (int)ofClamp(dim, 1, 10);
    isDecay = dec;
}


Trochoid::~Trochoid()
{
    
}


void Trochoid::setup()
{
    int k = 0;
    std::cout << "Create Trochoid" << std::endl;
    for (int i = 0; i < dimension; i++) {
        k = (int)ofRandom(4);
        angle.push_back(PI / 2 * k);
        std::cout << "[angle]" << angle[i] << std::endl;
        k = (int)ofRandom(1, 16);
        angleVelocity.push_back((PI / (180 * 10)) * k);
        std::cout << "[angleV]" << angleVelocity[i] << std::endl;
        k = ((ofRandom(-1,1) < 0) ? -1 : 1);
        direction.push_back(k);
        std::cout << "[direction]" << direction[i] << std::endl;
        if (isDecay) {
            decay.push_back(ofRandom(0.998, 1));
        } else {
            decay.push_back(1);
        }
        std::cout << "[decay]" << decay[i] << std::endl;
        amplitude.push_back(ofRandom(20,50));
        std::cout << "[amplitude]" << amplitude[i] << std::endl;
    }
    
    location.push_back(origin);
    for (int i = 1; i < dimension + 1; i++) {
        location.push_back(ofVec2f(0,0));
    }
}


void Trochoid::update()
{
    for (int i = 0; i < location.size() - 1; i++) {
        location.at(i + 1).x = location.at(i).x + std::cos(angle.at(i)) * amplitude.at(i);
        location.at(i + 1).y = location.at(i).y + std::sin(angle.at(i)) * amplitude.at(i);
        
        angle.at(i) += angleVelocity.at(i) * direction.at(i);
        if (amplitude.at(i) > 1) {
            amplitude.at(i) *= decay.at(i);
        }
    }
    
    point = location.back();
}


void Trochoid::display()
{
    for (int i = 0; i < location.size() - 1; i++) {
        ofNoFill();
        ofSetLineWidth(1);
        ofDrawLine(location.at(i), location.at(i + 1));
    }
    
    for (int i = 0; i < location.size(); i++) {
        ofFill();
        ofDrawCircle(location.at(i), 5);
    }
    
    locus.addVertex(ofVec3f(point.x, point.y, 0));
    locus.addColor(ofColor(255));
    locus.drawVertices();
}


void Trochoid::getLocations(std::vector<ofVec2f> &loc)
{
    loc = location;
}


ofVec2f Trochoid::getPoint()
{
    return point;
}

Link to the reference page

ソースコードで使用したAPIの中から要点になりそうなものをいくつか選んでリストアップしました。

categoryAPI/Lib
openframeworksofFbo
openframeworksofColor
c++std::vector

Development environment

  • openframeworks 0.10.1
  • c++
  • macOS
  • Xcode