1

I'm trying to get a shape to have some shading due to a light source but I'd like the shape to all be one colour.

My problem is that no matter how hard I try I cannot seem to get any shading on a singular colour model. I've simplified my model to a single triangle to make this example clearer:

#include <GL/glut.h>
#include <math.h>
#include <iostream>

#include<map>
#include<vector>

using namespace std;

/* Verticies for simplified demo */
float vertices[][3] = {
            {0.1, 0.1, 0.1},
            {0.2, 0.8, 0.3},
            {0.3, 0.5, 0.5},
            {0.8, 0.2, 0.1},
           };
const int VERTICES_SIZE = 4;
/* Polygons for simplified demo */
int polygon[][3] = {
                {0, 1, 3},
                {0, 2, 1},
                {0, 3, 2},
                {1, 2, 3},
            };
const int POLYGON_SIZE = 4;
/* Average point for looking at */
float av_point[3];

/*
 * Holds the normal for each vertex calculated by averaging the
 * planar normals that each vertex is connected to.
 * It holds {index_of_vertex_in_vertices : normal}
 */
map<int, float*> vertex_normals;

/*
 * Calculates average point in list of vertices
 * Stores in result
 */
void averagePoint(float vertices[][3], int length, float result[3]) {
  for(int i = 0; i < length; i++) {
    result[0] += vertices[i][0];
    result[1] += vertices[i][1];
    result[2] += vertices[i][2];
  }

  result[0] /= length;
  result[1] /= length;
  result[2] /= length;
}

/*
 * Performs inplace normalisation of vector v
 */
void normalise(float v[3]) {
  GLfloat length = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  v[0] /= length;
  v[1] /= length;
  v[2] /= length;
}

/*
 * Performs cross product of vectors u and v and stores
 * result in result
 * Normalises result.
 */
void crossProduct(float u[], float v[], float result[]) {
  result[0] = u[1] * v[2] - u[2] * v[1];
  result[1] = u[2] * v[0] - u[0] * v[2];
  result[2] = u[0] * v[1] - u[1] * v[0];
}

/*
 * Calculates normal for plane
 */
void calculate_normal(int polygon[3], float vertices[][3], float normal[3]) {
  GLfloat u[3], v[3];
  for (int i = 0; i < 3; i++) {
    u[i] = vertices[polygon[0]][i] - vertices[polygon[1]][i];
    v[i] = vertices[polygon[2]][i] - vertices[polygon[1]][i];
  }

  crossProduct(u, v, normal);
  normalise(normal);
}

/*
 * Populates vertex_normal with it's averaged face normal
 */
void calculate_vertex_normals (map<int, float*> &vertex_normal){
  map<int, vector<int> > vertex_to_faces;
  map<int, float*> faces_to_normal;
  // Loop over faces
  for (int i = 0; i < POLYGON_SIZE; i++) {
    float* normal = new float[3];
    calculate_normal(polygon[i], vertices, normal);
    for (int j = 0; j < 3; j++) {
     vertex_to_faces[polygon[i][j]].push_back(i);
    }
    faces_to_normal[i] = normal;
  }


  vertex_normal.clear();
  // Loop over vertices
  for (int v = 0; v < VERTICES_SIZE; v++) {
    vector<int> faces = vertex_to_faces[v];
    int faces_count = 0;
    float* normal = new float[3];
    for (vector<int>::iterator it = faces.begin(); it != faces.end(); ++it){
      normal[0] += faces_to_normal[*it][0];
      normal[1] += faces_to_normal[*it][1];
      normal[2] += faces_to_normal[*it][2];
      faces_count++;
    }
    normal[0] /= faces_count;
    normal[1] /= faces_count;
    normal[2] /= faces_count;
    vertex_normal[v] = normal;
  }

  // Delete normal declared in first loop
  for (int i = 0; i < POLYGON_SIZE; i++) {
    delete faces_to_normal[i];
  }
}

/*
 * Draws polygons in polygon array.
 */
void draw_polygon() {
  for(int i = 0; i < POLYGON_SIZE; i++) {
    glBegin(GL_POLYGON);
    for(int j = 0; j < 3; j++) {
      glNormal3fv(vertex_normals[polygon[i][j]]);
      glVertex3fv(vertices[polygon[i][j]]);
    }
    glEnd();
  }
}


