实验四 自由曲线曲面算法实验实验项目性质:设计性实验所属课程名称:3D 游戏图形学实验计划学时:3学时一、 实验目的和要求1. 了解自由曲线和曲面的生成原理;2. 掌握并实现Bezier 曲线和B 样条曲线的生成算法;3. 实现Bezier 曲面的生成算法。
二、 实验原理1. Bezier 曲线是通过一组多边形折线的顶点来定义的。
如果折线的顶点固定不变,则由其定义的Bezier 曲线是唯一的。
在折线的各顶点中,只有第一点和最后一点在曲线上且作为曲线的起始处和终止处,其他的点用于控制曲线的形状及阶次。
曲线的形状趋向于多边形折线的形状,要修改曲线,只要修改折线的各顶点就可以了。
因此,多边形折线又称Bezier 曲线的控制多边形,其顶点称为控制点。
三次多项式,有四个控制点,如图1所示,其数学表示如下:,300.31 1.32 2.33 3.30()()()()()()i i i Q t PB t P B t PB t P B t P B t ===+++∑32230123(1)3(1)3(1),[0,1]t P t t P t t P t P t =-+-+-+∈(1)其矩阵形式为01322313313630()(1),[0,1]33001000P P Q t t t t t P P --⎡⎤⎡⎤⎢⎥⎢⎥-⎢⎥⎢⎥=∈⎢⎥⎢⎥-⎢⎥⎢⎥⎣⎦⎣⎦(2)2. B 样条曲线保留了Bezier 曲线的优点,对Bezier 曲线进行了拓广,用B 样条基代替Bernstein 基,克服了Bezier 曲线由于整体表示带来的不具备局部性质的缺点。
B 样条曲线的数学定义为0n k k,m k p(t)P B (t)==∑(3)式中,(0,1,,)k P k n = 为n+1个控制点,由控制点顺序连成的折线称为B 样条控制多边形。
m 是一个阶参数,可以取2到控制顶点个数n+1之间的任一整数,m-1是B 样条曲线的次数。
参数t 的选取取决于B 样条结点矢量的选取。
k,m B (t)是B 样条基函数,()()k 1,1,,11,1111 ()0 ()k k k k m k m k m k m k m k k m k t t t B t t t t t B t B t B t t t t t ++-+-+-++≤<⎧=⎨⎩--=+--若其它 (4) k t 是结点值,01(,,,)n m T t t t += 构成了m-1次B 样条函数的结点矢量,其中的结点是非减序列,所生成的B 样条曲线定义在从结点值1m t -到结点值1n t +的区间上,而每个基函数定义在t 的取值范围内的k t 到k+m t 的子区间内。
从式(3)和(4)可以看出,仅仅给定控制点和参数m 还不足以完全表达B 样条曲线,还需要给定结点矢量并使用公式(4)来获得基函数。
对于三次均匀周期性B 样条曲线,m=4,如果用4个控制点来拟合三次曲线,则n=3。
假设结点矢量(0,1,2,3,4,5,6,7)T =,于是得到基函数计算式为:()(),1,,11,11 1()0 ()11k k m k m k m k t k B t t k k m t B t B t B t m m -+-≤<+⎧=⎨⎩-+-=+--其他 (5)最终得到该B 样条曲线的矩阵形式为,0010414243423013223()1331363011303061410 t [0,1)nk k mk ,,,,B B p t P B P P B (t)B (t)B (t)B (t)P P P P t t t P P T M G ==⎡⎤⎢⎥⎢⎥=⋅⎡⎤⎣⎦⎢⎥⎢⎥⎣⎦--⎡⎤⎡⎤⎢⎥⎢⎥-⎢⎥⎢⎥⎡⎤=⋅⋅⋅⎣⎦⎢⎥⎢⎥-⎢⎥⎢⎥⎣⎦⎣⎦=⋅⋅∈∑ (6) 三、 实验内容1.下面的代码用来生成三次Bezier 曲线,将代码补充完整,编译运行;修改代码,利用OpenGL 函数生成三次Bezier 曲线。
参考代码:#include <GL/glut.h>#include <stdio.h>#include <stdlib.h>#include <vector>using namespace std;struct Point{int x, y;};Point pt[4],bz[11];vector <Point> vpt;bool bDraw;int nInput;void CaleBZPoints(){添加代码;生成Bezier 曲线上的点;}void ControlPoint(vector <Point> vpt){glPointSize(2);for(int i=0;i<vpt.size();i++){glBegin(GL_POINTS);glColor3f(1.0f,0.0f,0.0f); glVertex2i(vpt[i].x,vpt[i].y);glEnd();}}void PolylineGL(Point * pt, int num){glBegin(GL_LINE_STRIP);for(int i=0;i<num;i++){glColor3f(1.0f,1.0f,1.0f);glVertex2i(pt[i].x,pt[i].y);}glEnd();}void myDisplay(){glClear(GL_COLOR_BUFFER_BIT);glColor3f(1.0f,1.0f,1.0f);if(vpt.size()>0){ControlPoint(vpt);}if(bDraw){PolylineGL(pt, 4);CaleBZPoints();PolylineGL(bz,11);}glFlush();}void Init(){glClearColor(0.0,0.0,0.0,0.0);glShadeModel(GL_SMOOTH);printf("Please Click left button of mouse to input control point of Bezier Curve!\n");}void Reshape(int w, int h){glViewport(0,0,(GLsizei)w,(GLsizei)h);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluOrtho2D(0.0,(GLdouble)w,0.0,(GLdouble)h);}void mouse(int button, int state, int x, int y){switch(button){case GLUT_LEFT_BUTTON:if(state==GLUT_DOWN){if(nInput==0){pt[0].x=x;pt[0].y=480-y;nInput=1;vpt.clear();vpt.push_back(pt[0]);bDraw=false;glutPostRedisplay();}else if(nInput==1){pt[1].x=x;pt[1].y=480-y;vpt.push_back(pt[1]);nInput=2;glutPostRedisplay();}else if(nInput==2){pt[2].x=x;pt[2].y=480-y;vpt.push_back(pt[2]);nInput=3;glutPostRedisplay();}else if(nInput==3){pt[3].x=x;pt[3].y=480-y;bDraw=true;vpt.push_back(pt[3]);nInput=0;glutPostRedisplay();}}break;default:break;}}int main(int argc, char * argv[]){glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);glutInitWindowPosition(100,100);glutInitWindowSize(640,480);glutCreateWindow("Hello World!");Init();glutDisplayFunc(myDisplay);glutReshapeFunc(Reshape);glutMouseFunc(mouse);glutMainLoop();return 0;}2. 改写教材P241程序8-1,实现三次均匀周期性B样条曲线的生成算法,并利用OpenGL函数生成同样的三次周期性B样条曲线。
参考代码:#include <GL/glut.h>#include <math.h>#include <stdlib.h>class Pt3D{public:GLfloat x,y,z;};void GetCnk(GLint n, GLint *c){GLint i,k;for(k=0;k<=n;k++){c[k]=1;for(i=n;i>=k+1;i--) c[k]=c[k]*i;for(i=n-k;i>=2;i--) c[k]=c[k]/i;}}void GetPointPr( GLint *c, GLfloat t, Pt3D *Pt, int ControlN, Pt3D *ControlP){GLint k,n=ControlN-1;GLfloat Bernstein;Pt->x=0.0; Pt->y=0.0; Pt->z=0.0;for(k=0; k<ControlN; k++){Bernstein=c[k]*pow(t,k)*pow(1-t,n-k);Pt->x += ControlP[k].x*Bernstein;Pt->y += ControlP[k].y*Bernstein;Pt->z += ControlP[k].z*Bernstein;}}void BezierCurve(GLint m, GLint ControlN, Pt3D *ControlP){GLint *C,i;Pt3D CurvePt;C = new GLint[ControlN];GetCnk(ControlN-1, C);glBegin (GL_POINTS);for(i=0;i<m;i++){GetPointPr(C,(GLfloat)i/(GLfloat)m, &CurvePt, ControlN, ControlP);glVertex2f(CurvePt.x, CurvePt.y);}glEnd();delete [] C;}void initial(void){glClearColor (1.0, 1.0, 1.0, 0.0);// pNurb=gluNewNurbsRenderer();}void Display(void){glClear(GL_COLOR_BUFFER_BIT);GLint ControlN=4,m=500;Pt3DControlP[4]={{-80.0,-40.0,0.0},{-10.0,90.0,0.0},{10.0,-90.0,0.0},{80. 0,40.0,0.0}};glColor3f(0.0, 0.0, 0.0);BezierCurve(m,ControlN,ControlP);// gluBeginCurve(pNurb);for(GLint i=0;i<4;i++)glVertex3f(ControlP[i].x,ControlP[i].y,ControlP[i].z);glEnd();glFlush();}void Reshape(GLint newWidth, GLint newHeight){glViewport(0,0,newWidth,newHeight);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluOrtho2D(-100.0,100.0,-100.0,100.0);}void main(void){glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);glutInitWindowPosition(100, 100);glutInitWindowSize(400, 400);glutCreateWindow("Bezier曲线");initial();glutDisplayFunc(Display);glutReshapeFunc(Reshape);glutMainLoop();}3. 利用OpenGL函数实现Bezier曲面的生成算法。