✠OpenGL-11-参数曲面

Posted itzyjr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了✠OpenGL-11-参数曲面相关的知识,希望对你有一定的参考价值。


“贝塞尔曲线”和“贝塞尔曲面”,这些方法通常用于高效地对各种曲面 3D 物体进行建模。用它们可以生成任意精度的曲线。

二次贝塞尔曲线

二次贝塞尔曲线由一组参数方程定义, 方程组中使用 3 个控制点指定特定的曲线的形状,每个控制点都是 2D 空间中的一个点。

针对各种 t 值收集大量的点 P(t),则会产生一条曲线,如上图所示。采样的 t 的参数值越多,生成的点 P(t)越多,得到的曲线则越平滑。

现在可以导出二次贝塞尔曲线的分析定义。首先,我们注意到连接两个点 pa 和 pb 的线段 pa−pb 上的任意点 p 可以用参数 t 表示如下:
p ( t ) = t p a + ( 1 − t ) p b p(t)=tp_a+(1-t)p_b p(t)=tpa+(1t)pb
使用该等式,我们解出点 p01 和 p12(分别在 p0−p1 和 p1−p2 上的点)如下:
p 01 = t p 1 + ( 1 − t ) p 0 p 12 = t p 2 + ( 1 − t ) p 1 p_{01}=tp_1+(1-t)p_0\\\\ p_{12}=tp_2+(1-t)p_1 p01=tp1+(1t)p0p12=tp2+(1t)p1


可参见Blog“第7章 CustomView绘图进阶-贝济埃曲线
P ( t ) = ( 1 − t ) 2 p 0 + ( − 2 t 2 + 2 t ) p 1 + t 2 p 2 P(t) = (1-t)^2p_0 + (-2t^2+2t)p_1+t^2p_2 P(t)=(1t)2p0+(2t2+2t)p1+t2p2

三次贝塞尔曲线




P ( t ) = ∑ i = 0 3 p i B i ( t ) 其 中 , B 0 ( t ) = ( 1 − t ) 3 B 1 ( t ) = 3 t 3 − 6 t 2 + 3 t B 2 ( t ) = − 3 t 3 + 3 t 2 B 3 ( t ) = t 3 P(t)=\\sum_{i=0}^3{p_iB_i(t)}\\\\ 其中,\\\\ B_0(t)=(1-t)^3\\\\ B_1(t)=3t^3-6t^2+3t\\\\ B_2(t)=-3t^3+3t^2\\\\ B_3(t)=t^3 P(t)=i=03piBi(t)B0(t)=(1t)3B1(t)=3t36t2+3tB2(t)=3t3+3t2B3(t)=t3
渲染贝塞尔曲线时,可以使用许多不同的技术。其中一种方法是,使用固定的增量,在0.0~1.0 范围内,迭代增加得出 t 的后继值。例如,当增量为 0.1 时,我们可以使用 t 值为0.0、 0.1、 0.2、 0.3 等的循环。对于 t 的每个值,计算贝塞尔曲线上的对应点,并绘制连接连续点的一系列线段,算法如下:

void drawBezierCurve(controlPointVector C) {
	currentPoint = C[0];// 曲线从第一个控制点开始
	t = 0.0;
	while (t <= 1.0) {
		// 计算混合函数在t时对控制点的加权和,作为曲线的下一个点
		nextPoint = (0, 0);
		for (int i = 0; i <= 3; i++)
			nextPoint += blending(i, t) * C[i];
		drawLine(currentPoint, nextPoint);
		currentPoint = nextPoint;
		t += increment;
	}
}

double blending(int i, double t) {
	switch(i) {
		case 0: return (1-t)*(1-t)*(1-t);// (1-t)^3
		case 1: return 3*t*(1-t)*(1-t);// 3t(1-t)^2
		case 2: return 3*t*t*(1-t);// 3t^2(1-t)
		case 3: return t*t*t;// t^3
	}
}

下面画一个曲线:

vector<glm::vec3> drawBezierCurve(vector<glm::vec3> Ctrl) {
	vector<glm::vec3> points;
	points.push_back(Ctrl[0]);
	double t = 0.0;
	while (t <= 1.0) {
		glm::vec3 nextPoint;
		nextPoint.x = 0;
		nextPoint.y = 0;
		nextPoint.z = 0;
		for (int i = 0; i <= 3; i++) {
			nextPoint.x += blending(i, t) * C[i].x;
			nextPoint.y += blending(i, t) * C[i].y;
		}
		points.push_back(nextPoint);
		t += 0.1;
	}
	return points;
}

void setupVertices(void) {
	vector<glm::vec3> Ctrl;
	Ctrl.push_back(glm::vec3(0.1, 0.5, 0));
	Ctrl.push_back(glm::vec3(0.4, 0.9, 0));
	Ctrl.push_back(glm::vec3(0.6, 0.95, 0));
	Ctrl.push_back(glm::vec3(0.9, 0.55, 0));
	vector<glm::vec3> points = drawBezierCurve(Ctrl);
	...
}

void display(...) {
	...
	glLineWidth(1.0);
	glDrawArrays(GL_LINE_STRIP, 0, values.size() / 3);
}

在XY平面画了一条三次贝塞尔曲线,如下图:

二次贝塞尔曲面

贝塞尔曲线定义了曲线(在 2D 或 3D 空间中),而贝塞尔曲面定义了 3D 空间中的曲面。将我们在曲线中看到的概念扩展到曲面, 需要将参数方程组中的参数个数从一个扩展到两个。对于贝塞尔曲线,我们将参数称为 t。对于贝塞尔曲面,我们将参数称为 u 和 v。曲线由点 P(t)组成,而曲面将由点 P(u, v)组成,如下图所示。

对于二次贝塞尔曲面,每个轴 u 和 v 上有3 个控制点,总共 9 个控制点。下图使用蓝色展示了一组共 9 个控制点(通常称为控制点“网格”)的示例,以及相应的曲面(红色)。

P ( u , v ) = ∑ i = 0 2 ∑ j = 0 2 p i j B i ( u ) B j ( v ) 其 中 , B 0 ( u ) = ( 1 − u ) 2 B 1 ( u ) = − 2 u 2 + 2 u B 2 ( u ) = u 2 B 0 ( v ) = ( 1 − v ) 2 B 1 ( v ) = − 2 v 2 + 2 v B 2 ( v ) = v 2 P(u,v)=\\sum_{i=0}^2\\sum_{j=0}^2{p_{ij}B_i(u)B_j(v)}\\\\ 其中,\\\\ B_0(u)=(1-u)^2\\\\ B_1(u)=-2u^2+2u\\\\ B_2(u)=u^2\\\\ B_0(v)=(1-v)^2\\\\ B_1(v)=-2v^2+2v\\\\ B_2(v)=v^2\\\\ P(u,v)=i=02j=02pijBi(u)Bj(v)B0(u)=(1u)2B1(u)=2u2+2uB2(u)=u2B0(v)=(1v)以上是关于✠OpenGL-11-参数曲面的主要内容,如果未能解决你的问题,请参考以下文章

OpenCASCADE 参数曲面面积

MATLAB | 如何绘制三维曲线曲面多边形投影(三视图)?

MATLAB | 如何绘制三维曲线曲面多边形投影(三视图)?

基于B样条基函数的隐式曲面重建

zbrush曲面增加厚度

第83天 blender小技巧-02曲面刻字