/*
 * Sets up lighting and material properties
 */
void init()
{
  // Calculate average point for looking at
  averagePoint(vertices, VERTICES_SIZE, av_point);

  // Calculate vertices average normals
  calculate_vertex_normals(vertex_normals);

  glClearColor (0.0, 0.0, 0.0, 0.0);
  cout << "init" << endl;

  // Intialise and set lighting parameters
  GLfloat light_pos[] = {1.0, 1.0, 1.0, 0.0};
  GLfloat light_ka[] = {0.2, 0.2, 0.2, 1.0};
  GLfloat light_kd[] = {1.0, 1.0, 1.0, 1.0};
  GLfloat light_ks[] = {1.0, 1.0, 1.0, 1.0};

  glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
  glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ka);
  glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_kd);
  glLightfv(GL_LIGHT0, GL_SPECULAR, light_ks);

  // Initialise and set material parameters
  GLfloat material_ka[] = {1.0, 1.0, 1.0, 1.0};
  GLfloat material_kd[] = {0.43, 0.47, 0.54, 1.0};
  GLfloat material_ks[] = {0.33, 0.33, 0.52, 1.0};
  GLfloat material_ke[] = {0.0, 0.0, 0.0, 0.0};
  GLfloat material_se[] = {10.0};

  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,  material_ka);
  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,  material_kd);
  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,  material_ks);
  glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION,  material_ke);
  glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, material_se);

  // Smooth shading
  glShadeModel(GL_SMOOTH);

  // Enable lighting
  glEnable (GL_LIGHTING);
  glEnable (GL_LIGHT0);

  // Enable Z-buffering
  glEnable(GL_DEPTH_TEST);
}

/*
 * Free's resources
 */
void destroy() {
  for (int i = 0; i < VERTICES_SIZE; i++) {
    delete vertex_normals[i];
  }
}

/*
 * Display simple polygon
 */
void display (){
  glClear  (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  draw_polygon();
  glutSwapBuffers();
}

/*
 * Sets up camera perspective and view point
 * Looks at average point in model.
 */
void reshape (int w, int h)
{
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(70, 1.0, 0.1, 1000);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  gluLookAt(0, 0, 1, av_point[0], av_point[1], av_point[2], 0, 0.5, 0);
}

int main (int argc, char **argv)
{

  // Initialize graphics window
  glutInit(&argc, argv);
  glutInitWindowSize(256, 256);
  glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE);

  // Initialize OpenGL
  init();

  glutCreateWindow("Rendering");
  glutDisplayFunc(display);
  glutReshapeFunc(reshape);

  glutMainLoop   ();

  destroy();

  return 1;
}

I'm really new to OpenGL so I'm hoping that it's something simple. Since I've remembered to set my normals so I'm not sure what else is going wrong.

The end aim is to render a face with Gouraud shading (and then textures) for my coursework however we've almost been left to figure out OpenGL (1.4 - course requirement) for ourselves, and we aren't allowed to use shaders. I'm trying to create something similar to this picture (taken from Google): enter image description here

with my triangle.

genpfault
  • 51,148
  • 11
  • 85
  • 139
