Снимка от sskennel.
Днешната сесия за въпроси и отговори се отнася до нас с любезното съдействие на SuperUser - подразделение на Stack Exchange, обединяване на уеб сайтове с въпроси и отговори.
Въпроса
Reader на SuperUser Sathy поставя въпроса:
Тук можете да видите екранна снимка на малка програма C ++, наречена Triangle.exe, с въртящ се триъгълник, базиран на API на OpenGL.
Бях просто любопитен и исках да знам целия процес от двойно кликване върху Triangle.exe под Windows XP, докато не мога да видя триъгълника въртящ се на монитора. Какво се случва, как взаимодействат процесора (който първо обработва.exe) и графичния процесор (който най-накрая извежда триъгълника на екрана)?
Предполагам, че участващи в показването на този въртящ се триъгълник е предимно следния хардуер / софтуер, между другото:
железария
- HDD
- Системна памет (RAM)
- процесор
- Видео памет
- GPU
- ЛСД дисплей
Софтуер
- Операционна система
- API за DirectX / OpenGL
- Nvidia Шофьор
Може ли някой да обясни процеса, може би с някаква схема за илюстрация?
Не трябва да е сложно обяснение, което да обхваща всяка една стъпка (предполагам, че ще надхвърли обхвата), но обяснение, което може да последва един междинен IT човек.
Сигурен съм, че много хора, които дори биха се нарекли ИТ професионалисти, не могат да опишат правилно този процес.
Отговорът
Изображение от JasonC, налице като тапет тук.
Той пише:
Реших да напиша малко за аспекта на програмирането и как компонентите разговарят един с друг. Може би това ще хвърли светлина върху определени области.
Презентацията
Какво е необходимо, за да имате дори единствения образ, който сте публикували във въпроса си, изчертан на екрана?
Има много начини да рисувате триъгълник на екрана. За простота, нека приемем, че не са използвани буфери на върха. (А връх буфере област на паметта, където съхранявате координатите.) Да предположим, че програмата просто е казала на графичния обработващ тръбопровод за всеки един връх (един връх е просто координати в пространството) в един ред.
Но, преди да можем да направим нещо, първо трябва да поемем някои скелета. Ще видим защо по късно:
// Clear The Screen And The Depth Buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Reset The Current Modelview Matrix glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // Drawing Using Triangles glBegin(GL_TRIANGLES); // Red glColor3f(1.0f,0.0f,0.0f); // Top Of Triangle (Front) glVertex3f( 0.0f, 1.0f, 0.0f); // Green glColor3f(0.0f,1.0f,0.0f); // Left Of Triangle (Front) glVertex3f(-1.0f,-1.0f, 1.0f); // Blue glColor3f(0.0f,0.0f,1.0f); // Right Of Triangle (Front) glVertex3f( 1.0f,-1.0f, 1.0f); // Done Drawing glEnd();
И какво направи това?
Когато пишете програма, която иска да използва графичната карта, обикновено ще изберете някакъв интерфейс за водача. Някои добре познати интерфейси за водача са:
- OpenGL
- Direct3D
- CUDA
За този пример ще се придържаме към OpenGL. Сега, твоите интерфейс на водача е това, което ви дава всички инструменти, от които се нуждаете, за да направите програмата си говоря към графичната карта (или драйвера, който след това преговори към картата).
Този интерфейс е длъжен да ви даде сигурност инструменти, Тези инструменти имат формата на приложния програмен интерфейс, който можете да извикате от програмата си.
Този приложно поле е това, което виждаме да се използва в примера по-горе. Нека да разгледаме по-отблизо.
Скелето
Преди да можете наистина да направите някоя действителна рисунка, ще трябва да изпълните настройвам, Трябва да определите своя изглед (областта, която действително ще бъде изобразена), вашата гледна точка ( камера в твоя свят), какви анти-плисета ще използваш (за да изгладиш ръба на своя триъгълник) …
Но няма да погледнем към това. Ще се вгледаме в нещата, които трябва да направите всеки кадър, Като:
Изчистване на екрана
Графичният тръбопровод няма да изчисти екрана за вас на всеки кадър. Ще трябва да го кажете. Защо? Това е причината:
Ако не изчистите екрана, просто ще го направите изтегляне всеки кадър. Затова се обаждаме
glClear
с
GL_COLOR_BUFFER_BIT
комплект. Другият бит (
GL_DEPTH_BUFFER_BIT
) казва на OpenGL да изчисти дълбочинабуфер. Този буфер се използва, за да се определи кои пиксели са пред (или зад) други пиксели.
Трансформация
Трансформацията е частта, в която вземаме всички входни координати (върховете на нашия триъгълник) и прилагаме нашата матрица ModelView. Това е матрицата обяснява как нашето модел (върховете) се въртят, мащабират и пренасят (преместват).
След това прилагаме нашата прожекционна матрица. Това премества всички координати, така че да са изправени правилно пред камерата.
Сега отново се трансформираме с матрицата на Viewport. Правим това, за да мащабираме нашите модел до размера на нашия монитор. Сега имаме набор от върхове, които са готови да бъдат представени!
Ще се върнем на трансформацията малко по-късно.
чертеж
За да нарисуваме триъгълник, можем просто да кажем на OpenGL да започне ново списък на триъгълници чрез обаждане
glBegin
с
GL_TRIANGLES
константа. Има и други форми, които можете да рисувате. Като триъгълна ивица или триъгълник.Това са преди всичко оптимизации, тъй като те изискват по-малко комуникация между процесора и графичния процесор, за да привлече същото количество триъгълници.
След това можем да предоставим списък от три върха, които трябва да съставят всеки триъгълник. Всеки триъгълник използва 3 координати (тъй като сме в 3D пространство). Освен това, аз също предлагам цвят за всеки връх, като се обадите
glColor3f
преди повикване
glVertex3f
Сянката между трите върха (3 ъгъла на триъгълника) се изчислява от OpenGL автоматично, Той ще интерполира цвета върху цялото лице на полигона.
взаимодействие
Сега, когато щракнете върху прозореца. Приложението трябва само да заснеме прозоречното съобщение, което сигнализира за щракване. След това можете да изпълните всяко действие във вашата програма, която искате.
Това получава много по-трудно, когато искате да започнете да взаимодействате с 3D сцената.
Първо трябва ясно да знаете в кой пиксел потребителят е щракнал върху прозореца. След това вземете вашите перспективав зависимост от това, можете да изчислите посоката на лъча, от точката на щракване на мишката в сцената ви. След това можете да изчислите дали има някакъв обект в сцената ви пресича с този лъч. Сега знаете дали потребителят е кликнал върху обект.
И така, как да го завъртите?
Трансформация
Аз съм запознат с два типа трансформации, които обикновено се прилагат:
- Матрична трансформация
- Костно-базирана трансформация
Разликата е, че кости засягат единични върхове, Матриците винаги влияят на всички изведени върхове по същия начин. Нека да разгледаме един пример.
пример
По-рано заредихме нашата идентификационна матрица преди да рисуваме нашия триъгълник. Матрицата за самоличност е тази, която просто осигурява без трансформация изобщо. Така че, каквото и да привличам, е засегната само от моята гледна точка. Така че, триъгълникът изобщо няма да се завърти.
Ако искам да го завъртя сега, бих могъл да направя самата математика (на процесора) и просто да се обадя
glVertex3f
сдруг координатите (които се въртят). Или можех да позволя на GPU да свърши цялата работа, като се обади
glRotatef
преди рисуване:
// Rotate The Triangle On The Y axis glRotatef(amount,0.0f,1.0f,0.0f);
amount
е, разбира се, само фиксирана стойност. Ако искаш вдъхновявам, ще трябва да следите
amount
и го увеличавайте на всеки кадър.
Така че, изчакайте какво стана с всички матрични разговори по-рано?
В този прост пример не е нужно да се интересуваме от матрици. Ние просто се обаждаме
glRotatef
и се грижи за всичко това за нас.
glRotate
произвежда ротация на
angle
степени около вектора x y z. Текущата матрица (seeglMatrixMode) се умножава по матрица на въртене с продукта, заместващ текущата матрица, тъй като ifglMultMatrix са били извикани със следната матрица като аргумент:
x 2 1 - c + cx y y 1 - c - zx zz 1 - c + y s y y x 1 - c + z sy 2 1 - c + cyz z 1 - c - x s 0 x z z 1 - c - y syz 1 1 - c + x sz 2 1 - c + c 0 0 0 0 1
Е, благодаря за това!
заключение
Очевидно е, че има много разговори да се OpenGL. Но това не казва нас нищо. Къде е комуникацията?
Единственото, което ни казва OpenGL в този пример, е когато е свършено, Всяка операция ще отнеме известно време. Някои операции са невероятно дълги, други са невероятно бързи.
Изпращане на връх към GPU ще бъде толкова бързо, че дори не бих знаел как да го изразя. Изпращането на хиляди върхове от процесора към графичния процесор, всеки един кадър, най-вероятно няма никакъв проблем.
Изчистване на екрана може да отнеме милисекунда или по-лошо (имайте предвид, обикновено имате само около 16 милисекунди от времето, за да рисувате всеки кадър), в зависимост от това колко голяма е визуалната ви кутия. За да го изчистите, OpenGL трябва да рисува всеки един пиксел в цвета, който искате да изчисти, което може да бъде милиони пиксели.
Освен това, можем само да поискаме OpenGL за възможностите на нашия графичен адаптер (максимална разделителна способност, максимум анти-алиазинг, максимална дълбочина на цветовете, …).
Но можем и да запълним текстурата с пиксели, всеки от които има специфичен цвят. Така всеки пиксел има стойност и текстурата е гигантски "файл", пълен с данни. Можем да го заредим в графичната карта (като създадем буфер за текстура), след това да заредим shader, да кажем, че shader да използва нашата текстура като вход и да изпълнява някои изключително тежки изчисления на нашия "файл".
След това можем да "направим" резултата от изчисленията (под формата на нови цветове) в нова текстура.
По този начин можете да направите GPU да работи за вас по други начини. Предполагам, че CUDA изпълнява подобен аспект, но никога не съм имал възможността да работя с него.
Наистина леко докоснахме целия въпрос. Програмирането с 3D графики е зловещо звяр.
Имате ли нещо, което да добавите към обяснението? Звучи в коментарите. Искате ли да прочетете повече отговори от други потребители на Stack Exchange? Вижте цялата тема на дискусията тук.