《计算机图形学基础》
实验4 OpenGL中基本图形的绘制
一、实验目的及要求
1. 掌握OpenGL中点的绘制方法。
2. 掌握OpenGL中直线的绘制方法。
3. 掌握OpenGL中多边形面的绘制方法。
4. 掌握OpenGL中字符函数的绘制方法。
二、实验环境
主要是软件开发环境 vc 6.0
三、实验内容
OpenGL实现直线段的反走样。
四、实验结果
五、程序代码
#include <gl/glut.h>
GLuint lineList; //指定显示列表ID
void Initial()
{
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
glLineWidth(12.0f);
glColor4f (0.0, 0.6, 1.0, 1.0);
lineList = glGenLists(1);
glNewList(lineList, GL_COMPILE); //定义显示列表
glBegin(GL_LINE_LOOP);
glVertex2f(1.0f, 1.0f);
glVertex2f(4.0f, 2.0f);
glVertex2f(2.0f, 5.0f);
glEnd();
glEndList();
}
void ChangeSize(GLsizei w, GLsizei h)
{
if(h == 0) h = 1;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w<=h)
gluOrtho2D(0.0, 5.0, 0.0, 6.0*(GLfloat)h/(GLfloat)w);
else
gluOrtho2D(0.0, 5.0*(GLfloat)w/(GLfloat)h, 0.0, 6.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void Displayt(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glCallList(lineList);
glFlush();
}
void Displayw(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_LINE_SMOOTH); //使用反走样
glEnable (GL_BLEND); //启用混合函数
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //指定混合函数
glCallList(lineList);
glFlush();
}
void main(void)
{
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(300, 300);
glutCreateWindow("原始图形");
glutDisplayFunc(Displayt);
glutReshapeFunc(ChangeSize);
Initial();
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(300, 300);
glutInitWindowSize(300, 300);
glutCreateWindow("反走样图形");
glutDisplayFunc(Displayw);
glutReshapeFunc(ChangeSize);
Initial();
glutMainLoop();
}
六、心得体会
在光栅图形显示器上绘制非水平且非垂直的直线或多边形边界时,或多或少会呈现锯齿状或台阶状外观。这是因为直线、多边形、色彩边界等是连续的,而光栅则是由离散的点组成,在光栅显示设备上表现直线、多边形等,必须在离散位置采样。由于采样不充分重建后造成的信息失真,就叫走样。而用于减少或消除这种效果的技术,就称为反走样。OpenGL实现反走样需要满足两个条件,一是启用混合,二是启用针对几何图元的反走样处理。
要使用OpenGL的混合功能,只需要调用:glEnable(GL_BLEND)。
要关闭OpenGL的混合功能,只需要调用:glDisable(GL_BLEND)。
第二篇:交互式图形学-基于OPenGL自顶向下(第五版)课后实例程序全
怎么上传不了啊!!!!!
A.1 Sierpinski
镂垫程序
/* two-dimensional Sierpinski gasket */
/* generated using randomly selected vertices */
/* and bisection */
#include <GL/glut.h>
/*you may have to change the include to<glut.h> or
elsewhere depending on where it is stored on your system */
/* glut.h usually has included for gl.h and glu.h */
void myinit(void)
{
/* attributes */
glClearColor(1.0, 1.0, 1.0, 1.0); /* white background */
glColor3f(1.0, 0.0, 0.0); /* draw in red */
/* set up viewing */
/* 50.0 × 50.0 camera coordinate window with origin lower left */ glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 50.0, 0.0, 50.0);
glMatrixMode(GL_MODELVIEW);
}
void display(void)
{
/* A triangle */
GLfloat vertices[3][2]={{0.0,0.0},{25.0,50.0},{50.0,0.0}};
int i, j, k;
int rand(); /* standard random number generator */
GLfloat p[2] ={7.5,5.0}; /* an arbitrary initial point inside traingle */ glClear(GL_COLOR_BUFFER_BIT); /* clear the window */
586 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
glBegin(GL_POINTS);
/* compute and plots 5000 new points */
for( k=0; k<5000; k++)
{
j=rand()%3; /* pick a vertex at random */
/* Compute point halfway between selected vertex and old point */
p[0] = (p[0]+vertices[j][0])/2.0;
p[1] = (p[1]+vertices[j][1])/2.0;
/* plot new point */
glVertex2fv(p);
}
glEnd();
glFlush(); /* clear buffers */
}
void main(int argc, char** argv)
{
/* Standard GLUT initialization */
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); /* default, not needed */ glutInitWindowSize(500,500); /* 500 × 500 pixel window */
glutInitWindowPosition(0,0); /* place window top left on display */ glutCreateWindow("Sierpinski Gasket"); /* window title */
glutDisplayFunc(display);
/* display callback invoked when window opened */
myinit(); /* set attributes */
glutMainLoop(); /* enter event loop */
}
A.2 生成Sierpinski镂垫的递归程序
/* Recursive subdivision of triangle to form Sierpinski gasket */ /* number of recursive steps given on command line */
#include <GL/glut.h>
#include<stdlib.h>
/* initial triangle */
GLfloat v[3][2]={{-1.0, -0.58}, {1.0, -0.58}, {0.0, 1.15}};
附录A 实 例 程 序
int n;
void triangle( GLfloat *a, GLfloat *b, GLfloat *c)
/* display one triangle */
{
glVertex2fv(a);
glVertex2fv(b);
glVertex2fv(c);
}
void divide_triangle(GLfloat *a, GLfloat *b, GLfloat *c, int m) {
/* triangle subdivision using vertex numbers */
GLfloat v0[2], v1[2], v2[2];
int j;
if(m>0)
{
for(j=0; j<2; j++) v0[j]=(a[j]+b[j])/2;
for(j=0; j<2; j++) v1[j]=(a[j]+c[j])/2;
for(j=0; j<2; j++) v2[j]=(b[j]+c[j])/2;
divide_triangle(a, v0, v1, m-1);
divide_triangle(c, v1, v2, m-1);
divide_triangle(b, v2, v0, m-1);
}
else triangle(a,b,c); /* draw triangle at end of recursion */ }
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_TRIANGLES);
divide_triangle(v[0], v[1], v[2], n);
glEnd();
glFlush();
}
void myinit()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-2.0, 2.0, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
glClearColor(1.0, 1.0, 1.0, 1.0);
glColor3f(0.0,0.0,0.0);
}
void main(int argc, char **argv)
{
n=atoi(argv[1]); /* or set number of subdivision steps here */ 587
588 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutCreateWindow("Sierpinski Gasket");
glutDisplayFunc(display);
myinit();
glutMainLoop();
}
A.3 三维Sierpinski镂垫的递归程序
/* Recursive subdivision of a tetrahedron to form 3D Sierpinski gasket */ /* number of recursive steps given on command line */
#include <stdlib.h>
#include <GL/glut.h>
/* initial tetrahedron */
GLfloat v[4][3]={{0.0, 0.0, 1.0},{0.0, 0.942809, -0.33333},
{-0.816497, -0.471405, -0.333333},{0.816497, -0.471405, -0.333333}};
GLfloat colors[4][3]={{1.0,0.0,0.0},{0.0,1.0,0.0},
{0.0,0.0,1.0},{0.0,0.0,0.0}};
int n;
void triangle( GLfloat *va, GLfloat *vb, GLfloat *vc)
{
glVertex3fv(va);
glVertex3fv(vb);
glVertex3fv(vc);
}
void tetra(GLfloat *a, GLfloat *b, GLfloat *c, GLfloat *d)
{
glColor3fv(colors[0]);
triangle(a,b,c);
glColor3fv(colors[1]);
triangle(a,c,d);
glColor3fv(colors[2]);
triangle(a,d,b);
glColor3fv(colors[3]);
triangle(b,d,c);
}
void divide_tetra(GLfloat *a, GLfloat *b, GLfloat *c, GLfloat *d, int m) {
GLfloat mid[6][3];
int j;
附录A 实 例 程 序
if(m>0)
{
/* compute six midpoints */
for(j=0; j<3; j++) mid[0][j]=(a[j]+b[j])/2;
for(j=0; j<3; j++) mid[1][j]=(a[j]+c[j])/2;
for(j=0; j<3; j++) mid[2][j]=(a[j]+d[j])/2;
for(j=0; j<3; j++) mid[3][j]=(b[j]+c[j])/2;
for(j=0; j<3; j++) mid[4][j]=(c[j]+d[j])/2;
for(j=0; j<3; j++) mid[5][j]=(b[j]+d[j])/2;
/* create 4 tetrahedrons by subdivision */
divide_tetra(a,mid[0],mid[1],mid[2], m-1);
divide_tetra(mid[0],b,mid[3],mid[5], m-1);
divide_tetra(mid[1],mid[3],c,mid[4], m-1);
divide_tetra(mid[2],mid[4],d,mid[5], m-1);
}
else tetra(a,b,c,d); /* draw tetrahedron at end of recursion */ }
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_TRIANGLES);
divide_tetra(v[0],v[1],v[2],v[3],n);
glEnd();
glFlush();
}
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-2.0, 2.0, -2.0 * (GLfloat) h / (GLfloat) w, 2.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0);
else
glOrtho(-2.0 * (GLfloat) w / (GLfloat) h,
2.0 * (GLfloat) w / (GLfloat) h, -2.0, 2.0, -10.0, 10.0); glMatrixMode(GL_MODELVIEW);
glutPostRedisplay();
}
void main(int argc, char **argv)
{
n=atoi(argv[1]); /* or enter number of subdivision steps here */ 589
590 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500);
glutCreateWindow("3D Gasket");
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glEnable(GL_DEPTH_TEST);
glClearColor (1.0, 1.0, 1.0, 1.0);
glutMainLoop();
}
A.4 Marching-Square程序
/* generates contours using marching squares */
/* region size */
#define X_MAX 1.0
#define Y_MAX 1.0
#define X_MIN -1.0
#define Y_MIN -1.0
/* number of cells */
#define N_X 50
#define N_Y 50
/* contour value */
#define THRESHOLD 0.0
#include<gl/glut.h>
void display()
{
double f(double,double);
int cell(double,double,double,double);
void lines(int,int,int,double,double,double,double);
double data[N_X][N_Y];
int i,j;
int c;
glClear(GL_COLOR_BUFFER_BIT);
/* form data array from function */
for(i=0;i<N_X;i++)
for(j=0;j<N_Y;j++)
data[i][j]=f(X_MIN+i*(X_MAX-X_MIN) /(N_X-1.0),
附录A 实 例 程 序
Y_MIN+j*(Y_MAX-Y_MIN)/(N_Y-1.0));
/* process each cell */
for(i=0;i<N_X;i++)
for(j=0;j<N_Y;j++)
{
c=cell(data[i][j],data[i+1][j],data[i+1][j+1],data[i][j+1]);
lines(c,i,j,data[i][j],data[i+1][j],data[i+1][j+1],data[i][j+1]); }
glFlush();
}
/* define function f(x,y) */
double f(double x, double y)
{
double a=0.49, b=0.5;
/* ovals of Cassini */
return (x*x+y*y+a*a)*(x*x+y*y+a*a)-4*a*a*x*x-b*b*b*b;
}
/* define cell vertices */
int cell(double a,double b,double c, double d)
{
int n=0;
if(a>THRESHOLD) n+=1;
if(b>THRESHOLD) n+=8;
if(c>THRESHOLD) n+=4;
if(d>THRESHOLD) n+=2;
return n ;
}
/* draw line segments for each case */
void lines(int num,int i,int j,double a ,double b,double c,double d) {
void draw_one(int,int,int,double,double,double,double);
void draw_adjacent(int,int,int, double,double,double,double); void draw_opposite(int,int,int,double,double,double,double);
switch(num)
{
case 1 : case 2: case 4 : case 7: case 8: case 11: case 13: case 14: 591
592 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
draw_one(num,i,j,a,b,c,d);
break;
case 3: case 6: case 9: case 12:
draw_adjacent(num,i,j,a,b,c,d);
break;
case 5: case 10:
draw_opposite(num,i,j,a,b,c,d);
break;
case 0: case 15:
break;
}
}
void draw_one(int num,int i,int j,double a,double b,double c,double d) {
double x1,y1,x2,y2;
double ox,oy;
double dx,dy;
dx=(X_MAX-X_MIN)/(N_X-1.0);
dy=(Y_MAX-Y_MIN)/(N_Y-1.0);
ox=X_MIN+i*(X_MAX-X_MIN)/(N_X-1.0);
oy=Y_MIN+j*(Y_MAX-Y_MIN)/(N_Y-1.0);
switch(num)
{
case 1 : case 14:
x1=ox;
y1=oy+dy*(THRESHOLD-a)/(d-a);
x2=ox+dx*(THRESHOLD-a)/(b-a);
y2=oy;
break;
case 2: case 13:
x1=ox;
y1=oy+dy*(THRESHOLD-a)/(d-a);
x2=ox+dx*(THRESHOLD-d)/(c-d);
y2=oy+dy;
break;
case 4: case 11:
x1=ox+dx*(THRESHOLD-d)/(c-d);
y1=oy+dy;
x2=ox+dx;
y2=oy+dy*(THRESHOLD-b)/(c-b);
break;
case 7: case 8:
x1=ox+dx*(THRESHOLD-a)/(b-a);
y1=oy;
x2=ox+dx;
y2=oy+dy*(THRESHOLD-b)/(c-b);
附录A 实 例 程 序
break;
}
glBegin(GL_LINES);
glVertex2d(x1,y1);
glVertex2d(x2,y2);
glEnd();
}
void draw_adjacent(int num,int i,int j,double a,double b,double c ,double d) {
double x1,y1,x2,y2;
double ox,oy;
double dx,dy;
dx=(X_MAX-X_MIN)/(N_X-1.0);
dy=(Y_MAX-Y_MIN)/(N_Y-1.0);
ox=X_MIN+i*(X_MAX-X_MIN)/(N_X-1.0);
oy=Y_MIN+j*(Y_MAX-Y_MIN)/(N_Y-1.0);
switch(num)
{
case 3 : case 12:
x1=ox+dx*(THRESHOLD-a)/(b-a);
y1=oy;
x2=ox+dx*(THRESHOLD-d)/(c-d);
y2=oy+dy;
break;
case 6: case 9:
x1=ox;
y1=oy+dy*(THRESHOLD-a)/(d-a);
x2=ox+dx;
y2=oy+dy*(THRESHOLD-b)/(c-b);
break;
}
glBegin(GL_LINES);
glVertex2d(x1,y1);
glVertex2d(x2,y2);
glEnd();
}
void draw_opposite(int num,int i,int j,double a,double b,double c ,double d) {
double x1,y1,x2,y2,x3,y3,x4,y4;
double ox,oy;
double dx,dy;
dx=(X_MAX-X_MIN)/(N_X-1.0);
dy=(Y_MAX-Y_MIN)/(N_Y-1.0);
ox=X_MIN+i*(X_MAX-X_MIN)/(N_X-1.0);
oy=Y_MIN+j*(Y_MAX-Y_MIN)/(N_Y-1.0);
switch(num)
{ 593
594 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
case 5 :
x1=ox;
y1=oy+dy*(THRESHOLD-a)/(d-a);
x2=ox+dx*(THRESHOLD-a)/(b-a);
y2=oy;
x3=ox+dx*(THRESHOLD-d)/(c-d);
y3=oy+dy;
x4=ox+dx;
y4=oy+dy*(THRESHOLD-b)/(c-b);
break;
case 10:
x1=ox;
y1=oy+dy*(THRESHOLD-a)/(d-a);
x2=ox+dx*(THRESHOLD-d)/(c-d);
y2=oy+dy;
x3=ox+dx*(THRESHOLD-d)/(c-d);
y3=oy;
x4=ox+dx;
y4=oy+dy*(THRESHOLD-b)/(c-b);
break;
}
glBegin(GL_LINES);
glVertex2d(x1,y1);
glVertex2d(x2,y2);
glVertex2d(x3,y3);
glVertex2d(x4,y4);
glEnd();
}
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
gluOrtho2D(X_MIN, X_MAX, Y_MIN * (GLfloat) h / (GLfloat) w, Y_MAX * (GLfloat) h / (GLfloat) w);
else
gluOrtho2D(X_MIN * (GLfloat) w / (GLfloat) h,
X_MAX * (GLfloat) w / (GLfloat) h, Y_MIN, Y_MAX); glMatrixMode(GL_MODELVIEW);
}
void main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitWindowSize(500, 500);
glutCreateWindow("contour plot");
附录A 实 例 程 序
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glClearColor(0.0, 0.0, 0.0, 1.0);
glColor3f(1.0,1.0,1.0);
glutMainLoop();
}
595
A.5 生成正方形的程序
/* This program illustrates the use of the GLUT library for
interfacing with a Window System */
/* The program opens a window, clears it to black,
then draws a box at the location of the mouse each time the
left button is clicked. The right button exits the program.
The program also reacts correctly when the window is
moved or resized by clearing the new window to black. */
#include <GL/glut.h>
#include <stdlib.h>
/* globals */
GLsizei wh = 500, ww = 500; /* initial window size */
GLfloat size = 3.0; /* half side length of square */
void drawSquare(int x, int y)
{
y=wh-y;
glColor3ub( (char) rand()%256, (char) rand()%256, (char) rand()%256); glBegin(GL_POLYGON);
glVertex2f(x+size, y+size);
glVertex2f(x-size, y+size);
glVertex2f(x-size, y-size);
glVertex2f(x+size, y-size);
glEnd();
glFlush();
}
/* reshaping routine called whenever window is resized
or moved */
void myReshape(GLsizei w, GLsizei h)
{
596 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
/* adjust clipping box */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, (GLdouble)w, 0.0, (GLdouble)h, -1.0, 1.0); glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/* adjust viewport and clear */
glViewport(0,0,w,h);
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
/* set global size for use by drawing routine */
ww = w;
wh = h;
}
void myinit(void)
{
glViewport(0,0,ww,wh);
/* Pick 2D clipping window to match size of screen window. This choice avoids having to scale object coordinates each time window is resized. */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, (GLdouble) ww, 0.0, (GLdouble) wh, -1.0, 1.0);
/* set clear color to black and clear window */
glClearColor (0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
}
void mouse(int btn,int state,int x,int y)
{
if(btn==GLUT_RIGHT_BUTTON &&state==GLUT_DOWN) exit(0) }
/* display callback required by GLUT*/
viod display()
{}
int main(int argc,char** argv)
{
附录A 实 例 程 序
glutInit(&argc,argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutCreateWindow("square");
myinit();
glutReshapeFunc (my Reshape);
glutMouseFunc (mouse)
glutMotionFunc (drawSqure);
glutDisp layFunc (display);
glutMainLoop();
} 597
A.6 画图程序
/* simple painting program with text, lines, triangles, rectangles,and points */
#define NULL 0
#define LINE 1
#define RECTANGLE 2
#define TRIANGLE 3
#define POINTS 4
#define TEXT 5
#include <stdlib.h>
#include <GL/glut.h>
void mouse(int, int, int, int);
void key(unsigned char, int, int);
void display(void);
void drawSquare(int, int);
void myReshape(GLsizei, GLsizei);
void myinit(void);
void screen_box(int, int, int);
void right_menu(int);
void middle_menu(int);
void color_menu(int);
void pixel_menu(int);
void fill_menu(int);
int pick(int, int);
/* globals */
GLsizei wh = 500, ww = 500; /* initial window size */ GLfloat size = 3.0; /* half side length of square */ int draw_mode = 0; /* drawing mode */
int rx, ry; /* raster position */
598 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
GLfloat r = 1.0, g = 1.0, b = 1.0; /* drawing color */
int fill = 0; /* fill flag */
void drawSquare(int x, int y)
{
y=wh-y;
glColor3ub( (char) rand()%256, (char) rand()%256, (char) rand()%256); glBegin(GL_POLYGON);
glVertex2f(x+size, y+size);
glVertex2f(x-size, y+size);
glVertex2f(x-size, y-size);
glVertex2f(x+size, y-size);
glEnd();
}
/* rehaping routine called whenever window is resized
or moved */
void myReshape(GLsizei w, GLsizei h)
{
/* adjust clipping box */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, (GLdouble)w, 0.0, (GLdouble)h, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/* adjust viewport and clear */
glViewport(0,0,w,h);
glClearColor (0.8, 0.8, 0.8, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
display();
glFlush();
/* set global size for use by drawing routine */
ww = w;
wh = h;
}
void myinit(void)
{
glViewport(0,0,ww,wh);
附录A 实 例 程 序
/* Pick 2D clipping window to match size of X window.
This choice avoids having to scale object coordinates
each time window is resized.*/
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, (GLdouble) ww , 0.0, (GLdouble) wh , -1.0, 1.0);
/* set clear color to black and clear window */
glClearColor (0.8, 0.8, 0.8, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
}
void mouse(int btn, int state, int x, int y)
{
static int count;
int where;
static int xp[2],yp[2];
if(btn==GLUT_LEFT_BUTTON && state==GLUT_DOWN)
{
glPushAttrib(GL_ALL_ATTRIB_BITS);
where = pick(x,y);
glColor3f(r, g, b);
if(where != 0)
{
count = 0;
draw_mode = where;
}
else switch(draw_mode)
{
case(LINE):
if(count==0)
{
count++;
xp[0] = x;
yp[0] = y;
}
else
{
glBegin(GL_LINES);
glVertex2i(x,wh-y);
glVertex2i(xp[0],wh-yp[0]);
glEnd();
draw_mode=0;
count=0;
}
break; 599
600 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
case(RECTANGLE):
if(count == 0)
{
count++;
xp[0] = x;
yp[0] = y;
}
else
{
if(fill) glBegin(GL_POLYGON); else glBegin(GL_LINE_LOOP); glVertex2i(x,wh-y);
glVertex2i(x,wh-yp[0]);
glVertex2i(xp[0],wh-yp[0]); glVertex2i(xp[0],wh-y);
glEnd();
draw_mode=0;
count=0;
}
break;
case (TRIANGLE):
switch(count)
{
case(0):
count++;
xp[0] = x;
yp[0] = y;
break;
case(1):
count++;
xp[1] = x;
yp[1] = y;
break;
case(2):
if(fill) glBegin(GL_POLYGON); else glBegin(GL_LINE_LOOP); glVertex2i(xp[0],wh-yp[0]); glVertex2i(xp[1],wh-yp[1]); glVertex2i(x,wh-y);
glEnd();
draw_mode=0;
count=0;
}
break;
case(POINTS):
{
drawSquare(x,y);
count++;
}
break;
附录A 实 例 程 序
case(TEXT):
{
rx=x;
ry=wh-y;
glRasterPos2i(rx,ry);
count=0;
}
}
glPopAttrib();
glFlush();
}
}
int pick(int x, int y)
{
y = wh - y;
if(y < wh-ww/10) return 0;
else if(x < ww/10) return LINE;
else if(x < ww/5) return RECTANGLE; else if(x < 3*ww/10) return TRIANGLE; else if(x < 2*ww/5) return POINTS; else if(x < ww/2) return TEXT;
else return 0;
}
void screen_box(int x, int y, int s ) {
glBegin(GL_QUADS);
glVertex2i(x, y);
glVertex2i(x+s, y);
glVertex2i(x+s, y+s);
glVertex2i(x, y+s);
glEnd();
}
void right_menu(int id)
{
if(id == 1) exit(0);
else display();
}
void middle_menu(int id)
{
}
void color_menu(int id)
{
if(id == 1) {r = 1.0; g = 0.0; b = 0.0;} 601
602 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
else if(id == 2) {r = 0.0; g = 1.0; b = 0.0;} else if(id == 3) {r = 0.0; g = 0.0; b = 1.0;} else if(id == 4) {r = 0.0; g = 1.0; b = 1.0;} else if(id == 5) {r = 1.0; g = 0.0; b = 1.0;} else if(id == 6) {r = 1.0; g = 1.0; b = 0.0;} else if(id == 7) {r = 1.0; g = 1.0; b = 1.0;} else if(id == 8) {r = 0.0; g = 0.0; b = 0.0;} }
void pixel_menu(int id)
{
if (id == 1) size = 2 * size;
else if (size > 1) size = size/2;
}
void fill_menu(int id)
{
if (id == 1) fill = 1;
else fill = 0;
}
void key(unsigned char k, int xx, int yy) {
if(draw_mode!=TEXT) return;
glColor3f(0.0,0.0,0.0);
glRasterPos2i(rx,ry);
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, k); /* glutStrokeCharacter(GLUT_STROKE_ROMAN,i); */ rx+=glutBitmapWidth(GLUT_BITMAP_9_BY_15,k);
}
void display(void)
{
int shift=0;
glPushAttrib(GL_ALL_ATTRIB_BITS);
glClearColor (0.8, 0.8, 0.8, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
screen_box(0,wh-ww/10,ww/10);
glColor3f(1.0, 0.0, 0.0);
screen_box(ww/10,wh-ww/10,ww/10);
glColor3f(0.0, 1.0, 0.0);
screen_box(ww/5,wh-ww/10,ww/10);
glColor3f(0.0, 0.0, 1.0);
screen_box(3*ww/10,wh-ww/10,ww/10);
glColor3f(1.0, 1.0, 0.0);
screen_box(2*ww/5,wh-ww/10,ww/10);
glColor3f(0.0, 0.0, 0.0);
附录A 实 例 程 序
screen_box(ww/10+ww/40,wh-ww/10+ww/40,ww/20); glBegin(GL_LINES);
glVertex2i(wh/40,wh-ww/20);
glVertex2i(wh/40+ww/20,wh-ww/20);
glEnd();
glBegin(GL_TRIANGLES);
glVertex2i(ww/5+ww/40,wh-ww/10+ww/40); glVertex2i(ww/5+ww/20,wh-ww/40);
glVertex2i(ww/5+3*ww/40,wh-ww/10+ww/40); glEnd();
glPointSize(3.0);
glBegin(GL_POINTS);
glVertex2i(3*ww/10+ww/20, wh-ww/20);
glEnd();
glRasterPos2i(2*ww/5,wh-ww/20);
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, 'A'); shift=glutBitmapWidth(GLUT_BITMAP_9_BY_15, 'A'); glRasterPos2i(2*ww/5+shift,wh-ww/20);
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, 'B'); shift+=glutBitmapWidth(GLUT_BITMAP_9_BY_15, 'B'); glRasterPos2i(2*ww/5+shift,wh-ww/20);
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, 'C'); glFlush();
glPopAttrib();
}
int main(int argc, char** argv)
{
int c_menu, p_menu, f_menu;
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(500, 500);
glutCreateWindow("square");
glutDisplayFunc(display);
c_menu = glutCreateMenu(color_menu);
glutAddMenuEntry("Red",1);
glutAddMenuEntry("Green",2);
glutAddMenuEntry("Blue",3);
glutAddMenuEntry("Cyan",4);
glutAddMenuEntry("Magenta",5);
glutAddMenuEntry("Yellow",6);
glutAddMenuEntry("White",7);
glutAddMenuEntry("Black",8);
p_menu = glutCreateMenu(pixel_menu);
glutAddMenuEntry("increase pixel size", 1); glutAddMenuEntry("decrease pixel size", 2); f_menu = glutCreateMenu(fill_menu); 603
604 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
glutAddMenuEntry("fill on", 1);
glutAddMenuEntry("fill off", 2);
glutCreateMenu(right_menu);
glutAddMenuEntry("quit",1);
glutAddMenuEntry("clear",2);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutCreateMenu(middle_menu);
glutAddSubMenu("Colors", c_menu);
glutAddSubMenu("Pixel Size", p_menu);
glutAddSubMenu("Fill", f_menu);
glutAttachMenu(GLUT_MIDDLE_BUTTON);
myinit ();
glutReshapeFunc (myReshape);
glutKeyboardFunc(key);
glutMouseFunc (mouse);
glutMainLoop();
}
A.7 使用双缓存的程序
/*
* double.c
* This program demonstrates double buffering for
* flicker-free animation. The left and middle mouse
* buttons start and stop the spinning motion of the square. */
#include <GL/glut.h>
#include <stdlib.h>
#include <math.h>
#define DEGREES_TO_RADIANS 3.14159/180.0
static GLfloat spin = 0.0;
GLfloat x,y;
int singleb, doubleb;
void square()
{
glBegin(GL_QUADS);
glVertex2f(x,y);
glVertex2f(-y,x);
glVertex2f(-x,-y);
glVertex2f(y,-x);
glEnd();
}
void displayd(void)
附录A 实 例 程 序
{
glClear(GL_COLOR_BUFFER_BIT);
square();
glutSwapBuffers();
}
void displays(void)
{
glClear(GL_COLOR_BUFFER_BIT);
square();
glFlush();
}
void spinDisplay(void)
{
spin = spin + 2.0;
if (spin > 360.0) spin = spin - 360.0;
x=25.0 * cos(DEGREES_TO_RADIANS*spin);
y=25.0 * sin(DEGREES_TO_RADIANS*spin);
glutSetWindow(singleb);
glutPostRedisplay();
glutSetWindow(doubleb);
glLoadIdentity();
glutPostRedisplay();
}
void myinit(void)
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
glShadeModel(GL_FLAT);
}
void mouse(int btn, int state, int x, int y)
{
if(btn==GLUT_LEFT_BUTTON && state==GLUT_DOWN) glutIdleFunc(spinDisplay);
if(btn==GLUT_MIDDLE_BUTTON && state==GLUT_DOWN) glutIdleFunc(NULL);
}
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-50.0, 50.0, -50.0*(GLfloat)h/(GLfloat)w, 50.0*(GLfloat)h/(GLfloat)w, -1.0, 1.0); else 605
606 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
glOrtho(-50.0*(GLfloat)w/(GLfloat)h,
50.0*(GLfloat)w/(GLfloat)h, -50.0, 50.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
/* Main Loop
* Open window with initial window size, title bar, * RGBA display mode, and handle input events.
*/
int main(int argc, char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
singleb=glutCreateWindow("single buffered");
myinit();
glutDisplayFunc(displays);
glutReshapeFunc(myReshape);
glutIdleFunc(spinDisplay);
glutMouseFunc(mouse);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
doubleb=glutCreateWindow("double buffered");
myinit();
glutDisplayFunc(displayd);
glutReshapeFunc(myReshape);
glutIdleFunc(spinDisplay);
glutMouseFunc(mouse);
glutMainLoop();
}
A.8 选择模式拾取程序
/* demonstrates picking used selection mode */
#include <stdlib.h>
#include <stdio.h>
#include <GL/glut.h>
void init()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
}
void drawObjects(GLenum mode)
附录A 实 例 程 序
{
if(mode == GL_SELECT) glLoadName(1);
glColor3f(1.0, 0.0, 0.0);
glRectf(-0.5, -0.5, 1.0, 1.0);
if(mode == GL_SELECT) glLoadName(2);
glColor3f(0.0, 0.0, 1.0);
glRectf(-1.0, -1.0, 0.5, 0.5);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
drawObjects(GL_RENDER);
glFlush();
}
/* processHits prints out the contents of the
* selection array.
*/
void processHits (GLint hits, GLuint buffer[])
{
unsigned int i, j;
GLuint ii, jj, names, *ptr;
printf("hits = %d\n", hits);
ptr=(GLuint *) buffer;
for (i = 0; i < hits; i++) { /* for each hit */ names = *ptr;
ptr+=3;
for (j = 0; j < names; j++)
{ /* for each name */
if(*ptr==1) printf ("red rectangle\n");
else printf ("blue rectangle\n");
ptr++;
}
printf ("\n");
}
}
#define SIZE 512
void mouse(int button, int state, int x, int y)
{
GLuint selectBuf[SIZE];
GLint hits;
GLint viewport[4];
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
glGetIntegerv(GL_VIEWPORT, viewport); 607
608 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
glSelectBuffer (SIZE, selectBuf);
glRenderMode(GL_SELECT);
glInitNames();
glPushName(0);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
/* create 5×5 pixel picking region near cursor location */ gluPickMatrix((GLdouble) x, (GLdouble) (viewport[3] - y), 5.0, 5.0, viewport);
gluOrtho2D(-2.0, 2.0, -2.0, 2.0);
drawObjects(GL_SELECT);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glFlush();
hits = glRenderMode(GL_RENDER);
processHits(hits, selectBuf);
glutPostRedisplay();
}
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D (-2.0, 2.0, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 27:
exit(0);
break;
}
}
/* Main Loop */
附录A 实 例 程 序
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
} 609
A.9 立方体旋转程序
/* Rotating cube with color interpolation */
/* Demonstration of use of homogeneous coordinate
transformations and simple data structure for representing cube from Chapter 4 */
/* Colors are assigned to the vertices */
/* cube is centered at orign*/
#include <stdlib.h>
#include <GL/glut.h>
GLfloat vertices[][3] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0}, {1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0}, {1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}};
GLfloat colors[][3] = {{0.0,0.0,0.0},{1.0,0.0,0.0}, {1.0,1.0,0.0}, {0.0,1.0,0.0}, {0.0,0.0,1.0},
{1.0,0.0,1.0}, {1.0,1.0,1.0}, {0.0,1.0,1.0}};
void polygon(int a, int b, int c, int d)
{
/* draw a polygon via list of vertices */
glBegin(GL_POLYGON);
glColor3fv(colors[a]);
glVertex3fv(vertices[a]);
glColor3fv(colors[b]);
glVertex3fv(vertices[b]);
610 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
glColor3fv(colors[c]);
glVertex3fv(vertices[c]);
glColor3fv(colors[d]);
glVertex3fv(vertices[d]);
glEnd();
}
void colorcube(void)
{
/* map vertices to faces */
polygon(0,3,2,1);
polygon(2,3,7,6);
polygon(0,4,7,3);
polygon(1,2,6,5);
polygon(4,5,6,7);
polygon(0,1,5,4);
}
static GLfloat theta[] = {0.0,0.0,0.0};
static GLint axis = 2;
void display(void)
{
/* display callback, clear frame buffer and z buffer, rotate cube and draw, swap buffers */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity();
glRotatef(theta[0], 1.0, 0.0, 0.0);
glRotatef(theta[1], 0.0, 1.0, 0.0);
glRotatef(theta[2], 0.0, 0.0, 1.0);
colorcube();
glFlush();
glutSwapBuffers();
}
void spinCube()
{
/* Idle callback, spin cube 2 degrees about selected axis */
theta[axis] += 2.0;
if( theta[axis] > 360.0 ) theta[axis] -= 360.0;
/* display(); */
glutPostRedisplay();
}
附录A 实 例 程 序
void mouse(int btn, int state, int x, int y)
{
/* mouse callback, selects an axis about which to rotate */
if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN) axis = 0;
if(btn==GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) axis = 1; if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN) axis = 2; }
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-2.0, 2.0, -2.0 * (GLfloat) h / (GLfloat) w,
2.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0);
else
glOrtho(-2.0 * (GLfloat) w / (GLfloat) h,
2.0 * (GLfloat) w / (GLfloat) h, -2.0, 2.0, -10.0, 10.0); glMatrixMode(GL_MODELVIEW);
}
void main(int argc, char **argv)
{
glutInit(&argc, argv);
/* need both double buffering and z buffer */
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500);
glutCreateWindow("colorcube");
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glutIdleFunc(spinCube);
glutMouseFunc(mouse);
glEnable(GL_DEPTH_TEST); /* Enable hidden-surface removal */ glutMainLoop();
} 611
A.10 利用顶点数组旋转立方体程序
/* rotating cube with vertex arrays */
#include <stdlib.h>
#include <GL/glut.h>
612 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
GLfloat vertices[] = {-1.0,-1.0,-1.0,1.0,-1.0,-1.0,
1.0,1.0,-1.0,-1.0,1.0,-1.0,-1.0,-1.0,1.0,
1.0,-1.0,1.0,1.0,1.0,1.0,-1.0,1.0,1.0};
GLfloat colors[] = {0.0,0.0,0.0,1.0,0.0,0.0,
1.0,1.0,0.0, 0.0,1.0,0.0, 0.0,0.0,1.0,
1.0,0.0,1.0, 1.0,1.0,1.0, 0.0,1.0,1.0};
GLubyte cubeIndices[]={0,3,2,1,2,3,7,6,0,4,7,3,1,2,6,5,4,5,6,7,0,1,5,4};
static GLfloat theta[] = {0.0,0.0,0.0};
static GLint axis = 2;
void display(void)
{
/* display callback, clear frame buffer and z buffer,
rotate cube and draw, swap buffers */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(1.0,1.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0);
glTranslatef(0.0, 3.0, 0.0);
glRotatef(theta[0], 1.0, 0.0, 0.0);
glRotatef(theta[1], 0.0, 1.0, 0.0);
glRotatef(theta[2], 0.0, 0.0, 1.0);
glColorPointer(3,GL_FLOAT, 0, colors);
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, cubeIndices);
glutSwapBuffers();
}
void spinCube()
{
/* Idle callback, spin cube 2 degrees about selected axis */
theta[axis] += 2.0;
if( theta[axis] > 360.0 ) theta[axis] -= 360.0;
glutPostRedisplay();
}
void mouse(int btn, int state, int x, int y)
{
/* mouse callback, selects an axis about which to rotate */
附录A 实 例 程 序
if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN) axis = 0;
if(btn==GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) axis = 1; if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN) axis = 2; }
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-4.0, 4.0, -3.0 * (GLfloat) h / (GLfloat) w,
5.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0);
else
glOrtho(-4.0 * (GLfloat) w / (GLfloat) h,
4.0 * (GLfloat) w / (GLfloat) h, -3.0, 5.0, -10.0, 10.0); glMatrixMode(GL_MODELVIEW);
}
void main(int argc, char **argv)
{
/* need both double buffering and z buffer */
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500);
glutCreateWindow("colorcube");
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glutIdleFunc(spinCube);
glutMouseFunc(mouse);
glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glColorPointer(3,GL_FLOAT, 0, colors);
glClearColor(1.0,1.0,1.0,1.0);
glColor3f(1.0,1.0,1.0);
glutMainLoop();
} 613
A.11 用虚拟跟踪球实现立方体旋转程序
/* Rotating cube demo with trackball */
#include <math.h>
#include <GL/glut.h>
614 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
#define bool int
#define false 0
#define true 1
int winWidth, winHeight;
float angle = 0.0, axis[3], trans[3];
bool trackingMouse = false;
bool redrawContinue = false;
bool trackballMove = false;
/* Draw the cube */
GLfloat vertices[][3] = {
{-1.0,-1.0,-1.0}, {1.0,-1.0,-1.0}, {1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0}, {1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0} };
GLfloat colors[][3] = {
{0.0,0.0,0.0}, {1.0,0.0,0.0}, {1.0,1.0,0.0}, {0.0,1.0,0.0}, {0.0,0.0,1.0}, {1.0,0.0,1.0}, {1.0,1.0,1.0}, {0.0,1.0,1.0}
};
void polygon(int a, int b, int c , int d, int face)
{
/* draw a polygon via list of vertices */
glBegin(GL_POLYGON);
glColor3fv(colors[a]);
glVertex3fv(vertices[a]);
glVertex3fv(vertices[b]);
glVertex3fv(vertices[c]);
glVertex3fv(vertices[d]);
glEnd();
}
void colorcube(void)
{
/* map vertices to faces */
polygon(1,0,3,2,0);
polygon(3,7,6,2,1);
polygon(7,3,0,4,2);
polygon(2,6,5,1,3);
polygon(4,5,6,7,4);
polygon(5,4,0,1,5);
附录A 实 例 程 序
}
/* These functions implement a simple trackball-like motion control */
float lastPos[3] = {0.0F, 0.0F, 0.0F};
int curx, cury;
int startX, startY;
void trackball_ptov(int x, int y, int width, int height, float v[3]) {
float d, a;
/* project x,y onto a hemisphere centered within width, height */ v[0] = (2.0F*x - width) / width;
v[1] = (height - 2.0F*y) / height;
d = (float) sqrt(v[0]*v[0] + v[1]*v[1]);
v[2] = (float) cos((M_PI/2.0F) * ((d < 1.0F) ? d : 1.0F));
a = 1.0F / (float) sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); v[0] *= a;
v[1] *= a;
v[2] *= a;
}
void mouseMotion(int x, int y)
{
float curPos[3], dx, dy, dz;
trackball_ptov(x, y, winWidth, winHeight, curPos);
if(trackingMouse)
{
dx = curPos[0] - lastPos[0];
dy = curPos[1] - lastPos[1];
dz = curPos[2] - lastPos[2];
if (dx || dy || dz) {
angle = 90.0F * sqrt(dx*dx + dy*dy + dz*dz);
axis[0] = lastPos[1]*curPos[2] - lastPos[2]*curPos[1];
axis[1] = lastPos[2]*curPos[0] - lastPos[0]*curPos[2];
axis[2] = lastPos[0]*curPos[1] - lastPos[1]*curPos[0];
lastPos[0] = curPos[0];
lastPos[1] = curPos[1];
lastPos[2] = curPos[2];
}
}
glutPostRedisplay();
}
void startMotion(int x, int y)
615
616 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
{
trackingMouse = true;
redrawContinue = false;
startX = x; startY = y;
curx = x; cury = y;
trackball_ptov(x, y, winWidth, winHeight, lastPos); trackballMove=true;
}
void stopMotion(int x, int y)
{
trackingMouse = false;
if (startX != x || startY != y) {
redrawContinue = true;
} else {
angle = 0.0F;
redrawContinue = false;
trackballMove = false;
}
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
/* view transform */
if (trackballMove)
{
glRotatef(angle, axis[0], axis[1], axis[2]);
}
colorcube();
glutSwapBuffers();
}
void mouseButton(int button, int state, int x, int y) {
if(button==GLUT_RIGHT_BUTTON) exit(0);
if(button==GLUT_LEFT_BUTTON) switch(state)
{
case GLUT_DOWN:
y=winHeight-y;
startMotion(x,y);
break;
case GLUT_UP:
stopMotion(x,y);
附录A 实 例 程 序
break;
}
}
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
winWidth = w;
winHeight = h;
}
void spinCube()
{
if (redrawContinue) glutPostRedisplay();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500);
glutCreateWindow("colorcube");
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glutIdleFunc(spinCube);
glutMouseFunc(mouseButton);
glutMotionFunc(mouseMotion);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-2.0, 2.0, -2.0, 2.0, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
glutMainLoop();
} 617
A.12 观察者漫游程序
/*rotating cube with viewer movement from Chapter 5*/
/*cube definition and display similar to rotating-cube program*/
/* We use the Lookat function in the display callback to point the viewer, whose position can be altered by the x,X,y,Y,z, and Z keys */
The perspective view is set in the reshape callback */
#include <stdlib.h>
#include <GL/glut.h>
618 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
GLfloat vertices[][3] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0}, {1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0},
{1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}};
GLfloat colors[][3] = {{0.0,0.0,0.0},{1.0,0.0,0.0},
{1.0,1.0,0.0}, {0.0,1.0,0.0}, {0.0,0.0,1.0},
{1.0,0.0,1.0}, {1.0,1.0,1.0}, {0.0,1.0,1.0}};
void polygon(int a, int b, int c, int d)
{
glBegin(GL_POLYGON);
glColor3fv(colors[a]);
glVertex3fv(vertices[a]);
glVertex3fv(vertices[b]);
glVertex3fv(vertices[c]);
glVertex3fv(vertices[d]);
glEnd();
}
void colorcube()
{
polygon(0,3,2,1);
polygon(2,3,7,6);
polygon(0,4,7,3);
polygon(1,2,6,5);
polygon(4,5,6,7);
polygon(0,1,5,4);
}
static GLfloat theta[] = {0.0,0.0,0.0};
static GLint axis = 2;
static GLdouble viewer[]= {0.0, 0.0, 5.0}; /* initial viewer
location */
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* Update viewer position in modelview matrix */
glLoadIdentity();
gluLookAt(viewer[0],viewer[1],viewer[2], 0.0, 0.0, 0.0,
0.0, 1.0, 0.0);
/* rotate cube */
glRotatef(theta[0], 1.0, 0.0, 0.0);
glRotatef(theta[1], 0.0, 1.0, 0.0);
附录A 实 例 程 序
glRotatef(theta[2], 0.0, 0.0, 1.0);
colorcube();
glFlush();
glutSwapBuffers();
}
void mouse(int btn, int state, int x, int y)
{
if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN) axis = 0; if(btn==GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) axis = 1; if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN) axis = 2; theta[axis] += 2.0;
if( theta[axis] > 360.0 ) theta[axis] -= 360.0;
display();
}
void keys(unsigned char key, int x, int y)
{
/* Use x, X, y, Y, z, and Z keys to move viewer */
if(key == 'x') viewer[0]-= 1.0;
if(key == 'X') viewer[0]+= 1.0;
if(key == 'y') viewer[1]-= 1.0;
if(key == 'Y') viewer[1]+= 1.0;
if(key == 'z') viewer[2]-= 1.0;
if(key == 'Z') viewer[2]+= 1.0;
display();
}
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
/* Use a perspective view */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w<=h)
glFrustum( -2.0, 2.0, -2.0 * (GLfloat) h/ (GLfloat) w, 2.0* (GLfloat) h / (GLfloat) w, 2.0, 20.0);
else glFrustum(-2.0, 2.0, -2.0 * (GLfloat) w/ (GLfloat) h, 2.0* (GLfloat) w / (GLfloat) h, 2.0, 20.0);
/* Or we can use gluPerspective */
/* gluPerspective(45.0, w/h, -10.0, 10.0); */
glMatrixMode(GL_MODELVIEW);
} 619
620 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
void main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutCreateWindow("colorcube");
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutKeyboardFunc(keys);
glEnable(GL_DEPTH_TEST);
glutMainLoop();
}
A.13 球体的细分逼近程序
/* Recursive subdivision of tetrahedron (Chapter 6). Three display modes: wire frame, constant, and interpolative shading */
/* Program also illustrates defining materials and light sources int init() */
/* mode 0 = wire frame, mode 1 = constant shading,
mode 3 = interpolative shading */
#include <stdlib.h>
#include<math.h>
#include <GL/glut.h>
typedef float point[3];
/* initial tetrahedron */
point v[]={{0.0, 0.0, 1.0}, {0.0, 0.942809, -0.33333},
{-0.816497, -0.471405, -0.333333}, {0.816497, -0.471405, -0.333333}};
static GLfloat theta[] = {0.0,0.0,0.0};
int n;
int mode;
void triangle( point a, point b, point c)
/* display one triangle using a line loop for wire frame, a single
normal for constant shading, or three normals for interpolative shading */ {
附录A 实 例 程 序
if (mode==0) glBegin(GL_LINE_LOOP);
else glBegin(GL_POLYGON);
if(mode==1) glNormal3fv(a);
if(mode==2) glNormal3fv(a);
glVertex3fv(a);
if(mode==2) glNormal3fv(b);
glVertex3fv(b);
if(mode==2) glNormal3fv(c);
glVertex3fv(c);
glEnd();
}
void normal(point p)
{
/* normalize a vector */
float d =0.0;
int i;
for(i=0; i<3; i++) d+=p[i]*p[i];
d=sqrt(d);
if(d>0.0) for(i=0; i<3; i++) p[i]/=d;
}
void divide_triangle(point a, point b, point c, int m)
{
/* triangle subdivision using vertex numbers
righthand rule applied to create outward pointing faces */
point v1, v2, v3;
int j;
if(m>0)
{
for(j=0; j<3; j++) v1[j]=a[j]+b[j];
normal(v1);
for(j=0; j<3; j++) v2[j]=a[j]+c[j];
normal(v2);
for(j=0; j<3; j++) v3[j]=b[j]+c[j];
normal(v3);
divide_triangle(a, v1, v2, m-1);
divide_triangle(c, v2, v3, m-1);
divide_triangle(b, v3, v1, m-1);
divide_triangle(v1, v3, v2, m-1);
}
else(triangle(a,b,c)); /* draw triangle at end of recursion */ }
void tetrahedron(int m)
{ 621
622 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
/* apply triangle subdivision to faces of tetrahedron */
divide_triangle(v[0], v[1], v[2], m);
divide_triangle(v[3], v[2], v[1], m);
divide_triangle(v[0], v[3], v[1], m);
divide_triangle(v[0], v[2], v[3], m);
}
void display(void)
{
/* Displays all three modes, side by side */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
mode=0;
tetrahedron(n);
mode=1;
glTranslatef(-2.0, 0.0,0.0);
tetrahedron(n);
mode=2;
glTranslatef(4.0, 0.0,0.0);
tetrahedron(n);
glFlush();
}
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-4.0, 4.0, -4.0 * (GLfloat) h / (GLfloat) w,
4.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0);
else
glOrtho(-4.0 * (GLfloat) w / (GLfloat) h,
4.0 * (GLfloat) w / (GLfloat) h, -4.0, 4.0, -10.0, 10.0); glMatrixMode(GL_MODELVIEW);
display();
}
void myinit()
{
GLfloat mat_specular[]={1.0, 1.0, 1.0, 1.0};
GLfloat mat_diffuse[]={1.0, 1.0, 1.0, 1.0};
GLfloat mat_ambient[]={1.0, 1.0, 1.0, 1.0};
附录A 实 例 程 序
GLfloat mat_shininess={100.0};
GLfloat light_ambient[]={0.0, 0.0, 0.0, 1.0};
GLfloat light_diffuse[]={1.0, 1.0, 1.0, 1.0};
GLfloat light_specular[]={1.0, 1.0, 1.0, 1.0};
/* set up ambient, diffuse, and specular components for light 0 */
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
/* define material proerties for front face of all polygons */
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess);
glShadeModel(GL_SMOOTH); /* enable smooth shading */
glEnable(GL_LIGHTING); /* enable lighting */
glEnable(GL_LIGHT0); /* enable light 0 */
glEnable(GL_DEPTH_TEST); /* enable z buffer */
glClearColor (1.0, 1.0, 1.0, 1.0);
glColor3f (0.0, 0.0, 0.0);
}
void main(int argc, char **argv)
{
n=atoi(argv[1]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500);
glutCreateWindow("sphere");
myinit();
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glutMainLoop();
} 623
A.14 Mandelbrot集程序
#include<stdio.h>
#include<stdlib.h>
#include<gl/glut.h>
/* default data */
#define CENTERX -0.5
624 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
#define CENTERY 0.5
#define HEIGHT 0.5
#define WIDTH 0.5
#define MAX_ITER 100
/* N * M array to be generated */
#define N 500
#define M 500
float height=HEIGHT;
float width = WIDTH;
float cx = CENTERX;
float cy = CENTERY;
int max = MAX_ITER;
int n=N;
int m=M;
/* use unsigned bytes for image */
GLubyte image[N][M];
/* complex data type and complex add,mult,and magnitude functions probably not worth overloaded */
typedef float complex[2];
void add(complex a,complex b,complex p)
{
p[0]=a[0]+b[0];
p[1]=a[1]+b[1];
}
void mult(complex a,complex b,complex p)
{
p[0]=a[0]*b[0]-a[1]*b[1];
p[1]=a[0]*b[1]+a[1]*b[0];
}
float mag2(complex a)
{
return (a[0]*a[0]+a[1]*a[1]);
}
void form(float a,float b,complex p)
{
p[0]=a;
p[1]=b;
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
附录A 实 例 程 序
glDrawPixels(n,m,GL_COLOR_INDEX,GL_UNSIGNED_BYTE,image); }
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
gluOrtho2D(0.0, 0.0, (GLfloat) n,(GLfloat)m* (GLfloat ) h /
(GLfloat) w);
else
gluOrtho2D(0.0, 0.0, (GLfloat)n*(GLfloat) w / (GLfloat) h, (GLfloat) m);
glMatrixMode(GL_MODELVIEW);
glutPostRedisplay();
}
void myinit()
{
float redmap[256],greenmap[256],bluemap[256];
int i;
glClearColor (1.0, 1.0, 1.0, 1.0);
gluOrtho2D(0.0, 0.0, (GLfloat)n, (GLfloat)m);
/* define pseudocolor maps,ramps for red and blue,
random for green */
for(i=0;i<256;i++)
{
redmap[i]=i/255.0;
greenmap[i]=rand()%255/255.0;
bluemap[i]=1.0-i/255;
}
glPixelMapfv(GL_PIXEL_MAP_I_TO_R,256,redmap);
glPixelMapfv(GL_PIXEL_MAP_I_TO_G,256,greenmap);
glPixelMapfv(GL_PIXEL_MAP_I_TO_B,256,bluemap);
}
main(int argc, char **argv)
{
int i,j,k;
float x,y,v;
complex c0,c,d;
scanf("%f",&cx);/*center x*/
scanf("%f",&cy); /*center y*/
scanf("%f",&width); /*rectangle width*/
height = width; /*rectangle height*/
625
626 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
scanf("%d",&max); /*maximum iteration*/
for(i=0;i<n;i++)for(j=0;j<m;j++)
{
/* starting point */
x=i*(width/(n-1))+cx-width/2;
y=j*(height/(m-1))+cy-height/2;
form(0,0,c);
form(x,y,c0);
/* complex iteration */
for(k=0;k<max;k++)
{
mult(c,c,d);
add(d,c0,c);
v=mag2(c);
if(v>4.0) break ;/* assume not in set if mag>4 */ }
/*assign gray level to point based on its magnitude*/
if(v>1.0) v=1.0; /* clamp if v>1 */
image[i][j]=255*v;
}
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB );
glutInitWindowSize(N,M);
glutCreateWindow("Mandelbrot set");
myinit();
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glutMainLoop();
}
A.15 Bresenham画线算法
#include<GL/glut.h>
#include<stdio.h>
#define BLACK 0
void draw_pixel(int ix,int iy,int value)
{
glBegin(GL_POINTS);
glVertex2i(ix,iy);
glEnd();
}
附录A 实 例 程 序
bres(int x1,int y1,int x2,int y2) {
int dx,dy,i,e;
int incx,incy,inc1,inc2; int x,y;
dx=x2-x1;
dy=y2-y1;
if(dx<0) dx=-dx;
if(dy<0) dy=-dy;
incx=1;
if(x2<x1) incx=-1;
incy=1;
if(y2<y1) incy=-1;
x=x1;
y=y1;
if(dx>dy)
{
draw_pixel(x,y,BLACK); e=2*dy-dx;
inc1 = 2*(dy-dx);
inc2 = 2*dy;
for(i=0;i<dx;i++)
{
if(e>=0)
{
y+=incy;
e+=inc1;
}
else
e+=inc2;
x+=incx;
draw_pixel(x,y,BLACK); }
}
else
{
draw_pixel(x,y,BLACK); e=2*dx-dy;
inc1=2*(dx-dy);
inc2=2*dx;
for(i=0;i<dy;i++)
{
if(e>=0)
{
x+=incx;
e+=inc1; 627
628 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
}
else
e+=inc2;
y+=incy;
draw_pixel(x,y,BLACK);
}
}
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
bres(200,200,100,50);
glFlush();
}
void myinit()
{
glClearColor(1.0,1.0,1.0,1.0);
glColor3f(1.0,0.0,0.0);
glPointSize(1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,499.0,0.0,499.0);
}
void main(int argc,char **argv)
{
/* standard GLUT initialization */
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB );/*default,not needed*/ glutInitWindowSize(500,500); /* 500×500 pixel window */
glutInitWindowPosition(0,0);/* place window top left on display */ glutCreateWindow("Bresenham's algorithm ");/* window title */
glutDisplayFunc(display); /* display callback invoked when window opened */
myinit(); /*set attributes */
glutMainLoop(); /* enter event loop */
}
A.16 带纹理立方体的旋转程序
#include <stdlib.h>
#include <GL/glut.h>
附录A 实 例 程 序
GLfloat planes[]= {-1.0, 0.0, 1.0, 0.0};
GLfloat planet[]= {0.0, -1.0, 0.0, 1.0};
GLfloat vertices[][3] = {{-1.0,-1.0,-1.0}, {1.0,-1.0,-1.0}, {1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0}, {1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}};
GLfloat colors[][4] = {{0.0,0.0,0.0,0.5}, {1.0,0.0,0.0,0.5},
{1.0,1.0,0.0,0.5}, {0.0,1.0,0.0,0.5}, {0.0,0.0,1.0,0.5}, {1.0,0.0,1.0,0.5}, {1.0,1.0,1.0,0.5}, {0.0,1.0,1.0,0.5}};
void polygon(int a, int b, int c, int d)
{
glBegin(GL_POLYGON);
glColor4fv(colors[a]);
glTexCoord2f(0.0,0.0);
glVertex3fv(vertices[a]);
glColor4fv(colors[b]);
glTexCoord2f(0.0,1.0);
glVertex3fv(vertices[b]);
glColor4fv(colors[c]);
glTexCoord2f(1.0,1.0);
glVertex3fv(vertices[c]);
glColor4fv(colors[d]);
glTexCoord2f(1.0,0.0);
glVertex3fv(vertices[d]);
glEnd();
}
void colorcube(void)
{
/* map vertices to faces */
polygon(0,3,2,1);
polygon(2,3,7,6);
polygon(0,4,7,3);
polygon(1,2,6,5);
polygon(4,5,6,7);
polygon(0,1,5,4);
}
static GLfloat theta[] = {0.0,0.0,0.0};
static GLint axis = 2;
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity();
glRotatef(theta[0], 1.0, 0.0, 0.0);
glRotatef(theta[1], 0.0, 1.0, 0.0);
glRotatef(theta[2], 0.0, 0.0, 1.0); 629
630 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
colorcube();
glutSwapBuffers();
}
void spinCube()
{
theta[axis] += 2.0;
if( theta[axis] > 360.0 ) theta[axis] -= 360.0;
glutPostRedisplay();
}
void mouse(int btn, int state, int x, int y)
{
if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN) axis = 0; if(btn==GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) axis = 1; if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN) axis = 2; }
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-2.0, 2.0, -2.0 * (GLfloat) h / (GLfloat) w,
2.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0);
else
glOrtho(-2.0 * (GLfloat) w / (GLfloat) h,
2.0 * (GLfloat) w / (GLfloat) h, -2.0, 2.0, -10.0, 10.0); glMatrixMode(GL_MODELVIEW);
}
void key(unsigned char k, int x, int y)
{
if(k == '1') glutIdleFunc(spinCube);
if(k == '2') glutIdleFunc(NULL);
if(k == 'q') exit(0);
}
void main(int argc, char **argv)
{
GLubyte image[64][64][3];
int i, j, r, c;
for(i=0;i<64;i++)
{
for(j=0;j<64;j++)
{
c = ((((i&0x8)==0)^((j&0x8))==0))*255;
image[i][j][0]= (GLubyte) c;
附录A 实 例 程 序
image[i][j][1]= (GLubyte) c;
image[i][j][2]= (GLubyte) c;
}
}
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500);
glutCreateWindow("colorcube");
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glutIdleFunc(spinCube);
glutMouseFunc(mouse);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glTexImage2D(GL_TEXTURE_2D,0,3,64,64,0,GL_RGB,GL_UNSIGNED_BYTE, image);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glutKeyboardFunc(key);
glClearColor(1.0,1.0,1.0,1.0);
glutMainLoop();
} 631
A.17 GLSL程序
/* display teapot with vertex and fragment shaders */
/* sets up elapsed time parameter for use by shaders */
#include<stdio.h>
#include<stdlib.h>
#include<gl/glut.h>
const float nearVal =1.0f;
const float farVal =300.0f ;
const float lightPos[3] ={3.0f,3.0f,3.0f};
int width =512;
int height =512;
GLint program =0;
GLint timeParam;
/* shader reader */
/* create nulll terminated string from file */
char *readShaderSource(const char *shaderFile)
{
632 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
struct stat statBuf;
FILE *fp =fopen(shaderFile,"r");
char *buf;
stat(shaderFile,&statBuf);
buf=(char *)malloc(statBuf.st_size+1*sizeof(char)); fread(buf,1,statBuf.st_size,fp);
buf[statBuf.st_size]=' ';
fclose(fp);
return buf;
}
/* error printing function */
static void chechError(GLint status,const char *msg) {
if(!status)
{
printf("%s\n",msg);
exit(EXIT_FAILURE);
}
}
/* standard OpenGL initialization */
static void init()
{
const float teapotColor[] ={0.3f,0.5f,0.4f,1.0f};
const float teapotSpecular[] ={0.8f,0.8f,0.8f,1.0f}; const float teapotShininess[] ={80.0f};
glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,teapotColor); glMaterialfv(GL_FRONT,GL_SPECULAR,teapotSpecular); glMaterialfv(GL_FRONT,GL_SHININESS,teapotShininess);
glClearColor(1.0f,1.0f,1.0f,1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f,0.0f,10.0f);
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
}
附录A 实 例 程 序
/* GLSL initialization */
static void initShader(const char *vShaderFile,const char *fShaderFile) {
GLint vShader =0;
GLint fShader =0;
GLint status =0;
/* read shader file */
char *vSource = readShaderSource(vShaderFile);
char *fSource = readShaderSource(fShaderFile);
/* created program and shader objects */
vShader = glCreateShaderObject(GL_VERTEX_SHADER);
fShader = glCreateShaderObject(GL_FRAGMENT_SHADER);
program = glCreateProgramObject();
/* attach shaders to the program object */
glAttachObject(program,vShader);
glAttachObject(program,fShader);
/* read shaders */
glShaderSource(vShader,1,&vShaderFile,NULL);
checkError(status,"Fail to read vertex shader");
glShaderSource(fShader,1,&fShaderFile,NULL);
checkError(status,"Fail to read vertex shader");
/* compile shaders */
glCompileShader(vShader);
glCompileShader(fShader);
/* error check */
glGetObjectParameteriv(vShader,GL_OBJECT_COMPILE_STATUS,&status); checkError(status,"Failed to compile the vertx shader");
glGetObjectParameteriv(fShader,GL_OBJECT_COMPILE_STATUS,&status); checkError(status,"Failed to compile the fragment shader.");
/* link */
glLinkProgam(program);
glGetObjectParameteriv(program,GL_OBJECT_LINK_STATUS,&status); 633
634 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
checkError(status,"Failed to link the shader program object.");
/* use program object */
glUseProgramObject(program);
/* set up uniform parameter */
timeParam = glGetUniformLocation(program,"time");
}
static void draw()
{
/* send elapsed time to shaders */
glUniform1f(timeParam,gltuGet(GL_ELAPSED_TIME));
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glTranslatef(0.0f,0.0f,-10.0f);
glutSolidTeapot(2.0);
glutSwapBuffers();
}
static void reshape(int w,int h)
{
width =w;
height =h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0,(double)width/(double)height,nearVal,farVal); glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0,0,width,height);
glutPostRedisplay();
}
static void keyboard(unsigned char key,int x,int y)
{
switch(key)
{
case 27 :
case 'Q':
case 'q':
exit(EXIT_SUCCESS);
break;
附录A 实 例 程 序
default:
break;
}
}
void main(int argc, char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
glutInitWindowSize(width,height);
glutCreateWindow("Simple GLSL example");
glutDisplayFunc(draw);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
init();
initShader("vPhong.glsl","fPassThrough.glsl");
glutMainLoop();
}
/* the following code is for the vertex and fragment shaders */
/* shader code is assumed to be in separate files */
//Vphong.glsl
//modified Phong vertex shader
uniform float time;
void main(int argc, char *argv[])
{
gl_Position = gl_ModelviewProjectionMatrix * gl_Vertex;
vec4 eyePosition =gl_ModelVewMatrix * gl_Vertex;
vec4 eyeLightPos = gl_LightSource[0].postion;
vec3 eyeNormalVec = normalize(gl_NormalMatrix * gl_Normal);
vec3 eyeLightVec = normalize(eyeLightPos.xyz-eyePosition.xyz); vec3 eyeViewVec = -normalize(eyePosition.xyz);
vec3 eyeHalfVec = normalize(eyeLightVec+eyeViewVec);
float Kd = max(dot(eyeLightVec,eyeNormalVec),0.0);
float Ks = pow(dot(eyeNormalVec,eyeHalfVec),gl_FrontMaterial.shininess); float Ka = 1.0;
gl_FrontColor = Kd * gl_FrontLightProduct[0].diffuse+
Ks * gl_FrontLightProduct[0].specular+
gl_FrontLightModelProduct.sceneColor;
} 635
636 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
// fPassThrough.glsl
// Pass through fragment shader.
void main()
{
gl_FragColor = gl_Color;
}
A.18 场景图形示例
//scene.cc
#include "Scene.h"
#define BaseRadius 0.2
#define Radius 0.08
#define BaseLen 1
#define UpLen 0.6
#define LowLen 0.6
#define EyeRadius 0.04
#define ChairLegLen 0.55
int main(int argc, char **argv)
{
float v[][3]={{-0.3,-0.2,0.0},{0.3, -0.2, 0.0}, {0.3, 0.2, 0.0},{-0.3, 0.2, 0.0} };
//Light nodes
Light *Light1=new Light;
Light *Light2=new Light;
TurnOff *Off1=new TurnOff(Light1);
TurnOff *Off2=new TurnOff(Light2);
//Setting Light Values :
Light1->SetValue(POSITION, -2, -3, 1.5, 1); Light1->SetValue(SPOT_DIRECTION, 2, 3, -1.5); Light1->SetValue(CUTOFFANGLE, 40.0);
Light1->TurnOn();
Light2->SetValue(POSITION, 5, 5, 5, 0);
Light2->SetValue(SPECULAR, 1.0, 1.0, 1.0, 1.0); Light2->SetValue(DIFFUSE, 1.0, 1.0, 1.0, 1.0); Light2->TurnOn();
//Nodes for Camera:
附录A 实 例 程 序
Camera *Camera1=new Camera(PERSPECTIVE);
Camera1->SetValue(POSITION, 2.2, 0.9, 3); Camera1->SetValue(AIMAT, 0, 0, 0);
Camera1->SetValue(UPDIRECTION, 0, 1, 0);
Camera1->SetValue(ASPECT, 1);
Camera1->SetValue(NEAR, 1);
Camera1->SetValue(FAR, 20);
Camera1->SetValue(YANGLE, 50);
//Nodes for Robot:
Material *RobotMat=new Material;
Material *EyeMat=new Material;
Cylinder *Base=new Cylinder;
Sphere *Head=new Sphere;
Sphere *EyeL=new Sphere;
Sphere *EyeR=new Sphere;
Cylinder *UpperArmL=new Cylinder;
Cylinder *UpperArmR=new Cylinder;
Cylinder *LowerArmL=new Cylinder;
Cylinder *LowerArmR=new Cylinder;
Cylinder *UpperLegL=new Cylinder;
Cylinder *UpperLegR=new Cylinder;
Cylinder *LowerLegL=new Cylinder;
Cylinder *LowerLegR=new Cylinder;
Polygon *Paper=new Polygon;
Transformation *EyeLTrans=new Transformation; Transformation *EyeRTrans=new Transformation; Transformation *HeadTrans=new Transformation; Transformation *UpArmLTrans=new Transformation; Transformation *UpArmRTrans=new Transformation; Transformation *LowArmTrans=new Transformation; Transformation *UpLegLTrans=new Transformation; Transformation *UpLegRTrans=new Transformation; Transformation *LowLegTrans=new Transformation; Transformation *BaseTrans=new Transformation;
//Robot Value:
RobotMat->SetValue(DIFFUSE, 0.0, 0.0, 1.0, 1.0); RobotMat->SetValue(AMBIENT, 0.0, 0.0, 1.0, 1.0); RobotMat->SetValue(SPECULAR, 1.0, 1.0, 1.0, 1.0); RobotMat->SetValue(SHININESS, 100.0);
EyeMat->SetValue(DIFFUSE, 1.0, 1.0, 1.0, 1.0); EyeMat->SetValue(AMBIENT, 1.0, 1.0, 1.0, 1.0); EyeMat->SetValue(SPECULAR, 1.0, 1.0, 1.0, 1.0); EyeMat->SetValue(SHININESS, 100.0);
637
638 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
Base->SetValue(HEIGHT, BaseLen);
Base->SetValue(RADIUS, BaseRadius);
Head->SetValue(RADIUS, BaseRadius);
EyeL->SetValue(RADIUS, EyeRadius);
EyeR->SetValue(RADIUS, EyeRadius);
UpperArmL->SetValue(HEIGHT, UpLen);
UpperArmL->SetValue(RADIUS, Radius);
LowerArmL->SetValue(HEIGHT, LowLen);
LowerArmL->SetValue(RADIUS, Radius);
UpperArmR->SetValue(HEIGHT, UpLen);
UpperArmR->SetValue(RADIUS, Radius);
LowerArmR->SetValue(HEIGHT, LowLen);
LowerArmR->SetValue(RADIUS, Radius);
UpperLegL->SetValue(HEIGHT, UpLen);
UpperLegL->SetValue(RADIUS, Radius);
LowerLegL->SetValue(HEIGHT, LowLen);
LowerLegL->SetValue(RADIUS, Radius);
UpperLegR->SetValue(HEIGHT, UpLen);
UpperLegR->SetValue(RADIUS, Radius);
LowerLegR->SetValue(HEIGHT, LowLen);
LowerLegR->SetValue(RADIUS, Radius);
Paper->SetVerticesv(v, 4);
Paper->SetMaterial(EyeMat);
EyeLTrans->SetValue(TRANSLATION, BaseRadius-EyeRadius/2, 0, 0, 0); EyeLTrans->SetValue(ROTATION, 30, 0, 0, 1, 1);
EyeRTrans->SetValue(TRANSLATION, BaseRadius-EyeRadius/2, 0, 0, 0); EyeRTrans->SetValue(ROTATION, -30, 0, 0, 1, 1);
HeadTrans->SetValue(TRANSLATION, 0, 0, BaseLen+BaseRadius+BaseRadius/3, 0); UpArmLTrans->SetValue(TRANSLATION, 0, 0, -UpLen, 0);
UpArmLTrans->SetValue(ROTATION, -45, 0, 1, 0, 1);
UpArmLTrans->SetValue(TRANSLATION, 0, BaseRadius+Radius, BaseLen, 2); UpArmRTrans->SetValue(TRANSLATION, 0, 0, -UpLen, 0);
UpArmRTrans->SetValue(ROTATION, -45, 0, 1, 0, 1);
UpArmRTrans->SetValue(TRANSLATION, 0, -(BaseRadius+Radius), BaseLen, 2); LowArmTrans->SetValue(TRANSLATION, 0, 0, -UpLen, 0);
LowArmTrans->SetValue(ROTATION, -45, 0, 1, 0, 1);
UpLegLTrans->SetValue(TRANSLATION, 0, 0, -UpLen, 0);
UpLegLTrans->SetValue(ROTATION, -90, 0, 1, 0, 1);
UpLegLTrans->SetValue(TRANSLATION, 0, BaseRadius+Radius, 0, 2); UpLegRTrans->SetValue(TRANSLATION, 0, 0, -UpLen, 0);
UpLegRTrans->SetValue(ROTATION, -100, 0, 1, 0, 1);
UpLegRTrans->SetValue(TRANSLATION, 0, -(BaseRadius+Radius), 0, 2); LowLegTrans->SetValue(TRANSLATION, 0, 0, -UpLen, 0);
LowLegTrans->SetValue(ROTATION, 95, 0, 1, 0, 1);
BaseTrans->SetValue(ROTATION, -90, 1, 0, 0, 0);
BaseTrans->SetValue(ROTATION, -10, 0, 0, 1, 1);
Head->SetTransform(HeadTrans);
附录A 实 例 程 序
EyeL->SetTransform(EyeLTrans);
EyeR->SetTransform(EyeRTrans);
EyeR->SetMaterial(EyeMat);
EyeL->SetMaterial(EyeMat);
UpperArmL->SetTransform(UpArmLTrans);
LowerArmL->SetTransform(LowArmTrans);
UpperArmR->SetTransform(UpArmRTrans);
LowerArmR->SetTransform(LowArmTrans);
UpperLegL->SetTransform(UpLegLTrans);
LowerLegL->SetTransform(LowLegTrans);
UpperLegR->SetTransform(UpLegRTrans);
LowerLegR->SetTransform(LowLegTrans);
Base->SetTransform(BaseTrans);
Paper->SetTransform(ROTATION, 20, 0, 1, 0, 0);
Paper->SetTransform(TRANSLATION, 0.05, -0.15, -0.2, 1);
//Set Relationship in Robot:
RobotMat->AddChild(Light1);
Light1->AddChild(Base);
Base->AddChild(Off1);
Off1->AddChild(Light2);
Light2->AddChild(Head);
Head->AddChild(Off2);
Head->AddChild(EyeL);
Head->AddChild(EyeR);
Base->AddChild(UpperArmL);
UpperArmL->AddChild(LowerArmL);
Base->AddChild(UpperArmR);
UpperArmR->AddChild(LowerArmR);
Base->AddChild(UpperLegL);
UpperLegL->AddChild(LowerLegL);
Base->AddChild(UpperLegR);
UpperLegR->AddChild(LowerLegR);
LowerArmR->AddChild(Paper);
//Nodes for Chair:
Cube *Seat=new Cube(0.7, 0.06, 0.7);
Line *Leg1=new Line;
Line *Leg2=new Line;
Line *Leg3=new Line;
Line *Leg4=new Line;
DrawStyle *LegStyle=new DrawStyle;
Color *ChairColor=new Color;
//Chair Value:
float v1[][3]={{-0.3, 0, 0.3},{-0.35, -1*ChairLegLen, 0.3}}; float v2[][3]={{0.3, 0, 0.3},{0.35, -1*ChairLegLen, 0.3}}; 639
640 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
float v3[][3]={{0.3, 0, -0.3},{0.35, -1*ChairLegLen, -0.3}}; float v4[][3]={{-0.3, 0, -0.3},{-0.35, -1*ChairLegLen, -0.3}};
ChairColor->SetValue(RED);
Seat->SetTransform(TRANSLATION, 0, -0.15, 0, 0);
LegStyle->SetValue(LINEWIDTH, 7);
Leg1->SetStyle(LegStyle);
Leg1->SetVerticesv(v1);
Leg2->SetStyle(LegStyle);
Leg2->SetVerticesv(v2);
Leg3->SetStyle(LegStyle);
Leg3->SetVerticesv(v3);
Leg4->SetStyle(LegStyle);
Leg4->SetVerticesv(v4);
Seat->AddChild(Leg1);
Seat->AddChild(Leg2);
Seat->AddChild(Leg3);
Seat->AddChild(Leg4);
ChairColor->AddChild(Seat);
//Transformation Nodes for both Robot and Chair:
Transformation *Trans1=new Transformation;
Trans1->SetValue(TRANSLATION, -0.5, 0, 0, 2);
Trans1->AddChild(ChairColor);
Trans1->AddChild(RobotMat);
//Root Node:
Node *Root=new Node;
Root->AddChild(Trans1);
Root->AddChild(Camera1);
//Viewer:
GLViewer *MyViewer=new GLViewer;
MyViewer->Init(argc, argv);
MyViewer->SetValue(BACKCOLOR, GREY);
MyViewer->SetValue(BUFFER, DOUBLE);
MyViewer->CreateWin("Working Hard", 500, 500);
GLViewer *MyViewer2=new GLViewer;
MyViewer2->Init(argc, argv);
MyViewer2->SetValue(BACKCOLOR, MAGENTA);
MyViewer2->CreateWin("Working Hard2", 200, 200);
MyViewer2->SetValue(BUFFER, DOUBLE);
MyViewer->Show(Root);
附录A 实 例 程 序
MyViewer2->Show(Root);
return 0;
}
641
A.19 Bezier曲线程序
/* curves.c */
/*
**
** Bezier curve drawing program.
**
** q - Quit the program
** c - Clear the screen
** e - Erase the curves
** b - Draw Bezier curves
**
*/
#include <GL/glut.h>
void keyboard(unsigned char key, int x, int y);
#define MAX_CPTS 25 /* Fixed maximum number of control points */
GLfloat cpts[MAX_CPTS][3];
int ncpts = 0;
static int width = 500, height = 500; /* Window width and height */
static void drawCurves()
{
int i;
for(i=0;i<ncpts-3;i+=3)
{
/* draw the curve using OpenGL evaluators */
glMap1f(GL_MAP1_VERTEX_3,0.0,1.0,3,4,cpts[i]);
glMapGrid1f(30,0.0,1.0);
glEvalMesh1(GL_LINE,0,30);
}
glFlush();
}
static void display(void)
{
int i;
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POINTS);
642 交互式计算机图形学—— 基于OpenGL的自顶向下方法(第4版)
for (i = 0; i < ncpts; i++)
glVertex3fv(cpts[i]);
glEnd();
glFlush();
}
void mouse(int button, int state, int x, int y)
{
float wx, wy;
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
/* Translate back to our coordinate system */
wx = (2.0 * x) / (float)(width - 1) - 1.0;
wy = (2.0 * (height - 1 - y)) / (float)(height - 1) - 1.0;
/* See if we have room for any more control points */
if (ncpts == MAX_CPTS)
return;
/* Save the point */
cpts[ncpts][0] = wx;
cpts[ncpts][1] = wy;
cpts[ncpts][2] = 0.0;
ncpts++;
/* Draw the point */
glColor3f(0.0, 0.0, 0.0);
glPointSize(5.0);
glBegin(GL_POINTS);
glVertex3f(wx, wy, 0.0);
glEnd();
glFlush();
}
}
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 'q': case 'Q':
exit(0);
break;
case 'c': case 'C':
ncpts = 0;
glutPostRedisplay();
break;
case 'e': case 'E':
glutPostRedisplay();
break;
case 'b': case 'B':
附录A 实 例 程 序
drawCurves();
break;
}
}
void reshape(int w, int h)
{
width = w;
height = h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW);
glViewport(0, 0, w, h);
}
void main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB);
glutInitWindowSize(width, height); glutCreateWindow("curves");
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutReshapeFunc(reshape);
glClearColor(1.0, 1.0, 1.0, 1.0);
glColor3f(0.0,0.0,0.0);
glPointSize(5.0);
glEnable(GL_MAP1_VERTEX_3);
glutMainLoop();
}
643