自由曲线与曲面(II) 计算机科学与技术
自由曲面 在汽车、飞机、船舶的等产品的外形设计和放样工作中,曲面的应用非常广泛,这些部门对曲面的研究十分重视。从某种意义上讲,曲面的表示可以看作是曲线表示方法的延伸和扩展。 例如: 平面曲线: P(t)= [x(t) , y(t) ] 参数t 空间曲线: P(t)= [x(t) , y(t),z(t) ] 曲面: P(u,w)= x(u,w), y(u,w), z(u,w) 参数u,w
曲面的参数形式 曲面需要两个参数 x=x(u, v) y=y(u, v) z=z(u, v) p(u,v) = [x(u,v), y(u,v), z(u,v)]T 曲面的要求: 平滑性 可导性 易于求值 x y z p(u,0) p(1,v) p(0,v) p(u,1)
法向量计算 分别对u和v求导,得到曲面上一点的p的法向量
平面参数形式 点-向量形式 三点形式 n r p(u,v)=p0+uq+vr n = q x r q p0 n q = p1 – p0 r = p2 – p0
Bezier曲面 Bezier曲面是Bezier曲线的扩展,Bezier曲面的边界线就是由四条Bezier曲线构成的。以两组正交的Bezier曲线控制点构造空间网格来生成曲面。 依次用线段连接点列Pi,j(i=0,1,…,m;j=0,1,…,n)中相邻两点所形成的空间网格称为控制网格
双三次Bezier曲面 三次Bezier曲线段由四个控制点确定,当m=3,n=3时由4×4=16个控制点构成控制网格,其相应的曲面称为双三次Bezier曲面。16个控制点组成一个矩阵:
双三次Bezier曲面 令 P(u,v)=UMPMTVT
双三次Bezier曲面 生成曲面时可以通过先固定u, 变化v得到一簇Bezier曲线;然后固定v,变化u得到另一簇Bezier曲线,两簇曲线交织生成Bezier曲面。
双三次Bezier曲面的拼接 两张双三次Bezier曲面片也可以拼接在一起。其Beizer曲面片表述如下: 两片Bezier曲面的控制多边形。达到G0连续性的条件是: p3, i =q0, i (i = 0, 1, 2, 3)
双三次Bezier曲面的拼接 达到G1连续性的条件是: (i=0,1,2,3)。 一般情况下,在连接处保持一阶导数连续较为困难,要求两个控制多边形中位于交点处的两条边必须共线,但设计中很难做到这一点。 为满足G1连续性的条件的两片Bezier曲面的控制多边形。
OpenGL曲线和曲面 OpenGL通过求值器产生曲线和曲面 可以生成任意自由度的多项式曲线 可以将其他类型的多边形曲线和曲面转换成Bezier曲线和曲面 达到应用要求的精度
OpenGL绘制曲线 设定一维求值器(Evaluator) void glMap1f( GLenum target, //生成目标,最终生成绘制点用GL_MAP_VERTEX_3 GLfloat u1, //贝赛尔曲线模型的参数,这个参数定义域为[0,1] //如果生成完整的贝赛尔曲线必须在整个 GLfloat u2, //定义域当中生成。U1代表下限,U2代表上限, //一般分别设为0和1 GLint stride, //每个控制点所使用的浮点数个数 GLint order, //曲线的阶,等于曲线上的控制点数量 const GLfloat *points //指向控制点数组的指针 ); glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, cpts[i]);
OpenGL绘制曲线
OpenGL绘制曲线 2. 启动求值器函数 glEnable(参数) 参数与设定求值器第一个参数相同 关闭求值器函数 glDisable()
OpenGL绘制曲线 3. 调用计算坐标函数 void glMapGrid1f( GLint un, //定义一个均匀分布的网格,它是从u1到u2 GLfloat u1, //开始的网格点 GLfloat u2 //结束的网格点 ); void glEvalMesh1( GLenum mode, //绘图模式,GL_POINT点,GL_LINE线, //GL_FILL填充,当然GL_FILL应该用在曲面 GLint i1, //开始绘制的网格点 GLint i2 //结束绘制的网格点 ); 方法二:void glEvalCoord1{fd}[v](TYPE u); 该函数产生曲线坐标值并绘制。参数u是定义域内的值,这个函数调用一次只产生一个坐标。在使用glEvalCoord1*()计算坐标,因为u可取定义域内的任意值,所以由此计算出的坐标值也是任意的。
OpenGL绘制曲线-程序 定义控制点 设定求值器 GLint nNumPoints = 4; GLfloat ctrlPoints[4][3] = {{-0.5f, -0.5f, 0.0f}, {-1.5f, 0.5f, 0.0f}, {1.0f, -0.5f,0.0f}, {0.5f, 0.0f, 0.0f}}; 设定求值器 glMap1f(GL_MAP1_VERTEX_3, 0.0f, 100.0f, 3, //精度的数量 nNumPoints, // &ctrlPoints[0][0]); glEnable(GL_MAP1_VERTEX_3); //启用求值器
OpenGL绘制曲线-程序 方法1:计算坐标- 定义均匀分布的一维坐标值 方法2:计算坐标- 启用的一维求职器执行计算 glMapGrid1d(100, 0.0, 100.0); //定义一个均匀分布的0到100的网格,中间有100个阶段 glEvalMesh1(GL_LINE, 0,100); //从0到100的每一步调用glMapGrid1d函数; 方法2:计算坐标- 启用的一维求职器执行计算 glBegin(GL_LINE_STRIP); for(int i =0; i <= 100; i++) { glEvalCoord1f( (GLfloat)i ); } glEnd();
OpenGL绘制曲线-程序 运行结果
OpenGL绘制曲面 设定二维求值器 void glMap2f( GLenum target, GLfloat u1, GLfloat u2, GLint ustride, //u方向上一个控制点与下一个控制点的距离 GLint uorder, //阶数,等于控制点数量 GLfloat v1, GLfloat v2, GLint vstride, //u方向上一个控制点与下一个控制点的距离 GLint vorder, //阶数,等于控制点数量 const GLfloat *points );
OpenGL绘制曲面 glColor3f(0.0f, 0.0f, 1.0f); //设置映射方式,只需要设置一次可以在SetupRC中调用。 glMap2f(GL_MAP2_VERTEX_3, //生成的数据类型 0.0f, // u的下界 10.0f, //u的上界 3, //数据中点的间隔 4, //u方向上的阶 0.0f, //v的下界 10.0f, //v的上界 12, // 控制点之间的间隔 4, // v方向上的阶 &ctrlPoints[0][0][0]); //控制点数组 //启用求值器 glEnable(GL_MAP2_VERTEX_3); //从0到10映射一个包含10个点的网格 glMapGrid2f(10, 0.0f, 10.0f, 10, 0.0f, 10.0f); // 计算网格 glEvalMesh2(GL_LINE, 0, 10, 0, 10);