фото sskennel.
Сегодняшняя сессия вопросов и ответов приходит к нам, любезно предоставленной SuperUser - подразделением Stack Exchange, группировкой сайтов Q & A на уровне сообщества.
Вопрос
Читатель SuperUser Сатья задал вопрос:
Здесь вы можете увидеть скриншот небольшой C ++-программы под названием Triangle.exe с вращающимся треугольником на основе OpenGL API.
Мне было любопытно и хотелось узнать весь процесс, дважды щелкнув Triangle.exe под Windows XP, пока не увижу треугольник, вращающийся на мониторе. Что происходит, как взаимодействует CPU (который сначала обрабатывает.exe) и GPU (который, наконец, выводит треугольник на экране)?
Я предполагаю, что участие в отображении этого вращающегося треугольника в первую очередь относится к следующим аппаратным / программным средствам:
аппаратные средства
- жесткий диск
- Системная память (ОЗУ)
- ЦПУ
- Видеопамять
- GPU
- ЖК дисплей
Программного обеспечения
- Операционная система
- API DirectX / OpenGL
- Драйвер Nvidia
Может ли кто-нибудь объяснить процесс, может быть, с какой-то блок-схемой для иллюстрации?
Это не должно быть сложным объяснением, которое охватывает каждый отдельный шаг (предполагая, что это выходит за рамки), но объяснение, которое может пройти промежуточный ИТ-специалист.
Я почти уверен, что многие люди, которые даже назвали бы себя ИТ-специалистами, не могли правильно описать этот процесс.
Ответ
Изображение JasonC, доступное в качестве обоев здесь.
Он пишет:
Я решил немного написать о аспекте программирования и о том, как компоненты взаимодействуют друг с другом. Возможно, он прольет некоторый свет на определенные области.
Презентация
Что нужно, чтобы даже иметь тот единственный образ, который вы разместили в своем вопросе, нарисованный на экране?
Существует много способов нарисовать треугольник на экране. Для простоты предположим, что не использовались буферы вершин. (A буфер вершинэто область памяти, в которой вы храните координаты.) Предположим, что программа просто рассказала о конвейере обработки графики о каждой единственной вершине (вершина - это просто координата в пространстве) в строке.
Но, прежде чем мы можем что-либо нарисовать, мы сначала должны запустить некоторые леса. Посмотрим Зачем потом:
// 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. Теперь, ваш интерфейс к драйверу это то, что дает вам все инструменты, необходимые для создания вашей программы говорить на графическую карту (или драйвер, который затем переговоры к карте).
Этот интерфейс обязательно даст вам определенные инструменты, Эти инструменты имеют форму API, который вы можете вызывать из своей программы.
Этот API - это то, что мы видим в примере выше. Давайте посмотрим поближе.
Леса
Прежде чем вы сможете реально сделать какой-либо реальный рисунок, вам нужно будет выполнить настроить, Вы должны определить свой видовой экран (область, которая будет фактически отображаться), вашу перспективу ( камера в ваш мир), какое сглаживание вы будете использовать (чтобы сгладить очертания вашего треугольника) …
Но мы не будем смотреть на это. Мы просто заглянем в то, что вам нужно сделать каждый кадр, Подобно:
Очистка экрана
Графический конвейер не собирается очищать экран для каждого кадра. Вы должны это сказать. Зачем? Вот почему:
Если вы не очистите экран, вы просто нарисовать это каждый кадр. Вот почему мы называем
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 1 - c - z sx z 1 - c + y s 0 y x 1 - c + z sy 2 1 - c + cy z 1 - c - x s 0 x z 1 - c - y sy z 1 - c + x sz 2 1 - c + c 0 0 0 0 1
Хорошо, спасибо за это!
Заключение
То, что становится очевидным, - это много разговоров в OpenGL. Но это не говорит нас что-нибудь. Где сообщение?
Единственное, что говорит нам OpenGL в этом примере: когда это будет сделано, Каждой операции потребуется определенное количество времени. Некоторая операция занимает невероятно долго, другие невероятно быстрые.
Отправка вершины на GPU будет так быстро, я даже не знаю, как это выразить. Отправляя тысячи вершин из ЦП на GPU, каждый отдельный кадр, скорее всего, не проблема.
Очистка экрана может занять миллисекунду или хуже (имейте в виду, что вам обычно приходится всего 16 миллисекунд времени рисовать каждый кадр), в зависимости от того, насколько велика ваша область просмотра. Чтобы очистить его, OpenGL должен рисовать каждый пиксель в цвете, который вы хотите очистить, и это может быть миллионы пикселей.
Помимо этого, мы можем в значительной степени просто спросить OpenGL о возможностях нашего графического адаптера (максимальное разрешение, максимальное сглаживание, максимальная глубина цвета, …).
Но мы также можем заполнить текстуру пикселями, каждая из которых имеет определенный цвет. Таким образом, каждый пиксель имеет значение, а текстура представляет собой гигантский «файл», заполненный данными. Мы можем загрузить это в графическую карту (создав буфер текстуры), затем загрузим шейдер, скажем, что шейдер использует нашу текстуру в качестве входного сигнала и запускает очень тяжелые вычисления в нашем «файле».
Затем мы можем «вынести» результат наших вычислений (в виде новых цветов) в новую текстуру.
Вот как вы можете заставить GPU работать для вас другими способами. Я предполагаю, что CUDA работает аналогично этому аспекту, но у меня никогда не было возможности работать с ним.
Мы действительно только коснулись всего предмета. 3D-графика - это чертовски зверь.
Есть что добавить к объяснению? Звучит в комментариях. Хотите узнать больше ответов от других пользователей Windows? Посмотрите здесь полную дискуссионную тему.