Gönderen Konu: [C++] Std::Vector ve OpenGL Soruları  (Okunma sayısı 5255 defa)

[C++] Std::Vector ve OpenGL Soruları

« : 07.12.2007 00:53:04 »
Hızlı düğmeleri aç

fredi

İleti: 99

Çevrimdışı
  • **
  • Jr. Member
    • Profili Görüntüle
Herkese selam. Ragnor efendiyle birlikte demolarımız ve oyunlarımız için ufak tefek 2d bir framework hazırlama uğraşındayız ve şunu merak etmekteyiz.

1. Aşağıdakilerden hangisini kullanmak performans açısından daha iyidir?

a.
Kod: [Seç]

glBegin(GL_LINES);
   glVertex2d(a, b);
   glVertex2d(c, d);
glEnd();

glBegin(GL_LINES);
   glVertex2d(e, f);
   glVertex2d(g, h);
glEnd();


b.
Kod: [Seç]

glBegin(GL_LINES);
   glVertex2d(a, b);
   glVertex2d(c, d);

   glVertex2d(e, f);
   glVertex2d(g, h);
glEnd();


Tahminen b şıkkının daha iyi olduğunu düşünerek primitif çizdiren sınıfımıza "batching" olduğunu sandığım bir yöntem ekledik. Önce line'lar bir vektöre ekleniyor. Bir fonksiyon da bu vektörü baştan sona gezerek hepsini tek bir glBegin-glEnd çifti içerisinde çiziyor.

ıkinci sorum bu vektörden birşeyler silme hakkında.
şu anda böyle bir fonksiyona sahibim.

Kod: [Seç]

void IPrimitive::DeleteLine(int iNo)
{
std::vector::iterator iter;

for (iter = vecLines.begin(); iter != vecLines.end(); iter++)
{
if (iter->no == iNo)
{
                                  // MSVS 2005'te iterator döndürüyor bu  fonksiyon.
                                  // Nedenini bilmiyorum.
iter = vecLines.erase(iter);  
}
}
}


Sorun şu ki silinecek eleman vektöre son eklenen eleman ise run time error alıyorum. Eğer değilse sorunsuzca siliniyor. Vector'den eleman silme hakkında Google'da epey kaynak buldum ama hepsinde aynı sorunu aldım ya da doğru implement edemedim.

Aldığım error şu:
Alıntı

---------------------------
Microsoft Visual C++ Debug Library
---------------------------
Debug Assertion Failed!

Program: ...
File: d:\program files\microsoft visual studio 8\vc\include\vector
Line: 118

Expression: ("_Myptr < ((_Myvec *)(this->_Mycont))->_Mylast", 0)

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.

(Press Retry to debug the application)
---------------------------
Abort   Retry   Ignore  
---------------------------


şimdiden teşekkürler. :rolleyes:

[C++] Std::Vector ve OpenGL Soruları

« Yanıtla #1 : 07.12.2007 01:33:04 »
Hızlı düğmeleri aç

anesthetic

İleti: 403

Çevrimdışı
  • ****
  • Sr. Member
    • Profili Görüntüle
    • http://resident.tr-demoscene.info/
OpenGL Lines hakkında: Vertex array seçeneği ile karşılaştırınca ikisi de oldukça yavaş yöntemler. Yani çok çok çok line basılacak ve bu yüzden cpu tarafındaki kodun hızı önemliyse begin end combosu yanlış bir tercih. Yok eğer çok kastırıcı bi şey yoksa begin endin en kolay kullanımını bırakıp onu hızlandırmaya çalışmak mantıksız. ılkinin diğeri üzerindeki tek overheadi fazladan begin end çağrımları, yoksa ikisi de bir yerde bu çizim komutlarını tutup flush atınca asıl işlerini yapacaklar ve çizimler aynı sürecek.

ufak bi hesap yapalım. 100 line çizdirecek ol. ilk yöntem 4*100=400 function call yapacak, ikincisi ise 2*100+2=200 function call. ama vertex array kullansaydın 2 function call olacaktı, bu üçünün çizim süreleri aynı olacak.

stl::vector hakkında: erase, silinen elemandan bir sonraki elemana iterator dönecek. loopu while halinde yazarsak sorun açıkça ortaya çıkacak.

Kod: [Seç]
iter = vecLines.begin();
while ( iter != vecLines.end())
{
if (iter->no == iNo)
{
// tüm stl implementasyonlarında iter döner
iter = vecLines.erase(iter);  
}
iter++ ;
}


