Discontinuity when using Perlin noise

I am experimenting with Perlin noise and I noticed that there is a discontinuity/seam in my mesh whose z values are from Perlin noise:

Not sure why this is happening. Can someone tell me why this is the case and how I can fix this?

Here is the code for setting up the z-values:

for (int x = 0; x <= (MESH_SIZE + 1); x++) {
		for (int y = 0; y <= MESH_SIZE; y++) {
			int vertexCount = (x * MESH_SIZE) + y;

			float noiseVal = ofNoise(x * 0.1, y * 0.05);
			
			ofVec3f vertexPos = mesh.getVertex(vertexCount);
			vertexPos.z = ofMap(noiseVal, 0, 1, 0, 300, true);
			mesh.setVertex(vertexCount, vertexPos);
		}
	}

Hey @prithvidiamond1 welcome to the forum! It might be helpful if you post some code for how you are generating the ofMesh.

I wrote a quick test this morning and didn’t see any discontinuity with ofNoise. ofBook has some fantastic chapters on ofMesh, and also there is a nice discussion in the documentation too:
https://openframeworks.cc///documentation/3d/ofMesh/
The following should compile and run, and it might be helpful:
ofApp.h:

#pragma once
#include "ofMain.h"
class ofApp : public ofBaseApp{
    
public:
    void setup();
    void update();
    void draw();
    ofMesh mesh;
    int meshSize;
    ofEasyCam easyCam;
};

ofApp.cpp:

#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup(){
    mesh.setMode(OF_PRIMITIVE_TRIANGLES);
    meshSize = 100;
    float step = 2.f / static_cast<float>(meshSize);
    float scale = 500.f;
    // add some vertices
    for(size_t y{0}; y < meshSize; ++y){
        for(size_t x{0}; x < meshSize; ++x){
            glm::vec3 p(0.f);
            // start with normalized, centered at (0.0, 0.0),
            p.x = -1.f + (x * step);
            p.y = -1.f + (y * step);
            // then scale it up a bit
            p *= scale;
            mesh.addVertex(p);
        }
    }
    // add some indices
    for(size_t y{0}; y < meshSize - 1; ++y){
        for(size_t x{0}; x < meshSize - 1; ++x){
            size_t i = (y * meshSize) + x;
            mesh.addIndex((y * meshSize) + x);
            mesh.addIndex((y * meshSize) + (x+1));
            mesh.addIndex(((y+1) * meshSize) + x);
            mesh.addIndex((y * meshSize) + (x+1));
            mesh.addIndex(((y+1) * meshSize) + (x+1));
            mesh.addIndex(((y+1) * meshSize) + x);
        }
    }
    // add some ofNoise
    for(size_t y{0}; y < meshSize; ++y){
        for(size_t x{0}; x < meshSize; ++x){
            size_t i = (y * meshSize) + x;
            glm::vec3 p = mesh.getVertices().at(i);
            p.z = ofNoise(p.x * 0.01, p.y * 0.005);
            p.z = ofMap(p.z, 0.f, 1.f, 0.f, 300.f);
            mesh.getVertices().at(i) = p;
        }
    }
//--------------------------------------------------------------
void ofApp::update(){
    
}
//--------------------------------------------------------------
void ofApp::draw(){
    easyCam.begin();
    mesh.drawWireframe();
    easyCam.end();
}

The mesh is generated as follows and drawn as a wireframe:

    mesh.setMode(OF_PRIMITIVE_TRIANGLES);

	for (int x = 0; x <= MESH_SIZE; x++) {
		for (int y = 0; y <= MESH_SIZE; y++) {
			mesh.addVertex(ofPoint((x - (MESH_SIZE / 2)) * TILE_SIZE, (y - (MESH_SIZE / 2)) * TILE_SIZE, 0));
		}
	}

	for (int x = 0; x < MESH_SIZE; x++) {
		for (int y = 0; y < MESH_SIZE; y++) {
			mesh.addIndex((x * (MESH_SIZE + 1)) + y);
			mesh.addIndex((x * (MESH_SIZE + 1)) + (y + 1));
			mesh.addIndex(((x + 1) * (MESH_SIZE + 1)) + y);
			mesh.addIndex((x * (MESH_SIZE + 1)) + (y + 1));
			mesh.addIndex(((x + 1) * (MESH_SIZE + 1)) + (y + 1));
			mesh.addIndex(((x + 1) * (MESH_SIZE + 1)) + y);
		}
	}

Your code looks very similar to mine apart from a few differences such as building the mesh horizontally first as opposed to vertically like I did and also in terms of adding the vertices.

Hi @prithvidiamond1 just a quick tip while i see you are doing double loop for adding the indexes, you can just do:

int indexForMyIndices = 0;
for (int x = 0; x <= MESH_SIZE; x++) {
		for (int y = 0; y <= MESH_SIZE; y++) {
			mesh.addVertex(ofPoint((x - (MESH_SIZE / 2)) * TILE_SIZE, (y - (MESH_SIZE / 2)) * TILE_SIZE, 0));
            mesh.addIndex(indexForMyIndices++);
		}
	}

That way you dont have to think about indices offset etc…
And I believe the way you set your indices is done with the wrong offset.

Hmm, but wouldn’t the winding order be messed up since I want to use OF_PRIMITIVE_TRIANGLES to draw my mesh surface?

I found the problem. I was counting one more than necessary for x in the code for adding noise. However, not sure why the seam was going along the diagonal, I would have assumed it would run along the horizontal or vertical. Can someone explain why this occurred?

1 Like

Hey that’s great that you found it! I was just getting ready to work on it a bit.

So I noticed too that the seam was diagonal, maybe happening where x == y? I’m not sure about the math, but sometimes I find it helpful to step thru stuff with real numbers, in my head or on paper, just to make sure that things are getting calculated correctly. So if you do that you might find why its happening.

Also yes you are right in that the indices kinda match the ofMesh mode. OF_PRIMITIVE_TRIANGLES draws individual triangles, and there are 6 vertices for 2 triangles that form a rectangle (or square). The winding order is important when textures or normals are involved. I looked at your indices and I think they’re both forming triangles with the same (counter-clockwise) rotation. If something doesn’t look right with a texture or normals, then just try the clockwise direction. I’ve always used clockwise rotation and the textures look fine (not backwards).

I’ll bet pierre_tardif00’s idea works OK for an OF_PRIMITIVE_TRIANGLE_STRIP. If you look at the ofPlanePrimitive, the ofMesh mode is OF_PRIMITIVE_TRIANGLE_STRIP and I don’t think indices are specified.

Well, the thing is I don’t see anything special that is supposed to happen at x == y. As you suggested, I will step through the code line by line and maybe use some numbers to figure out what was going on.

As for the winding order, I don’t plan to do texturing so for now this should suffice. But thanks for the tip!

Your second loop is out of phase with the actual mesh topology because the comparison is done with <=. The diagonal line is actually the edge of noise, but it should be arranged one column wider.

2 Likes

Oh that makes so much sense, so it was just getting shifted down one place and to the right each iteration. Okay, great now I know why my code was behaving like that. Thank you so much!