Obecnie piszę dla naszego studia mały wieloplatformowy silnik gier 2D oparty na OpenGL. Kiedy badałem, której klasy Vector Vector użyć, natknąłem się na trzy różne paradygmaty projektowania:
Float & Call-by-value, jak w tym artykule Gamasutra . Wydaje się być szybki, ale oferuje niewielką precyzję (zobacz także ten wątek ). Pro: Szybki, przenośny i kompatybilny z większością bibliotek.
Podwójne i Call-by-referencyjne. Jeśli dobrze rozumiem powyższy artykuł, mógłbym również użyć 2 zmiennych o podwójnej precyzji zamiast 4 liczb zmiennoprzecinkowych. Zgodnie z powyższym wątkiem podwójny jest nadal wolniejszy niż pływak.
Szablon podwójny i zmiennoprzecinkowy: W popularnej książce „ Game Engine Architecture ” wykorzystuje się szablony, aby w razie potrzeby można było stosować zmiennoprzecinkowe i zmiennoprzecinkowe. Oczywistym minusem jest rozdęcie kodu. Wątpię też, czy kod można zoptymalizować bez pisania dwóch klas.
Z przyjemnością dowiem się, jakich rozwiązań używasz w swoich silnikach wewnętrznych i jak precyzyjne są np. Popularne silniki gier, więc mogę zdecydować, jakie rozwiązanie zastosuję w naszym silniku. W tej chwili myślę o zwykłym użyciu precyzji float i z nią żyć.
źródło
Odpowiedzi:
Zawsze używam liczb zmiennoprzecinkowych, chyba że mam powód, aby używać podwójnego, podobnie jak int, chyba że mam powód, aby używać int64_t.
Pływaki nie mają problemu z wykonywaniem dokładnej arytmetyki liczb całkowitych do 2 24 , czego boi się większość ludzi (głównie irracjonalnie). Podwajanie nie rozwiązuje problemu braku dokładności reprezentatywnych wartości - niezależnie od tego, czy otrzymujesz 0.10000001, czy 0.10000000000000001, nadal musisz upewnić się, że Twój kod uznaje go za „równy” 0,09999999.
Podwajanie jest wolniejsze na każdej platformie, na której zależy ci pisanie gier, zabierasz dwukrotnie przepustowość pamięci i masz mniej dostępnych instrukcji procesora.
Pływaki o pojedynczej precyzji pozostają standardem dla sprzętowych interfejsów graficznych, zarówno po stronie C / C ++, jak i wewnątrz shaderów.
Prawdopodobnie w pewnym momencie będziesz potrzebować podwójnego wektora, ale powinien on być używany w razie potrzeby, nie domyślnie.
Jeśli chodzi o szablony - masz rację, aby uzyskać maksymalną wydajność, i tak musisz ręcznie specjalizować szablony. Poza tym w weekend przeprowadziłem kilka testów dla kodu szablonowego (tworząc 4-osobowy IntRect i FloatRect) i stwierdziłem, że kompilacja wersji szablonowej zajęła około 20 razy więcej czasu niż tylko powtórzenie kodu, który wynosił około 15 linii . Powtarzanie jest do bani, ale czekanie na kompilacje jest do bani - i to nie tak, że nigdy nie będę potrzebować StringRect ani FooRect.
źródło
Struktura gry Microsoft XNA ma klasę Vector2, która wykorzystuje zmiennoprzecinkowe. Byłby to mój osobisty największy powód, aby pływać z floatami, ponieważ ufam, że mądrość i doświadczenie zespołu XNA są znacznie większe niż moje.
Uważam, że przeczytanie odpowiedzi w tym pytaniu przepełnienia stosu jest dość interesujące: „Float vs Double Performance” . Istnieje także wątek gamedev.net z dyskusją na temat podwójnej wydajności procesorów graficznych. Myślę, że można bezpiecznie założyć, że podwójne są wolniejsze niż zmiennoprzecinkowe, przynajmniej w wielu procesorach graficznych, a ja osobiście zawsze korzystałem z funkcji zmiennoprzecinkowych OpenGL w stosunku do podwójnych odpowiedników. Może to nie dotyczyć obecnie, ale jeśli weźmiesz pod uwagę, że nie każdy, kto uruchamia twoją grę, ma najnowszą kartę graficzną z natywną podwójną obsługą, myślę, że jest to wystarczający powód, aby używać liczb zmiennoprzecinkowych i uzyskać dodatkową wydajność.
źródło