örneğin a->b->c->d elemanları vektörde art arda olsunlar. biz b'yi silersek, erase c'yi dönecek. loopun sonunda kendi elimizde d'ye geçeceğiz. (c'yi hiç kontrol etmemiş olduk.)

eğer b'den sonra eleman olmasaydı (a->b->end) end'e gelecektik, sonra iter++ bizi endden sonra garbage bi bölgeye götürecek, haliye refere edersek runtime hatası olacak.

aklıma gelen en basit fix yine while loop üzerinden:

Kod: [Seç]
iter = vecLines.begin();
while ( iter != vecLines.end())
{
if (iter->no == iNo)
{
iter = vecLines.erase(iter);  
}
else iter++ ;
}

[C++] Std::Vector ve OpenGL Soruları

« Yanıtla #2 : 07.12.2007 01:39:26 »
Hızlı düğmeleri aç

fredi

İleti: 99

Çevrimdışı
  • **
  • Jr. Member
    • Profili Görüntüle
Benim de derdim overhead'di aslında. Aslında amacıma ulaştım, daha iyi bir yöntem buldum: vertex array :) Bir ara kodu vertex array'e geçirmeye çalışacağız çünkü şu anda bilmiyoruz ne olduğunu. [Sözde Ragnor OpenGl hakkında bilgili olacak]

Vector olayı düzeldi, gerçekten çok teşekkürler. :)

[C++] Std::Vector ve OpenGL Soruları

« Yanıtla #3 : 07.12.2007 01:44:18 »
Hızlı düğmeleri aç

anesthetic

İleti: 403

Çevrimdışı
  • ****
  • Sr. Member
    • Profili Görüntüle
    • http://resident.tr-demoscene.info/
hmm uykusuzluğuma ver :) vertexleri vektöre ekleyip tek tek glVertex'lemeye çalışıyormuşsun zaten. openglde bunun hızlı basit yolu var :) vertex arrayler.

bi arraya çizeceğin vektörlerin datasını koy (vertex array). bi arraye de bu arrayden çizileceklerin çizilme sırasını (index array). sonra drawarrays ile çizimi yap. index array'den istediğin zaman çizilmesini istemedeğin şeyleri çıkar.

daha da güzeli: array bozup düzeltmek yerine kimlerin çizilceğini tutan bir başka bool arrayi yap (edge flag array). o direk sen çizil sen çizilme desin. sen flag arrayde linelara true false at. bunların hepsi direk opengl özellikleri.

[C++] Std::Vector ve OpenGL Soruları

« Yanıtla #4 : 07.12.2007 01:45:05 »
Hızlı düğmeleri aç

anesthetic

İleti: 403

Çevrimdışı
  • ****
  • Sr. Member
    • Profili Görüntüle
    • http://resident.tr-demoscene.info/
son yazdığını görmeden yazdım üsttekini acayip durdu cevap kusura bakma :)

[C++] Std::Vector ve OpenGL Soruları

« Yanıtla #5 : 07.12.2007 01:58:26 »
Hızlı düğmeleri aç

fredi

İleti: 99

Çevrimdışı
  • **
  • Jr. Member
    • Profili Görüntüle
Ahah sorun değil.

Vertex ve Index array arraylerine yeni veri eklemek için nasıl bir yöntem kullanılıyor? Bu framework epey bi cross-platform olacağından Stl kullanmaktan kaçınmak istiyoruz, hatta hiç kullanmazsak en iyisi olacak.

[C++] Std::Vector ve OpenGL Soruları

« Yanıtla #6 : 07.12.2007 06:54:05 »
Hızlı düğmeleri aç

nightlord

İleti: 1.085

Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.nightnetwork.org
1- opengl destekleyen hemen her platformda stl de haydi haydi vardir. mumkun oldugunca cok stl (+ boost) kullanmanizi tavsiye ederim. stl kullanan bir kodu debug etmek bazen zor olabilir. Ama ben buna degecegini dusunuyorum. Yani hayir kalkip kendi linked list containerlarinizi yaratmayin :)
 
2- stl'i duzgun kullaniyorsaniz cogu zaman for veya while gibi donguler yazmaniza hic gerek kalmiyor olmali. onlarin yerine stl algoritmalarini kullanmalisiniz. std::for_each std::erase gibi. compilerlar tek satirlik algoritma cagrimlarini dongulerden cok daha iyi optimize ederler. cilginlar gibi heryerde for_each kullanabilmek icin functor kavramini ogrenmeniz ve stl ve boost bunyesindeki functor fonksiyonalitelerini kullanmaniz lazim (bind memfun vs)
 
