B样条曲线
B样条是使用更广泛的逼近样条类。B样条有两个贝塞尔样条所不具备的优点:1、B样条多项式次数可独立于控制点数目(有一定限制);2、B样条允许局部控制曲线或曲面。缺点是B样条比贝塞尔样条更复杂。我们可以把沿B样条曲线的坐标位置的计算表示写成混合函数公式的表达式:
B样条的局部控制可以由定义在u取值范围中子区间上的混合函数来实现。B样条曲线的混合函数由Cox-deBoor递归公式定义为
所选的一组子区间端点Uj称为节点(kont),而选定的一组之区间的端点整体称为节点向量(kont vector)。可以选择满足Uj=<Uj+1的任意值作为子区间端点。Umin和Umax的值取决于所选的控制点个数、参数d的取值、如何建立子区间(节点向量)。除了局部控制,B样条曲线允许通过改变控制点的个数来设计一条曲线,而不需要改变多项式的次数。也可以增加或修改控制点的数目来控制曲线形状。类似地,可以增加节点向量的值从而辅助曲线的设计。 B样条曲线具有以下性质:
- 在u取值范围内,多项式曲线的次数为d-1,并且具有C^d-2连续性。
- 对于n+1个控制点,曲线由n+1个混合函数进行描述。
- 每个混合函数Bk,d定义在u取值范围的d子区间上,以节点向量之Uk为起点。
- 参数u的取值范围由n+d+1个节点向量中指定的值分成n+d个子区间。
- 节点值记为{U0,U1,…,Un+d},所生成的B样条曲线仅定义在从节点值Ud-1到节点值Un+1的区间上。
- 每个样条曲线段(在两个相邻节点值间)受d个控制点影响。
- 任意一个控制点可以影响最多d条曲线段的形状。
- 对于从节点值Ud-1到Un+1区间上的任意值u,所有的基本函数之和为1:B0,d(u)+B1,d(u)+…+Bn,d(u) = 1。
给出控制点位置和参数d的值,则需要执行节点值,并使用Cox-deBoor递归关系来获得混合函数。节点向量有三种分类:均匀的、开放均匀的和非均匀的。
示例演示
按照《计算机图形学(第四版)》的公式,写出了程序在均匀的 节点向量情况下总是不对。所以做点小改动。首先Cox-deBoor递归公式改为如下:
然后,u等于节点值Un+1时减去一个很小的值。
/**********************************************************************
Copyright (c) Mr.Bin. All rights reserved.
For more information visit: http://blog.csdn.net/webzhuce
**********************************************************************/
#include <vtkPolyDataMapper.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkActor.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkProperty.h>
#include <vtkPoints.h>
#include <vtkSphereSource.h>
#include <vtkGlyph3DMapper.h>
#include "vtkBSplineSource.h"
int main()
{
double p0[3] = { -40.0, -40.0, 0.0 };
double p1[3] = { -20.0, 200.0, 0.0 };
double p2[3] = { 20.0, 200.0, 0.0 };
double p3[3] = { 40.0, -40.0, 0.0 };
vtkNew<vtkPoints> points;
points->InsertNextPoint(p0);
points->InsertNextPoint(p1);
points->InsertNextPoint(p2);
points->InsertNextPoint(p3);
// spline points
vtkNew<vtkSphereSource> spheresource;
spheresource->SetPhiResolution(20);
spheresource->SetThetaResolution(20);
spheresource->SetRadius(10);
spheresource->Update();
vtkNew<vtkPolyData> ctrlpointsdata;
ctrlpointsdata->SetPoints(points);
vtkNew<vtkGlyph3DMapper> ctrlpointsmapper;
ctrlpointsmapper->SetInputData(ctrlpointsdata);
ctrlpointsmapper->SetSourceConnection(spheresource->GetOutputPort());
ctrlpointsmapper->Update();
vtkNew<vtkActor> ctrlpointsactor;
ctrlpointsactor->SetMapper(ctrlpointsmapper);
ctrlpointsactor->GetProperty()->SetColor(1.0, 0.0, 0.0);
//spline
vtkNew<vtkBSplineSource> spline;
//open uniform
int d = 4;
std::vector<float> knots = { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,1.0f,1.0f };
open uniform
//int d = 3;
//std::vector<float> knots = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f};
spline->SetParameters(points, d, knots);
vtkNew<vtkPolyDataMapper> splinemapper;
splinemapper->SetInputConnection(spline->GetOutputPort());
vtkNew<vtkActor> splineactor;
splineactor->SetMapper(splinemapper);
splineactor->GetProperty()->SetColor(1.0, 0.0, 0.0);
//render
vtkNew<vtkRenderer> renderer;
renderer->AddActor(ctrlpointsactor);
renderer->AddActor(splineactor);
renderer->SetBackground(1.0, 1.0, 1.0);
vtkNew<vtkRenderWindow> renderwindow;
renderwindow->SetSize(400, 200);
renderwindow->AddRenderer(renderer);
vtkNew<vtkRenderWindowInteractor> interactor;
interactor->SetRenderWindow(renderwindow);
vtkNew<vtkInteractorStyleTrackballCamera> style;
interactor->SetInteractorStyle(style);
interactor->Initialize();
interactor->Start();
return EXIT_SUCCESS;
}
运行结果
1、均匀的节点向量
2、开放均匀的节点向量