Mesh lighting / normal issues

#1

I’m very new in Openframeworks, Processing and OpenGL. I have been reading some tutorials written for Processing and tried to implement them in Openframeworks. There is this generative mesh section, Processing seems to show normals correctly/properly without calculating them first and Openframeworks didn’t (I’m not sure about this though.). Here’s, what I have got:

So, my questions is, how is Processing displaying generative mesh properly and Openframeworks do not? What I’m doing wrong? Is it possible to get similar result in OF without calculating normals first?

My sample code:
code.zip (7.8 KB)

#2

it looks (I’m not 100% sure) like p5 computes normals automatically with a mode called “NORMAL_MODE_AUTO”

the code in this addon might be useful:

I also noticed there’s “getFaceNormals” in ofMesh, I’m going to investigate if it’s useful.

1 Like
#3

Thanks! I’ll try this.
I was trying to generate mesh using GL_QUAD_STRIPE flag. But, ofMesh does not support this. I tried ofVbo. But, if I use ofVbo, then,

for( y = 0 to ylen ){

    glBegin(GL_QUAD_STRIPE); // <--- I can not use it like this.

    for( x = 0 to xlen ){
        //bhuung-chuung.
    }
    glEnd();
}

So, I tried use to OpenGL and jumped into fire from frying pan. *sigh*

#4

I’d look at triangle trip which is very similar. with regards to my mesh code, you might need to generate an indiced mesh first using the other function in that addon.

#5

Processing does indeed calculate per-face normals for you, when you don’t set any normals between the beginShape/endShape calls. When you do set one or more normals, then of course those are used. So for example, when you want per-vertex normals, you also have to do it manually in Processing. The normal calculations done by Processing behind-the-scenes depend on the shape kind (TRIANGLES, TRIANGLE_FAN, TRIANGLE_STRIP, QUADS, and QUAD_STRIP). For reference, the normal calculations for all these can be found here.

I’ve taken the liberty to look into this, because it’s a good way for me to learn about OpenFramework. It seems the method getFaceNormals in ofMesh uses getFaceNormal, which in turn uses calculateFaceNormal. Looking at the calculateFaceNormal method, found here, it seems this method assumes a triangle face.

@Fahim_Ahmed All in all, I think there are at least a few options. You could either change your faces to triangles and go with existing normal calculation methods in OpenFrameworks or you could implement normal calculations yourself given your choice for QUAD_STRIPS. In the latter case you could take inspiration from Processing’s code, but then also note the assumptions made with regard to vertex order as included in Processing’s source code.

At the moment I do not have much time, but in the coming days I might be able to take a look at the actual code example you provided and see if I can make it work. It will be a good lesson for me as well! :smiley:

1 Like
#6

@amnon Thanks. I’ll take a look in Processing’s code.

#8

I’m not sure I understand your question. The normals are useful for lighting, you don’t “see” a normal per-se but if lighting is enabled and you place a light, as the shape is rendered it will be lit accordingly. would it help to see a small example of a triangle (or quad) strip with normals and lighting?

#9

I solved that problem this morning. I was calculating the normal in wrong way. Thanks for your helps and suggestions.

#10

@Fahim_Ahmed So I had some time to look into this. I made a few changes to your original code, namely:

  • Move declaration of variables to .h file.
  • Use an ofMesh instead of immediate drawing.
  • Use TRIANGLES instead of QUADS.
  • Use indices.
  • Calculate the face normals via the ofMesh getFaceNormals() method.
  • Add display of wireframe mesh.
  • Add display of normals (in blue) for debugging purposes.

The mesh displays correctly (faces & wireframe) and it seems the face normals are also correct (blue lines). However I still find the lighting a bit strange. You can disable the use of normals by pressing any key. For some reason there appear to be dark or bright ‘horizontal lines’ with regard to the lighting, which seems not quite correct. See the example image attached below. Note that FLAT shading is turned on on purpose. I have tried a few things to fix this, like changing the vertex winding order, calculate the normals manually, use an ofMesh without indices, etc. but I ended up with the same result or bugs. Since this is my first ever OF application, it’s probably due to my lack of knowledge of OF.

It would be great if someone could double-check the adapted code posted below and hopefully shed some light on the remaining issue! :confused:

Example Image

ofApp.h

#pragma once

#include "ofMain.h"

class ofApp : public ofBaseApp{

    public:
        void setup();
        void draw();

        ofVec3f calculateCenter(ofMeshFace *face);

        ofMesh mesh;
        ofEasyCam cam;
        ofLight light;

        int uCount, vCount;
        float uMin, uMax;
        float vMin, vMax;
        int offset;
        int normalSize;
};

ofApp.cpp

#include "ofApp.h"

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

    uCount  = 40;
    vCount  = 40;
    uMin    = -10;
    uMax = 10;
    vMin = -10;
    vMax = 10;
    offset = 30;
    normalSize = 10;

    ofBackground(0);
    ofEnableDepthTest();
    ofEnableAlphaBlending();
    glShadeModel(GL_FLAT);

    ofColor color;
    color.setBrightness(150);
    light.setDiffuseColor(color);
    light.enable();

    mesh.setMode(OF_PRIMITIVE_TRIANGLES);
    mesh.enableIndices();

    for (unsigned int iv = 0; iv < vCount; iv++) {
        for (unsigned int iu = 0; iu < uCount; iu++) {
            float u = ofMap(iu, 0, uCount, uMin, uMax);
            float v = ofMap(iv, 0, vCount, vMin, vMax);
            float z = cos(sqrt(u*u + v*v));
            ofVec3f pos(u * offset, v * offset, z * offset);
            mesh.addVertex(pos);
        }
    }

    for (unsigned int y = 0; y < vCount-1; y++) {
        for (unsigned int x = 0; x < uCount-1; x++) {
            mesh.addIndex(x+y*uCount);
            mesh.addIndex((x+1)+y*uCount);
            mesh.addIndex(x+(y+1)*uCount);

            mesh.addIndex((x+1)+y*uCount);
            mesh.addIndex((x+1)+(y+1)*uCount);
            mesh.addIndex(x+(y+1)*uCount);
        }
    }

    mesh.addNormals(mesh.getFaceNormals(TRUE));
}

