Ответы пользователя по тегу OpenGL
  • Чем отличается mvpmatrix от тех которые заданы по отдельности и надо ли их подключать (по отдельности) и в каких случаях?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Для лучшего понимания материала тебе стоит изучить, как минимум, эту статью.
    Если коротко
    ModelMatrix - это матрица преобразования локального пространства геометрии конкретного объекта.
    Внутри этого локального пространства геометрия объекта расположена относительно центра пространства. Чтобы геометрию модели отобразить в каком-либо целевом пространстве, необходимо произвести отображение локального пространства модели в целевое пространство. Именно таким отображением является ModelMatrix.

    ViewMatrix - матрица отображения любого внешнего пространства в пространство вида - пространство взора наблюдателя. Наблюдатель (камера) воспринимает объекты только внутри своего собственного локального пространства. Чтобы наблюдатель мог увидеть объект, объект необходимо отобразить из его родного пространства в пространство вида камеры, где он или попадет в область проекции, или не попадет.

    Projectionmatrix - матрица отображения видового пространства в пространство проекции вида. Фактически это отображение выполняет проецирование некоторого участка видового пространства на плоскость. Именно отображенная таким образом геометрия становится видимой при презентации кадра.

    Каждый объект сцены находится и анимируется внутри своего локального пространства. Чтобы объект на сцене встал в положенное ему место, его геометрия отображается из своего локального пространства в глобальное пространство сцены с помощью своей ModelMatrix.
    Чтобы сцена стала видна для камеры, всю ее геометрию требуется отобразить в пространство вида камеры с помощью матрицы ViewMatrix.
    Чтобы часть пространства вида камеры попала в область презентации кадра, всю геометрию видового пространства нужно отобразить в пространство проекции с помощью матрицы Projectionmatrix.
    При этом важно заметить, что матрицы Projectionmatrix и ViewMatrix уникальны для камеры, а вот матрицы ModelMatrix уникальны уже для каждого объекта отдельно.


    Отображение между пространствами выполняется через операцию перемножения позиции в исходном пространстве на матрицу преобразования пространства. Если подходить к этой задаче в лоб, то отображение каждой позиции потребует 16 операций перемножения над вещественными числами.
    Всего для заполнения области презентации кадра требуется выполнить, как минимум, три последовательных отображения геометрии, что будет означать по 48 операций умножения на каждую позицию отображаемой геометрии.

    Учитывая что Projectionmatrix и ViewMatrix в процессе презентации кадра являются неизменными, затраты в 48 операций на каждую позицию выглядят как расточительство. Если до презентации выполнить отображение самого пространства вида в пространство проекции, т.е. перемножить ViewMatrix и Projectionmatrix в правильном порядке, то с помощью результирующей матрицы viewProjectionMatrix число операций на одну позицию можно снизить до 32.
    Если же произвести отображение самого локального пространства модели в пространство презентации через перемножение матриц viewProjectionMatrix и ModelMatrix в правильном порядке, то благодаря полученной таким образом MVPMatrix число операций на одну позицию снизится до изначальных 16.

    Таким образом, матрицы viewProjectionMatrix и MVPMatrix просто позволяют снизить трудоемкость презентации кадра. Однако, во время презентации может потребоваться определение положения геометрии в каком-либо промежуточном пространстве, поэтому вдобавок к MVPMatrix в шейдер принято отдавать и ModelMatrix, и матрицы камеры.
    У каждой из матриц свой смысл. И если MVPMatrix бесспорно нужна всегда, то любую другую матрицу в шейдер добавлять стоит только исходя из осмысленной необходимости. Регистры GPU для шейдера не резиновые и могут очень быстро забиться избыточными данными. К тому же, чем меньше на каждом кадре в шейдер передается данных, тем быстрее выполняется презентация кадра.
    Ответ написан
  • Можно ли использовать sfml без openGL в C++?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Дело в том, что OpenGL является т.н. GAPI, т.е. интерфейсом прикладного программирования графики.
    На базе такого GAPI строятся движки, фреймворки и простые проекты. SFML, будучи фреймворком, точно так же базируется на OpenGL для работы с графикой.

    В связи с этим, если ты не планируешь работать с графикой, то можешь просто не использовать модули Window и Graphics. Как следствие, у тебя не будет возникать зависимости от OpenGL.
    Но если для тебя важно пользоваться графикой SFML, то в его стандартной поставке без OpenGL твой проект не соберется.
    Ответ написан
  • Почему не рисует ось z?

    @MarkusD
    все время мелю чепуху :)
    Для начала стоит учесть общую систему опознания осей в 3D-пространстве. Оси X, Y, Z помечаются каналами цветов R, G, B в однозначном соответствии. Ось X всегда и везде красная. Ось Y - зеленая. А ось Z - синяя.

    glVertex3f(0, 0,znear);
    glVertex3f(0, 0,zfar);

    Этот код говорит рисовать коллинеарную со взглядом линию. GPU не станет тратить ресурсы на всю линию и нарисует только одну точку, которая с высокой долей вероятности будет затерта при растеризации других примитивов. Ведь все три линии у тебя рисуются из нулевых координат.

    Сдвинь начальные координаты осей X и Y от нуля (хоть на 1pt), измени цвет оси Z, тогда ее станет немного лучше видно.
    Ответ написан
  • Как влияет перекрыетие объектов на скорость отрисовки?

    @MarkusD
    все время мелю чепуху :)
    Абсолютно точным ответом на твой вопрос является: смотря как настроишь контекст.

    Здесь стоит припомнить некоторые базовые этапы графического конвейера.

    Первым этапом является обработка вершинных данных. Она выполняется для каждой вершины в примитиве. Отказаться от обработки какой-либо вершины пользователь не в праве. С другой стороны, обработка вершинных данных, обычно, выполняется быстро и вершин, обычно, куда меньше чем фрагментов.
    Поэтому, чтобы загружать GPU только правильными вершинам, эти вершины стоит правильно выбрать для передачи ему. За это должна отвечать стадия отсечения примитивов при подготовке кадра к презентации.

    Вторым важным сейчас этапом является обработка фрагментных данных. Растеризация, если проще.
    Для растеризации каждый примитив бьется на фрагменты, обработка которых происходит в индивидуальном порядке. На этапе растеризации от обработки фрагмента уже можно отказаться прямо в шейдере. Это может немного ускорить презентацию кадра.
    Обработка фрагментов разной геометрии никак не регламентирована и может происходить в произвольном порядке.
    При этом, если один фрагмент имеет отношение к нескольким участкам геометрии, он будет вычислен из каждого такого участка. Это называется Overdraw (Перекрытие).
    Перекрытие не только ведет к обработке ненужных, часто не видимых, фрагментов, но и приводит к графическим артефактам, вроде z-fighting. Разработчики стараются не допускать перекрытия геометрии через более агрессивное отсечение полигонов в модели и сортировку геометрии, а не моделей, в пространстве. Так же есть ряд эффективных техник работы с буфером глубины (например), которые позволяют практически полностью справиться перекрытием.

    Поэтому, при правильной настройке контекста, при выборе только важной для кадра геометрии, при работе с буфером глубины, при использовании Adaptive Shading и вовремя отбрасывая фрагменты из стадии растеризации скорость презентации будет выше чем без всех этих настроек.
    Если ты сделаешь у себя z-prepass, то сортировка геометрии по расстоянию до камеры для тебя станет избыточной.
    Ответ написан
  • Как возможно задать параметры, а именно текстуру отдельно для каждого треугольника?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Коротко, тебе нужно усвоить вот этот урок.

    Развернуто:

    У тебя из атрибутов вершины сейчас есть только позиция. Уникальных вершин для твоей плоскости в таком случае будет всего 4. Под уникальностью у вершины понимается уникальность комбинации всех ее атрибутов.

    Сейчас тебе надо добавить атрибуты текстурных координат. Так как смешивание тебя не интересует, тебе необходим всего один набор текстурных координат на вершину. В таком случае уникальность твоей вершины будет обусловлена уже не просто ее позицией, но еще и уникальностью набора текстурных координат. Одновременно с этим новым правилом уникальности для вершины вводится и еще одно правило уникальности: уникальность по материалу.
    Когда ты добавляешь одну лишь текстуру, чтобы твоя отрисовка не встала на костыли тебе нужно поднять целую инфраструктуру обеспечения правильности ее работы.

    Под материалом понимается комплекс из программы и ресурсов, которые отображаются на геометрии.
    Материал отображает на геометрию заданный своими свойствами набор текстур и параметров. С точки зрения геометрии, материал - это DIP (Draw Indexed Primitive - твой glDrawElements). С точки зрения шейдера, материал - это комплекс из программы шейдера и набора входных/выходных параметров этой программы.
    Один материал одной геометрии - это один DIP с установкой набора текстур и параметров материала, а так же - с установкой нужного буфера индексов, вершин и инстансов.

    Ты хочешь чтобы Один набор треугольников твоей плоскости имел одну текстуру, а другой - другую. Вот и организуй два материала, у которых одна шейдерная программа, но две разные текстуры. Далее тебе надо ввести больше вершин, т.к. с вводом материала и текстурных координат, с учетом твоих требований, твои 4 вершины больше не могут обеспечить свою уникальность. В тех позициях плоскости, где два смежных треугольника отображают разные текстуры, тебе требуется ввести по две вершины вместо одной.
    Далее - организуй индексный буфер так, чтобы примитивы в нем описывались непрерывной последовательностью для каждого материала отдельно. Т.е. сперва все треугольники с одним материалом, потом все треугольники - с другим.
    Под конец определи инструкции для своей геометрии, сколько DIP-ов согласно твоим требованиям должно быть выполнено, для каких материалов и на какой геометрии.

    Таким образом ты реализуешь очень простую систему поддержки материалов и выполнишь свою задачу.
    Ответ написан
  • Как нарисовать такую звезду openGL?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Фигура состоит из 10 вершин, соединенных 10 ребрами.
    На первом шаге тебе надо равномерно распределить по единичной окружности 10 вершин. Сделать это нужно в специально отведенном массиве вершин, т.к. индексированные примитивы в этом старом режиме вывести нельзя.
    На втором этапе переключаем контекст на вывод замкнутой линии (GL_LINE_LOOP) и выводим все 10 точек из массива вершин, но со смещением на 3 точки и по модулю 10.

    Псевдокод:
    void display()
    {
       glClear( GL_COLOR_BUFFER_BIT );
       glBegin( GL_LINE_LOOP );
    
       for( size_t index = 0; index < vertices.size(); ++index )
       {
          const Vertex& vertex = vertices[ ( index * 3 ) % vertices.size() ];
          glVertex2i( vertex.x, vertex.y );
       }
    
       glEnd();
       glFlush(); 
    }
    Ответ написан
  • OpenGL и C++. Как лучше отсортировать полигоны?

    @MarkusD
    все время мелю чепуху :)
    Честно говоря, странно видеть в заголовке и тегах вопрос об OpenGL, а в теле вопроса - про коллизии и, возможно, физику.

    Видимое пространство и коллизионное пространство - это два абсолютно разных, но одновременно существующих пространства. Вершины видимого пространства являются крайне избыточными для работы в пространстве коллизий, самих вершин для качественной передачи визуальной информации требуется многократно больше, чем необходимо для точной симуляции коллизий. Для качественной симуляции коллизий вершины должны обладать совсем другими атрибутами, которые точно так же будут излишне перегружать размер вершины для пространства визуализации. И OpenGL к теме симуляции коллизий не имеет никакого отношения.

    Тебе надо иметь два набора вершин. Один - набор вершин для визуализации объекта. Второй - набор вершин для симуляции его физики, не только коллизий. И таких наборов может быть много. Для симуляции повреждений и деформаций, для скиннинга, для хитбоксов, для постройки маршрутов перемещений, для звуков...
    BSP подходят больше для отсечения видимой геометрии. В наши дни этот подход не оправдывает своих затрат, его не используют. Для эффективной симуляции коллизий лучше подходят QTree, OTree или KD-списки.

    Почитать начать можно отсюда: Study path for game programmer. Твой раздел: 9. Game Physics and Animation.
    Далее, тебе сюда: https://gamedev.ru/code/articles/?physics
    Да, геймдев все еще жив, хоть уже и не принадлежит Сереге Ваткину.
    Следом лучше пойти на хабр: [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11].
    У Фабьена Сангларда есть набор статей о внутреннем устройстве DOOM 3 и Quake 3, там есть материал и про столкновения.

    На этом этапе у тебя уже должно сформироваться представление о предметной области симуляции коллизий.
    Ответ написан
  • Как ограничить FPS в OpenGL и glut?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Само ограничение частоты кадров делается очень просто. Снаружи idle-функции нужно содержать переменную с временем последнего вызова idle-функции, а в самой функции нужно просто накопить дельту частоты кадров и вызвать glutPostRedisplay.
    double GetCurrentTime()
    {
    	using Duration = std::chrono::duration<double>;
    	return std::chrono::duration_cast<Duration>( 
    		std::chrono::high_resolution_clock::now().time_since_epoch() 
    	).count();
    }
    
    const double frame_delay = 1.0 / 60.0; // 60 FPS
    double last_render = 0;
    void OnIdle()
    {
    	const double current_time = GetCurrentTime();
    	if( ( current_time - last_render ) > frame_delay )
    	{
    		last_render = current_time;
    		glutPostRedisplay();
    	}
    }


    Данный код является сильно упрощенным механизмом, лишь показывающим общий принцип ограничения частоты кадров. Его можно применять там, где не требуется точный контроль дельты между кадрами. К слову, представление времени в типе double помогает легче находить дельту между кадрами и контролировать ошибку дельты.
    Для более точного контроля частоты кадров стоит обратиться, например, к такому материалу.
    Ответ написан
  • OpenGL не сразу отображает данные из кадрового буфера?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Я не вижу в твоем коде вызова glutIdleFunc. В документации написано что GLUT будет постоянно вызывать переданную функцию в свободное от обработки системных сообщений время. А если в glutIdleFunc передан nullptr (или idle-функция не была задана), то GLUT будет строго ждать следующего системного сообщения.

    Если я все правильно помню, то передача настоящей функции, в которой будет вызываться функция glutPostRedisplay, в glutIdleFunc приведет и к регулярной перерисовке экрана.
    Как правило, в качестве idle-функции в GLUT передают update-функцию, в которой обновляется состояние объектов перед рендерингом.
    Ответ написан
  • Что такое анимация и с чем ее кушать если OpenGL?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Spine C runtime.
    https://github.com/EsotericSoftware/spine-runtimes...
    Это не серебряная пуля и не идеальные практики. Пожалуй, в плане кода это пример наоборот, как код писать точно не надо.
    Но вот в плане реализации анимаций эта репка тебе очень поможет.

    Суть такова. Есть модель, она статична. Есть отрезок времени (таймлайн), на этом отрезке есть точки - ключевые кадры. Ключевой кадр несет в себе информацию о том, какую часть модели и как сместить. Чем проще инструкция в ключевом кадре, тем удобнее. Масштаб, поворот и смещение многие любят разделять по разным таймлайнам.
    OGL в этом деле не нужен, до поры.

    С помощью SRT таймлайнов можно анимировать объекты в пространстве целиком, но если тебе захочется точно так же анимировать части меша модели, то впереди тебя будут ждать трудности.
    Анимацию меша лучше реализовать на основе скелета. Это дело в двух словах уже не описать, тут лучше читать статьи.
    www.gamedev.ru/code/terms/SkeletalAnim
    www.gamedev.ru/code/articles/skeletal_animation
    https://habrahabr.ru/post/219509/
    https://habrahabr.ru/post/304042/
    www.gamedev.ru/code/articles/?id=4182

    Самое зерно скелетной анимации в том, что модель остается моделью, анимируются только кости скелета. И именно анимация кости приводит к перемещению фрагмента меша.

    Только на одной скелетной анимации далеко все равно не уедешь. Когда требуется на одной модели одновременно задействовать сразу несколько скелетных анимаций, если сделать в лоб, то меш поплывет во все стороны.
    Для смешивания различных скелетных анимаций применяют так называемые Blend Trees (ссылок под рукой нету, так что сорри).

    В общем, как то так анимация выглядит. Анимируем в цикле обновления, вершины трансформируем в момент формирования кадра. OGL нам нужен, собственно, чтобы нарисовать раскоряченый анимацией меш.
    OGL для непосредственного анимирования мешей тебе понадобится только тогда, когда ты достаточно глубоко нырнешь в анимации, в тот же момент ты уже полностью поймешь что от OGL понадобится для этого.
    Ответ написан
  • Как упаковать текстуры в libGDX?

    @MarkusD
    все время мелю чепуху :)
    Андрей, у тебя вопрос, как видно по тексту, немного о другом. По описанию видно что ты перед собой стену видишь, а про дверь в стене даже не подозреваешь. Итак, вот дверь, даже несколько. :)

    Первое - надо понять, насколько много графики у тебя в проекте. Для современного mid-end устройства на андроиде 5.0 совсем не проблема держать 2-4 RGBA текстуры с разрешением 4096 по ребру. Это не говоря о сопутствующих шейдерах, буферах растра/глубины/вершин/индексов. Минимализм в ресурсах приветствуется, но и зажимать себя в тески не стоит.

    Второе - давай взглянем на параграф "Open GL Version" странички https://developer.android.com/about/dashboards/ind...
    OpenGL 3.x занимает большую долю всех устройств. Эта версия OpenGL умеет работать с форматом ETC2 (благодаря заявленной поддержке от GPU), в котором уже можно сохранять альфу. А в вики ( https://en.wikipedia.org/wiki/Ericsson_Texture_Com... ) еще и написано про обратную совместимость.
    Тут в моем опыте пробел, с ETC2 я еще не работал и наглядно про обратную совместимость с ETC1 ничего не знаю. Поэтому предлагаю устроить обмен знаниями в этой теме. :)

    Третье - Аппаратно-поддерживаемых форматов сжатия текстур на самом деле много: S3TC, ATC, PVR-TC. ETC - не единственный. Каждый из форматов поддерживается своим производителем. ATC - Quallcomm; PVR-TC - Imagination Tec. Но вот S3TC (более известный как DXT3/DXT5) поддерживается обоими QC и ImgTec, но тайно. И только ARM Mali поддерживает один лишь формат ETC.
    К чему я это. Тройка профильных форматов и альфу поддерживает, и обрабатывается быстрее того же ETC (и уж тем боле пары ETC1).
    Поэтому может тебе удобнее будет использовать конвертацию в эту тройку форматов?
    У меня на гитхабе есть очень быстрая библиотека для программного чтения PVR-TC.v2 в RGBA буфер, что позволит загрузить текстуры для Mali GPU.
    Ответ написан