Sarah Tattersall
  • 1,275
  • 2
  • 21
  • 32
  • 1
    Why people still claim that FFP is *easier* than modern OpenGL is beyond me. Your code would probably benefit a lot if you didn't try to reimplement GLM and dropped the FFP. – Cubic Feb 10 '13 at 10:26
  • I'm not allowed. We have to use OpenGL 1.4 for our coursework, I've found lots of nice examples with the modern shaders approach but unfortunately I'm expected to produce something using the FFP. – Sarah Tattersall Feb 10 '13 at 10:32
  • My condolences then. Good luck. – Cubic Feb 10 '13 at 10:34
  • You have a flat polygon, with only a face normal, lit by an directional only light source. You should not expect any shading from that as nothing is varying across the polygon. – JasonD Feb 10 '13 at 10:45
  • I've just added in vertex normals which take the average of each face normal and still get nothing. How can I achieve shading? I'll update my example code. – Sarah Tattersall Feb 10 '13 at 10:53
  • 3
    OpenGL 1.4 is so old! Why anyone would teach like that? horrible... – fen Feb 10 '13 at 10:59
  • I'm sorry - it's a stipulation of my Graphics course! Bit silly! – Sarah Tattersall Feb 10 '13 at 11:01
  • Please make your title _describe the problem_, rather than simply listing technologies, so that it is informative in a list of questions. – Lightness Races in Orbit Feb 10 '13 at 11:19
  • Ok, well that didn't really improve matters – Lightness Races in Orbit Feb 10 '13 at 11:33
  • 1
    @SarahTattersall: Please tell your teacher/professor/TAs that they're covering outdated methods, which are only of interest if you're going to study or maintain old code. Every employer in the field of 3D graphics expects applicants to know how to use programmable graphics pipelines. It's now over 10 years the first programmable GPUs entered the market. – datenwolf Feb 10 '13 at 11:35
  • @datenwolf: Maybe the professor did it deliberately, so that the students would be unable to get free help from Stack Overflow on their homework? – Lightness Races in Orbit Feb 10 '13 at 11:37
  • @LightnessRacesinOrbit: Not really a reason. I know the FFP fairly well, and can give proper answer. – datenwolf Feb 10 '13 at 11:38
  • @datenwolf: Then go ahead and do that. :) – Lightness Races in Orbit Feb 10 '13 at 11:42
  • @SarahTattersall your code now compiles for me (on OSX) but produces a segmentation fault. You now need to describe what _actual_ problem _you're_ having with the code. – Alnitak Feb 10 '13 at 12:03
  • 1
    @LightnessRacesinOrbit: I've never seen you participating in OpenGL Q&A. The OpenGL tag is normally roamed by only the people mentioned in the tag's top users http://stackoverflow.com/tags/opengl/topusers – and the consensus among us is, that whenever somebody asks about how doing things with the FFP in a new project, we will try to nudge them toward using shaders. FFP is to graphics what BASIC is to programming languages. – datenwolf Feb 10 '13 at 12:37
  • @datenwolf: I'm sorry to hear that. – Lightness Races in Orbit Feb 10 '13 at 12:41
  • @LightnessRacesinOrbit: I made three orthogonal statements in my comment. To which of them relates your answer and in which way? – datenwolf Feb 10 '13 at 12:55
  • 1
    @datenwolf: All of them, in every way. Time to end this repartée! – Lightness Races in Orbit Feb 10 '13 at 13:09

2 Answers2

5

shading due to a light source but I'd like the shape to all be one colour.

Aren't those two requirements mutually exclusive? What exactly is your desired outcome. Can you draw a picture what you're imagining? When it comes to implementing, using shaders is a lot easier than juggling with a gazillion of OpenGL state machine switches.

Update

Anyway here's my revised version of OPs code that draws a single triangle subject to Gourad illumination. This code compiles and draw a single triangle with a hint of a specular reflex.

Let's go through what I did. First there's your original setup of the triangle. Nothing special here and nothing changed either (except a few includes) (EDIT) on second look I did a change. The use of a std::map was totally unaccounted for. We know the number of vertices and can just preallocate the normals' memory.

#include <GL/glut.h>
#include <math.h>

// for memcpy
#include <string.h>

#include <map>
#include <vector>
#include <iostream>

using namespace::std;

/* Verticies for simplified demo */
const int VERTICES_SIZE = 4;
float vertices[VERTICES_SIZE][3] = {
            {0.1, 0.1, 0.1},
            {0.2, 0.8, 0.3},
            {0.3, 0.5, 0.5},
            {0.8, 0.2, 0.1},
           };

// this is now a plain array
float vertex_normals[VERTICES_SIZE][3];

/* Polygons for simplified demo */
const int POLYGON_SIZE = 4;
int polygon[POLYGON_SIZE][3] = {
                {0, 1, 3},
                {0, 2, 1},
                {0, 3, 2},
                {1, 2, 3},
};

/* Average point for looking at */
float av_point[3];
    
