44. Evaluators, Curves and Surfaces
Dated: 14-07-2025
Evaluators
A Bézier curve
1 is a vector valued function
2 of one variable
where \(u \in [0, 1]\)
A Bézier surface
1 patch is a vector valued function
2 of two variables
To use an evaluator
, first define the function
C()
or S()
, enable it, and then use the glEvalCoord1()
or glEvalCoord2()
command instead of glVertex*()
.
One Dimensional Evaluators
This section presents an example of using one dimensional evaluators
to draw a curve
. It then describes the commands and equations that control evaluators
.
A Simple Bézier Curve
1
#include <GL/gl.h>
#include <GL/glu.h>
#include <stdlib.h>
#include <GL/glut.h>
GLfloat ctrlpoints[4][3] = {
{-4.0, -4.0, 0.0}, {-2.0, 4.0, 0.0},
{ 2.0, -4.0, 0.0}, { 4.0, 4.0, 0.0}
};
void init(void) {
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]);
glEnable(GL_MAP1_VERTEX_3);
}
void display(void) {
int i;
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINE_STRIP);
for (i = 0; i <= 30; i++)
glEvalCoord1f((GLfloat) i/30.0);
glEnd();
/* The following code displays the control points as dots. */
glPointSize(5.0);
glColor3f(1.0, 1.0, 0.0);
glBegin(GL_POINTS);
for (i = 0; i < 4; i++)
glVertex3fv(&ctrlpoints[i][0]);
glEnd();
glFlush();
}
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(
-5.0, 5.0, -5.0 * (GLfloat)h / (GLfloat)w,
5.0 * (GLfloat)h / (GLfloat)w, -5.0, 5.0
);
else
glOrtho(
-5.0 * (GLfloat)w / (GLfloat)h,
5.0 * (GLfloat)w / (GLfloat)h, -5.0, 5.0, -5.0, 5.0
);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
Code result
Pay attention to the following statement from the code
glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]);
Argument | Meaning |
---|---|
GL_MAP1_VERTEX_3 |
3 dimensional control points are provided and 3 dimensional vertices are produced |
\(0.0\) | Low value of parameter u |
\(1.0\) | High value of parameter u |
\(3\) | The number of floating point values to advance in the data between one control point and the next |
\(4\) | The order of of the spline which is degree + 1. Since it is cubic, therefore, degree is \(3\) |
&ctrlpoints[0][0] |
Pointer to the first control point's data |
Defining and Evaluating a One Dimensional Evaluator
The Bernstein polynomial of degree
\(n\) (or order
\(n + 1\)) is given by
If \(P_i\) is the set
3 of control points (of any dimension \(n\) then)
represents a Bézier curve
1 as \(u\) varies from \(0.0\) to \(1.0\).
To represent the same curve but \(u \in [u_1, u_2]\), evaluate
void glMap1f(GLenum target, TYPE u1, TYPE u2, GLint stride, GLint order, const TYPE *points);
void glMap1d(GLenum target, TYPE u1, TYPE u2, GLint stride, GLint order, const TYPE *points);
target
tells what the control points represent.vertices
RGBA
color datanormal vectors
4texture coordinates
u1
shows the lower range for variable \(u\).u2
shows the upper range for variable \(u\).stride
tells the number of single or double precision values in each block of storage.order
tells theorder
, that is \(\text{order} = \text{degree} + 1\)
Parameter | Meaning |
---|---|
GL_MAP1_VERTEX3 |
\(x, y, z\) vertex coordinates |
GL_MAP1_VERTEX4 |
\(x, y, z, w\) vertex coordinates |
GL_MAP1_INDEX |
color index |
GL_MAP1_COLOR_4 |
R , G , B , A |
GL_MAP1_NORMAL |
normal coordinates |
GL_MAP1_TEXTURE_COORD_1 |
\(s\) texture coordinates |
GL_MAP1_TEXTURE_COORD_2 |
\(s, t\) texture coordinates |
GL_MAP1_TEXTURE_COORD_3 |
\(s, t, r\) texture coordinates |
GL_MAP1_TEXTURE_COORD_4 |
\(s, t, r, q\) texture coordinates |
If you have both defined and enabled
GL_MAP1_VERTEX_3
GL_MAP1_COLOR_4
then calls to glEvalCoord1()
generate both
- position
- color
void glEvalCoord1f(TYPE u);
void glEvalCoord1d(TYPE u);
void glEvalCoord1fv(TYPE *u);
void glEvalCoord1dv(TYPE *u);
Causes evaluation of the enabled one dimensional maps
.
Defining Evenly Spaced Coordinate Values in One Dimension
void glMapGrid1f(GLint n, TYPE u1, TYPE u2);
void glMapGrid1d(GLint n, TYPE u1, TYPE u2);
Defines a grid
that goes from u1
to u2
in n
steps, which are evenly spaced.
void glEvalMesh1(GLenum mode, GLint p1, GLint p2);
Applies the currently defined map grid
to all enabled evaluators.
The mode can be
GL_POINT
GL_LINE
Two Dimensional Evaluators
In two dimensions, everything is similar to the one dimensional case, except that all the commands must take two parameters, \(u\) and \(v\), into account.
Mathematically, the definition of a Bézier surface
1 patch is given by
Where \(P_{ij}\) are a set
3 of \(m \times n\) control points and can represent
vertices
normals
4- colors
- texture coordinates
The procedure to use two dimensional evaluators is similar to the procedure for one dimension.
- Define the evaluator(s) with
glMap2*()
. - Enable them by passing the appropriate value to
glEnable()
. - Invoke them either by calling
glEvalCoord2()
between aglBegin()
andglEnd()
pair or by specifying and then applying a mesh withglMapGrid2()
andglEvalMesh2()
.
Defining and Evaluating a Two Dimensional Evaluator
Use glMap2*()
and glEvalCoord2*()
to define and then invoke a two dimensional evaluator.
glMap2f(GLenum target, TYPE u1, TYPE u2, GLint ustride, GLint uorder, TYPE v1, TYPE v2, GLint vstride, GLint vorder, TYPE points);
glMap2d(GLenum target, TYPE u1, TYPE u2, GLint ustride, GLint uorder, TYPE v1, TYPE v2, GLint vstride, GLint vorder, TYPE points);
void glEvalCoord2f(TYPE u, TYPE v);
void glEvalCoord2d(TYPE u, TYPE v);
void glEvalCoord2fv(TYPE *values);
void glEvalCoord2dv(TYPE *values);
Causes evaluation of the enabled two dimensional maps
. If either of the vertex evaluators is enabled
GL_MAP2_VERTEX_3
GL_MAP2_VERTEX_4
then the normal
4 to the surface is computed analytically.
Two Dimensional Example: a Bézier Surface
1
#include <GL/gl.h>
#include <GL/glu.h>
#include <stdlib.h>
#include <GL/glut.h>
GLfloat ctrlpoints[4][4][3] = {
{
{-1.5, -1.5, 4.0}, {-0.5, -1.5, 2.0},
{ 0.5, -1.5, -1.0}, { 1.5, -1.5, 2.0}
},
{
{-1.5, -0.5, 1.0}, {-0.5, -0.5, 3.0},
{ 0.5, -0.5, 0.0}, { 1.5, -0.5, -1.0}
},
{
{-1.5, 0.5, 4.0}, {-0.5, 0.5, 0.0},
{ 0.5, 0.5, 3.0}, { 1.5, 0.5, 4.0}
},
{
{-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0},
{ 0.5, 1.5, 0.0}, { 1.5, 1.5, -1.0}
}
};
void display(void) {
int i, j;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glPushMatrix ();
glRotatef(85.0, 1.0, 1.0, 1.0);
for (j = 0; j <= 8; j++) {
glBegin(GL_LINE_STRIP);
for (i = 0; i <= 30; i++)
glEvalCoord2f((GLfloat)i/30.0, (GLfloat)j/8.0);
glEnd();
glBegin(GL_LINE_STRIP);
for (i = 0; i <= 30; i++)
glEvalCoord2f((GLfloat)j/8.0, (GLfloat)i/30.0);
glEnd();
}
glPopMatrix();
glFlush();
}
void init(void) {
glClearColor(0.0, 0.0, 0.0, 0.0);
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4,0, 1, 12, 4, &ctrlpoints[0][0][0]);
glEnable(GL_MAP2_VERTEX_3);
glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_FLAT);
}
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(
-5.0, 5.0, -5.0 * (GLfloat)h / (GLfloat)w,
5.0 * (GLfloat)h / (GLfloat)w, -5.0, 5.0
);
else
glOrtho(
-5.0 * (GLfloat)w / (GLfloat)h,
5.0 * (GLfloat)w / (GLfloat)h, -5.0, 5.0, -5.0, 5.0
);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
Code Result
Defining Evenly Spaced Coordinate Values in Two Dimensions
void glMapGrid2f(GLint nu, TYPE u1, TYPE u2, GLint nv, TYPE v1, TYPE v2);
void glMapGrid2d(GLint nu, TYPE u1, TYPE u2, GLint nv, TYPE v1, TYPE v2);
void glEvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2);
Defines a two dimensional map grid that goes from u1
to u2
in nu
evenly spaced steps from v1
to v2
in nv
steps (glMapGrid2*()
) and then applies this grid to all enabled evaluators (glEvalMesh2()
).
The mode parameter is glEvalMesh2()
can be
GL_FILL
GL_POINT
GL_LINE
#include <GL/gl.h>
#include <GL/glu.h>
#include <stdlib.h>
#include <GL/glut.h>
GLfloat ctrlpoints[4][4][3] = {
{
{-1.5, -1.5, 4.0}, {-0.5, -1.5, 2.0},
{ 0.5, -1.5, -1.0}, { 1.5, -1.5, 2.0}
},
{
{-1.5, -0.5, 1.0}, {-0.5, -0.5, 3.0},
{ 0.5, -0.5, 0.0}, { 1.5, -0.5, -1.0}
},
{
{-1.5, 0.5, 4.0}, {-0.5, 0.5, 0.0},
{ 0.5, 0.5, 3.0}, { 1.5, 0.5, 4.0}
},
{
{-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0},
{ 0.5, 1.5, 0.0}, { 1.5, 1.5, -1.0}
}
};
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(85.0, 1.0, 1.0, 1.0);
glEvalMesh2(GL_FILL, 0, 20, 0, 20);
glPopMatrix();
glFlush();
}
void initlights(void) {
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};
GLfloat mat_shininess[] = {50.0};
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
}
void init(void) {
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
glMap2f(
GL_MAP2_VERTEX_3, 0, 1, 3, 4,
0, 1, 12, 4, &ctrlpoints[0][0][0]
);
glEnable(GL_MAP2_VERTEX_3);
glEnable(GL_AUTO_NORMAL);
glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
initlights();
}
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(
-5.0, 5.0, -5.0 * (GLfloat)h / (GLfloat)w,
5.0 * (GLfloat)h / (GLfloat)w, -5.0, 5.0
);
else
glOrtho(
-5.0 * (GLfloat)w / (GLfloat)h,
5.0 * (GLfloat)w / (GLfloat)h, -5.0, 5.0, -5.0, 5.0
);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
code result