Scientific Visualization and Animation using Bezier Surfaces
An Introduction |
Prof. David Bernstein |
Computer Science Department |
bernstdh@jmu.edu |
glMapGrid2f()
)glEvalMesh2()
#include <math.h> #include <stdlib.h> #include <stdio.h> #include <windows.h> #include "../sva/sva.h" // Must be after windows.h #include "GL/gl.h" /** * An application for "editing" Bezier surfaces * * Mouse Commands: * * Left-Drag: To move a point * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ /** * A second order surface */ GLfloat points[2][2][3] = { { {-2.0, -2.0, 0.0}, { 2.0, -2.0, 0.0}}, { {-2.0, 2.0, 0.0}, { 2.0, 2.0, 0.0}} }; int uSize = 2; int vSize = 2; /* * A fourth order surface GLfloat points[4][4][3] = { { {-2.0, -2.0, 0.0}, {-0.5, -2.0, 0.0}, { 0.5, -2.0, 0.0}, { 2.0, -2.0, 0.0}}, { {-2.0, -0.5, 0.0}, {-0.5, -0.5, 0.0}, { 0.5, -0.5, 0.0}, { 2.0, -0.5, 0.0}}, { {-2.0, 0.5, 0.0}, {-0.5, 0.5, 0.0}, { 0.5, 0.5, 0.0}, { 2.0, 0.5, 0.0}}, { {-2.0, 2.0, 0.0}, {-0.5, 2.0, 0.0}, { 0.5, 2.0, 0.0}, { 2.0, 2.0, 0.0}} }; int uSize = 4; int vSize = 4; */ // The number of subdivisions in the grid int gridSize = 20; int uSelected = -1; int vSelected = -1; // Empty SVA functions void onMouseMove(GLfloat x, GLfloat y){} void onTimer(int time){} // Prototypes GLfloat distanceSquared(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2); /** * Find the closest point controlling the curve * * @param x The x-coordinate to compare to * @param y The y-coordinate to compare to * @param z The z-coordinate to compare to * @param ui The u-index of the clossest point (OUT) * @param vi The v-index of the clossest point (OUR) */ void closestPointTo(GLfloat x, GLfloat y, GLfloat z, int &ui, int &vi) { GLfloat d, min; ui = -1; vi = -1; min = distanceSquared(points[0][0][0], points[0][0][1], points[0][0][2], x, y, z); ui = 0; vi = 0; for (int u=0; u<uSize; u++) { for (int v=0; v<vSize; v++) { d = distanceSquared(points[u][v][0], points[u][v][1], points[u][v][2], x, y, z); if (d < min) { ui = u; vi = v; min = d; } } } } /** * Return the squared Euclidean sistance between two points */ GLfloat distanceSquared(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2) { GLfloat d; d = (x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2) + (z1 - z2)*(z1 - z2); return d; } /** * Display Callback */ void onDisplay() { // Clear the screen glClear(GL_COLOR_BUFFER_BIT); // Set the color glColor3f(1.0, 0.0, 0.0); // // The evaluator glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, uSize, 0, 1, uSize*3, vSize, &points[0][0][0]); // Draw the mesh glEvalMesh2(GL_LINE, 0, gridSize, 0, gridSize); // Show the points glPointSize(3.); glBegin(GL_POINTS); { for (int u=0; u<uSize; u++) { for (int v=0; v<vSize; v++) { if ((u == uSelected) && (v == vSelected)) { glColor3f(1.0, 0.0, 1.0); glVertex3fv(&points[u][v][0]); } else { glColor3f(0.0, 1.0, 0.0); glVertex3fv(&points[u][v][0]); } } } glEnd(); } } /** * The mouse callback (i.e., the function that is called * each time a mouse button is pressed or released). * * @param button The button (e.g., GLUT_LEFT_BUTTON) * @param state The state (e.g., GLUT_UP or GLUT_DOWN) * @param x The x-position of the mouse * @param y The y-position of the mouse */ void onMouseClick(int button, int state, GLfloat x, GLfloat y) { if(button == SVA_LEFT_BUTTON) { if (state == SVA_DOWN) { closestPointTo(x, y, 0.0, uSelected, vSelected); } else { uSelected = -1; vSelected = -1; } svaRedisplay(); } } /** * The mouse drag callback * * @param x The x-position of the mouse * @param y The y-position of the mouse */ void onMouseDrag(GLfloat x, GLfloat y) { if ((uSelected >= 0) && (vSelected >= 0)) { points[uSelected][vSelected][0] = x; points[uSelected][vSelected][1] = y; svaRedisplay(); } } /** * The entry point of the application. * * @param argc The number of command line arguments * @param argv The array of command line arguments * @return A status code */ int main(int argc, char **argv) { float min[] = {-4.0, -4.0, -4.0}; float max[] = { 4.0, 4.0, 4.0}; int k; // Create and initialize the SVA window svaCreate(argc, argv, min, max); svaShowAxes(false); svaSetRotation(0.0, 0.0, 0.0); // Enable the 2-dimensional evaluator glEnable(GL_MAP2_VERTEX_3); glMapGrid2f(gridSize, 0.0, 1.0, gridSize, 0.0, 1.0); // Start the SVA visualization svaStartVisualization(); }
// Enable lighting and shading GLfloat ambient[] = {0.2, 0.2, 0.2, 1.0}; GLfloat position[] = {0.0, 0.0, 2.0, 1.0}; GLfloat diffuse[] = {0.7, 0.0, 0.1, 1.0}; GLfloat specular[] = {1.0, 1.0, 1.0, 1.0}; GLfloat shininess[] = {50.0}; glEnable(GL_LIGHTING); // Enable lighting glEnable(GL_LIGHT0); // Enable light 0 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_POSITION, position); glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, specular); glMaterialfv(GL_FRONT, GL_SHININESS, shininess); glEnable(GL_DEPTH_TEST); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); // Enable the 2-dimensional evaluator glEnable(GL_MAP2_VERTEX_3); glMapGrid2f(gridSize, 0.0, 1.0, gridSize, 0.0, 1.0);