From Pixels to Shapes
Transcription
From Pixels to Shapes
From Pixels to Shapes Any use of computers to make/create images. Areas? Applications? So, where does it all start? Any use of computers to make/create images. Areas? Modeling / Rendering / Animation / User Interaction / Virtual Reality / Visualization / Image Processing / 3D Scanning Applications? Video Games / Cartoons / Film Special Effects / CAD and CAM / Simulation / Medical Imaging / Information Visualization / Scientific Visualization / Charts (Business) So, where does it all start? Pixels! Fundamental Building Block Dots of Light Colors Resolution Wide variety Resolution Monitor Intensities and Gamma Frame Buffers RGB Color Alpha Channel Color Red Green Blue Yellow 1 1 0 White 1 1 1 Black 0 0 0 Cyan 0 1 1 Magenta 1 0 1 Where to we place the pixels? Clipping OpenGL and GLUT As you noticed yesterday, we don’t have machines yet – they are coming! (Picture Dr. Smith and I jumping up and down in excitement – the actual picture was too disturbing to place in the notes.) Currently, we will go over the code in the book and you may feel free to install versions on your own machines (as I mentioned yesterday). Hopefully, next week, we will quickly go back through the examples together and begin altering them and creating some of our own. (See Appendix A for instructions.) //Example1_1.cpp : a simple example to open a window #include <windows.h> //the windows include file, required by all windows applications #include <gl\glut.h> //the glut file for windows operations - it also includes gl.h and glu.h for the openGL library calls void Display(void) { glClear(GL_COLOR_BUFFER_BIT); //clear all pixels with the specified clear color glFlush(); //dont wait, start flushing opengl calls to display buffer } void init(void) { glClearColor(1.0,0.0,0.0,1.0); //set the clear color to be red glViewport(0,0,320,240); // set the viewport to be 320 by 240, the initial size of the window gluOrtho2D(0.0, 160.0, 0.0, 120.0); // set the 2D clipping area } void main(int argc, char* argv[]) { glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (320, 240); glutCreateWindow("My First OpenGL Window"); init(); glutDisplayFunc(Display); glutMainLoop(); } //the windows include file, required by all windows applications #include <windows.h> //the glut file for windows operations - it also includes gl.h and glu.h for the openGL library calls #include <gl\glut.h> void main(int argc, char* argv[]) { glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (320, 240); glutCreateWindow("My First OpenGL Window"); init(); glutDisplayFunc(Display); glutMainLoop(); } void init(void) { glClearColor(1.0,0.0,0.0,1.0); //set the clear color to be red glViewport(0,0,320,240); // set the viewport to be 320 by 240, the initial size of the window gluOrtho2D(0.0, 160.0, 0.0, 120.0); // set the 2D clipping area } void Display(void) { glClear(GL_COLOR_BUFFER_BIT); //clear all pixels with the specified clear color glFlush(); //dont wait, start flushing opengl calls to display buffer } Objects and scenes consist of combinations of shapes Points Lines Circles Rectangles Other graphics primitives Primitives in OpenGL are drawn as a point (one or more) which is represented as a “vertex” glVertex2f(1.0,2.0); refers to a vertex point at (1.0,2.0) Vertices are bracketed between calls to glBegin() and glEnd(). The type of primitive being drawn is passed in as a parameter to glBegin (in this case, GL_POINTS) //Example1_2.cpp : let the drawing begin #include <windows.h> //the windows include file, required by all windows applications #include <gl\glut.h> //the glut file for windows operations - it also includes gl.h and glu.h for the openGL library calls void Display(void) { glClear(GL_COLOR_BUFFER_BIT); //clear all pixels with the specified clear color glBegin(GL_POINTS); glColor3f(0.0, 1.0, 0.0); glVertex2f(10.,10.); glColor3f(1.0, 1.0, 0.0); glVertex2f(10.,110.); glColor3f(0.0, 0.0, 1.0); glVertex2f(150.,110.); glColor3f(1.0, 1.0, 1.0); glVertex2f(150.,10.); glEnd(); /* green */ /* yellow */ /* blue */ /* white */ glFlush(); //dont wait, start flushing opengl calls to display buffer } void reshape (int w, int h) { glViewport (0, 0, (GLsizei) w, (GLsizei) h); // on reshape and on startup, keep the viewport to be the entire size of the window glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluOrtho2D(0.0, 160.0, 0.0, 120.0); // keep our logical coordinate system constant } void init(void) { glClearColor(1.0,0.0,0.0,1.0); //set the clear color to be red glPointSize(5.0); // set the point size to be 3.0 pixels } void main(int argc, char* argv[]) { glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (320, 240); glutCreateWindow("My First OpenGL Window"); init(); glutDisplayFunc(Display); glutReshapeFunc(reshape); glutMainLoop(); } void main(int argc, char* argv[]) { glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (320, 240); glutCreateWindow("My First OpenGL Window"); init(); glutDisplayFunc(Display); glutReshapeFunc(reshape); glutMainLoop(); } void init(void) { glClearColor(1.0,0.0,0.0,1.0); //set the clear color to be red glPointSize(5.0); // set the point size to be 5.0 pixels } void Display(void) { glClear(GL_COLOR_BUFFER_BIT); //clear all pixels with the specified clear color glBegin(GL_POINTS); glColor3f(0.0, 1.0, 0.0); glVertex2f(10.,10.); glColor3f(1.0, 1.0, 0.0); glVertex2f(10.,110.); glColor3f(0.0, 0.0, 1.0); glVertex2f(150.,110.); glColor3f(1.0, 1.0, 1.0); glVertex2f(150.,10.); glEnd(); /* green */ /* yellow */ /* blue */ /* white */ glFlush(); //dont wait, start flushing opengl calls to display buffer } void reshape (int w, int h) { glViewport (0, 0, (GLsizei) w, (GLsizei) h); // on reshape and on startup, keep the viewport to be the entire size of the window glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluOrtho2D(0.0, 160.0, 0.0, 120.0); // keep our logical coordinate system constant } We know how to draw a line, circle, or other shape – how do we get a computer to do it? Find the right pixels to turn on – aka scan conversion or rasterizing Popular line drawing algorithm: midpointline algorithm Idea: Give the x,y coordinates of the endpoints Algorithm then calculates all the x,y coordinates between them. First, calculates physical pixels for each endpoint Ideal line drawn between them, used as a reference to determine which pixels to light up along the way. Pixels less than .5 units from the line are turned on Triangles and Polygons – drawn as series of lines (vertices connected by lines) To specify shapes, we use a call to glVertex surrounded by calls to glBegin() and glEnd() Arguments for glBegin are: Primitive Definition Meaning GL_POINTS Individual points GL_LINES Pair of vertices defining a line GL_LINE_STRIP Series of connected lines GL_TRIANGLES Strip of linked triangles GL_POLYGON Vertices define a simple convex polygon Curved shapes can also be created with algorithms or by drawing a large number of short, straight lines Remember your trigonometry? Any point on a circle’s radius (and centered at the origin) has an x,y coordinate pair that can be represented as a function of the angle theta the point makes with the axes (see fig 1.14, p. 21) P(theta)=((rcos(theta)),(rsin(theta))) GLint circle_points = 100; void MyCircle2f(GLfloat centerx, GLfloat centery, GLfloat radius) { GLint i; GLdouble theta; glBegin(GL_POLYGON); for (i = 0; i < circle_points; i++) { theta = 2*PI*i/circle_points; glVertex2f(centerx+radius*cos(theta), centery+radius*sin(theta)); } glEnd(); } Now, we can make a simple drawing – let’s look at the code for a stick figure (seen in your text as figure 1.15) //Example1_3 : A stick figure #include <windows.h> //the windows include file, required by all windows applications #include <math.h> // included for the cos and sin functions #include <gl\glut.h> //the glut file for windows operations - it also includes gl.h and glu.h for the openGL library calls // routine to draw a circle approximated by line segments #define PI 3.1415926535898 // recall that cos and sin functions require angles in radians so 2PI radians = 360 degrees, a full circle GLint circle_points = 100; void MyCircle2f(GLfloat centerx, GLfloat centery, GLfloat radius) { GLint i; GLdouble theta; glBegin(GL_POLYGON); for (i = 0; i < circle_points; i++) { theta = 2*PI*i/circle_points; glVertex2f(centerx+radius*cos(theta), centery+radius*sin(theta)); } glEnd(); } void Display(void) { //clear all pixels with the specified clear color glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0,0.8,0.1); MyCircle2f(80.,85., 10.); // the eyes are black points // set the point size to be 3.0 pixels glBegin(GL_POINTS); glColor3f(0.0, 0.0, 0.0); glVertex2f(77.,88.); glVertex2f(83.,88.); glEnd(); // polygonal body glColor3f(0.8,0.0,0.9); glBegin(GL_POLYGON); glVertex2f(75.,75.); glVertex2f(85.,75.); glVertex2f(100.,30.); glVertex2f(60.,30.); glEnd(); //rectangular legs glColor3f(1.0,0.8,0.1); glRectf(70.,5.,75.,30.); glRectf(85.,5.,90.,30.); // but lines for hands! glBegin(GL_LINES); glVertex2f (74.,70.); glVertex2f (50.,50.); glEnd(); glBegin(GL_LINES); glVertex2f (86.,70.); glVertex2f (110.,50.); glEnd(); //dont wait, start flushing opengl calls to display buffer glFlush(); } void reshape (int w, int h) { glViewport (0, 0, (GLsizei) w, (GLsizei) h); // on reshape and on startup, keep the viewport to be the entire size of the window glMatrixMode (GL_PROJECTION); glLoadIdentity (); // keep our logical coordinate system constant gluOrtho2D(0.0, 160.0, 0.0, 120.0); } void init(void){ //set the clear color to be white glClearColor(1.0,1.,1.0,1.0); // set the point size of points drawn to be 5.0 pixels glPointSize(5.0); // set the line width to be 5.0 pixels glLineWidth(5.0); // polygons drawn should be filled glPolygonMode(GL_FRONT, GL_FILL); } void main(int argc, char* argv[]) { glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (320, 240); glutCreateWindow("My First OpenGL Window"); init(); glutDisplayFunc(Display); glutReshapeFunc(reshape); glutMainLoop(); } Most scan conversion code creates jagged edges (known as “jaggies”) High resolution monitors – no big deal Low resolution monitors – harsh! Solution? Anti-Aliasing! Pixels set to different intensities and properly manipulated based on their position relative to one another can be manipulated so that they blend to form a smooth image. (We’re tricking our eyes!) For a line, this means turning on pixels with varying intensities instead of just on or off (like a dimmer on a light switch) Makes image look more continuous, though sometimes blurry. Two steps: Turn on antialiasing with glEnable(), passing in GL_POINT_SMOOTH or GL_LINE_SMOOTH as appropriate Enable blending by using a blending factor. Probably want to use GL_SRC_ALPHA (source) and GL_ONE_MINUS_SRC_ALPHA (destination) Commands – in the init() function: void init(void){ glEnable (GL_LINE_SMOOTH); glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glHint (GL_LINE_SMOOTH_HINT | GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE); //set the clear color to be white glClearColor(0.0,0.8,0.0,1.0); // set the point size of points drawn to be 5.0 pixels glPointSize(5.0); // set the line width to be 5.0 pixels glLineWidth(5.0); // polygons drawn should be filled glPolygonMode(GL_FRONT, GL_FILL); } //Example1_4.cpp : An anti-aliased stick figure #include <windows.h> //the windows include file, required by all windows applications #include <math.h> // included for the cos and sin functions #include <gl\glut.h> //the glut file for windows operations // it also includes gl.h and glu.h for the openGL library calls // routine to draw a circle approximated by line segments #define PI 3.1415926535898 GLint circle_points = 100; void MyCircle2f(GLfloat centerx, GLfloat centery, GLfloat radius){ GLint i; GLdouble angle; glBegin(GL_POLYGON); for (i = 0; i < circle_points; i++) { angle = 2*PI*i/circle_points; glVertex2f(centerx+radius*cos(angle), centery+radius*sin(angle)); } glEnd(); } void Display(void) { //clear all pixels with the specified clear color glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0,0.8,0.1); MyCircle2f(80.,85., 10.); // the eyes are black points // set the point size to be 3.0 pixels glBegin(GL_POINTS); glColor3f(0.0, 0.0, 0.0); glVertex2f(77.,88.); glVertex2f(83.,88.); glEnd(); // polygonal body glColor3f(0.8,0.0,0.9); glBegin(GL_POLYGON); glVertex2f(75.,75.); glVertex2f(85.,75.); glVertex2f(100.,30.); glVertex2f(60.,30.); glEnd(); //rectangular legs glColor3f(1.0,0.8,0.1); glRectf(70.,5.,75.,30.); glRectf(85.,5.,90.,30.); // but lines for hands! glBegin(GL_LINES); glVertex2f (74.,70.); glVertex2f (50.,50.); glEnd(); glBegin(GL_LINES); glVertex2f (86.,70.); glVertex2f (110.,50.); glEnd(); //dont wait, start flushing opengl calls to display buffer glFlush(); } void reshape (int w, int h) { // on reshape and on startup, keep the viewport to be the entire size of the window glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode (GL_PROJECTION); glLoadIdentity (); // keep our logical coordinate system constant gluOrtho2D(0.0, 160.0, 0.0, 120.0); } void init(void){ glEnable (GL_LINE_SMOOTH); glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glHint (GL_LINE_SMOOTH_HINT | GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE); //set the clear color to be white glClearColor(0.0,0.8,0.0,1.0); // set the point size of points drawn to be 5.0 pixels glPointSize(5.0); // set the line width to be 5.0 pixels glLineWidth(5.0); // polygons drawn should be filled glPolygonMode(GL_FRONT, GL_FILL); } void main(int argc, char* argv[]) { glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (320, 240); glutCreateWindow("Anti-Aliased Stick Figure"); init(); glutDisplayFunc(Display); glutReshapeFunc(reshape); glutMainLoop(); }