ASSIGNMENT 3 Assignment 3.1 • Растеризация на CUDA – Загрузить 3d модель (stanford bunny, dragon или buddha) – Преобразовать вершины – Растеризация в разделяемой памяти – Простое освещение 2011 Загрузка модели • Используйте .obj формат – текстовый файл с простой разметкой v -43.11835 v -12.49871 v -43.11835 v -12.49871 v -43.11835 v -12.49871 v -43.11835 v -12.49871 2.40170 28.98380 2.40170 28.98380 24.56909 28.98380 24.56909 28.98380 2.40170 50.53307 2.40170 50.53307 24.56909 50.53307 24.56909 50.53307 vn 0.00000 0.00000 -1.00000 vn 0.00000 0.00000 -1.00000 vn 0.00000 0.00000 -1.00000 vn 0.00000 0.00000 -1.00000 vn 0.00000 0.00000 1.00000 vn 0.00000 -0.00000 1.00000 vn -0.00000 0.00000 1.00000 vn 0.00000 0.00000 1.00000 f f f f f f f f f f f f 1//1 4//4 5//5 8//8 1//1 6//6 2//2 8//8 4//4 7//7 3//3 5//5 3//3 2//2 6//6 7//7 2//2 5//5 4//4 6//6 3//3 8//8 1//1 7//7 4//4 1//1 8//8 5//5 6//6 1//1 8//8 2//2 7//7 4//4 5//5 3//3 V – префикс задает вершину Vn – префикс задает нормаль f – префикс задает грань в формате: индекс вершины/индекс текстуры/индекс нормали. Индекс текстуры для задания не нужен. Индексы начинаются с ‘1’, в то время как массивы в С++ с ‘0’ 2011 Загрузка модели • Загрузку можете написать самостоятельно • Можете взять готовую в интернете – Например glm • Можете спросить в группе 2011 Преобразование вершин • Преобразование вершин бывает – Model или «модельное». Это преобразование вершин из координатного пространства модели в мировые координаты. Типичные преобразования – поворот, масштабирование и перенос. – View или «видовое». Это преобразование вершин из мировых координат в координаты камеры. Камера – это точка в пространстве, с направлением взгляда и вектором ориентации «вверх». В графических API камера распологается в точке (0,0,0), смотрит по вектору (0, 0, 1) (или (0, 0, -1)), и ориентирована по вектору вверх (0,1,0). – Projection или «проекции». Это преобразование вершин из координат камеры в координаты пространства отсечения. После умножения на матрицу проекции xyz координаты делятся на w. Полученные координаты лежат в пространстве отсечения (это куб [-1, 1]2 x [0, 1]). Вершины которые оказались вне этого куба – не попадают в пирамиду видимости. • Все преобразования вершин работают с векторами xyzw. – • Для точек w == 1, для направлений w == 0. Все матрицы преобразований – матрицы 4х4 – Как построить матрицу <insert name > – смотрим вызовы directx или спрашиваем в группе. 2011 Преобразование вершин • Преобразование вершин : – Пусть N треугольников, треугольник это 3 вершины идущие подряд: A1, B1, C1, … AN, BN, CN – Более оптимально разложить треугольники так: A1, A2, A3, .. AN, B1, B2, B3, .. ,BN, C1, C2, C3, .. ,CN Входной список вершин (N*3) Входной список нормалей (N*3) CUDA ядро (N*3) потоков: V * Model * View * Projection N * Model Выходной список вершин (N*3) Выходной список нормалей (N*3) 2011 Глобальная память для буфера кадра Color (uchar4) Depth (float) Окно растеризации (framebuffer) WxH пикселей – два массива данных в глобальной памяти. Размер – параметр. Хорошие размеры для эксперимента – 1024х1024. Их необходимо проинициализовать начальными значениями Например – черный цвет и глубина равная 1.0 (бесконечно далеко) 2011 Растеризация Всё окно разбивается на тайлы (tile). Размер тайла – например 8x8, 16x8, 16x16, 32x2, 32x4, 32x8, 32x16 пикселей. Вероятнее всего, оптимальный размер – 32x8, но это не известно Для каждого тайла запускается CUDA блок, в каждом блоке кол-во потоков == колву пикселей в тайле (это важно) 2011 Растеризация Рассмотрим работу отдельного тайла Рассмотрим работу отдельного тайла 2011 Растеризация • CUDA ядро: пусть размер блока Bx*By – Прочитать из глобальной памяти в разделяемую исходные значения цвета и глубины (1 поток читает по одному значению) __shared __ uchar4 color[Bx*By]; __shared__ float depth[Bx*By]; – синхронизация 2011 Растеризация • CUDA ядро: пусть размер блока Bx*By – Вычислить границы тайла в пространстве [-1, 1]2 Выходной список вершин (N*3) Выходной список нормалей (N*3) – Каждый поток читает треугольник из глобальной памяти и проверяет пересекает ли треугольник данный тайл • Т.е. Если N треугольников, то каждый поток пересекает N/(Bx*By) с тайлом чем больше потоков, тем лучше.2011 Растеризация • CUDA ядро: пусть размер блока Bx*By – Если треугольник пересекает тайл то его индекс в памяти записывается в массив разделяемой памяти __shared__ int smem_tri_idx[Bx*By] – Если треугольник не пересекает тайл то в разделяемую память записывается -1 – синхронизация 2011 Растеризация Пересекает поток №: Результат пересечения: Поток записал в shared: 0, 1, 0, 1, 0, -1, 2, 0, -1, 3, 0, -1, 4, 1, 4, 5, 1, 5, 6, 1, 6, 7 0 -1 2011 Растеризация Пересекает поток №: Результат пересечения: Поток записал в shared: 0, 1, 0, 1, 0, -1, 2, 0, -1, 3, 0, -1, Не пересекающие тайл треугольники нас не интересуют! 4, 1, 4, 5, 1, 5, 6, 1, 6, 7 0 -1 2011 Растеризация • CUDA ядро: – Синхронизация (индексы треугольников лежат в shared памяти) – Цикл (по размеру блока) • Каждый поток берет индекс треугольника • Читает треугольник из глобальной памяти – если индекс != -1 • Проверяет пересекает ли данный треугольник тот пиксел, которому соответствует поток 2011 Растеризация: тайл крупным планом 2011 Растеризация: тайл крупным планом • Как вычислить барицентрические коодинаты? – Разложить AP = u*AB + v*AC – 2 ур-ния (x, y) A – 2 неизвестные (u, v) – Решение через определитель – Если u >= 0 и v >= 0 и u+v <=1 • Пиксел лежит внутри треугольника B • Можно интерполировать вершинные аттрибуты P C 2011 Растеризация: тайл крупным планом • Нужно вычислить – Глубину точки • Сравнить с глубиной в разделяемой памяти • Если тест глубины пройден, тогда обновить глубину в разделяемой памяти и сделать расчет освещения – Расчет освещения и запись в разделяемую память • Вычислить единичную нормаль в точке n • Диффузное освещение L в точке P – Lp = max(0, dot(n, light_dir)) где light_dir – направление счета 2011 Растеризация Разделяемая память • CUDA ядро: – Продолжить процесс для следующих 64-ёх треугольников – Когда все треугольники закончились записать результат из разделяемой в глобальную память – Можно дальше растеризовать след. модель Глобальная память 2011 Результат • Резульатат растеризации записывайте в файл – Можете использовать devil • http://code.google.com/p/msu-openglcourse/wiki/Devil_Basics – Работает на нашем сервере 2011 Assignment 3.2 • Тоже самое что задание 3.1 но дополнительно на выбор: – Растеризовать не весь список треугольников, а предварительно составить более короткие списки треугольников • Используйте Thrust и операцию stream compaction – Более сложная модель освещения (например Phong) – Поддержка OpenGL (возможность полетать камерой) • Тогда проверять будем на windows машине • Быстрое создание gl окна http://code.google.com/p/msu-openglcourse/wiki/Freeglut_GLEW_Basics – Отложенное освещение (deferred shading) 2011 Глобальная память для буфера кадра Color (uchar4) Depth (float) 2011 Глобальная память для буфера кадра Q1 Q2 Depth (float) Color (uchar4) Q3 4 списка: Q1: Q4 Q2: Q3: Q4: 2011 Глобальная память для буфера кадра: можно иерархически Q11 Q13 Q3 4 списка: Q11: Q12: Q12 Q2 Q14 Color (uchar4) Depth (float) Q4 Q13: Q14: Q2: Q3: Q4: 2011 Assignment 3.2 • Более сложная модель освещения: – Очень подробное описание моделей с кодом шейдеров glsl можно найти тут: http://steps3d.narod.ru/tutorials/lighting-tutorial.html – Спрашивайте в нашей группе 2011 Assignment 3.2 • Deferred shading – Проблема в задании 3.1 в том, что когда часть потоков найдет пересечение пиксела с треугольником а часть нет, то возникнет простой в работе: – • Те потоки которые найдут пересечение с треугольником начнут вычислять освещение • Если освещение сложное – то это много математических инструкций • Остальные потоки (для которых пиксели не пересекают данный треугольник) ждут Решение: отложить процесс освещения до самого конца • Если пиксел пересекает треугольник, то запоминать индекс треугольника и барицентрические координаты u и v • В разделяемой памяти записывать глубину, индекс треугольника, u, v • После того как все треугольники проверены – вычислить освещение в тех пикселах для которых индекс треугольника != -1 2011 Общие правила по оформлению программ • Если сдаете по email – Email ДОЛЖЕН быть с темой CUDA ASSIGNEMENT 2011.N (N - номер задания, в данном случае 2) • Задание сложное – И на него у вас 1 неделя Недвусмысленный намек от кэпа – Не откладывайте с вопросами 2011 Общие правила по оформлению прорамм – Программа должна делать проверки на ошибки: • Наличие девайса? • Выделилась память? • И т.д. – Программа должна компилироваться с CUDA Toolkit 3.2 • Если писали на windows то vcproj для VS2005 / VS2008 либо (makefile + .bat) • Если писали на *nix то make 2011 Общие правила по оформлению программ • Если вы используете любые другие инклюды кроме стандартных – не расчитывайте, что они прописаны на проверяющей машине. • Пример того, чего не будет на машине: – cutil.h (требует установки CUDA SDK) • Пример того, что будет на машине: – cudart.h (ставиться вместе с CUDA toolkit) – stdio.h (стандартная C библиотека) – thrust – cufft 2011 Вопросы 2011