Jednostka centralna komputera (CPU) i jednostka przetwarzania grafiki (GPU) współdziałają w każdej chwili, gdy używasz komputera, aby zapewnić Ci wyraźny i responsywny interfejs wizualny. Czytaj dalej, aby lepiej zrozumieć, jak ze sobą współpracują.
zdjęcie zrobione przez sskennel .
Dzisiejsza sesja pytań i odpowiedzi jest dostępna dzięki uprzejmości SuperUser - części Stack Exchange, grupy witryn z pytaniami i odpowiedziami, prowadzonej przez społeczność.
Pytanie
Czytnik SuperUser Sathya zadał pytanie:
Tutaj możesz zobaczyć zrzut ekranu małego programu C ++ o nazwie Triangle.exe z obracającym się trójkątem opartym na API OpenGL.
Wprawdzie bardzo prosty przykład, ale myślę, że ma on zastosowanie do innych operacji związanych z kartami graficznymi.
Byłem po prostu zaciekawiony i chciałem poznać cały proces od dwukrotnego kliknięcia Triangle.exe pod Windows XP, aż zobaczę obracający się trójkąt na monitorze. Co się dzieje, jak współdziałają procesor (który najpierw obsługuje plik .exe) i GPU (który ostatecznie wyświetla trójkąt na ekranie)?
Myślę, że w wyświetlaniu tego obracającego się trójkąta zaangażowany jest przede wszystkim między innymi następujący sprzęt / oprogramowanie:
Sprzęt komputerowy
- HDD
- Pamięć systemowa (RAM)
- procesor
- Pamięć wideo
- GPU
- wyświetlacz LCD
Oprogramowanie
- System operacyjny
- DirectX / OpenGL API
- Sterownik Nvidia
Czy ktoś może wyjaśnić ten proces, może za pomocą jakiegoś schematu blokowego dla ilustracji?
Nie powinno to być skomplikowane wyjaśnienie obejmujące każdy krok (przypuszczam, że wykraczałoby to poza zakres), ale wyjaśnienie, które może zastosować średniozaawansowany informatyk.
Jestem prawie pewien, że wiele osób, które nazwaliby siebie nawet informatykami, nie potrafiło poprawnie opisać tego procesu.
Odpowiedź
Chociaż wielu członków społeczności odpowiedziało na to pytanie, Oliver Salzburg poszedł o krok dalej i odpowiedział nie tylko szczegółową odpowiedzią, ale także doskonałą grafiką towarzyszącą.
Zdjęcie: JasonC, dostępne jako tapeta tutaj .
On pisze:
Postanowiłem napisać trochę o aspekcie programistycznym io tym, jak komponenty komunikują się ze sobą. Może rzuci trochę światła na pewne obszary.
Prezentacja
Czego potrzeba, aby w ogóle mieć ten pojedynczy obraz, który zamieściłeś w swoim pytaniu, narysowany na ekranie?
Istnieje wiele sposobów narysowania trójkąta na ekranie. Dla uproszczenia załóżmy, że nie użyto żadnych buforów wierzchołków. (ZA bufor wierzchołków jest obszarem pamięci, w którym przechowujesz współrzędne.) Załóżmy, że program po prostu przekazał potokowi przetwarzania grafiki każdy pojedynczy wierzchołek (wierzchołek jest po prostu współrzędną w przestrzeni) w wierszu.
Ale , zanim będziemy mogli cokolwiek narysować, musimy najpierw uruchomić jakieś rusztowanie. Zobaczymy czemu później:
// Wyczyść ekran i bufor głębokości glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Zresetuj bieżącą macierz widoku modelu glMatrixMode (GL_MODELVIEW); glLoadIdentity (); // Rysowanie za pomocą trójkątów glBegin (GL_TRIANGLES); // Czerwony glColor3f (1,0f, 0,0f, 0,0f); // Góra trójkąta (przód) glVertex3f (0,0f, 1,0f, 0,0f); // Zielony glColor3f (0,0f, 1,0f, 0,0f); // Po lewej stronie trójkąta (przód) glVertex3f (-1,0f, -1,0f, 1,0f); // Niebieski glColor3f (0,0f, 0,0f, 1,0f); // Prawo trójkąta (przód) glVertex3f (1,0f, -1,0f, 1,0f); // Gotowe rysowanie glEnd ();
Więc co to zrobiło?
Kiedy piszesz program, który chce korzystać z karty graficznej, zwykle wybierasz jakiś rodzaj interfejsu do sterownika. Niektóre dobrze znane interfejsy do sterownika to:
- OpenGL
- Direct3D
- CUDA
W tym przykładzie będziemy trzymać się OpenGL. Teraz twój interfejs do kierowcy jest tym, co daje Ci wszystkie narzędzia potrzebne do stworzenia programu rozmowa do karty graficznej (lub sterownika, który wtedy rozmowy do karty).
Ten interfejs z pewnością da ci pewność przybory . Te narzędzia mają kształt OGIEŃ do którego możesz zadzwonić ze swojego programu.
To API jest tym, co widzimy w powyższym przykładzie. Przyjrzyjmy się bliżej.
Rusztowanie
Zanim zaczniesz naprawdę rysować, musisz wykonać Ustawiać . Musisz zdefiniować swój rzutni (obszar, który będzie faktycznie renderowany), swoją perspektywę ( aparat fotograficzny do swojego świata), jakiego antyaliasingu będziesz używać (aby wygładzić krawędzie trójkąta)…
Ale nie będziemy się tym zajmować. Rzucimy tylko okiem na rzeczy, które będziesz musiał zrobić każda rama . Lubić:
Czyszczenie ekranu
Potok graficzny nie wyczyści ekranu za każdą klatkę. Musisz to powiedzieć. Czemu? Dlatego:
Jeśli nie wyczyścisz ekranu, po prostu
remis
to w każdej klatce. Dlatego dzwonimy
glClear
z
GL_COLOR_BUFFER_BIT
zestaw. Drugi bit (
GL_DEPTH_BUFFER_BIT
) mówi OpenGL, aby wyczyścił plik
głębokość
bufor. Bufor ten służy do określenia, które piksele znajdują się przed (lub za) innymi pikselami.
Transformacja
Transformacja to część, w której bierzemy wszystkie współrzędne wejściowe (wierzchołki naszego trójkąta) i stosujemy naszą macierz ModelView. To jest matryca wyjaśnia jak nasz Model (wierzchołki) są obracane, skalowane i przesuwane (przesuwane).
Następnie stosujemy naszą macierz projekcji. Spowoduje to przesunięcie wszystkich współrzędnych, aby były prawidłowo skierowane w naszą stronę.
Teraz dokonujemy ponownej transformacji dzięki naszej macierzy Viewport. Robimy to, aby skalować nasz Model do rozmiaru naszego monitora. Teraz mamy zestaw wierzchołków, które są gotowe do renderowania!
Wrócimy do transformacji nieco później.
Rysunek
Aby narysować trójkąt, możemy po prostu powiedzieć OpenGL, aby rozpoczął nowy
lista trójkątów
poprzez dzwonienie
glBegin
z
GL_TRIANGLES
stały.
Istnieją również inne formularze, które możesz narysować. Jak
pasek trójkąta
lub a
trójkątny wentylator
. Są to przede wszystkim optymalizacje, ponieważ wymagają mniejszej komunikacji między procesorem a GPU, aby narysować taką samą liczbę trójkątów.
Następnie możemy podać listę zestawów 3 wierzchołków, które powinny tworzyć każdy trójkąt. Każdy trójkąt używa 3 współrzędnych (tak jak jesteśmy w przestrzeni 3D). Dodatkowo zapewniam również plik
kolor
dla każdego wierzchołka, wywołując
glColor3f
przed
powołanie
glVertex3f
.
Odcień między 3 wierzchołkami (3 rogami trójkąta) jest obliczany przez OpenGL automatycznie . Będzie interpolować kolor na całej powierzchni wielokąta.
Interakcja
Teraz po kliknięciu okna. Aplikacja musi tylko przechwycić plik komunikat w oknie co sygnalizuje kliknięcie. Następnie możesz uruchomić dowolną akcję w swoim programie.
To dostaje los trudniejsze, gdy chcesz rozpocząć interakcję ze swoją sceną 3D.
Najpierw musisz dokładnie wiedzieć, w którym pikselu użytkownik kliknął okno. Następnie zabierając perspektywiczny Uwzględniając, możesz obliczyć kierunek promienia od momentu kliknięcia myszą na twoją scenę. Następnie możesz obliczyć, czy w twojej scenie jest jakiś obiekt przecina się z tym promieniem . Teraz wiesz, czy użytkownik kliknął obiekt.
Jak więc sprawić, by się obracał?
Transformacja
Zdaję sobie sprawę z dwóch rodzajów transformacji, które są powszechnie stosowane:
- Transformacja oparta na macierzy
- Transformacja oparta na kości
Różnica jest taka kości wpływają na jednego wierzchołki . Macierze zawsze wpływają na wszystkie narysowane wierzchołki w ten sam sposób. Spójrzmy na przykład.
Przykład
Wcześniej załadowaliśmy nasze macierz jednostkowa przed narysowaniem naszego trójkąta. Macierz tożsamości to taka, która po prostu dostarcza bez transformacji w ogóle. Zatem na cokolwiek rysuję, wpływa tylko moja perspektywa. Tak więc trójkąt nie zostanie w ogóle obrócony.
Jeśli chcę teraz to obrócić, mógłbym sam wykonać obliczenia matematyczne (na procesorze) i po prostu zadzwonić
glVertex3f
z
inny
współrzędne (które są obracane). Albo mógłbym pozwolić GPU wykonać całą pracę, dzwoniąc
glRotatef
przed rysowaniem:
// Obróć trójkąt na osi Y glRotatef (amount, 0.0f, 1.0f, 0.0f);
ilość
to oczywiście tylko stała wartość. Jeśli chcesz
ożywiony
, będziesz musiał śledzić
ilość
i zwiększaj ją w każdej klatce.
Więc czekaj, co się stało z całą rozmową o macierzy wcześniej?
W tym prostym przykładzie nie musimy przejmować się macierzami. Po prostu dzwonimy
glRotatef
i zajmuje się tym wszystkim za nas.
glRotatetworzy obrótkątstopni wokół wektora x y z. Bieżąca macierz (patrz glMatrixMode ) jest mnożona przez macierz rotacji, przy czym iloczyn zastępuje obecną macierz, jakby glMultMatrix zostały wywołane z następującą macierzą jako argumentem:x 2 1 – c + c x y 1 – c – z s x z 1 – c + y s 0 y x 1 – c + z s y 2 1 – c + c y z 1 – c – x s 0 x z 1 – c – y s y z 1 – c + x s z 2 1 – c + c 0 0 0 0 1
Dzięki za to!
Wniosek
Staje się oczywiste, że dużo się mówi do OpenGL. Ale to nie mówi nas byle co. Gdzie jest komunikacja?
Jedyną rzeczą, którą OpenGL mówi nam w tym przykładzie, jest Kiedy się zakończy . Każda operacja zajmie pewien czas. Niektóre operacje trwają niewiarygodnie długo, inne są niezwykle szybkie.
Wysyłanie wierzchołka do GPU będzie tak szybki, że nawet nie wiedziałbym, jak to wyrazić. Przesyłanie tysięcy wierzchołków z CPU do GPU, w każdej pojedynczej klatce, najprawdopodobniej nie stanowi żadnego problemu.
Czyszczenie ekranu może zająć milisekundę lub gorzej (pamiętaj, że zwykle masz tylko około 16 milisekund czasu na narysowanie każdej klatki), w zależności od tego, jak duży jest twój widoczny obszar. Aby to wyczyścić, OpenGL musi narysować każdy piksel w kolorze, który chcesz wyczyścić, czyli miliony pikseli.
Poza tym możemy zapytać OpenGL tylko o możliwości naszego adaptera graficznego (maksymalna rozdzielczość, maksymalne wygładzanie krawędzi, maksymalna głębia kolorów…).
Ale możemy również wypełnić teksturę pikselami, z których każdy ma określony kolor. W ten sposób każdy piksel ma jakąś wartość, a tekstura jest gigantycznym „plikiem” wypełnionym danymi. Możemy załadować to na kartę graficzną (tworząc bufor tekstur), a następnie załadować plik moduł cieniujący powiedz temu modułowi cieniującemu, aby użył naszej tekstury jako danych wejściowych i wykonał bardzo ciężkie obliczenia na naszym „pliku”.
Możemy wtedy „wyrenderować” wynik naszych obliczeń (w postaci nowych kolorów) na nową teksturę.
W ten sposób możesz sprawić, by GPU działało dla Ciebie na inne sposoby. Zakładam, że CUDA działa podobnie jak w tym aspekcie, ale nigdy nie miałem okazji z tym pracować.
Naprawdę tylko nieznacznie poruszyliśmy cały temat. Programowanie grafiki 3D to piekielna bestia.
Masz coś do dodania do wyjaśnienia? Dźwięk w komentarzach. Chcesz przeczytać więcej odpowiedzi od innych zaawansowanych technicznie użytkowników Stack Exchange? Sprawdź cały wątek dyskusji tutaj .