/*
 * Calculates average point in list of vertices
 * Stores in result
 */
void averagePoint(float vertices[][3], int length, float result[3]) {
  for(int i = 0; i < length; i++) {
    result[0] += vertices[i][0];
    result[1] += vertices[i][1];
    result[2] += vertices[i][2];
  }

  result[0] /= length;
  result[1] /= length;
  result[2] /= length;
}

/*
 * Performs inplace normalisation of vector v
 */
void normalise(float v[3]) {
  GLfloat length = sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  v[0] /= length;
  v[1] /= length;
  v[2] /= length;
}

/*
 * Performs cross product of vectors u and v and stores
 * result in result
 * Normalises result.
 */
void crossProduct(float u[], float v[], float result[]) {
  result[0] = u[1] * v[2] - u[2] * v[1];
  result[1] = u[2] * v[0] - u[0] * v[2];
  result[2] = u[0] * v[1] - u[1] * v[0];
}

/*
 * Calculates normal for plane
 */
void calculate_normal(int polygon[3], float vertices[][3], float normal[3]) {
  GLfloat u[3], v[3];
  for (int i = 0; i < 3; i++) {
    u[i] = vertices[polygon[0]][i] - vertices[polygon[1]][i];
    v[i] = vertices[polygon[2]][i] - vertices[polygon[1]][i];
  }

  crossProduct(u, v, normal);
  normalise(normal);
}

EDIT: My next change was here. See the comment

/*
 * Populates normals with it's averaged face normal
 *
 * Passing the normal output buffer as a parameter was a bit
 * pointless, as this procedure accesses global variables anyway.
 * Either pass everything as parameters or noting at all,
 * be consequent. And doing it mixed is pure evil.
 */
void calculate_vertex_normals()
{
  // We love RAII, no need for new and delete!
  vector< vector<int> > vertex_to_faces(POLYGON_SIZE);
  vector< vector<float> > faces_to_normal(POLYGON_SIZE);

  // Loop over faces
  for (int i = 0; i < POLYGON_SIZE; i++) {
    vector<float> normal(3);
    calculate_normal(polygon[i], vertices, &normal[0]);
    for (int j = 0; j < 3; j++) {
     vertex_to_faces[polygon[i][j]].push_back(i);
    }
    faces_to_normal[i] = normal;
  }

  // Loop over vertices
  for (int v = 0; v < VERTICES_SIZE; v++) {
    // avoid a copy here by using a reference
    vector<int> &faces = vertex_to_faces[v];
    int faces_count = 0;
    float normal[3];
    for (vector<int>::iterator it = faces.begin(); it != faces.end(); ++it){
      normal[0] += faces_to_normal[*it][0];
      normal[1] += faces_to_normal[*it][1];
      normal[2] += faces_to_normal[*it][2];
      faces_count++;
    }
    // dividing a vector obtained by a number of unit length vectors
    // summed by the number of unit vectors summed does not normalize
    // it. You need to normalize it properly!
    normalise(normal);

    // memcpy is really be best choice here
    memcpy(vertex_normals[v], normal, sizeof(normal));
  }
}

draw_polygon is a rather unhappy name for this function. It draws a triangulated mesh. *EDIT: Also it can be written much nicer by employing vertex arrays (available since 1994 with OpenGL-1.1).

/* 
 * Draws polygons in polygon array.
 */
void draw_polygon() {
  glEnableClientState(GL_VERTEX_ARRAY);
  glEnableClientState(GL_NORMAL_ARRAY);

  glVertexPointer(3, GL_FLOAT, 0, &vertices[0][0]);
  glNormalPointer(GL_FLOAT, 0, &vertex_normals[0][0]);

  glDrawElements(GL_TRIANGLES, POLYGON_SIZE*3, GL_UNSIGNED_INT, polygon);
}

Here it's getting interesting. A common misconception is, that people think OpenGL is "initialized". That's not the case. What you initialize is data. In your case your geometry data

/*
 * Sets up lighting and material properties
 */
void init_geometry()
{
  // Calculate average point for looking at
  averagePoint(vertices, VERTICES_SIZE, av_point);

  // Calculate vertices average normals
  calculate_vertex_normals(vertex_normals);
}

