Bezier的定义
贝塞尔曲面是贝塞尔曲线在二维上的扩展。它由一组控制点定义,通过这些控制点生成光滑的曲面。贝塞尔曲面通常用两个参数 u u u和 v v v来表示,这两个参数的取值范围都在 [0, 1] 之间。
数学表示
P
(
u
,
v
)
=
∑
i
=
0
n
∑
j
=
0
m
p
i
j
⋅
B
i
,
n
(
u
)
⋅
B
j
,
m
(
v
)
P(u,v)=\sum_{i=0}^n\sum_{j=0}^m p_{ij}\cdot B_{i,n}(u)\cdot B_{j,m}(v)
P(u,v)=∑i=0n∑j=0mpij⋅Bi,n(u)⋅Bj,m(v)
其中:
●
P
(
u
,
v
)
P(u,v)
P(u,v)是曲面上的一个点。
●
P
i
,
j
P_{i,j}
Pi,j是控制点矩阵中的一个控制点。
●
B
i
,
n
(
u
)
B_{i,n}(u)
Bi,n(u)和
B
j
,
m
(
v
)
B_{j,m}(v)
Bj,m(v)是bezier基函数,它们的定义是:
B
i
,
n
(
u
)
=
C
n
i
u
i
(
1
−
u
)
n
−
i
=
n
!
i
!
(
n
−
i
)
!
u
i
(
1
−
u
)
n
−
i
(
i
=
0
,
1
,
.
.
.
.
n
)
B_{i,n}\left(u\right)=C_{n}^{i}u^{i}\left(1-u\right)^{n-i}=\frac{n!}{i!\left(n-i\right)!}u^{i}\left(1-u\right)^{n-i}\quad\left(i=0,1,....n\right)
Bi,n(u)=Cniui(1−u)n−i=i!(n−i)!n!ui(1−u)n−i(i=0,1,....n)
B
j
,
m
(
v
)
=
C
v
j
v
j
(
1
−
v
)
m
−
j
=
m
!
j
!
(
m
−
j
)
!
v
j
(
1
−
v
)
m
−
j
(
j
=
0
,
1
,
.
.
.
.
n
)
B_{j,m}\left(v\right)=C_{v}^{j}v^{j}\left(1-v\right)^{m-j}=\frac{m!}{j!\left(m-j\right)!}v^{j}\left(1-v\right)^{m-j}\quad\left(j=0,1,....n\right)
Bj,m(v)=Cvjvj(1−v)m−j=j!(m−j)!m!vj(1−v)m−j(j=0,1,....n)
控制点
控制点矩阵定义了贝塞尔曲面的形状。控制点的个数决定了曲面的阶数(degree)。例如,一个四阶的贝塞尔曲面需要 5 × 5 5×5 5×5个控制点。通过移动控制点,可以调整贝塞尔曲面的形状。
特性
● 局部控制:移动一个控制点只会影响该点附近的曲面区域,而不会影响整个曲面。
● 多项式性质:贝塞尔曲面的每个参数方向上都是贝塞尔多项式的线性组合。
● 仿射不变性:贝塞尔曲面在进行仿射变换(例如平移、旋转、缩放)时,其形状不变。
应用
贝塞尔曲面广泛应用于各种设计和动画中,包括:
● 汽车和飞机设计:贝塞尔曲面用于设计光滑的车身和机翼。
● 动画和特效:用于生成复杂的角色和场景。
● 3D建模:在3D建模软件中,贝塞尔曲面常用于创建复杂的曲面模型。
OpenGL代码
BezierSurface::BezierSurface(std::vector<std::vector<glm::vec3>> controlPoints) : Object()
{
this->controlPoints = controlPoints;
CalculateVertices();
SetData();
}
float BezierSurface::binomialCoefficient(int n, int k)
{
// n! / (i! * (n - i)!)
if (k > n)
return 0;
if (k == 0 || k == n)
return 1;
float coeff = 1.0f;
for (int i = 1; i <= k; ++i)
{
coeff *= (n - (k - i));
coeff /= i;
}
return coeff;
}
float BezierSurface::bezierBasis(int n, int i, float t)
{
// binomialCoefficient(n, i) * pow(t, i) * pow(1 - t, n - i)
return binomialCoefficient(n, i) * pow(t, i) * pow(1 - t, n - i);
}
Vertex BezierSurface::CalculatePoint(float u, float v)
{
int m = controlPoints.size() - 1;
int n = controlPoints[0].size() - 1;
Vertex vertex;
glm::vec3 point(0.0f);
glm::vec2 tex(0.0f);
for (int i = 0; i <= m; ++i)
{
for (int j = 0; j <= n; ++j)
{
float basisU = bezierBasis(m, i, u);
float basisV = bezierBasis(n, j, v);
point += controlPoints[i][j] * basisU * basisV;
}
}
vertex.position = point;
tex.x = u;
tex.y = 1.0F - v;
vertex.texCoord = tex;
return vertex;
}
void BezierSurface::CalculateVertices()
{
vertices.clear();
std::vector<Vertex> tvs;
// 计算顶点
for (int i = 0; i <= 100; ++i)
{
for (int j = 0; j <= 100; ++j)
{
float u = (float)i / 100.0f;
float v = (float)j / 100.0f;
Vertex vertex = CalculatePoint(u, v);
vertices.push_back(vertex);
}
}
// 索引
indices.resize(100 * 100 * 6 * sizeof(unsigned int));
// 计算索引
for (int i = 0; i < 100; ++i)
{
for (int j = 0; j < 100; ++j)
{
int index = i * 101 + j;
indices.push_back(index);
indices.push_back(index + 1);
indices.push_back(index + 101);
indices.push_back(index + 1);
indices.push_back(index + 101);
indices.push_back(index + 102);
}
}
// 计算法线
CalculateNormal();
}