3- eger ayni vertex containerina surekli vertex ekleyip cikarma durumundaysaniz (ortalama 1000 vertexe her frame mesela 100 tane ekleyip 100 tane cikariyor falansaniz) duruma gore vector yerine list kullanip vertexarray yerine direk glVertex cagrilari kullanmak daha hayirli olabilir. ama bi bakmak lazim. genel olarak vertek gruplarinda vertexlerin sayisini dinamik olarak degistirmemeye calismakta fayda var.

[C++] Std::Vector ve OpenGL Soruları

« Yanıtla #7 : 07.12.2007 11:30:21 »
Hızlı düğmeleri aç

skate

İleti: 5.245

A Sinner Scener
Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.akaydin.com/
her iki yöntemin de implementasyonu kolay olduğu için benim tavsiyem farklı yöntemler kullanan iki extended fonksiyon yazmanız ve her ikisinin FPS testini yapmanız olacaktır. benim tahminim sizin yapmaya çalıştığınız şeyde vertex array'in daha hızlı olacağı yönünde. eğer çok dinamik bir yapı kullanmayacaksanız arraylerde elinizden geldiğince precalculation kullanmanızı tavsiye ederim. maximum performans ancak bu şekilde alınır. mesela LOD gibi bir olay için kesinlikle precalculation öneririm. tabii yapmak istediğinizin tam olarak ne olduğunu bilmiyorum henüz.

[C++] Std::Vector ve OpenGL Soruları

« Yanıtla #8 : 07.12.2007 15:02:48 »
Hızlı düğmeleri aç

fredi

İleti: 99

Çevrimdışı
  • **
  • Jr. Member
    • Profili Görüntüle
Aslında vector'le ilgili sorunum hakkında bilgi araştırırken std::remove_if diye bir algoritma gözüme çarptı. Nasıl kullanıldığını tam anlamadım ama sanırım onu kullanmak en iyi çözüm vectorden belli elemanları silerken. Nasıl kullanıldığını anlatabilecek bir babayiğit var mı? :)

@Skate: Aslında iki üç tane çizgi çizdririrken dağlar kadar performans artışı yaptırmaya çalışmıyoruz. O yüzden sadece "en azından doğru yolu kullanalım" dediğimizden sormuştum o soruyu. Ama dediğin gibi precalc. yöntemlerine yönelmeliyiz.

Teşekkürler hepinize :)

[C++] Std::Vector ve OpenGL Soruları

« Yanıtla #9 : 07.12.2007 23:58:37 »
Hızlı düğmeleri aç

nightlord

İleti: 1.085

Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.nightnetwork.org
http://www.cplusplus.com/reference/algorithm/remove_if.html
 
baslangic ve bitis iteratorleri ile bir predicate veriyorsunuz. predicate true false donduren bir functor demek. true dondurmeyen objeler container'in basina toplaniyor. bunlarin sonuncusundan bir sonraya bakan bir iterator donduruluyor. linkteki sayfada bir ornek var.
 
dondurulen iteratorden containerin sonuna kadarki elemanlari kullandiginiz containerin erase methodu ile silebilirsiniz. tek satirda soyle kullanabilirsiniz
 
Kod: [Seç]
myCont.erase( std::remove_if(myCont.begin(), myCont.end(), pred), myCont.end() );

[C++] Std::Vector ve OpenGL Soruları

« Yanıtla #10 : 08.12.2007 00:05:43 »
Hızlı düğmeleri aç

fredi

İleti: 99

Çevrimdışı
  • **
  • Jr. Member
    • Profili Görüntüle
Bu bool döndüren fonksiyona verilecek parametreleri falan remove_if nasıl biliyor? Yani fonksiyon illa vector'ün ait olduğu tipte bir parametre almak zorunda da, remove_if fonksiyona parametre olarak o anki elemanı mı geçiyor?

Sanırım bu functor olayını çalışmam gerekiyor :)

[C++] Std::Vector ve OpenGL Soruları

« Yanıtla #11 : 08.12.2007 03:09:09 »
Hızlı düğmeleri aç

nightlord

İleti: 1.085

Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.nightnetwork.org
evet aynen oyle predicate bir parametre alan ve bool donduren bir fonsiyon veya "0 parametre alan () operatoru overload edilmis bir class" (yani functor)
 
pred'e gecirilen parametre sirasi gelen obje oluyor.
 
functor ozel bir class tipine sahip bir obje demek. o class tipinin ozelligi operator()'un overloaded olmasi. mesela
 
Kod: [Seç]

class A{
public:
    bool operator()(){ return true;}
};
 
