Mesh append in a thread

I have some large meshes I want to save as a single mesh, they are in a vector. If I iterate through the vector and draw them then I have quite a good framerate, however if I iterate through them and append a new mesh with the meshes from the vector and then draw the new mesh the operation seems very heavy and my frame rate drops significantly.

When I look at the append function it seems just to do a copy, unless there is indices and these are iterated through as they are added.

Is there a more efficient way to append a mesh? I have tried to make a threaded class to append the meshes but performance seems worse - I am assuming this is quite a misunderstanding on my part of how to optimise this operation.

I have a vector of shared pointers of generator objects that make the meshes:

std::vector<std::shared_ptr<meshGenerator>> generators;

and the generators have this function to retrieve the mesh:

const ofVboMesh& getMesh() const;

my attempt at a class to thread the append operation is here (just adapted from the thread channel example):

The .h file

#pragma once
#include "ofMain.h"

class meshJoiningThread: public ofThread {
public:
	meshJoiningThread();
	~meshJoiningThread();
	void combineMeshes(std::vector<ofVboMesh> & meshvector);
	void update();
	ofVboMesh & getCombinedMesh();
	void draw();

private:
	void threadedFunction();
	ofThreadChannel<std::vector<ofVboMesh>> toCombine;
	ofThreadChannel<ofVboMesh> combined;
	ofVboMesh finalMesh;
};

And the cpp file:

#include "meshJoiningThread.h"
#include "ofConstants.h"

meshJoiningThread::meshJoiningThread(){

	startThread();
}

meshJoiningThread::~meshJoiningThread(){
	toCombine.close();
	combined.close();
	waitForThread(true);
}

void meshJoiningThread::combineMeshes(std::vector<ofVboMesh>  & meshvector){

	toCombine.send(meshvector);
}

void meshJoiningThread::update(){

	while(combined.tryReceive(finalMesh)){
		
	}
	
}


ofVboMesh & meshJoiningThread::getCombinedMesh(){
	return finalMesh;
}


void meshJoiningThread::draw(){
    finalMesh.draw();
    cout << ofToString(finalMesh.getVertices().size()) <<endl;
}


void meshJoiningThread::threadedFunction(){
    std::vector<ofVboMesh>  inMeshVec;
    
    while(toCombine.receive(inMeshVec)){
        ofVboMesh tCombinMesh;
        for (int i = 0; i < inMeshVec.size(); i++) {
            tCombinMesh.append(inMeshVec[i]);
        }

#if __cplusplus>=201103
        combined.send(std::move(tCombinMesh));
#else
        combined.send(tCombinMesh);
#endif
	}
}

Is my assumption that I can speed up my app by putting the append function in a thread misguided? Does my threaded class make sense? Is there any other way to optimise this operation?

Cheers

1 Like

I haven’t tested your code but I assume ofMesh::append() causes memory allocation in every call. ofMesh::append() uses vector::insert(). So if you don’t allocate enough memory, vector will try to expand its capacity (and copy).
How about create ofVboMesh and allocate possible max amount of vertices you could use and re use it in each call?

Ok, that is a good idea, should I do this in the constructor of the class like this:

meshJoiningThread::meshJoiningThread(){

	startThread();
    std::vector<glm::vec3> points;
    points.reserve(1000);
    std::vector<ofFloatColor> colours;
    points.reserve(1000);
    std::vector<ofIndexType> indices;
    indices.reserve(3000);
    finalMesh.addVertices(points);
    finalMesh.addColors(colours);
    finalMesh.addIndices(indices);
}

And then as my mesh is updated in each frame I would need to remove the old vertices, colours and indices. If I call finalMesh.clear() then is the memory I reserved is cleared and no longer allocated?

Exactly, ofVboMesh::clear() will discard allocated memory.
So I would suggest 2 solutions.

  1. Set ofFloatColor(0,0,0,0) for unused vertices.
    If the data itself is not so important, this way you can make unused vertices transparent and hide it.

  2. Use ofVbo::draw() function
    *Please notice this not ofVboMesh but ofVbo.
    ofVbo provides partial draw feature. here is the declaration of ofVbo::draw()
    To use this from ofVboMesh, you can write like tCombinMesh.getVbo().draw(...)

Usually, I use solution 1. Somehow solution 2 did not work last time. (But it should, I think).

As I update the mesh every frame I cannot just keep appending vertices and indices I don’t need, the mesh will become too large too fast and slower than i already have.

I am not sure how suggestion2 will help, can you explain a little more?

solution 1
I meant stop calling append() and use setVertex() function. This way you can overwrite old vertices.

solution 2
With ofVbo::draw, you can select which vertices to draw by setting first index and total number of vertices. So let’s say you have 1000 vertices but only want to draw vertices 0~99, you can write draw(OF_MESH_WIREFRAME, 0, 100); But this also needs setVertex() instead of calling append(). Of course please avoid addVertex() as well.

1 Like