Задание 3 (1124483), страница 3
Текст из файла (страница 3)
Сначала все ветки в цикле, потом все листья вцикле. Цикл отрисовки веток таков:Для всех существующих веток в дереве1. Получи модельную матрицу для этой ветки из класса дерева.2. Рассчитай остальные матрицы (модельно-видовую, матрицу нормалей, проекций).3. Передай все матрицы в шейдер.4. Отправь объект ветки на отрисовку.Обращаю внимание, что не требуется создавать множество экземпляров Branch и Leaf!Достаточно одно экзепляра каждого вида, к которому много раз обращаются из цикла.Расчет нормалейДля правильной раскраски с использованием модели Фонга необходимо корректновычислить нормали в каждой точке модели.
Можно сделать это как при генерацииобъекта на CPU, так и в геометрическом шейдере, получив за это дополнительные баллы.Здесь приведен общий алгоритм для любой поверхности, построить нормали к простойфигуре (например, конусу), можно проще, вычислив их аналитически.Идея вычисления гладкой нормали состоит в следующем:1) вычисляется нормаль для каждого треугольника2) нормаль в вершине вычисляется как взвешенная сумма нормалей для всехтреугольников, куда она входит (смежных с вершиной треугольников)Недостаток этого подхода в том, что нормали в острых пиках получатся слишкомплавными.
Чтобы сохранить "гористость" местности, можно использовать дубликатывершин с одинаковыми координатами и разными нормалями, взятыми напрямую изнормали ко всему треугольнику.Рис. Слева - пример гладкой нормали, справа - пример дублирования вершины с разныминормалямиРассмотрим случай, когда у каждой вершины имеется 6 смежных треугольников.Нормаль к каждому треугольнику ABC вычисляется по формуле:n = [C-A;B-A] = (C-A)x(B-A)Если сетка равномерна по x и y c шагом 1, то можно упростить данную формулу:n(A,B,C) = {Az-Cz, Az-Bz, 0}n(B,D,C) = {Bz-Dz, Cz-Dz, 0}Гладкую нормаль в вершине A с шестью смежными треугольниками с нормалями n1 ... n6можно посчитать например так:nA = sum(ni*wi)/sum(wi),где wi могут бытьлибо все равны 1,либо равны величине угла в прилегающей вершине треугольникалибо равны длине противолежащей стороны,либо заданы иным способом, обеспечивающим красивый результат.Определить, нужно ли дублировать вершину в данной точке можно по некоторомуэмпирическому правилу.
Например, вершина дублируется, если угол между нормалями уданной пары треугольников превосходит 60 градусов (или 90 градусов) и т.п. правила.ОсвещениеФормулы для расчета классической модели Фонга можно посмотреть здесь.В фрагментном шейдере необходимо рассчитать направление векторов от точки листа иливетки на источник и на камеру. Положение источника ля версий не выше 120 задаетсявстроенной переменной gl_LightSource (в случае, если в коде на cpu источникприсутствовал в виде glLight(...)).
В противном случае вы можете передать в шейдернужное число источников с параметрами, используя uniform (рекомендуется киспользованию в OpenGL 3 и выше). Для вычисления отраженного вектора в кодешейдера рекомендуется использовать команду reflect. Объектам соответствуют материалыи текстуры, с которыми рекомендуется связать uniform переменные. Uniform-ы можнозаполнять при отрисовке каждой конкретной модели.КамераНа самом деле можно себе представить, что камера помещена в центре сцены, а всеостальные объекты движутся и вращаются вокруг нее. С камерой связана модельновидовая матрица. Модельно-видовую матрицу нужно передать в вершинный шейдер (этоуже сделано в шаблоне). Для обработки событий с клавиатуры нужно объявить функциюkeyPressed, а затем указать opengl, что эту функцию следует использовать каксоответствующий обработчик.glutKeyboardFunc(keyPressed);Для обработки событий с мыши - аналогично, нужно объявить функцию mouseFunc, азатем указать ее opengl посредством фунции glutMouseFunc.void glutMouseFunc(void (*func)(int button, int state, int x, int y));Примеры кода можно найти в методичке.
При создании камеры вам пригодится аппаратлинейной алгебры. Камера по сути - это точка в пространстве с заданной ориентацией.Ориентацию можно задавать двумя углами в сферической системе координат. Кромеклассических путей решения задачи, можно попробовать подход с кватернионами.Подсказки к решению (бонусы)ТекстурыПример использования текстуры дан в шаблоне. Для использования полноценных текстурих необходимо предварительно загрузить из файла. Размер текстуры должен быть кратенстепеням двойки, также должно использоваться выравнивание рядов по 4 байта в памяти.Чтобы обойти это ограничение используйте glPixelStorei.ТесселяцияО работе с тесселяционными шейдерами подробно написано здесь.
Тесселяцияреализуется с помощью двух шейдеров (1 и 2). После генерации всех подразбиений вгеометрическом шейдере можно пересчитать нормали и текстурные координаты.Сферическое или кубическое окружениеДля реализации требуется текстура, которая как бы натянута на бесконечно удаленныеобъекты. Необходимо написать фрагментный шейдер, который работает следующимобразом: для текущего пикселе определяется, в какую точку сферической текстурыпроецируется луч, выпущенный из камеры и проходящий через данную точку. То естьнужно определить углы камеры, которые и будут являться координатами внутрисферической текстуры. Затем требуется выбрать из текстуры выбранное значение цвета изаписать его в буфер кадра.Тень дереваВозможно несколько различных вариантов реализации теней.
Можно реализовать какпростейшие резкие тени от Солнца либо более реалистичные размытые тени от двух иболее источников. Поощряются все известные методы реализации теней (shadowvolumes и др.).Управление мышьюДвижение мыши в горизонтальной плоскости (смещение по оси X) управляет угломповорота направления взгляда в горизонтальной плоскости (α, от 0 до 2*PI). Движениемыши в вертикальной плоскости (смещение по оси Y) управляет углом поворотанаправления взгляда в вертикальной плоскости относительно горизонта (β, от -PI до PI).Зная оба угла, вектор направления взгляда в мировых координатах вычисляетсяследующим образом:direction_z = sin(β);direction_x = cos(α) * cos(β);direction_y = sin(α) * cos(β);а затем нормализуется.Вектор направления "вбок" вычисляется как векторное произведение вектора направлениявертикально вверх, то есть вектора (0, 0, 1) и уже известного вектора направления взгляда.Вектор направления "вверх" вычисляется как векторное произведение векторанаправления взгляда и вектора направления "вбок".Положение камеры в OpenGL 1.0 можно передать через gluLookAt(...).
Подсказка:параметр target можно положить равным position + directionВ OpenGL 3.0 можно использовать аналогичную функцию из библиотеки glm.Смещение позиции камеры должно происходить не на фиксированное расстояние за одинкадр, а вычисляться, исходя из скорости передвижения камеры, и времени, ушедшего наобсчет последнего кадра.
Передвижение камеры должно осуществляться в направлениивзгляда. Скажем, по левой кнопке мыши - вперед, а по правой - назад. Для того, чтобызасечь время, можно воспользоваться функцией time = glutGet(GLUT_ELAPSED_TIME)ИнстанцированиеДля инстанцирования однотипных мешей (веток или листьев) с разными модельновидовыми матрицами используется функцияglDrawElementsInstanced. Можно прочитатьпро инстанцирование тут.Bump mapping, occlusion mapping, normal mappingСуществуют техники, позволяющие создавать иллюзию рельефа поверхности за счетсмещения вершин в шейдерах относительно направления взгляда, используя информациюо нормалях. Подробнее..