//--------------------------------------------------------------
void ofApp::draw(){
    if (ofGetKeyPressed()) {
        mesh.disableNormals();
    } else {
        mesh.enableNormals();
    }
    cam.begin();

    ofEnableLighting();
    ofSetColor(255);
    mesh.drawFaces();

    ofDisableLighting();
    ofSetColor(255, 200);
    mesh.drawWireframe();

    ofSetColor(0, 0, 255);
    vector<ofMeshFace> faces = mesh.getUniqueFaces();
    ofMeshFace face;
    ofVec3f c, n;
    for(unsigned int i = 0; i < faces.size(); i++){
        face = faces[i];
        c = calculateCenter(&face);
        n = face.getFaceNormal();
        ofLine(c.x, c.y, c.z, c.x+n.x*normalSize, c.y+n.y*normalSize, c.z+n.z*normalSize);
    }

    cam.end();
}

ofVec3f ofApp::calculateCenter(ofMeshFace *face) {
    int lastPointIndex = 3;
    ofVec3f result;
    for (unsigned int i=0; i < 3; i++){
        result += face->getVertex(i);
    }
    result /= lastPointIndex;
    return result;
}
1 Like
#11

I tried your sample. There was a problem in your normal calculation. I think, some faces return flipped normal direction. I used Zach’s method from ofxMeshUtils. It worked.

testApp:

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

	uCount  = 40;
	vCount  = 40;
	uMin    = -10;
	uMax = 10;
	vMin = -10;
	vMax = 10;
	offset = 30;
	normalSize = 10;

	ofBackground(0);
	ofEnableDepthTest();
	ofEnableAlphaBlending();
	ofSetGlobalAmbientColor(0);
	
	glShadeModel(GL_FLAT);

	ofColor color;
	color.setBrightness(150);
	light.setDiffuseColor(color);
	light.enable();

	mesh.setMode(OF_PRIMITIVE_TRIANGLES);
	mesh.enableIndices();

	for (unsigned int iv = 0; iv < vCount; iv++) {
		for (unsigned int iu = 0; iu < uCount; iu++) {
			float u = ofMap(iu, 0, uCount, uMin, uMax);
			float v = ofMap(iv, 0, vCount, vMin, vMax);
			float z = cos(sqrt(u*u + v*v));
			ofVec3f pos(u * offset, v * offset, z * offset);
			mesh.addVertex(pos);
		}
	}

	for (unsigned int y = 0; y < vCount-1; y++) {
		for (unsigned int x = 0; x < uCount-1; x++) {
			mesh.addIndex(x+y*uCount);
			mesh.addIndex((x+1)+y*uCount);
			mesh.addIndex(x+(y+1)*uCount);

			mesh.addIndex((x+1)+y*uCount);
			mesh.addIndex((x+1)+(y+1)*uCount);
			mesh.addIndex(x+(y+1)*uCount);
		}
	}

	calcNormals(mesh);	
}


//--------------------------------------------------------------
void testApp::draw(){
	if (ofGetKeyPressed()) {
		mesh.disableNormals();
	} else {
		mesh.enableNormals();
	}
	cam.begin();

	ofEnableLighting();
	ofEnableDepthTest();
	ofSetColor(200);
	mesh.drawFaces();

	ofDisableDepthTest();
	ofDisableLighting();

	cam.end();
}

ofVec3f testApp::calculateCenter(ofMeshFace *face) {
	int lastPointIndex = 3;
	ofVec3f result;
	for (unsigned int i=0; i < 3; i++){
		result += face->getVertex(i);
	}
	result /= lastPointIndex;
	return result;
}

//From Zach ofxMeshUtils
//ofZach/ofxMeshUtils/blob/master/src/ofxMeshUtils.cpp#L32-L58
void testApp::calcNormals(ofMesh &mesh) {
	for( int i=0; i < mesh.getVertices().size(); i++ ) mesh.addNormal(ofPoint(0,0,0));

	for( int i=0; i < mesh.getIndices().size(); i+=3 ){
		const int ia = mesh.getIndices()[i];
		const int ib = mesh.getIndices()[i+1];
		const int ic = mesh.getIndices()[i+2];

		ofVec3f e1 = mesh.getVertices()[ia] - mesh.getVertices()[ib];
		ofVec3f e2 = mesh.getVertices()[ic] - mesh.getVertices()[ib];
		ofVec3f no = e2.cross( e1 );

		// depending on your clockwise / winding order, you might want to reverse the e2 / e1 above if your normals are flipped. 

		mesh.getNormals()[ia] += no;
		mesh.getNormals()[ib] += no;
		mesh.getNormals()[ic] += no;
	}
}
1 Like
I need suggestion for a generative mesh
How to set the normals of a polyhedron to have flat faces?
#12

Aaaaaaah, great! :smile: Thanks for pointing out Zach’s code snippet again, I missed that the first time. Now I also understand my own mistake better. I mixed up face/vertex normals and I didn’t consider that a vertex is part of multiple faces. It seems this method efficiently calculates the vertex normals by adding up the normals of each face that the specified vertex is part of (via the indices). It doesn’t normalize the final value, but I suppose that isn’t necessary, unless you want to actually display the normals themselves. Well, you learn the most from your mistakes! :blush:

#13

cool! glad that’s helpful !