How to properly create a Mesh to update its coordinates

I have a very basic question about mesh implementation, I don’t really understand it yet.
I want to replicate a Processing code that’s very simple, but I don’t find the correct method to translate it to OF.
Processing code:

float noise_offset=0;
int   xyScale=8;
int   zScale=200;
float currScale=0.1f;
int   numSegments=80;
float xoff = 0;
float yoff = 0;

void setup() {
  size(1280, 720, P3D);
  noiseDetail(2);
  noStroke();
}

void draw() {
  //background(0);
  fill(0, 50);
  rect(0, 0, width, height);
  noise_offset+=0.1;

  //int idx=0;
  // scale the noise function based on mouseX when mouse is pressed
  if (mousePressed) {
    currScale+=(((width/2)-mouseX)*0.001-currScale)*0.01;
  } else {
    // get the movement direction from mouse coordinates
    float angle=atan2((height/2)-mouseY, (width/2)-mouseX);
    float xySpeed=sqrt(sq((width/2)-mouseX)+sq((height/2)-mouseY))*currScale*0.005;
    xoff+=xySpeed*cos(angle);
    yoff+=xySpeed*sin(angle);
  }

  float currZ;
  //setup perspective
  translate(0, height/3.0, 0);
  rotateX(PI/4); //camera angle
  // build the 3d mesh
  for (int y=0; y<numSegments; y++) {
    beginShape(TRIANGLE_STRIP);
    for (int x=0; x<numSegments*2; x++) {
      currZ=noise(xoff+x*currScale, yoff+y*currScale, currScale);
      fill(currZ*500+100-y*8, max(255-y*8, 0), 255-currZ*500, y*10);
      vertex(x*xyScale, y*xyScale, currZ*zScale);
      vertex(x*xyScale, (y+1)*xyScale, noise(xoff+x*currScale, yoff+(y+1)*currScale, currScale)*zScale);
      vertex((x+1)*xyScale, (y+1)*xyScale, noise(xoff+(x+1)*currScale, yoff+(y+1)*currScale, currScale)*zScale);
      vertex(x*xyScale, y*xyScale, currZ*zScale);
    }
    endShape();
  }
}

Then in OF, I have declared this:

class ofApp : public ofBaseApp{
    
public:
    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);
    
    ofVboMesh mainMesh;
    
    float   noise_offset=0;
    int     xyScale=8;
    int     zScale=200;
    int     width;
    int     height;
    float   currScale=0.1f;
    int     numSegments=80;
    float   xoff = 0;
    float   yoff = 0;
};

started with a setup:

//--------------------------------------------------------------
void ofApp::setup(){
    width = ofGetWidth();
    height = ofGetHeight();
    ofEnableDepthTest();
    ofEnableSmoothing();
    // ofEnableAlphaBlending();
    /*for (int y=0; y<numSegments; y++) {
        for (int x=0; x<numSegments*2; x++) {
            mainMesh.addVertex(glm::vec3(x,y,0));
            mainMesh.addColor(ofFloatColor(0,0,0));
        }
    }
    
    
    for (int y = 0; y<numSegments-1; y++){
        for (int x=0; x<numSegments*2-1; x++){
            mainMesh.addIndex(x+y*numSegments*2);                // 0
            mainMesh.addIndex((x+1)+y*numSegments*2);            // 1
            mainMesh.addIndex(x+(y+1)*numSegments*2);            // 10
            mainMesh.addIndex(x+y*numSegments*2);                // 0
            
        }
    }*/
    
}

The update:

void ofApp::update(){
    noise_offset+=0.1;
    if (ofGetMousePressed()) {
        currScale+=(((width/2)-mouseX)*0.001-currScale)*0.01;
    } else {
        // get the movement direction from mouse coordinates
        float angle=atan2((height/2)-mouseY, (width/2)-mouseX);
        float xySpeed=sqrt( ((width/2)-mouseX)*((width/2)-mouseX)+ ((height/2)-mouseY) * ((height/2)-mouseY)) * currScale*0.005;
        xoff+=xySpeed*cos(angle);
        yoff+=xySpeed*sin(angle);
    }
    
}

And the draw:

