Update Mesh slow-down

Hi guy, i’m new on OF, since yesterday exactly. :smile:

I don"t understand how i can refresh my mesh with no lag. I create just 1000 lines and my fps become low. It’s my code?

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){

	mesh.setMode(OF_PRIMITIVE_LINES);

	image.load("test.jpg");

	myPanel.setup("COLOR");
	myPanel.add(drawMyMesh.setup("drawMyMesh", 20, 0, 255));
	myPanel.add(actionRadius.setup("Action Radius", 15, 0, 30));

}

//--------------------------------------------------------------
void ofApp::update(){

	mesh.clear();

	float intensityThreshold = drawMyMesh;
	int w = image.getWidth();
	int h = image.getHeight();
	for (int x = 0; x < w; ++x) {
		for (int y = 0; y < h; ++y) {
			ofColor c = image.getColor(x, y);
			float intensity = c.getLightness();
			if (intensity <= intensityThreshold) {
				float saturation = c.getSaturation();
				float z = ofMap(saturation, 0, 255, -100, 100);
				ofVec3f pos(x * 5, y * 5, z);
				mesh.addVertex(pos);
				mesh.addColor(c);
			}
		}
	}

	float connectionDistance = actionRadius;
	int numVerts = mesh.getNumVertices();
	for (int a = 0; a < numVerts; ++a) {
		ofVec3f verta = mesh.getVertex(a);
		for (int b = a + 1; b < numVerts; ++b) {
			ofVec3f vertb = mesh.getVertex(b);
			float distance = verta.distance(vertb);
			if (distance <= connectionDistance) {
				mesh.addIndex(a);
				mesh.addIndex(b);
			}
		}
	}
	
}

//--------------------------------------------------------------
void ofApp::draw(){
	ofColor centerColor = ofColor(255, 255, 255);
	ofColor edgeColor = ofColor(125, 125, 125);
	ofBackgroundGradient(centerColor, edgeColor, OF_GRADIENT_CIRCULAR);

	easyCam.begin();
		ofPushMatrix();
			ofTranslate(-ofGetWidth() / 2, -ofGetHeight() / 2);
			mesh.draw();
		ofPopMatrix();
	easyCam.end();

	myPanel.draw();
}

the way you are getting the color from the image in the first loop is relatively slow. a faster way to do it is:

        float intensityThreshold = drawMyMesh;
        for (auto line: image.getPixels().getLines()) {
            auto x = 0;
            for (auto pixel: line.getPixels()) {
                ofColor c = pixel.getColor();
                float intensity = c.getLightness();
                if (intensity <= intensityThreshold) {
                    float saturation = c.getSaturation();
                    float z = ofMap(saturation, 0, 255, -100, 100);
                    ofVec3f pos(x * 5, line.getLineNum() * 5, z);
                    mesh.addVertex(pos);
                    mesh.addColor(c);
                }
                ++x;
            }
        }

in the second loop you could optimize a bit by using the squaredDistance instead of the plain distance which avoids a square root which is really expensive in terms of cpu usage.

but the problem really is in the second loop, you are going through all the vertices for every vertex, depending on what the first loop does you can easily get thousands of millions of iterations which there’s no way to optimize. you could try going through one in 2 or 3 vertices or pixels instead of going through all of them.

also if you are just planing to work with static images you can regenerate the mesh only when the parameters change instead of in every update by adding a listener to the parameters:

drawMyMesh.addListener(this, &ofApp::parametersChanged);
actionRadius.addListener(this, &ofApp::parametersChanged);

then:

void ofApp::parametersChanged(float & v){
    // update the mesh here instead of in update
}
1 Like

OMG thank you arturo!

it’s working very nice now (not really for the ofxIntSlider, but never mind). Say me, if you have the time, if my code it’s correct for you.

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup() {

	mesh.setMode(OF_PRIMITIVE_LINES);

	image.load("test.jpg");
	image.resize(100, 100);

	myPanel.setup("COLOR");
	myPanel.add(drawMyMesh.setup("drawMyMesh", 20, 0, 255));
	myPanel.add(actionRadius.setup("Action Radius", 30, 0, 100));

}

//--------------------------------------------------------------
void ofApp::update() {
	drawMyMesh.addListener(this, &ofApp::parametersChanged);
	actionRadius.addListener(this, &ofApp::parametersChanged);
	

}

//--------------------------------------------------------------
void ofApp::draw() {
	ofColor centerColor = ofColor(255, 255, 255);
	ofColor edgeColor = ofColor(125, 125, 125);
	ofBackgroundGradient(centerColor, edgeColor, OF_GRADIENT_CIRCULAR);

	easyCam.begin();
		ofPushMatrix();
			ofTranslate(-ofGetWidth() / 2, -ofGetHeight() / 2);
			mesh.draw();
		ofPopMatrix();
	easyCam.end();

	myPanel.draw();
}

void ofApp::parametersChanged(int & drawMyMesh) {
	mesh.clear();

	float intensityThreshold = drawMyMesh;
	for (auto line : image.getPixels().getLines()) {
		auto x = 0;
		for (auto pixel : line.getPixels()) {
			ofColor c = pixel.getColor();
			float intensity = c.getLightness();
			if (intensity <= intensityThreshold) {
				float saturation = c.getSaturation();
				float z = ofMap(saturation, 0, 255, -100, 100);
				ofVec3f pos(x * 5, line.getLineNum() * 5, z);
				mesh.addVertex(pos);
				mesh.addColor(c);
			}
			++x;
		}
	}

	float connectionDistance = actionRadius;
	int numVerts = mesh.getNumVertices();
	for (int a = 0; a < numVerts; a += 4) {
		ofVec3f verta = mesh.getVertex(a);
		for (int b = a + 1; b < numVerts; b += 4) {
			ofVec3f vertb = mesh.getVertex(b);
			float distance = verta.distance(vertb);
			if (distance <= connectionDistance) {
				mesh.addIndex(a);
				mesh.addIndex(b);
			}
		}
	}
}

you don’t need to add the listeners in update every frame, only once in setup