I've got an OpenGL program running, and it displays geometry, but it's all "flat," one gray tone, with no diffuse shading or specular reflection:
Pictured are three tori, each made of quad strips. We should see shading, but we don't. What am I doing wrong?
Here is the code where I set the vertices and normals (draw_torus() is called to build a display list):
/* WrapTorus, adapted from
http://www.math.ucsd.edu/~sbuss/MathCG/OpenGLsoft/WrapTorus/WrapTorus.html
by Sam Buss */
/*
* Issue vertex command for segment number j of wrap number i.
* Normal added by Lars Huttar.
* slices1 = numWraps; slices2 = numPerWrap.
*/
void putVert(float i, float j, float slices1, float slices2, float majR, float minR) {
float wrapFrac = j / slices2;
/* phi is rotation about the circle of revolution */
float phi = PI2 * wrapFrac;
/* theta is rotation about the origin, in the xz plane. */
float theta = PI2 * (i + wrapFrac) / slices1;
float y = minR * (float)sin(phi);
float r = majR + minR * (float)cos(phi);
float x = (float)sin(theta) * r;
float z = (float)cos(theta) * r;
/* normal vector points to (x,y,z) from: */
float xb = (float)sin(theta) * majR;
float zb = (float)cos(theta) * majR;
glNormal3f(x - xb, y, z - zb);
glVertex3f(x, y, z);
}
static void draw_torus(int numPerWrap, int numWraps, float majR, float minR) {
int i, j;
glBegin( GL_QUAD_STRIP );
for (i=0; i < numWraps; i++ ) {
for (j=0; j < numPerWrap; j++) {
putVert((float)i, (float)j, (float)numWraps, (float)numPerWrap, majR, minR);
putVert((float)(i + 1), (float)j, (float)numWraps, (float)numPerWrap, majR, minR);
}
}
putVert(0.0, 0.0, (float)numWraps, (float)numPerWrap, majR, minR);
putVert(1.0, 0.0, (float)numWraps, (float)numPerWrap, majR, minR);
glEnd();
}
Is there something wrong with the order of vertices?
Here is the part of the init function where the display list is built:
GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat color[4] = { 0.5, 0.6, 0.7, 1.0 };
...
glShadeModel(GL_SMOOTH);
torusDL = glGenLists (1);
glNewList(torusDL, GL_COMPILE);
setMaterial(color, white, 100);
draw_torus(8, 45, 1.0, 0.05);
glEndList();
where setMaterial() just does:
static void setMaterial(const GLfloat color[3], const GLfloat hlite[3], int shininess) {
glColor3fv(color);
glMaterialfv(GL_FRONT, GL_SPECULAR, hlite);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
glMateriali(GL_FRONT, GL_SHININESS, shininess); /* [0,128] */
}
Here is lighting that's also done during initialization:
GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0};
GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0};
GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
GLfloat color[4] = {0.20, 0.20, 0.20, 1.00};
GLfloat spec[4] = {0.30, 0.30, 0.30, 1.00};
GLfloat shiny = 8.0;
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glLightfv(GL_LIGHT0, GL_POSITION, pos);
glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
Here is where the display list gets called, in the draw function:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glLoadIdentity();
glScalef(3.5, 3.5, 3.5);
for (i = 0; i < ac->nrings; i++) {
glScalef(0.8, 0.8, 0.8);
glRotatef(...);
glCallList(torusDL);
}
glFlush();
glPopMatrix();
glXSwapBuffers(dpy, window);
The full .c source file for this "glx hack" is here. In case it makes a difference, this code is in the context of xscreensaver.
As you see, glEnable(GL_NORMALIZE) normalizes the normal vectors after the transformations used for lighting calculations (in fixed-function pipelines). These calculations rely on unit length normals for correct results.
It's worth pointing out that the transforms applied to normal vectors are not the same as the transforms applied to vertex geometry. The OpenGL 2.1 specification describes the transform, as do many other resources. As a vector, a normal has the homogeneous representation: [nx, ny, nz, 0] - a point at 'infinity', and a mathematically elegant way to unify matrix and 4-vector operations in the GL pipeline.
Of course, you could perform this normalization yourself, and it may be more efficient to do so, as your torus geometry is only generated once for a pre-compiled display list:
nx = x - b, ny = y, nz = z - zb;
nl = 1.0f / sqrtf(nx * nx + ny * ny + nz * nz);
glNormal3f(nx * nl, ny * nl, nz * nl);
Be sure to check (nl) for division by zero (or some epsilon), if that's a possibility.
Related
First of all, let me tell i am quite new using OpenGL and C++. However, i want to get involved with this two topics.
So let me explain my case, ive been searching how to get the new coordinates of an object after glTrasnlatef and glRotatef were applied. However, i did not find the find info, actually i found some info about java but i am not getting it, as i told you i am working with C++.
I read there is something to deal with the glPushMatrix(); function but idont know how to handle it.
I know that after applying some trnaslation and rotation i am doing changes into the actual matrix.
Finally, the main purpose of this is because ill use those vertices from the rombohedrom and do a lot of translations and rotations, those are going to be needed as well.
So far this is my code (BTW i am working with lines and the vertices of course because i only need those).
i will really appreciate if someone can address me through the right path.
Thanks in advance
Alberto
#include <GL/glut.h>
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
// Global variables
double rotate_y=0;
double rotate_x=0;
int width = 640;
int height = 640;
#define PI 3.14159265
float theta = 60;
float edgeLength = 1;
float sinThetaOverHypotenuse = (sin((theta*PI)/180))/edgeLength;
vector<vector<float>> coordinates{{0.0, 0.0, 0.0},
{1.0, 0.0, 0.0},
{1.0, 0.0, 0.0},
{1.5, sinThetaOverHypotenuse, 0.0},
{1.5, sinThetaOverHypotenuse, 0.0},
{0.5, sinThetaOverHypotenuse, 0},
{0.5, sinThetaOverHypotenuse, 0},
{0.0, 0.0, 0.0}};
void rhombohedrom()
{
vector<vector<float>> rotated {};
// glClearColor(1,1,0,0)
// Clear screen and Z-buffer
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH ) / 300.0;
double h = glutGet( GLUT_WINDOW_HEIGHT ) / 300.0;
glOrtho( -1 * w, 1 * w, -1 * h, 1 * h, 10, -10);
glMatrixMode( GL_MODELVIEW );
// Reset transformations
glLoadIdentity();
// Rotate when user changes rotate_x and rotate_y
glRotatef( rotate_x, 1.0, 0.0, 0.0 );
glRotatef( rotate_y, 0.0, 1.0, 0.0 );
/*
FACE 0
FACE 0
FACE 0
FACE 0
*/
// random color side - front
glBegin(GL_LINE_LOOP);
glColor3f( 0.7, 0.3, 0.8 );
for (int i = 0; i < 8; ++i)
{
glVertex3f(coordinates[i][0], coordinates[i][1], coordinates[i][2]);
}
glEnd();
/*
FACE 1
FACE 1
FACE 1
FACE 1
*/
glPushMatrix();
glTranslatef(0.0,0.0,0.0);
glRotatef(90.0, 1.0, 0.0, 0.0);
glBegin(GL_LINE_LOOP);
glColor3f( 1.0, 1.0, 1.0 );
for (int i = 0; i < 8; ++i)
{
glVertex3f(coordinates[i][0], coordinates[i][1], coordinates[i][2]);
}
glEnd();
glPopMatrix();
/*
FACE 2
FACE 2
FACE 2
FACE 2
*/
glPushMatrix();
glTranslatef(0.5,0.0,sinThetaOverHypotenuse);
glBegin(GL_LINE_LOOP);
glColor3f( 0.5, 0.5, 0.0 );
for (int i = 0; i < 8; ++i)
{
glVertex3f(coordinates[i][0], coordinates[i][1], coordinates[i][2]);
}
glEnd();
glPopMatrix();
/*
FACE 3
FACE 3
FACE 3
FACE 3
*/
glPushMatrix();
glTranslatef(0.5,sinThetaOverHypotenuse,0.0);
glRotatef(90.0, 1.0, 0.0, 0.0);
glBegin(GL_LINE_LOOP);
glColor3f( 0.5, 0.0, 0.0 );
for (int i = 0; i < 8; ++i)
{
glVertex3f(coordinates[i][0], coordinates[i][1], coordinates[i][2]);
}
glEnd();
glPopMatrix();
glFlush();
glutSwapBuffers();
}
void specialKeys(int key, int x, int y)
{
// Right arrow - increase rotation by 5 degree
if (key == GLUT_KEY_RIGHT)
rotate_y += 5;
// Left arrow - decrease rotation by 5 degree
else if (key == GLUT_KEY_LEFT)
rotate_y -= 5;
else if (key == GLUT_KEY_UP)
rotate_x += 5;
else if (key == GLUT_KEY_DOWN)
rotate_x -= 5;
// Request display update
glutPostRedisplay();
}
int main(int argc, char *argv[])
{
// Initialize GLUT and process user parameters
glutInit(&argc,argv);
glutInitWindowSize(width,height);
// Position of the window
glutInitWindowPosition(10,10);
// Request double buffered true color window with Z-buffer
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
// Create window
glutCreateWindow("rhombohedrom");
// Enable Z-buffer depth test
glEnable(GL_DEPTH_TEST);
// Callback functions
glutDisplayFunc(rhombohedrom);
glutSpecialFunc(specialKeys);
//
glutMainLoop();
return 0;
}
First, I want to address some remarks such as:
glPushMatrix() is an old way, try to use the MVP technique which will help you solving your problem. So, you have to write your Vertex Shader and pass the Matrices through what called uniform in OpenGL. Obviously, you have to use new Routines.
glPopMatrix() is also an old routine.
I'm happy to answer your further questions if you want to know more about those remarks.
Use Vertex Shader instead of simple calculus using the CPU!
you can change glTranslatef() and glRotatef() by lookAt so you can change the scale, rotation and translation.
Use Vertex Shader instead of using or stressing the CPU by graphic calculus. Even if you have an Intel integrated GPU
I'm using opengl for educational purposes, but I'm having trouble creating multiple spotlights to represent street lamps. I use an iterator to create several however in the end only the last spotlight gets the light, I believe the problem is in the addlight method however I do not know what is happening.
In image below you can see happen.
https://imgur.com/Y77eHln
#include "CreateLamps.h"
std::vector<SpotLight> lamp;
CreateLamps::CreateLamps(int number) {
for (int i = 0; i < number; i++) {
SpotLight *spot = new SpotLight(-8.0f, 5.f, (i*10) + 30.0f, 1.f);
lamp.push_back(*spot);
}
}
void CreateLamps::Add() {
std::vector<SpotLight>::iterator it = lamp.begin();
while (it != lamp.end())
{
glPushMatrix();
glTranslatef(1, 0, 30.0);
glTranslatef(it->position[0], it->position[3] * 3, it->position[2]);
glRotatef(100.f, -5.0, -10, 0);
it->addlight();
it->draw();
it++;
glPopMatrix();
}
}
#include "SpotLight.h"
using namespace std;
GLfloat target[3] = { 0.0f, 0.0f, 0.0f };
GLfloat color[3] = { 1.0f, 1.0f, 1.0f };
GLfloat cutoff(5.0f);
GLfloat exponent(15.0f);
SpotLight::SpotLight(GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
position[0] = x;
position[1] = y;
position[2] = z;
position[3] = w;
direction[0] = target[0] - position[0];
direction[1] = target[1] - position[1];
direction[2] = (target[2] - position[2]);
}
void SpotLight::addlight() {
glEnable(GL_LIGHT1);
glLightfv(GL_LIGHT1, GL_DIFFUSE, color);
glLightfv(GL_LIGHT1, GL_SPECULAR, color);
glLightfv(GL_LIGHT1, GL_POSITION, position);
glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, direction);
glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, cutoff);
glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, exponent);
}
void SpotLight::draw() {
if (!glIsEnabled(GL_LIGHT1))
return;
glPushMatrix();
GLfloat up[3] = { 0, 1, 0 };
lookAt(position, target, up);
GLfloat ambient[4] = { 0.8f, 0.8f, 0.8f, 1.0f };
GLfloat diffuse[4] = { 0.01f, 0.01f, 0.01f, 1.0f };
GLfloat specular[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat shininess = 32.0f;
glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
glMaterialf(GL_FRONT, GL_SHININESS, shininess);
glutSolidCone(0.3, 0.6, 10, 10);
glPushMatrix();
glTranslatef(0, 0, 0.1f);
glutSolidCylinder(0.2, 0.39, 10, 10);
glPopMatrix();
glDisable(GL_LIGHTING);
glColor3fv(color);
glutSolidSphere(0.2, 100, 100);
glEnable(GL_LIGHTING);
glPopMatrix();
}
void SpotLight::normalize(const GLfloat* vec, GLfloat* output)
{
GLfloat length = sqrtf(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
output[0] /= length;
output[1] /= length;
output[2] /= length;
}
void SpotLight::cross(const GLfloat* vec1, const GLfloat* vec2, GLfloat * output) {
output[0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
output[1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
output[2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
}
void SpotLight::lookAt(GLfloat* eye, GLfloat* center, GLfloat* up)
{
GLfloat f[3] = { center[0] - eye[0],
center[1] - eye[1],
center[2] - eye[2] };
normalize(f, f);
GLfloat u[3];
normalize(up, u);
GLfloat s[3];
cross(f, u, s);
normalize(s, s);
cross(s, f, u);
normalize(u, u);
}
void drawScene() {
glPushMatrix();
glTranslatef(pointlight.position[0], pointlight.position[1], pointlight.position[2]);
pointlight.addLight();
glPopMatrix();
// Draw road
glPushMatrix();
glScalef(10, 10, 8.5);
glTranslatef(-0.018f, 0, 0.75);
glRotatef(180.f, 0, 1, 0);
models[0]->renderTheModel();
glPopMatrix();
//Draw Car Model
glPushMatrix();
glMultMatrixf(carros[0]->local);
carros[0]->draw();
glPopMatrix();
//Draw spotlights
glPushMatrix();
lamps->Add();
glPopMatrix();
}
You are only ever setting LIGHT1, which means only 1 light is going to have been enabled (the last one). If you specify GL_LIGHT0 + index, you'll be able to enable more.
void SpotLight::addlight(int index) {
glEnable(GL_LIGHT0 + index);
glLightfv(GL_LIGHT0 + index, GL_DIFFUSE, color);
glLightfv(GL_LIGHT0 + index, GL_SPECULAR, color);
glLightfv(GL_LIGHT0 + index, GL_POSITION, position);
glLightfv(GL_LIGHT0 + index, GL_SPOT_DIRECTION, direction);
glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, cutoff);
glLightf(GL_LIGHT0 + index, GL_SPOT_EXPONENT, exponent);
}
And then you simply need to pass the index in when enabling
void CreateLamps::Add() {
std::vector<SpotLight>::iterator it = lamp.begin();
while (it != lamp.end())
{
glPushMatrix();
glTranslatef(1, 0, 30.0);
glTranslatef(it->position[0], it->position[3] * 3, it->position[2]);
glRotatef(100.f, -5.0, -10, 0);
it->addlight(it - lamp.begin());
it->draw();
it++;
glPopMatrix();
}
}
Just be aware that you might run out of lights after 8, so you might want to check the value of GL_MAX_LIGHTS...
int numLights = 0;
glGetIntegerv(GL_MAX_LIGHTS, &numLights);
std::cout << "GL_MAX_LIGHTS " << numLights << std::endl;
Presumably you are drawing the road after drawing all of the lights.
Your code does this:
For each light:
Set light 1 according to that light's parameters
Draw the shape of the light itself
Draw the road.
When the road gets drawn, light 1 is set up with the parameters of the last light that was drawn. So it uses these light parameters to draw the road. You overwrote all the parameters of the other lights already.
If you want to draw the road with all the lights, then all the lights have to be set up when you draw the road. Not just the last one.
Note that you can only set up 8 lights at once in OpenGL. If have more than 8 lights pointing at the road, you will have to split up the road into different sections so that each section has up to 8 lights.
Standard disclaimer in case you aren't aware already: You are using old-style (fixed-function) OpenGL which has been superseded by shader-based OpenGL (version 3 and 4). This API is okay for simple programs but it won't let you use the full flexibility and performance of your graphics card.
I am working on the solar system and I am trying to get the sun to be the central light source of this program but it's not working the way I thought it would.
Here is a picture of what I have without lighting.
Here is the same program with lighting.
A different angle here so you can see that the Earth has no shadow as it is supposed to (ignore the red on the moon, that's for my reference)
I don't know if you can tell, but it looks like the light is centered in each sphere, and not in the Sun.
The shadow on the Earth is as if the light was coming from the top. Same with the Sun. The Sun here is not a light source, it's just a sphere that is also being lit by some some source. There is no shadow from the Earth on the moon or from the moon on the Earth.
This here is the code that draws the system
GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat pos[] = { 0.0, 0.0, 1.0, 0.0 };
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightf(GL_LIGHT0, GL_POSITION, pos);
//SUN
//Picture location, major radius, minor radius, major orbit, minor orbit, angle
Planet Sun ("/home/rodrtu/Desktop/SolarSystem/images/Sun.png",
100, 99, 200.0, 0.0, 0.0);
double sunOrbS = 0;
double sunRotS = rotatSpeed/10;
//orbit speed, rotation speed, moon reference coordinates (Parent planet's major and minor Axis)
Sun.displayPlanet(sunOrbS, sunRotS, 0.0, 0.0);
//EARTH
Planet Earth ("/home/rodrtu/Desktop/SolarSystem/images/EarthTopography.png",
50, 49, 500.0, 450.0, 23.5);
double eaOrbS = orbitSpeed*2;
double eaRotS = rotatSpeed*5;
Earth.displayPlanet(eaOrbS, eaRotS, 0.0, 0.0);
//Orbit path
drawCircle(800, 720, 1, 50);
//EARTH'S MOON
Planet Moon ("/home/rodrtu/Desktop/SolarSystem/images/moonTest.png",
25, 23, 100.0, 100.0, 15);
double moOrbS = rotatSpeed*4;
double moRotS = eaOrbS;
Moon.displayPlanet(moOrbS, moRotS, Earth.getMajorAxis(), Earth.getMinorAxis());
orbitSpeed+=.9;
if (orbitSpeed > 359.0)
orbitSpeed = 0.0;
rotatSpeed+=2.0;
if (rotatSpeed > 719.0)
rotatSpeed = 0.0;
These next two functions are responsible for coordinates and drawing the spheres
void Planet::setOrbit(double orbitSpeed, double rotationSpeed,
double moonOrbitX, double moonOrbitY)
{
majorAxis = orbitSemiMajor * cos(orbitSpeed / 180.0 * Math::Constants<double>::pi);
minorAxis = orbitSemiMinor * sin(orbitSpeed / 180.0 * Math::Constants<double>::pi);
glTranslate(majorAxis+moonOrbitX, minorAxis+moonOrbitY, 0.0);
glRotatef(orbitAngle, 0.0, 1.0, 1.0);
glRotatef(rotationSpeed, 0.0, 0.0, 1.0);
}
void Planet::displayPlanet(double orbitSpeed,double rotationSpeed,
double moonOrbitX, double moonOrbitY)
{
GLuint surf;
Images::RGBImage surfaceImage;
surfaceImage=Images::readImageFile(texture);
glEnable(GL_TEXTURE_2D);
glGenTextures(0, &surf);
glBindTexture(GL_TEXTURE_2D, surf);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
surfaceImage.glTexImage2D(GL_TEXTURE_2D,0,GL_RGB);
glPushMatrix();
setOrbit(orbitSpeed,rotationSpeed, moonOrbitX, moonOrbitY);
drawSolidPlanet(equatRadius, polarRadius, 1, 40, 40);
glPopMatrix();
}
If I'm way off on what I am doing could you point me to a good tutorial? I have read a few but I guess I didn't understand them as I thought I did.
If I'm on track, could you show me where I'm wrong and what I need to do right?
You need to call glLightfv(GL_LIGHT0, GL_POSITION, pos); and set the position of the light source to the center of the sun.
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):
with my triangle.
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;
}
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.
I was trying to make a small wave generator in OpenGL with C++, using an evaluator.
However, I haven't had much luck since my evaluator only gets partially lit.
Why does this happen?
Below I include full source code for completeness' sake, you'll probably only have to look at init(), display() and the constants at the top of the file.
#include <gl/glui.h>
#include <math.h>
const int DIMX = 500;
const int DIMY = 500;
const int INITIALPOS_X = 200;
const int INITIALPOS_Y = 200;
// Aspect ratio (calculated on the fly)
float xy_aspect;
// UI aux. matrices
float view_rotate[16] = { 1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1 };
float obj_pos[] = { 0.0, 0.0, 0.0 };
float obj_pan[] = { 0.0, 0.0, 0.0 };
// Referential axis
double axis_radius_begin = 0.2;
double axis_radius_end = 0.0;
double axis_lenght = 16.0;
int axis_nslices = 8;
int axis_nstacks = 1;
// Light 0 properties
float light0_position[] = {5.0, 5.0, 5.0, 0.0};
float light0_ambient[] = {0.0, 0.0, 0.0, 1.0};
float light0_diffuse[] = {0.6, 0.6, 0.6, 1.0};
float light0_specular[] = {1.0, 1.0, 1.0, 1.0};
float light0_kc = 0.0;
float light0_kl = 1.0;
float light0_kq = 0.0;
double light0x = 5.0;
double light0y = 5.0;
double light0z = 5.0;
double symb_light0_radius = 0.2;
int symb_light0_slices = 8;
int symb_light0_stacks =8;
// Ambient light source properties
float light_ambient[] = {0.5, 0.5, 0.5, 1.0}; /* Set the background ambient lighting. */
// Windowing related variables
int main_window;
GLUquadric* glQ;
GLUI *glui;
const unsigned int gridSize = 40;
float grid[gridSize][gridSize][3];
const int uSize = gridSize;
const int vSize = gridSize;
GLfloat ambient[] = {0.2, 0.2, 0.2, 1.0};
GLfloat position[] = {0.0, 0.0, 2.0, 1.0};
GLfloat mat_diffuse[] = {0.6, 0.6, 0.6, 1.0};
GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
float mat_shininess[] = {50.0};
void display(void) {
static float value = 0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glFrustum( -xy_aspect*.04, xy_aspect*.04, -.04, .04, .1, 50.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( obj_pos[0], obj_pos[1], -obj_pos[2]-25 );
glTranslatef( obj_pan[0], obj_pan[1], obj_pan[2] );
glRotated( 20.0, 1.0,0.0,0.0 );
glRotated(-45.0, 0.0,1.0,0.0 );
glMultMatrixf( view_rotate );
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glColor3f(1.0,0.0,0.0);
glPushMatrix();
glRotated(90.0, 0.0,1.0,0.0 );
gluCylinder(glQ, axis_radius_begin, axis_radius_end,
axis_lenght, axis_nslices, axis_nstacks);
glPopMatrix();
glColor3f(0.0,1.0,0.0);
glPushMatrix();
glRotated(-90.0, 1.0,0.0,0.0 );
gluCylinder(glQ, axis_radius_begin, axis_radius_end,
axis_lenght, axis_nslices, axis_nstacks);
glPopMatrix();
glColor3f(0.0,0.0,1.0);
glPushMatrix();
gluCylinder(glQ, axis_radius_begin, axis_radius_end,
axis_lenght, axis_nslices, axis_nstacks);
glPopMatrix();
light0_position[0] = light0x;
light0_position[1] = light0y;
light0_position[2] = light0z;
glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
glColor3f(1.0,1.0,0.0);
gluQuadricOrientation( glQ, GLU_INSIDE);
glPushMatrix();
glTranslated(light0x,light0y,light0z);
gluSphere(glQ, symb_light0_radius, symb_light0_slices, symb_light0_stacks);
glPopMatrix();
gluQuadricOrientation( glQ, GLU_OUTSIDE);
gluQuadricDrawStyle(glQ, GLU_FILL);
gluQuadricNormals(glQ, GLU_SMOOTH);
gluQuadricOrientation(glQ, GLU_OUTSIDE);
gluQuadricTexture(glQ, GL_FALSE);
for (unsigned int y = 0; y < vSize; ++y) {
for (unsigned int x = 0; x < uSize; ++x) {
float xVal = 5*3.14/gridSize*x;
float yVal = 5*3.14/gridSize*y;
grid[y][x][0] = (float) x/gridSize*10.0;
grid[y][x][1] = sin(xVal + value) + sin(yVal + value);
grid[y][x][2] = (float) y/gridSize*10.0;
}
}
glMap2f(GL_MAP2_VERTEX_3, 0, 1 , 3, uSize, 0, 1, uSize * 3, vSize, &grid[0][0][0]);
glEvalMesh2(GL_FILL, 0, gridSize, 0, gridSize);
value += 3.14/25;
if (value > 3.14*2)
value = 0;
// swapping the buffers causes the rendering above to be shown
glutSwapBuffers();
glFlush();
}
/* Mouse handling */
void processMouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
}
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
}
glutPostRedisplay();
}
void processMouseMoved(int x, int y)
{
// pedido de refrescamento da janela
glutPostRedisplay();
}
void processPassiveMouseMoved(int x, int y)
{
// pedido de refrescamento da janela
glutPostRedisplay();
}
void reshape(int w, int h)
{
int tx, ty, tw, th;
GLUI_Master.get_viewport_area( &tx, &ty, &tw, &th );
glViewport( tx, ty, tw, th );
xy_aspect = (float)tw / (float)th;
glutPostRedisplay();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27: // tecla de escape termina o programa
exit(0);
break;
}
}
void glut_idle( void )
{
if ( glutGetWindow() != main_window )
glutSetWindow(main_window);
glutPostRedisplay();
}
void init()
{
glQ = gluNewQuadric();
glFrontFace(GL_CCW); // Front faces defined using a counterclockwise rotation
glDepthFunc(GL_LEQUAL); // Por defeito e GL_LESS
glEnable(GL_DEPTH_TEST); // Use a depth (z) buffer to draw only visible objects
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
// Face Culling para aumentar a velocidade
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK); // GL_FRONT, GL_BACK, GL_FRONT_AND_BACK
// Define que modelo de iluminacao utilizar; consultar o manual de referencia
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, light_ambient); // define luz ambiente
glLightModelf (GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
// por defeito a cor de fundo e o preto
// glClearColor(1.0,1.0,1.0,1.0); // cor de fundo a branco
// declaracoes para a fonte luz GL_LIGHT0
glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, light0_kc);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, light0_kl);
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, light0_kq);
// NOTA: a direccao e a posicao de GL_LIGHT0 estao na rotina display(), pelo
// que as isntrucoes seguntes nao sao necessarias
//glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 90.0);
//glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);
//glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
glEnable(GL_MAP2_VERTEX_3);
glMapGrid2f(gridSize, 0.0, 1.0, gridSize, 0.0, 1.0);
glShadeModel(GL_SMOOTH);
glPolygonMode(GL_FRONT, GL_FILL);
//glPolygonMode(GL_FRONT, GL_LINE);
}
void do_nothing(int key, int x, int y) {}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize (DIMX, DIMY);
glutInitWindowPosition (INITIALPOS_X, INITIALPOS_Y);
main_window = glutCreateWindow (argv[0]);
glutDisplayFunc(display);
GLUI_Master.set_glutReshapeFunc(reshape);
GLUI_Master.set_glutKeyboardFunc (keyboard);
GLUI_Master.set_glutMouseFunc(processMouse);
glutMotionFunc(processMouseMoved);
glutPassiveMotionFunc(processPassiveMouseMoved);
GLUI_Master.set_glutSpecialFunc( do_nothing );
/*** Create the bottom subwindow ***/
glui = GLUI_Master.create_glui_subwindow( main_window, GLUI_SUBWINDOW_BOTTOM );
glui->set_main_gfx_window( main_window );
GLUI_Rotation *view_rot = glui->add_rotation( "Rotation", view_rotate );
view_rot->set_spin( 1.0 );
glui->add_column( false );
GLUI_Translation *trans_z = glui->add_translation( "Zoom", GLUI_TRANSLATION_Z, &obj_pos[2] );
trans_z->set_speed( .1 );
glui->add_column(false);
GLUI_Translation *trans_pan = glui->add_translation("Pan", GLUI_TRANSLATION_XY, &obj_pan[0]);
trans_pan->set_speed(.1);
GLUI_Master.set_glutIdleFunc( glut_idle );
init();
glutMainLoop();
return 0;
}
You say OpenGL evaluators don't need normals to set. This is only partly true. You only don't need to set normals if you enable automatically generated normals for evaluators by calling:
glEnable(GL_AUTO_NORMAL);
Just enabling GL_NORMALIZE won't do it.
But you can of course also specify your own normals by providing control points for GL_MAP2_NORMAL in the same way like for GL_MAP2_VERTEX_3.
And the answer won't be complete without mentioning that OpenGL evaluators are highly deprecated and most probably implemented in softare by the driver. So just rolling your own Bezier evaluation code (which is not very hard) and generating a simple mesh grid drawn as GL_TRIANGLES will surely be a better idea.