void ofApp::draw(){
    ofBackground(0);
    float currZ;
    //setup perspective
    ofTranslate(0, height/3.0, 0);
    
    ofRotateDeg( PI/4, 0, 0, 1 );
    // build the 3d mesh
    int c = 0;
    int mod = 0;
    for (int y=0; y<numSegments; y++) {
        mainMesh.setMode(OF_PRIMITIVE_TRIANGLE_STRIP);
        for (int x=0; x<numSegments*2; x++) {
            currZ=ofNoise(xoff+x*currScale, yoff+y*currScale, currScale);
            ofColor sampleColor = ofColor(currZ*500+100-y*8, max(255-y*8, 0), 255-currZ*500, y*10);
            glm::vec3 top(x*xyScale, y*xyScale, currZ*zScale);
            glm::vec3 left(x*xyScale, (y+1)*xyScale, ofNoise(xoff+x*currScale, yoff+(y+1)*currScale, currScale)*zScale);
            glm::vec3 right((x+1)*xyScale, (y+1)*xyScale, ofNoise(xoff+(x+1)*currScale, yoff+(y+1)*currScale, currScale)*zScale);
            glm::vec3 top2(x*xyScale, y*xyScale, currZ*zScale);
            
            mainMesh.addVertex(top);
            mainMesh.addColor(sampleColor);
            mainMesh.addVertex(left);
            mainMesh.addColor(sampleColor);
            mainMesh.addVertex(right);
            mainMesh.addColor(sampleColor);
            mainMesh.addVertex(top2);
            mainMesh.addColor(sampleColor);
           
            //ofVertex(x*xyScale, y*xyScale, currZ*zScale);
            //ofVertex(x*xyScale, (y+1)*xyScale, ofNoise(xoff+x*currScale, yoff+(y+1)*currScale, currScale)*zScale);
            //ofVertex((x+1)*xyScale, (y+1)*xyScale, ofNoise(xoff+(x+1)*currScale, yoff+(y+1)*currScale, currScale)*zScale);
            //ofVertex(x*xyScale, y*xyScale, currZ*zScale);
        }
    }
    mainMesh.draw();
    mainMesh.clear();
}

I might be doing wrong the vertex of the mesh, I also think that I don’t need to create and erase the vertex every cycle. But, when I try with fixed vertex I don’t understand how to define properly the IDs.
Any suggestion? by far I’m just following the ofBook tutorial, but still not sure about the result I have in OF.

I have followed the meshFromCameraExample, and now it is working.
The mesh in the setup is now like this:

    for (int y=0; y<meshX; y++) {
        for (int x=0; x<meshY; x++) {
            mesh.addVertex(glm::vec3(x,y,0));
            mesh.addColor(ofColor(255,255,255));
        }
    }
    
    
    for (int y = 0; y<meshX-1; y++){
        for (int x=0; x<meshY-1; x++){
            mesh.addIndex(x+y*meshY);
            mesh.addIndex((x)+(y+1)*meshY);
            mesh.addIndex((x+1)+(y+1)*meshY);
            
            mesh.addIndex((x)+y*meshY);
            mesh.addIndex((x+1)+(y)*meshY);
            mesh.addIndex((x+1)+(y+1)*meshY);
        }
    }

Hey @Dazzid_of , glad you found the example and added some indices! There are a few different modes for drawing triangles. The OF_TRIANGLE_STRIP mode draws a strip of them, so adding indices to describe the order in which the vertices are drawn is important when drawing strip.

If the OF_PRIMITIVE_TRIANGLES mode is used, each set of 3 vertices describes a complete triangle. So the drawing order is basically contained withing the ordering of the vertices, and the indices are not needed. But, there will be many more vertices as some some will be repeated for single triangles that share vertices.

thanks! your comment suddenly gives me some range of experimentation.

When using OF_PRIMITIVE_TRIANGLE_STRIP, the left and right sides of the mesh get connected creating a line that is crossing all along the surface. Looks cool, but how can I tell the indices or the drawing mode to close the sides and don’t connect? I guess in Processing it is just the beginShape and endShape.

Hey so I think what might be happening with the OF_PRIMITIVE_TRIANGLE_STRIP is that the entire mesh is just one long strip, and there is no distinction for when 1 row ends and another begins within that strip. So the triangle at the end of the row is connected to the one that starts the following row. These triangles won’t connect with the OF_PRIMITIVE_TRIANGLES mode.

Also, the order of the indices create an orientation, or handedness, to the mesh. Different orientations for the triangles affect how a texture binds to the mesh. In the code you posted above, the first 3 indices have a counter-clockwise handedness, while the second 3 are clockwise. So keep that in mind if you’re planning to bind a texture at some point.

I’ve always like the way this is described in the documentation page for ofMesh.

So this makes a plane, kinda like the ofPlanePrimitive, and all the triangles have the same orientation.

    int width = 100;
    int height = 50;
    int scale = 10;
    mesh.setMode(OF_PRIMITIVE_TRIANGLES);  // this is the default mode
    
    for(size_t y{0}; y < height; ++y)
    {
        for(size_t x{0}; x < width; ++x)
        {
            mesh.addVertex(glm::vec3(x, y, 0) * scale);
            mesh.addColor(ofFloatColor(1.0, 0.0, 0.5));
        }
    }
    
    for(size_t y{0}; y < height - 1; ++y)
    {
        for(size_t x{0}; x < width - 1; ++x)
        {
            mesh.addIndex(x + (y * width));
            mesh.addIndex(x + ((y + 1) * width));
            mesh.addIndex((x + 1) + ((y + 1) * width));
            
            mesh.addIndex(x + (y * width));
            mesh.addIndex((x + 1) + ((y+1) * width));
            mesh.addIndex((x + 1) + (y * width));
        }
    }
}