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、開放均勻的節點向量