int main(){
    A myA;
    if ( myA() ){
        ...
    }
    ....
}

Functorlari anlamak STL algoritmalrini ve boost kullanmanin onkosulu. Bir kavradiginiz zaman onunuzu cok acacak ve C++ kod yazma hizinizi yaklasik 10 kat artiracak :)
 
mesela
 
Kod: [Seç]

class cSoldier{
public:
    ...
    bool mIsDead();
    ...
};
 
class cGame{
public:
    ...
    void mManageSoldiers();
    ...
private:
    ...
    std::list aSoldiers;
    ...
};
 
void cGame::mManageSoldiers(){
    ...
    aSoldiers.erase( std::remove_if( aSoldiers.begin(), aSoldiers.end(),
                                     std::mem_fun( &cSoldier::mIsDead ) ),
                     aSoldiers.end() );
    ...
}

buradaki mem_fun bir stl guzelligidir. orada bize bir functor classi yaratmaya yariyor. yukaridaki ilk ornekteki gibi operator()'u overload edilmis bir class yaratmis oluyor (bunu templateler sayesinde perde arkasinda yapiyor). bu yaratilmis class'in overload edilmis olan () operatorunun tek yaptigi is de cSoldier::mIsDead'i cagirmak. bunun icin bu metod oyle yaratiliyor ki, ilk parametre olarak cSoldier tipinden bir obje aliyor, ve ardindan da mIsDead ne kadar parametre aliyorsa o kadar parametre daha aliyor ve mIsDead ile ayni tipten bir deger geri donduruyor yani soyle bir kod uretiliyor arkada gibi dusunebilirsiniz:
 
Kod: [Seç]

class PerdeArkasiFunctor{
public:
    bool operator()( cSoldier* i ){ return i->mIsDead(); }
};

Bu kod gercekte boyle degil tabi gercek uretilen kodun template'i daha farkli ama anlatimi kolaylastirmak icin bunu kullandim. mem_fun hakkinda daha cok bilgi icin:
 
http://www.sgi.com/tech/stl/mem_fun_t.html
 
Bunlari yazarken birkez daha bir c++ tutoriali yazmak konusunda gaza geldim ama daha sirasi degil :)

[C++] Std::Vector ve OpenGL Soruları

« Yanıtla #12 : 08.12.2007 03:56:30 »
Hızlı düğmeleri aç

fredi

İleti: 99

Çevrimdışı
  • **
  • Jr. Member
    • Profili Görüntüle
Anladım hoş bi olaymış. Sanırım bundan sonra STL ve Boost konusunda ilerleme katedmem gerekiyor. Ragnor kodu anlayabilsin diye char'dan öteye geçemedik de :P

Aslında abi bu STL ile tek sorunum compiler errorlarında çıkan yazıların ilk bakışta çok cesaret kırıcı olması. Ne bileyim, tonlarca < >, bol underscore'lu değişken isimleri vs. Öyle yani :)

[C++] Std::Vector ve OpenGL Soruları

« Yanıtla #13 : 08.12.2007 05:50:29 »
Hızlı düğmeleri aç

nightlord

İleti: 1.085

Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.nightnetwork.org
Dogru... STL kullanirken en buyuk zorluk budur. Bununla ilgili olarak Effective STL kitabinda Scott Meyers soyle bir yol tavsiye eder. Cikan hatayi alip oldugu gibi notepad'e yapistirin. Sonra yavas yavas text replace yapin. hata mesajinda ne zaman bir template adi gecse o template'a arguman olarak verilen butun class isimleri falan da kocamaaan bir hede< hodo, budu, ...> gurubunun icinde hata raporuna eklenir. bunlari tek kelime ile search/replace yapin. Eger ne oldugun anlamazsaniz direk "something" falan koyun der Scott Amca. bunu iteratif olarak 3-4 kere yaptiginizda o zaman genelde bir paragraflik STL hata mesajlari bir satirlik anlamli cumleler haline gelirler.

[C++] Std::Vector ve OpenGL Soruları

« Yanıtla #14 : 09.12.2007 00:09:32 »
Hızlı düğmeleri aç

fredi

İleti: 99

Çevrimdışı
  • **
  • Jr. Member
    • Profili Görüntüle
Bu arada yakalamışkan sormak istiyorum. Kodun neresinin neden olduğundan emin olmadığım bir warning alıyorum.

Alıntı
Warning   1   warning C4312: 'type cast' : conversion from 'uintptr_t' to 'void *' of greater size   d:\program files\microsoft visual studio 8\vc\include\xlocnum   590


Nedendir?