Here comes the tricky part: OpenGL fixed function illumination is a state as everything else. When you call glLightfv it will set internal parameters based on state when being called. The position is transformed by the modelview when calling this. But without a proper modelview being set up, you can't setup the illumination. Hence I put it into its own function, which we call right after setting up modelview in the drawing function.

void setup_illumination()
{
  // Intialise and set lighting parameters
  GLfloat light_pos[] = {1.0, 1.0, 1.0, 0.0};
  GLfloat light_ka[] = {0.2, 0.2, 0.2, 1.0};
  GLfloat light_kd[] = {1.0, 1.0, 1.0, 1.0};
  GLfloat light_ks[] = {1.0, 1.0, 1.0, 1.0};

  glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
  glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ka);
  glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_kd);
  glLightfv(GL_LIGHT0, GL_SPECULAR, light_ks);

  // Initialise and set material parameters
  GLfloat material_ka[] = {1.0, 1.0, 1.0, 1.0};
  GLfloat material_kd[] = {0.43, 0.47, 0.54, 1.0};
  GLfloat material_ks[] = {0.33, 0.33, 0.52, 1.0};
  GLfloat material_ke[] = {0.0, 0.0, 0.0, 0.0};
  GLfloat material_se[] = {10.0};

  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,  material_ka);
  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,  material_kd);
  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,  material_ks);
  glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION,  material_ke);
  glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, material_se);

  // Smooth shading
  glShadeModel(GL_SMOOTH);

  // Enable lighting
  glEnable (GL_LIGHTING);
  glEnable (GL_LIGHT0);
}

For the drawing function a few things were changed. See the comments in the code

/*
 * Display simple polygon
 */
