Bu yazımızda NURBS (Non-Uniform Rational B Spline ) sınıflarını
inceleyeceğiz ve az sayıda koordinatlarla eğrinin/yüzeyin nasıl gösterilebileceğini
inceleyeceğiz.
Matematiksel temelleri :
Grafiksel programlarda her zaman elimizde denklemi olan
yüzeyler olmaz, dolayısı ile koordinatlarını bildiğimiz bir sistemi nasıl gösterebiliriz?
Diyelim elimizde üç nokta var ve grafiğimiz sadece bu üç noktadan oluşuyor. Bu
üç noktadan bir çizgi mi geçecek? Yoksa bir parabol mu yoksa tamamen başka bir
fonksiyon mu? Bunların cevabı çoğu zaman kullanıcıya kalmıştır. Kısaca söylemek gerekirse
tanımlayacağımız parametreler ışığında elimizdeki noktalara uygun bir fonksiyon tanımlanacak
ve o fonksiyonun görüntüsü alınacak.İşin uyguluma kısmından önce NURBS nedir
kısaca açıklayayım. Uniform veya Non Uniform kontrol noktalarının eğri üzerindeki
etkisini belirlemektedir.Örneğimizde Non-Uniform bir spline kullanılmıştır.Uniform
spline kullanmak isteseydik bütün değerleri artarak giden değerler olarak girecektik.B-Spline
ise özel bir fonksiyondur.Bu fonksiyon ile noktalarımız en optimum eğri denklemini
verecektir.Ayrıca değişik Spline fonksiyonları da vardır (cubic,quadratic,TPS,RBF,MQ...).Nümerik
metod dersi almış olanlar kaynaklarından bakarak bu fonksiyonlara erişebilirler.
Yeni Sınıflarımız :
Sınıf |
Açıklama |
SoNurbsCurve : |
Eğrinin bilgilerinin ve metodlarının tutulduğu sınıf.
Bu sınıf bizden knot vektörlerini ve koordinatları beklemektedir. Knot vektörleri
eğrinin şeklini belirleyecektir. Elimizdeki nokta sayısına ek olarak 8 tane fazla
knot tanımlayabiliriz. Bu bize maksimum 8. dereceden bir eğri verecektir. Yani elimizde
10 tane nokta varsa knot sayısı 18 olacaktır. Detaylı örneği kod üzerinde açıklayacağım. |
SoCoordinate3
: |
3 Boyutlu koordinatların
ve metodlarının tutulduğu sınıftır. Amacı görüntü üretmek değil koordinat bilgileri
değişik sınıfların kullanabileceği şekilde saklamaktır. |
SoDrawStyle
: |
Renderin nasıl
edileceğini belirlememizi sağlayan sınıftır. Render işleminin çizgisel mi noktasal
mı olacağını ve bunun özelliklerini belirler. |
Uygulama
:
Uygulama olarak
heliks tarzında, z yönünde arttıkça çapı küçülen 13 nokta tanımlıyoruz.Daha sonra
bu noktalara uyacak şekilde bir eğri tanımlıyoruz, bunun için ise knotları tanımlıyoruz.
Kodda da görebileceğiniz gibi 17 knot tanımladık ve değerlere dikkat ederseniz bu
knotlar ya sabit kalmakta ya da artmaktadır. Örnek üzerinde bu değerlerin ağırlıklarını
açıklayacağım.
Uygulama Kodumuz
:
// yeni headerler ekliyoruz bunlar SoDrawStyle,SoCoordinate3 ve SoNurbsCurve
// bu koda yeni bakıyorsanız bir önceki yazımı okumanızı tavsiye ederim
#include <Inventor/Qt/SoQt.h>
#include <Inventor/Qt/SoQtRenderArea.h>
#include <Inventor/Qt/viewers/SoQtExaminerViewer.h>
#include <Inventor/SoDB.h>
#include <Inventor/nodes/SoCone.h>
#include <Inventor/nodes/SoCube.h>
#include <Inventor/nodes/SoDirectionalLight.h>
#include <Inventor/nodes/SoGroup.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoPerspectiveCamera.h>
#include <Inventor/nodes/SoRotation.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoSphere.h>
#include <Inventor/nodes/SoTranslation.h>
#include <Inventor/sensors/SoTimerSensor.h>
#include <Inventor/actions/SoGLRenderAction.h>
#include <qapplication.h>
#include <qgroupbox.h>
#include <qlayout.h>
#include <Inventor/nodes/SoEventCallback.h>
#include <Inventor/events/SoKeyboardEvent.h>
#include <Inventor/sensors/SoTimerSensor.h>
#include <Inventor/actions/SoGLRenderAction.h>
#include <Inventor/nodes/SoDrawStyle.h>
#include <Inventor/nodes/SoComplexity.h>
#include <Inventor/nodes/SoCoordinate3.h>
#include <Inventor/nodes/SoNurbsCurve.h>
// global olarak controlPts nesnesini tanımlıyoruz
SoCoordinate3 *controlPts;
// Şeklimizin koordinatlarını aşağıda tanımlıyoruz
float pts[13][3] = {
{ 6.0, 0.0, 6.0},
{-5.5, 0.5, 5.5},
{-5.0, 1.0, -5.0},
{ 4.5, 1.5, -4.5},
{ 4.0, 2.0, 4.0},
{-3.5, 2.5, 3.5},
{-3.0, 3.0, -3.0},
{ 2.5, 3.5, -2.5},
{ 2.0, 4.0, 2.0},
{-1.5, 4.5, 1.5},
{-1.0, 5.0, -1.0},
{ 0.5, 5.5, -0.5},
{ 0.0, 6.0, 0.0}};
/* Eğrimizin şeklini belirleyen asıl kısım aşağıda bu değerler ile eğrimizin hangi
noktada ne kadar eğik olacağı belirlenmektedir */
float knots[17] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10};
void main(int argc, char **argv)
{
QWidget *myWindow = SoQt::init(argv[0]);
if (myWindow == NULL) exit(1);
// Ana nesnemizi oluşturuyoruz
SoSeparator *curveSep = new SoSeparator;
curveSep->ref();
// SoDrawStyle nesnesi oluşturup bunun genişliğini 4 yapıyoruz
SoDrawStyle *drawStyle = new SoDrawStyle;
drawStyle->lineWidth = 4;
curveSep->addChild(drawStyle);
// Yeni bir koordinat nesnesi ve NurbsCurve nesnesi oluşturuyoruz
controlPts = new SoCoordinate3;
SoNurbsCurve *curve = new SoNurbsCurve;
/* Aşağıda gördüğünüz gibi SoCoordinate3 nesnesinin setValues metodu
bizden başlangıç noktasını ve kaç tane nokta vermemiz gerektiğini ve noktaları ister
*/
controlPts->point.setValues(0, 13, pts);
/* kontrol noktalarını 13 olarak ayarlıyoruz bu örneğimizde kontrol
nokta sayısı koordinat sayısı ile eşit */
curve->numControlPoints = 13;
/* En son olarak knot vektörünün değerlerini nesnemize geçiriyoruz
*/
curve->knotVector.setValues(0, 17, knots);
/* addChild metodları ile nesneleri birbirlerine ekliyoruz */
curveSep->addChild(controlPts);
curveSep->addChild(curve);
SoQtExaminerViewer *myViewer = new SoQtExaminerViewer(myWindow);
myViewer->setSceneGraph(curveSep);
SoQt::show(myWindow);
SoQt::mainLoop();
//return 0;
}
|
Kodu çalıştırınca :
Gelelim knot vektörü içinde ki değerlerin anlamlarına
: knot vektörü içindeki değerler kontrol noktalarında "basis functionun" başlayacağını
ve biteceğini belirtmektedir. Sizin bilmeniz gereken tek şey şu; hangi noktalarda
tekrar varsa o koordinattaki değerler eğrinin şeklini daha fazla belirlemektedir.
(1)
Yukarıda gördüğünüz örnekte, sağ tarafta elimizde
5 tane koordinat var (siyah noktalar) ve buna bir eğri tanımlıyoruz. Solda ise knot
diyebileceğimiz dizi var. Knottaki değerlerin herbiri o noktadaki koordinatın etkisinin
vermektedir. Dolayısı ile ortalarda 4,4,4 olması bize orta noktadaki değerin
fazla ağırlığı olduğunu göstermektedir. Eğer eğrimizin başlangıç ve bitiş noktalarından
geçmesini istiyorsak yukarıdaki diziyi 0,0,0,1,2,3,4,4,4 yaparsak eğrimiz başlangıç
ve bitiş noktalarından geçer ve eğri orta noktada daha düz bir eğim alır.
Sonuç olarak :
Genelde cisimlerin denklemleri olmadığı için(küre,küp,koni
gibi) mecburen koordinatlardan yola çıkarak cismin şeklini kestirmeye çalışırız. Bunu
yaparken de değişik fonksiyonlarla bu noktalardan anlamlı şekil çıkartırız. Fonksiyonları
tanımlamak için de knot vektörlerini kullanırız. NURBS sınıfları işte bu noktada kullanılmaktadır.
Gelecek yazımda vertex tabanlı modellemeyi işleyeceğim.
Kaynaklar:
(1): http://www-evasion.imag.fr/Membres/FrancoisFaure/doc/inventorMentor/sgi_html/ch08.html
Sorularınız için : [email protected]
Makale:
3D Grafik Programlama 2 : NURBS C++ ve C++.NET dili Özkan Eren
|