void display (void)
{
  // float window sizes are usefull for view volume calculations
  //
  // requesting the window dimensions for each drawing iteration
  // is just two function calls. Compare this to the number of function
  // calls a typical application will do for the actual rendering
  // Trying to optimize away those two calls is a fruitless microoptimization
  float const window_width  = glutGet(GLUT_WINDOW_WIDTH);
  float const window_height = glutGet(GLUT_WINDOW_HEIGHT);
  float const window_aspect = window_width / window_height;

  // glViewport operates independent of the projection --
  // another reason to put it into the drawing code
  glViewport(0, 0, window_width, window_height);

  glClearDepth(1.);
  glClearColor (0.0, 0.0, 0.0, 0.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  // It's a often made mistake to setup projection in the window resize
  // handler. Projection is a drawing state, hence should be set in
  // the drawing code. Also in most programs you will have multiple
  // projections mixed throughout rendering a single frame so there you
  // actually **must** set projection in drawing code, otherwise it
  // wouldn't work.
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(70, window_aspect, 1, 100);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  gluLookAt(0, 0, -3, av_point[0], av_point[1], av_point[2], 0, 1, 0);
 
  // Fixed function pipeline light position setup calls operate on the current
  // modelview matrix, so we must setup the illumination parameters with the
  // modelview matrix at least after the view transformation (look-at) applied.
  setup_illumination();
 
  // Enable depth testing (z buffering would be enabled/disabled with glDepthMask)
  glEnable(GL_DEPTH_TEST);

  draw_polygon();

  glutSwapBuffers();
}
   
int main (int argc, char **argv)
{    
  // Initialize graphics window
  glutInit(&argc, argv);
  glutInitWindowSize(256, 256);
  glutInitDisplayMode    (GLUT_DEPTH | GLUT_DOUBLE);

  // we actually have to create a window
  glutCreateWindow("illuination");

  // Initialize geometry
  init_geometry();

  glutDisplayFunc(display);

  glutMainLoop();

  return 0;
}
Community
  • 1
  • 1
datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • 1
    your other answer got deleted because it had already been flagged for moderation _before_ you announced that you were going to update it. It's nice that you've fixed the OPs code, but justing posting the new version also isn't an answer. You should really explain _how_ you've fixed it. – Alnitak Feb 10 '13 at 12:13
  • @Alnitak: Here you go, added the explanation. – datenwolf Feb 10 '13 at 12:21
  • @LightnessRacesinOrbit: Well, it's rather commonplace in the OpenGL tag to be done this way. Graphics is a complicated thing and often the original problem isn't clear right away. So the established method in the OpenGL tag is to iteratively work toward the solution together with the OP. OPs wanted to shade a shape in a single colour, which by definition is no shading at all. So I ask back to refine it. The way I went to work toward an answer for this question is like I did so often with all the other unclear questions in the opengl tag, and it worked very well so far. – datenwolf Feb 10 '13 at 12:56
  • 1
    @datenwolf: Sounds like the OpenGL tag treats the established Stack Overflow mechanics with a certain amount of disregard. SO rules are not for "all of SO except the OpenGL tag". SO is not a "chat" or "discussion forum"; it is not the place for iteratively working towards anything. – Lightness Races in Orbit Feb 10 '13 at 13:02
  • @LightnessRacesinOrbit: The goal of a SO answer should be something that's correct, concise and most importantly usefull for others. How well experienced are you in graphics programming? It's very often the case that you can not give the right or a meaningful answer right away when it comes to graphics, because it's such a delicate subject and you have to make a number of adjustments as you go along. I don't see a problem here, as long as the final product of the collaborative effort of quenstioner and answerer is something that's correct and usefull for future readers. – datenwolf Feb 10 '13 at 13:18
  • @LightnessRacesinOrbit: Or to put it in other words: StackOverflow is not a forum, it's not a discussion platform, it's a *knowledge database*. Kind of like Wikipedia, where things may very well start as stubs and get expanded on the way. – datenwolf Feb 10 '13 at 13:20
  • @datenwolf: Yes, exactly. Except for the stub part. It's a Q&A, so answers are expected to actually answer something. That's why the system has "this is not an answer" flags. Posting a stub that says "I don't know what the question is" and asking questions is _not_ okay; you should post comments on the question until you know what's going on, and then post an answer when you've spent time forming it. SO is not a race. – Lightness Races in Orbit Feb 10 '13 at 13:22
  • @LightnessRacesinOrbit: Unfortunately comments are not as versatile in formatting and editing as answers. I often found myself in a position where I started off with a comment only to find that I and the OP drew a really long thread in the comments on the question, while it would have been better placed in the answer, expanding it while the comments trickle in. In this question OP's question was rather unclear, and my answer only matched that. The question didn't get better but at least now there's some code doing a sensible thing. – datenwolf Feb 10 '13 at 13:26
  • @datenwolf: It sounds like the OpenGL tag routinely works contrary to the SO mechanic. I'll raise this on meta. In the meantime if you would like any further information to understand the way that Stack Overflow is supposed to work, I'll be happy to help you out in chat a bit later; right now I have to go get some food. – Lightness Races in Orbit Feb 10 '13 at 13:27
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/24267/discussion-between-datenwolf-and-lightness-races-in-orbit) – datenwolf Feb 10 '13 at 13:32
  • @datenwolf: A bit later; right now I have to go get some food. – Lightness Races in Orbit Feb 10 '13 at 13:32
  • @datenwolf Just got back - thank you so much for your help and patience (and everyone else). This explained the solution really well. – Sarah Tattersall Feb 10 '13 at 14:46
0

You seem to have an array called vertices (which is the correct spelling), and another array called verticies, in several places (calculate_normal is the most obvious example). Is this a mistake? It could be messing up your normal calculations where you take one co-ordinate from the first array but the second co-ordinate from a different, unrelated array.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • mistake sorry! I tried to correct the spelling in my example and missed off a few places. – Sarah Tattersall Feb 10 '13 at 11:43
  • @Sarah: Please ensure that your testcase/example is the code that you are actually running before posting. Now I wonder what other typos you may have missed that will distract us and take our time away from finding your true problem. – Lightness Races in Orbit Feb 10 '13 at 11:46
  • 1
    @SarahTattersall he's right - I just tried to build your code and there are still numerous compile errors in it. Even when I fixed the obvious typos, added required `#include`, etc there was still a call to an undefined `set_normal` function. – Alnitak Feb 10 '13 at 11:51