Страницы

Поиск по вопросам

Показаны сообщения с ярлыком opengl. Показать все сообщения
Показаны сообщения с ярлыком opengl. Показать все сообщения

среда, 15 апреля 2020 г.

Книга по OpenGL [закрыт]

#книги #opengl

                            
             
                
                    
                        
                            Закрыт. На этот вопрос невозможно дать объективный ответ.
Ответы на него в данный момент не принимаются.
                            
                        
                    
                
            
                    
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы на него можно было дать ответ, основанный на фактах и цитатах, отредактировав его.
                        
                        Закрыт 4 года назад.
                    
                
        

Подскажите пожалуйста более-менее актуальную книгу по OpenGL желательно чтобы там
была расписана работа с шейдерами и их встраивание в приложение , можно C++ или Java    


Ответы

Ответ 1



Довольно доходчиво изложены основы OpenGL в этой книге. По шейдерам лучше отдельную книгу читать, например эту: "OpenGL. Трехмерная графика и язык программирования шейдеров. Для профессионалов" А ещё тут есть несколько полезных уроков. А вообще, я бы порекомменодовал Вам пользоваться XNA 4 + с#. Но выбор, в основном, зависит от целей Вашего проекта.

Ответ 2



Есть ещё OpenGL суперкнига. Последнее переведённое на русский 3-е издание. Там описывается OpenGL 2.0. Я думаю, что его возможностей вполне хватит. Если же нет, то читай 5-е издание на английском. Там уже есть OpenGL 3.x.

Ответ 3



OpenGl red book - больше справочная OpenGl orange book - шейдеры OpenGl blue book - туториалы OpenGl insights - особенности, которых часто нет в документациях желательно, начиная с 3.2, потому что ранние уже не актуальны.

Как работает функция вершинного шейдера OpenGL gl_ClipDistance?

#opengl

                    
Есть какая-либо информация на этот счёт или простой пример? Мне показалась, эта функция
довольно интересной, но возникли трудности в её реализации.     


Ответы

Ответ 1



gl_ClipDistance - это не функция, а одна из частей input'a или output'a вершинного или геометрического шейдера. Если в соответствующем шейдере задать этот параметр, то можно производить клиппинг произвольных вершин на основании расстояния до соответствующих плоскостей. Пример использования в геометрическом шейдере можно найти здесь. В этом аспекте не очень понятна фраза про трудности с ее реализацией, хотя, я конечно могу допустить, что вы занимаетесь какой-нибудь задачей типа, например, портирования компилятора GLSL на мобильные девайсы. В таком случае имеет смысл глянуть, например, на библиотеку Mesa3d и посмотреть как соответствующие вещи реализованы там, благо opensource.

суббота, 11 апреля 2020 г.

Подключение GLEW к Visual Studio

#visual_studio #opengl

                    
Пытаюсь подключить GLEW к Visual Studio Express 2013.

Что я сделал:

В настройках указал пути к папкам с дополнительными заголовочными файлами (сделал
папку include и указал путь в настройках проекта) и библиотекам (сделал папку lib и
тоже указал путь).

Положил C:\Users\%User%\Desktop\glew-1.12.0-win32\glew-1.12.0\bin\Release\Win32\glew32
в %Папка с проектом%\Debug. Также в свойствах проекта у меня стоит "Все конфигурации".
Сделал это по инструкции установки GLFW (когда устанавливал GLFW, то в инструкции нужно
было сделать этот шаг).

C:\Users\Andrew\Desktop\glew-1.12.0-win32\glew-1.12.0\include\GL все файлы в %Папка
с проектом%\%Папка с названием проекта%\include.

C:\Users\Andrew\Desktop\glew-1.12.0-win32\glew-1.12.0\lib\Release\Win32 все lib'ы
в %Папка с проектом%\%Папка с названием проекта%\lib.

Также у меня установлен GLFW, но он работает.

Ошибки с GLEW (вставил пример кода с использованием GLFW и GLEW):
    


Ответы

Ответ 1



Если ошибка 0xc0000007b , то попробуй скомпилировать в режиме Release, а не Debug : http://www.cyberforum.ru/visual-cpp/thread845225.html Если это сработает, то можно в Debug исправить опцию на Project -> Properties -> C/C++ -> Code Generation -> Runtime Library : Multi-threaded DLL (/MD) . После этого у меня заработал и Debug режим. Только сперва удали созданные папки Debug в папке проекта и построй приложения заново уже с новыми настройками.

Ответ 2



Для подключения GLEW(x64) нужно сделать следующее: glew32.lib, glew32s.lib положить сюда: C:\Program Files (x86)\%VS FOLDER%\VC\lib\amd64 glew.h, glxew.h, wglew.h положить сюда: C:\Program Files (x86)\%VS FOLDER%\VC\include\GL glew32.dll положить сюда: C:\Windows\System32 Далее выбрать нужный проект, нажать правой кнопкой мышки, выбрать Properties-> Configuration Properties -> Linker -> Input -> Additional Depencecies. В текстовое окно вписать glew32.lib. Важно! Конфигурация солюшена должна быть x64.

вторник, 31 марта 2020 г.

Как повернуть треугольник к новой нормали?

#алгоритм #opengl #геометрия


Жил был треугольник и была у него нормаль, но вот однажды нормаль изменила ему и
стала смотреть в другую сторону, на совсем другой вектор.

Погоревал треугольник 1мс и решил тоже повернутся чтоб зажили они как и прежде.

Задачка:
Как повернуть треугольник к его нормали? что бы жили они долго и по перпендикулярному?
    


Ответы

Ответ 1



выбираем нулевую вершину треугольника A за базовую точку откладываем от неё произвольный вектор, перпендикулярный новой нормали и с длиной вектора AB вычисляем вектор AD , перпендикулярный N и AB', как их векторное произведение находим вектор AC' как линейную комбинацию AB' и AD, обеспечивающую нужную длину AC и угол AC'B' Для других вариантов постановка задачи не обеспечивает достаточно данных.

пятница, 20 марта 2020 г.

Как генерировать случайные числа в шейдерах OpenGL?

#opengl


Есть такая неплохая функция - noise. Но она по непонятным причинам не работает. Может
кому-нибудь известны и другие способы генерации случайных значений?     


Ответы

Ответ 1



Есть четыре шумовые функции, noise1, noise2, noise3 и noise4. Но, они не всегда поддерживаются. По этой причине, обычно используют шумовую текстуру, заранее заготовленную.

воскресенье, 15 марта 2020 г.

OpenGL Освещение

#cpp #qt #opengl #qt5


Проблема: некорректно работает освещение, выглядит так, будто источник света перемещается
параллельно с вращением объекта. По идее источник света должен быть статичным. Объект
может вращается вокруг своего центра с помощью мыши (и функции glRotated()).
Код:  

//Инициализация света, находится в методе initializeGL()
//Часть параметров такие же как и стандартные
GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f }; 
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightSpecular[]= { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[]= { 10.0f, 10.0f, 10.0f, 1.0f };
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); //Я предположил, что загрузка единичной матрицы мне поможет, но нет
glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
glLightfv(GL_LIGHT1, GL_SPECULAR, LightSpecular);
glEnable(GL_LIGHT1); //Источник света один


//Отрисовка фигуры
void Canvas::drawAll() //Отрисовка всех фигур
{
   names = 0;
   for(int i = 0; i < figures; i++)
   {
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      glTranslated(motionX, motionY, zoom); //motionX/Y вычисляются при перемещении
курсора при нажатой ПКМ
      glRotated(rotationX, 1.0, 0.0, 0.0); //rotationX/Y также, только при ЛКМ
      glRotated(rotationY, 0.0, 1.0, 0.0);
      if(allFigures[i]->visible)draw(allFigures[i]);
   }
}


Пишу на Qt5.3. Вот как это выглядит: ссылка
    


Ответы

Ответ 1



Оказалось что это ответ: Похоже на глючные нормали

понедельник, 24 февраля 2020 г.

Можно-ли изменить данные в массиве VBO?

#cpp #opengl


Здравствуйте. Обращаюсь к специалистам OpenGL. Рисую трехмерную сцену с группой объектов VAO

for(auto VAO: vao_list)
{
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, nullptr);
    glBindVertexArray(0);
}


Все по "букварю", все работает. Но вот один из объектов, размером этак 40К вершин,
потребовалось немного изменить: удалить 3 из 40 000  вершин. Можно конечно перезалить
модифицированный объект, но для этого его образ надо вначале построить в оперативной
памяти а потом перезалить в память графического процессора. А если меняющихся объектов
в сцене большинство, то все их (копии) придется держать в оперативке, там править и
перезаливать в графичекий буфер. Получается двойная работа, наверно тогда проще использовать
"glDrawArrays", который рисует массивы прямо из оперативной памяти:

glEnableVertexAttribArray(idx_vertex_coord3d);
glEnableVertexAttribArray(idx_texture_coord);
glDrawArrays(GL_TRIANGLES, 0, count_of_vertices);
glDisableVertexAttribArray(idx_texture_coord);
glDisableVertexAttribArray(idx_vertex_coord3d);


но в этом случае память графического процессора (очень дорогая и быстрая) простаивает.
Вот собственно вопрос: а можно ли как-то частично изменять объект размещенный в VAO
(в графической памяти), удаляя/добавляя часть вершин в нем не перезаписывая VAO полностью?
    


Ответы

Ответ 1



VAO и VBO На всякий случай вначале скажу немного про VAO и VBO. VAO не хранит данные объекта, а хранит только ссылки на один или несколько VBO и прочее состояние, необходимое для рисования объекта. Поэтому работать мы будем с VBO. Если несколько атрибутов вершин хранятся в нескольких VBO, то все их придётся править по отдельности. Изменение VBO будет сразу же доступно пользователям связанного VAO. Рассуждения об удалении Начнём с экстремально простого случая: при удалении вершин с конца вообще ничего изменять не нужно. Просто рисуем вызовом glDrawElements(GL_TRIANGLE_STRIP, num_elements - 3, GL_UNSIGNED_BYTE, nullptr); вместо glDrawElements(GL_TRIANGLE_STRIP, num_elements, GL_UNSIGNED_BYTE, nullptr); Если же удаляемые вершины хранятся в начале или в середине, то задача их удаления аналогична задаче удаления элементов из середины обычного массива в памяти. Например, если есть массив: int a[] = {1,2,3,4,5,6}; то мы не можем удалить из него элементы 2 и 3, не оставив на их месте нули или какие-нибудь специальные значения значения, указывающие на то, что данные удалены. Чтобы не оставлять этих значений, мы можем либо перевыделить память под новый массив нужной длины и скопировать туда значения, либо скопировать 5 и 6 на место 2 и 3 и запомнить, что теперь длина массива равна 4 вместо 6. Оставшаяся в хвосте память под 2 элемента будет потрачена впустую, но при 40000 элементов ей можно пренебречь. То же самое можно применить и к массиву в видеопамяти: Можно вызвать glBufferData для выделения нового буфера. Можно заменить кусок данных от начала удаляемого куска до конца буфера новыми значениями с помощью glBufferSubData, не забыв про уменьшение num_elements. Сдвинуть данные копированием внутри буфера не получится, ибо регионы памяти при копировании внутри буфера не должны пересекаться. Вышеперечисленные методы могут иметь смысл при изменении/"удалении" большого количества данных, но, как вы заметили, совершенно не подходят для удаления трёх точек из 40000. То есть полностью удалить точки не получится, и придётся искать обходной путь. Возможное решение Функция glBufferSubData позволяет указывать смещение и длину заменяемых данных. Поэтому с её помощью можно переписать как весь буфер, так и любую его часть, хоть один единственный элемент. Если нам нужно удалить 3 из 40000 точек из модели, то не обязательно их удалять из буфера! Давайте просто перезапишем их значениями подходящей соседней вершины. Например, пусть есть ломаная из 8 вершин на плоскости: 2 3 5 7 /-------\ /\ /----8 / \ / \ / / \/ \/ /1 4 6 Если мы сделаем вершину 5 равной вершине 6, то получим тот же эффект, что и при удалении вершины 5: появится отрезок, визуально соединяющий вершины 4 и 6, а длина отрезка 5-6 станет нулевой: 2 3 7 /-------\ /----8 / \ / / \------/ /1 4 5,6 В выборе между перерасходом памяти на 3 вершины или расходом времени на пересоздание буфера на 40000 вершин логично отдать предпочтение первому варианту. Usage pattern Из вашего описания кажется, что "удалять" удалять точки вы будете редко, т.е. не на каждом кадре. Буфер же будет использоваться только для вывода графики, но не для transform feedback и прочих таких хитростей. Если так, то при создании буфера не забудьте в последнем аргументе glBufferData указать GL_DYNAMIC_DRAW. Однако, без тестов производительности конкретного приложения здесь нельзя давать однозначную рекомендацию. При очень редком обновлении буфера GL_STATIC_DRAW может оказаться быстрее. Напротив, при очень частом лучшим выбором может быть GL_STREAM_DRAW. Комментарий от автора вопроса Небольшой пример. Спасибо, все встало на свои места. В добавление к вашему ответу хочу добавить демо-код для одного из перечисленных вами вариантов решения: GLfloat* vertices = new GLfloat[9]; // элемент из 3 вершин ... GLuint pos_Buf; glGenBuffers(1, &pos_Buf); // передаем данные в GPU glBindBuffer(GL_ARRAY_BUFFER, pos_Buf); glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), vertices, GL_STATIC_DRAW); // освободить память после переноса данных в GPU delete [] vertices; ... // Если надо изменить, например, седьмой элемент массива: // Пример изменения данных, размещенных в графической памяти // Вариант - glUnmapBuffer // ---------------------------------------------------- glBindBuffer(GL_ARRAY_BUFFER, pos_Buf); data = (GLfloat *) glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); data[7] = 0.4f; glUnmapBuffer(GL_ARRAY_BUFFER); ... // Вариант 2 - glBufferSubData // ---------------------------------------------------- glBindBuffer(GL_ARRAY_BUFFER, pos_Buf); GLintptr offset = 7*sizeof(float); float pos_SubD[] = {0.0f}; glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(float), pos_SubD); ... // В нужный момент этот VBO можно удалить glDeleteBuffers(1, &vboId);

четверг, 13 февраля 2020 г.

Как сделать эффект “Туман Войны” используя графические примитивы?

#java #opengl


Делаю игру (курсовой проект) и надо создать эффект "Туман Войны" (это когда первоначально
карта вся затемнена и открывается постепенно вокруг персонажа при его движении). 
Использую Slick (игровая библиотека основанная на LWJGL). Видел на форуме этой библиотеки
создание такого эффекта, но там очень сложно (мне уж по крайней мере). 
Появилась идея как сделать это самому используя круг и прямоугольник. Рисуем карту,
рисуем персонажа, поверх всего рисуем черный прямоугольник с прозрачным "как бы встроеным"
кругом . При движении персонажа, к этой фигуре (круг+прямоугольник) будет добавляться
новый прозрачный круг с другими координатами. 
Незнаю как соединить прямоугольник и круг так, как мне надо. 
Круг заливаю прозрачным цветом, там есть класс     Color (red, green, blue, alpha)
P.S работа с прямоугольником и кругом практически такая же, как и в AWT.
P.P.S возможно моя идея бредовая и не эффективная, если знаете реализацию "тумана
войны" лучше и проще скажите мне её пожалуйста)
LWJGL - работа с openGL.    


Ответы

Ответ 1



Можно и без примитивов обойтись. По идее, в OpenGL была такая фича как координаты тумана, позволяющая задать уровень затуманенности отдельных частей сцены. Координаты тумана - это атрибут вершины, а туман - тот, который настраивается через glFog. Можно сделать сетку(допустим, M*N, где M,N - размеры карты) из квадов чёрного цвета и по мере продвижения игрока выставлять её вершинам ненулевую альфу. Сетку рисовать поверх левела, конечно же. Можно взять текстуру(изначально - чёрную/непрозрачную), при каждом передвижении игрока отрисовать в неё прозрачную область(рендеринг в текстуру может быть непривычным, но эта техника весьма распространена и даёт отличные результаты, в том числе и в этом случае), а потом натянуть эту текстуру на один квад размером на всю карту и отрисовать поверх всего. Если какие-то техники заинтересовали - могу рассказать подробнее :)

Ответ 2



Я бы сделал так, на примере tilemap делаем карту, спрайты тумана войны и накладываем их поверх карты, то есть первоначально вся карта будет под спрайтами тумана, на карте делаем точку(respawn), где появляется персонаж в начале игры и задаём параметры, чтобы вокруг него, в радиусе нескольких тайлов, спрайты тумана исчезали, вот так вот.

вторник, 28 января 2020 г.

Как рисовать 2D пользовательский интерфейс в игре поверх 3D?

#java #opengl #разработка_игр #gui #lwjgl


Я создал 3D игру наподобие Minecraft на языке Java при помощи библиотеки LWJGL. Так
же могу передвигаться по миру, смотреть вверх, вниз, оглядываться, и так далее. А как
отобразить панель, наподобие той, которую я выделил красным цветом на прикреплённом
рисунке? 



Допустим, эти квадратики я нарисовал в Paint'е и сохранил в файле panel.png, но как
её отобразить?

Напишите примерный исходный код.
    


Ответы

Ответ 1



В коде инициализации экрана (перед главным циклом) написать следующий код: GL11.glEnable(GL11.GL_TEXTURE_2D); GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GL11.glMatrixMode(GL11.GL_MODELVIEW); GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glLoadIdentity(); GL11.glOrtho(0, Display.getWidth(), Display.getHeight(), 0, 1, -1); GL11.glMatrixMode(GL11.GL_MODELVIEW); Texture i4 = TextureLoader.getTexture("PNG", new FileInputStream("textures" + File.separator + "myTexture.png")); А в главном цикле следующее: while (!Display.isCloseRequested()) { GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); i4.bind(); GL11.glBegin(GL11.GL_QUADS); // Координаты и разрешение текстуры GL11.glTexCoord2f(0F, 0F); GL11.glVertex2f(100F, 100F); GL11.glTexCoord2f(1F, 0F); GL11.glVertex2f(100F + (float) i4.getTextureWidth(), 100F); GL11.glTexCoord2f(1F, 1F); GL11.glVertex2f(100F + (float) i4.getTextureWidth(), 100F + (float) i4.getTextureHeight()); GL11.glTexCoord2f(0F, 1F); GL11.glVertex2f(100F, 100F + (float) i4.getTextureHeight()); GL11.glEnd(); }

Ответ 2



Создайте отдельный контейнер для спрайтов, закреплённый относительно камеры и разместите в нём спрайты пользовательского интерфейса. В качестве контейнера можно использовать поростой прямоугольник с текстурой (канвой). С текстурой (канвой) можно оперировать через PixelWriter и PixelReader, перерисовывая области на плоскости. Либо можно сделать аналог Group из JavaFX, так же закрепить его экземпляр относительно камеры и уже добавлять 3D элементы интерфейса. UPD: Посмотрите обсуждение здесь https://github.com/LWJGL/lwjgl3/issues/101 UPD2: Вот здесь вопрос уже обсуждался https://gamedev.stackexchange.com/questions/18468/making-a-hud-gui-with-opengl-lwjgl (Кратко: человек отрисовывает мир, а потом уже интерфейс поверх мира только и всего). UPD3: И ещё одна рекомендация здесь https://gamedev.stackexchange.com/a/29284 - использовать готовую библиотеку для GUI в LWJGL - Nifty (http://void256.github.io/blog/ -> https://github.com/nifty-gui/nifty-gui)

Ответ 3



В общем подход такой: Рисуем игру в объемной проекции (перспектива и т.п.) Переключаем проекцию на ортографическую Выключаем буфер глубины Рисуем интерфейс

Ответ 4



В андроиде есть FrameLayout для отображения одного контента поверх второго, думаю такая штука есть и в вашей отрасли

воскресенье, 26 января 2020 г.

OpenGL - “Поймать Мышь”

#cpp #opengl #графика


У меня есть код для преобразований координат мыши в OpenGL координаты.
И вроде отрисовывается и всё прекрасно, но при подведении мыши к краю,
центр квадрата (это полигон по координатам мыши) смещается в сторону.

Кто сталкивался с проблемой или у кого есть рабочий код по отлову координат в OpenGL?

ТОЛЬКО НЕ GLUT! 


Этого дела полно в Сети.
Пишу не под ним.


Ссылка на исходники

~Координаты мыши

GLvoid MouseCord(int mouse_x, int mouse_y, CVector3& p1)
{
// mouse_x, mouse_y  - оконные координаты курсора мыши.
// p1, p2            - возвращаемые параметры - концы селектирующего отрезка,
//                     лежащие соответственно на ближней и дальней плоскостях
//                     отсечения.
GLint    viewport[4];    // параметры viewport-a.
GLdouble projection[16]; // матрица проекции.
GLdouble modelview[16];  // видовая матрица.
GLdouble vx,vy,vz;       // координаты курсора мыши в системе координат viewport-a.
GLdouble wx,wy,wz;       // возвращаемые мировые координаты.

glGetIntegerv(GL_VIEWPORT,viewport);           // узнаём параметры viewport-a.
glGetDoublev(GL_PROJECTION_MATRIX,projection); // узнаём матрицу проекции.
glGetDoublev(GL_MODELVIEW_MATRIX,modelview);   // узнаём видовую матрицу.
// переводим оконные координаты курсора в систему координат viewport-a.
vx = mouse_x;
vy = viewport[3] - mouse_y - 1;
// вычисляем ближний конец селектирующего отрезка.
vz = -1;
gluUnProject(vx, vy, vz, modelview, projection, viewport, &wx, &wy, &wz);
p1.x = wx*100;
p1.y = wy*100;
p1.z = wz;
system("cls");
std::cout<<"p1.x: "<


Ответы

Ответ 1



К сожалению ваши исходники не доступны. Лучше бы добавили скриншоты проблемы. Вы можете попробовать ортогональную проекцию, может ли она. Если преобразовывать координаты мыши в 3Д координаты ОпенГЛ, то вы должны получить луч, а не точку, т.к. при разном значении vz координат мыши, вы получите разные координаты z в 3D. Тут есть 2 варианта решения: Вы переводите 2 точки координат мыши с разными vz и получив луч в 3Д пространстве, найти точку пересечения его с интересующей вас плоскостью. Это ваша конечная точка. Найти какое должно быть значение vz для конкретной точки в 3Д пространстве. Если ваша плоскость находится "лицом" к камере, то берёте любую точку на ней и проецируете её на экран. Затем берёте знамение Z этой точки спроецированной на экран и используете её как значение для vz.

четверг, 23 января 2020 г.

Как прикрепить патч для dll к проекту?

#sdl #opengl #cpp #dll


Я написал приложение на SDL + OPENGL + C++ в CodeBlocks. Обнаружил, что при запуске
исполняемого файла, скомпилированного в релизе (при запуске в релизе в самой среде
всё отлично работает) приложение некоторые .png файлы не загружает (а именно png-24)
и выдаёт в файл для ошибок (stderr) "libpng warning: Interlace handling should be turned
on when using png_ read_ image". Как выяснилось, sdl_ image использует такую libpng(а
именно libpng15-15.dll, другие я пробовал, sdl_image вроде требует именно эту либу),
в которой функция png_read_image имеет ошибку. Я долго искал решение (png-24 нужны),
качал вроде бы более новые версии libpng, но всё тщетно. Нашёл патч, который должен
фиксить эту ошибку:
--- libpng-1.5.0/pngread.c.ark  2011-01-14 12:27:23.440018507 +0100
+++ libpng-1.5.0/pngread.c  2011-01-14 12:28:02.866685173 +0100
@@ -841,7 +841,7 @@ png_read_image(png_structp png_ptr, png_
    }
    else
    {
-      if (!(png_ptr->transformations & PNG_INTERLACE))
+      if (png_ptr->interlaced && !(png_ptr->transformations & PNG_INTERLACE))
   {
      /* Caller called png_start_read_image or png_read_update_info without
       * first turning on the PNG_INTERLACE transform.  We can fix this here,

но не пойму? как его прицепить к  проекту. Скомпилировать свою libpng из исходников
пока не получается (очень не хочется этим заниматься). Помогите пожалуйста!    


Ответы

Ответ 1



Вам придётся скомпилировать libpng. Патч предназначен для исходников, к исходникам его и надо применять. Вы не сможете так просто применить патч исходников для бинарника. В качестве ненадёжной альтернативы, можно попробовать дизассемблировать код libpng, найти нужную функцию, и применить патч вручную. Однако, это имеет право не сработать -- например, если оптимизатор заинлайнил кое-где вызов этой функции. Короче говоря, легче скомпилировать. Кстати, может быть, легче будет уговорить sdl_image использовать другую версию libpng?

Ответ 2



Итак, нашёлся ответ. Собственно я нашёл решение только по другим странностям, когда релиз и дебаг версии начали работать совсем не так, как скомпилированные .ехе. начали вылетать ошибки на простейших функциях opengl и сам .ехе вариант очень тормозил. Оказывается я в начале сунул какую-то кривую версию библиотеки opengl в папку и компилятор работал с нормальной, а вот ехе с кривой.

Проблема в OpenGL с неверными координатами вывода изображения

#java #android #opengl #opengles


Всем привет! Возникла проблема с glViewport в OpenGL ES 2.0 под Android.
Я реализовал следующий алгоритм. Изображение генерируется в текстуру с использованием
FBO. Шейдер, который генерирует изображение, также принимает на вход предыдущую отрисованную
текстуру того же размера. Шейдер использует ее для более быстрой генерации следующей
текстуры. 
Для всего этого у меня есть 2 фреймбуфера (+ экранный фреймбуфер), к каждому из которых
приаттачена 1 текстура. После каждого цикла отрисовки ссылки на фреймбуферы меняются
местами, чтобы каждый раз не копировать предыдущее изображение.
Размер текстуры степени 2, т.е. размеры текстуры и экрана не совпадают.

Итак, проблема в том, что на экран рендерится не вся текстура, а лишь ее часть.

Код отрисовки:

//Меняем местами ссылки на буферы
evenRender = !evenRender;
int srcFB = evenRender? 0:1;
int dstFB = evenRender? 1:0;

//Привязываем буфер, куда будет генерироваться изображение
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferID[dstFB]);
//Выбираем размеры окна вывода как размеры экрана устройства
**GLES20.glViewport(0, 0, mScreenWidth, mScreenHeight);**
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

//Выбираем предыдущую отрисованную текстуру
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + srcFB);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameTextureID[srcFB]);

//Устанавливаем шейдер для генерации изображения
GLES20.glUseProgram(sp_ImageGeneration);

int mPositionHandle = GLES20.glGetAttribLocation(sp_ImageGeneration, "vPosition");
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, offscreen_vertexBuffer);
GLES20.glEnableVertexAttribArray(mPositionHandle);

int mTexCoordLoc = GLES20.glGetAttribLocation(sp_ImageGeneration, "a_texCoord");
GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, offscreen_uvBuffer);
GLES20.glEnableVertexAttribArray(mTexCoordLoc);

...

//Отправляем шейдеру предыдущую отрисованную текстуру
int mSamplerLoc = GLES20.glGetUniformLocation (sp_ImageGeneration, "prev_frame" );
GLES20.glUniform1i(mSamplerLoc, srcFB);

GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_UNSIGNED_SHORT,
drawListBuffer);

GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTexCoordLoc);

//Привязываем экранный буфер
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glViewport(0, 0, mScreenWidth, mScreenHeight);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

//Выбираем текстуру в том буфере, куда генерировалось изображение
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + dstFB);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameTextureID[dstFB]);

// Устанавливаем простой шейдер
GLES20.glUseProgram(sp_Image);

mPositionHandle = GLES20.glGetAttribLocation(sp_Image, "vPosition");
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);
GLES20.glEnableVertexAttribArray(mPositionHandle);
mTexCoordLoc = GLES20.glGetAttribLocation(sp_Image, "a_texCoord" );
GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, uvBuffer);
GLES20.glEnableVertexAttribArray(mTexCoordLoc);

...

//Отправляем шейдеру текстуру, куда генерировалось изображение
mSamplerLoc = GLES20.glGetUniformLocation (sp_Image, "s_texture" );
GLES20.glUniform1i(mSamplerLoc, dstFB);

GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_UNSIGNED_SHORT,
drawListBuffer);

GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTexCoordLoc);
GLES20.glUseProgram(0);

GLES20.glActiveTexture(0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);


Координаты треугольников, на которые происходит отрисовка:

float koefWidth = (float)texSize / mScreenWidth;
float koefHeight = (float)texSize / mScreenHeight;

vertices = new float[] {
        0, 0, 0f,
        0, mScreenHeight * koefHeight, 0f,
        mScreenWidth * koefWidth, mScreenHeight * koefHeight, 0f,
        mScreenWidth * koefWidth, 0, 0f
};

offscreen_vertices = new float[] {
        0, 0, 0f,
        0, mScreenHeight * koefHeight* koefHeight, 0f,
        mScreenWidth * koefWidth * koefWidth , mScreenHeight * koefHeight* koefHeight, 0f,
        mScreenWidth * koefWidth * koefWidth, 0, 0f
};


texSize - размер текстуры. Например, mScreenWidth = 800, mScreenHeight = 600, texSize
= 1024.

Координаты текстур uvs и offscreen_uvs одинаковы:

uvs = new float[] {
            0, 0,
            0, 1,
            1, 1,
            1, 0,
    };


Фреймбуферы и текстуры для них были созданы так:

    frameBufferID = new int[2];
    frameTextureID = new int[2];

    GLES20.glGenFramebuffers(2, frameBufferID, 0);
    GLES20.glGenTextures(2, frameTextureID, 0);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferID[0]);
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameTextureID[0]);

    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, texSize, texSize,
0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, null);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
GLES20.GL_TEXTURE_2D, frameTextureID[0], 0);

    //Next framebuffer
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferID[1]);
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + 1);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameTextureID[1]);
    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, texSize, texSize,
0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, null);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
GLES20.GL_TEXTURE_2D, frameTextureID[1], 0);


Я очень долго пробовал менять значения в glViewport, выделенном звездочками, а также
координаты треугольников. Но тогда либо возникали графические артефакты, либо сильно
падала производительность.
Заранее спасибо!
    


Ответы

Ответ 1



Вопрос решен. Оказалось, "графические артефакты" были связаны со спецификой работы моего шейдера. Он берет текстуры из фреймбуфера, но я не учитывал то, что эти текстуры были уменьшены glViewport'ом. Из-за этого данные текстур обрабатывались неправильно, что и выливалось в артефакты результирующего изображения. Решилось добавлением в шейдер соответствующих коэффициентов при обработке текстур. Эта проблема мучила меня на протяжении недели, и теперь я очень рад! :)

В чем различие между attribute от uniform?

#opengl #glsl


Читаем:


  Атрибуты (attribute) — это свойство вершины. У вершины могут быть
  различные атрибуты. Например, координаты положения в пространстве,
  координаты вектора нормали, цвет. Кроме того, вы можете передавать в
  вершинный шейдер какие-либо свои атрибуты. Важно понять, что атрибут —
  это свойство вершины, и поэтому он должен быть задан для каждой
  вершины. Атрибуты передаются в только вершинный шейдер. Атрибуты
  доступны вершинному шейдеру только для чтения и не могут быть
  перезаписаны.
  
  Юниформы (uniform) — это внешние данные, которые могут быть
  использованы для расчетов, но не могут быть перезаписаны. Униформы
  могут быть переданы как в вершинный, так и во фрагментный шейдеры.
  Униформы никак не связаны с конкретной вершиной и являются глобальными
  константами. Например, в качестве униформ можно передать в шейдер
  координаты источника света и координаты глаза (камеры).


Для первых:

Атрибуты доступны вершинному шейдеру только для чтения и не могут быть перезаписаны.

Для вторых:

Юниформы (uniform) — это внешние данные, которые могут быть использованы для расчетов,
но не могут быть перезаписаны.

Вывод: 

и те и другие можно читать но нельзя перезаписать.

Вопрос:

Чем они различаются?
    


Ответы

Ответ 1



Еще добавлю примеры: Для uniform это глобальные, вроде параметров освещения, текстур модели, каких-либо коэффициентов. Они видны во всех шейдерах, собранных в программу Для attributes это цвет, нормаль, uv, позиция, тангент и т.д.

Ответ 2



Униформ - это константа переданная программистом в шейдер, где она будет использоваться как константа. Атрибут же - это константа вершины. Атрибут будет использован для расчёта свойств вершины, например, для вычисления текстурной координаты вершины, потом эти рассчитанные данные будут интерполированы для использования во фрагментном шейдере. У каждой вершины свои атрибуты, которые используются в вершинном шейдере, а униформы - это просто константы, которые используются в обоих шейдерах. А как раз вариинг - это рассчитанное значение для вершины, которое во фрагментном шейдере будет интерполировано в зависимости от расстояния до вершин. Программист передаёт данные для вершин в атрибутах - координаты, текстурные координаты, нормаль, цвет, да вообще на самом деле что угодно ещё. В шейдере это будет выглядеть как одна переменная, например, цвет, но - в реальности для каждой вершины в атрибут будут заноситься значения именно для этой вершины, и будет вызываться вершинный шейдер. Если смотреть на вершинный шейдер как на функцию/метод, то атрибуты - это параметры этой функции, а сама функция вызывается видеокартой для каждой вершины. Задачей программиста же является загрузить в видеокарту атрибуты для каждой вершины. То есть имеем, например, 20 вершин, значит надо передать 20 координат, 20 вершиных координат, 20 нормалей и пр. (всё, что нужно для конкретного шейдера). Видеокарта получает эти массивы. В начале отрисовки происходит "обсчёт" вершин. Для каждой вершины из массивов берутся соответствующие значения атрибутов и подставляются в вершинный вертекс, он выполняется, и производит вычисления для конкретной вершины основываясь на именно её атрибутах.

среда, 22 января 2020 г.

Использование буферов OpenGL в OpenCL - ошибка “InvalidContext”

#c_sharp #opengl #opencl


Мне требуется использовать буферы OpenGL в OpenCL.
при использовании метода clCreateFromGLBuffer выдаёт ошибку InvalidContext.
я где то прочитал что нужно добавить свойства при создании контекста OpenCl 

ContextProperty[] contextProperties = new[]
{
     new ContextProperty(ContextProperties.CL_GL_CONTEXT_KHR, Win32.wglGetCurrentContext()),
     new ContextProperty(ContextProperties.CL_WGL_HDC_KHR,Win32.GetDC(Process.GetCurrentProcess().MainWindowHandle)),
     new ContextProperty(ContextProperties.CL_CONTEXT_PLATFORM,_platform.handle), 
}


я добавил но появилась ошибка при создании контекста


  System.AccessViolationException: Попытка чтения или записи в защищенную память.
Это часто свидетельствует о том, что другая память повреждена.


Также, констант CL_GL_CONTEXT_KHR и CL_WGL_HDC_KHR не было в библиотеке которую я
скачал в NuGet значения констант я нашёл на на этом сайте

Как это исправить?

полный код

Glfw.Init();
window = Glfw.CreateWindow(500, 500, "");
Glfw.MakeContextCurrent(window);
OpenGL gl = new OpenGL();

Platform[] platforms = Cl.GetPlatformIDs(out errorCode);
foreach (Platform platform in platforms)
{
     Device[] devices = Cl.GetDeviceIDs(platform, DeviceType.Gpu, out errorCode);

     if (devices.Length == 0)
     {
          continue;
     }

     _platform = platform;
     _device = devices[0];
     break;
}
ContextProperty[] contextProperties = new[]
{
     new ContextProperty(ContextProperties.CL_GL_CONTEXT_KHR, Win32.wglGetCurrentContext()),
            new ContextProperty(ContextProperties.CL_WGL_HDC_KHR,Win32.GetDC(window.Ptr)),
            new ContextProperty(ContextProperties.CL_CONTEXT_PLATFORM,_platform.handle), 

};
_context = Cl.CreateContext(contextProperties, 1, new Device[] {_device}, null, IntPtr.Zero,
out errorCode);

    


Ответы

Ответ 1



вообщем ему не хватало одного элемента в массиве. ContextProperty[] contextProperties = new[] { new ContextProperty(ContextProperties.CL_GL_CONTEXT_KHR, wglGetCurrentContext()), new ContextProperty(ContextProperties.CL_WGL_HDC_KHR,wglGetCurrentDC()), new ContextProperty(ContextProperties.CL_CONTEXT_PLATFORM,_platform.handle), new ContextProperty(0,IntPtr.Zero), }; вот так всё работает.

Как в Android над Activity с OpenGL поместить слой с полями для ввода текста?

#android #activity #opengl


Добрый день. Собственно такая вот у меня проблема. Есть Activity с OpenGL. Всё рендерится
замечательно. Большинство функций вынесено в библиотеку и методы помечены, как native.
Но вот в определенный момент мне бы хотелось, чтобы пользователь мог ввести данные:
логин, пароль. Эти данные используются для идентификации. Уже почти неделю бьюсь, никак
не могу ничего толкового придумать.    


Ответы

Ответ 1



Никак не пойму почему нельзя просто поднять поверх еще 1 активити. Прозрачную по бокам и с диалог боксом в центре? Пример Intent intent = new Intent(openGLactivity, YourLoginPasswordActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); openGLactivity.startActivity(intent);

суббота, 11 января 2020 г.

Как сохранить пропорции 2D объекта в окне рендера OpenGL?

#cpp #opengl


Есть круг.  



Но если изменить размеры окна(ресайз) например вот так:



или так:  



То получается овал.

Вопрос: как сделать, чтобы при ресайзе, круг всегда оставался кругом?

Код:

#include "stdafx.h"
#include 
#include 

/* подключаем библиотеку GLUT */
#include 

static GLfloat spin = 0.0;


void init(void)
{   
    //glClearColor() устанавливает черный цвет фона
    glClearColor(0.0, 0.0, 0.0, 0.0);
    //glShadeModel(GL_FLAT);////Режим без сглаживания
    glShadeModel(GL_SMOOTH); //Сглаживание. По умолчанию установлен режим GL_SMOOTH.

}

void display(void)
{
    // glClear() очищает фон .
    //В дальнейшем, всякий раз, когда  glClear() будет вызываться,
    //она будет очищать окно в черный цвет .
    glClear(GL_COLOR_BUFFER_BIT);
    glPushMatrix();
    //glRotatef(Angle,Xtrue,Ytrue,Ztrue) отвечает за вращения объекта вдоль
    glRotatef(spin, 0.0, 0.0, 1.0);

    //glColor3f() устанавливает цвет прорисовки - белый цвет.
    glColor3f(1.0, 1.0, 1.0);
    //glColor3f(1.0, 0.0, 0.0);//-красный.

    #define PI 3.1415926535898
    GLint circle_points = 25;
    //glBegin() и glEnd() определяют обьект, который будет прорисован .
    glBegin(GL_LINE_LOOP);
    for (int i = 0; i < circle_points; i++) {
        double angle = 2 * PI*i / circle_points;
        //glVertex2f() определяет вершины полигона, в качестве параметров - 2 координаты
x, y.
        glVertex2f(cos(angle), sin(angle));
    }
    glEnd();


    glBegin(GL_LINE_LOOP);
    for (int i = 0; i < circle_points; i++) {
        double angle = 6 * PI*i / circle_points;
        glVertex2f(cos(angle), sin(angle));
    }
    glEnd();

    glBegin(GL_LINE_LOOP);
    for (int i = 0; i < circle_points; i++) {
        double angle = 20 * PI*i / circle_points;
        glVertex2f(cos(angle), sin(angle));
    }
    glEnd();

    glPopMatrix();
    /*glutSwapBuffers(), делающий свопинг буффера .
    Имеется 2 буффера, и пока на экран не выводится полностью один из них,
    второй остается полностью за кадром, и не произойдет наложения одного надругой .*/
    glutSwapBuffers();
}

void spinDisplay(void)
{
    spin = spin + 0.05;
    if (spin > 360.0)
        spin = spin - 360.0;
    glutPostRedisplay();
}

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    //glOrtho() определяет координатную систему .
    glOrtho(-2.0, 2.0, -2.0, 2.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void mouse(int button, int state, int x, int y)
{
    switch (button) {
    case GLUT_LEFT_BUTTON:
        if (state == GLUT_DOWN)
            glutIdleFunc(spinDisplay);
        break;
    case GLUT_MIDDLE_BUTTON:
        if (state == GLUT_DOWN)
            glutIdleFunc(NULL);
        break;
    default:
        break;
    }
}

/*
* double buffer display mode.
* Register mouse input callback functions
*/
int main(int argc, char** argv)
{
    // glutInit(int *argc, char **argv) - самая первая команда инициализации
    glutInit(&argc, argv);
    //glutInitDisplayMode(unsigned int mode) - устанавливает цветовую модель - RGBA
или color - index .
    //Например, glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH) -
    //устанавливает  двойной буфер, цветовую модель RGB .
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    //glutInitWindowSize(int width, int size) - размер окна
    glutInitWindowSize(250, 250);
    //glutInitWindowPosition(int x, int y) - установливает начало координат окна.
    glutInitWindowPosition(100, 100);
    //int glutCreateWindow() - создает окно
    glutCreateWindow(argv[0]);
    init();
    //glutDisplayFunc() - вызывается всякий раз при перерисовке окна .
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMouseFunc(mouse);
    //glutMainLoop(void) - эта функция вызывается после всех остальных .
    glutMainLoop();
    return 0;
}


UPDATE:

Добавил -

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    double aspect = (double)w / h;
    //glOrtho() определяет координатную систему .
    glOrtho(-2.0 * aspect, 2.0 * aspect, -2.0, 2.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}


Итого всё в порядке,но...

Так хорошо.



Так не хорошо.


    


Ответы

Ответ 1



Вам нужно сделать изменение ширины/высоты в glOrtho при изменении размеров окна, чтобы сохранялись пропорции отрисовки. Попробуйте так: double ww = w, hh = h; if (w > h) glOrtho(-2.0 * (ww/hh), 2.0 * (ww/hh), -2.0, 2.0, -1.0, 1.0); else glOrtho(-2.0, 2.0, -2.0 * (hh/ww), 2.0 * (hh/ww), -1.0, 1.0); В книгах по OpenGL часто такой приём используется.

OpenGL Нужно ли постоянно включать/выключать GL_BLEND

#opengl


когда рисуются прозрачные объекты то включается GL_BLEND, когда рисование заканчивается
то GL_BLEND выключается.
Может не нужно выключать, один раз включить при запуске программы и всё? 
Постоянное включение/выключение как то влияет на производительность?
    


Ответы

Ответ 1



Постоянное включение/выключение как то влияет на производительность? Да, любая функция, изменяющая контекст, сначала дожидается готовности GPU, а затем стопорит и CPU, и GPU до окончания передачи изменений. Может не нужно выключать, один раз включить при запуске программы и всё? Если вашим контекстом больше никто не пользуется (а в большинстве случаев так оно и есть), то необходимости в восстановлении настроек нет. В придачу, операционная система сама сохраняет их перед обращением к другому OpenGL-приложению и восстанавливает обратно при возвращении к вам.

четверг, 9 января 2020 г.

Странности с индексированием вершин и интерполяцией цветов в OpenGL

#cpp #opengl #графика


Заметил интересную особенность в OpenGL, связанную с индексированием вершин, и пока-что
не могу понять почему так происходит.

Итак, в чем суть:

Порядок обхода вершин для видимых граней у меня по часовой стрелке. Есть 4 вершины
(обычный прямоугольник), заданы они примерно следующим образом:


В массиве они лежат вот так :

    vertices[DefaultGeometryType::PLANE] = {
        { { (size / 2), (size / 2), 0.0f },{ 1.0f,0.0f,0.0f },{ 1.0f,1.0f } },
        { { (size / 2), -(size / 2), 0.0f },{ 0.0f,1.0f,0.0f },{ 1.0f,0.0f } },
        { { -(size / 2), -(size / 2), 0.0f },{ 0.0f,0.0f,1.0f },{ 0.0f,0.0f } },
        { { -(size / 2), (size / 2),  0.0f },{ 1.0f,1.0f,0.0f },{ 0.0f,1.0f } },
    };


Затем у меня есть массив индексов для этого квадрата. Он выглядит так :

    indices[DefaultGeometryType::PLANE] = {
        0,1,2,0,2,3
    };


Таким образом получается, что квадрат разбивается на 2 треугольника с общими вершинами
0 и 2 (диагональ 0-2 будет общим ребром для этих двух треугольников). В итоге я получаю
вот такую картину:



Вроде бы все в порядке. И тут я решил немного поменять индексы, чтобы общим ребром
для двух треугольников была диагональ не 0-2 а 3-1. Я изменил индексы следующим образом:

3,0,1,1,2,3


И в итоге квадрат стал выглядеть вот так:



Согласитесь, картина совершенно другая. Такое ощущение что интерполяция цветов происходит
не совсем корректно. Я пробовал разные варианты порядка индексов, но всегда получалось
так, что когда прямоугольник делится по диагонали 0-2 - все хорошо, а когда 3-1 - такая
странная картина. Но почему? Может это какое-то неправильное индексирование вершин?
Есть ли какие-то правила корректного индексирования? Или же я что-то упускаю и на самом
деле так и должно быть?
    


Ответы

Ответ 1



Картинки правильные. Просто вы видимо ожидаете получить в итоге gradient-to-gradient gradient, а по факту тут два отдельных градиента. Заметьте, что цвет вершины, не принадлежащей данному треугольнику, для вычисления цвета пикселей этого треугольника не используется. Для построения "правильного" градиента пришлось бы сначала рассчитать градиент для каждого пикселя между вершинами 0 - 1 и 2 - 3, а затем рисовать сетку прямоугольников высотой в один пиксель. В более продвинутой форме такое реализуется например в Direct2d:

четверг, 2 января 2020 г.

Для чего нужны фреймбуферы?

#opengl #графика #webgl #opengles


Для чего нужны фреймбуферы в opengl? Я может не точно задаю вопрос, но я и не понимаю
как его задать. Я читаю книгу по opengl es 3. Там описано какие есть функции, но для
чего использовать или когда использовать я не пойму. Также есть что-то типа рендерить
фреймбуфер в текстуру.
    


Ответы

Ответ 1



Что такое фреймбуфер (OpenGL FrameBuffer, WebGL FrameBuffer)? Когда Вы вызываете методы отрисовки, в соответствии с текущими настройками графического конвейера заполняется несколько буферов размером с область отрисовки (буфер цвета, опционально буфер глубины, буфер трафарета). Такая группа буферов и называется фреймбуфером. Базовый фреймбуфер создается и настраивается в момент создания окна приложения. Базовый фреймбуфер привязывается по умолчанию. У Вас есть возможность создавать и привязывать дополнительные фреймбуферы. Создавая собственный фреймбуфер Вы получаете дополнительное пространство куда можно направить ортрисовку. Привязывая не базовый фреймбуфер Вы говорите таким образом конвейеру, что хотите чтобы все последующие вызовы отрисовки происходили в него. Фреймбуфер, сам по себе это только точка привязки, к нему привязываются так называемые рендер-тектуры. Рендер текстуры уже будут хранить непосредственно цветовую информацию. После наполнения фрейм буфера(ов) Вы привязываете базовй фреймбуфер и рисуете уже на экране, используя при отрисовке информацию из фреймбуфера(ов). Для чего это можно и нужно использовать? Самое очевидное - программная генерация текстур. Deferred Shading - Отложенное освещение и затенение. Это такая техника, при которой финальный цвет фрагмента определяется при отрисовке одного прямоугольника, закрывающего всю область экрана. При этом во фрагментном шейдере берутся значения из рендер текстур и из этих значений вычисляется финальный цвет. Тут есть важный момент что в этом случае скорость выполнения второго этапа не зависит от сложности сцены, а зависит от размера кадра. G-Buffer (Geometry Buffer) - специальное название для группы текстур при отложенном рендеринге: Результат (много источников света): Depth of Field или DoF - глубина резкости, пожалуй самый простой для понимания эффект - он применяет blur помноженный на значение из текстуры глубины. High Dynamic Range Compression или HDR - технология расширения диапазона яркости кадра подробнее тут (тут) Bloom - своеобразный эффект свечения, заключается в размытии границ ярких объектов. Screen Space Ambient Occlusion (SSAO), обманка с самозатенением - про я недавно писал ответ на вопрос тут. Screen Space Reflections (SSR) - Алгоритм который позволяет получить отражения для плоских поверхностей. При этом отразится может лишь то, что попало в кадр - подходит для горизонтальных поверхностей вроде луж на земле. Screen Space Subsurface Scattering (SSSS) - Подповерхностное рассеивание описывает механизм распространения света, при котором свет, проникая внутрь полупрозрачного тела через его поверхность, рассеивается внутри самого тела, многократно отражаясь от частиц тела в случайном направлении и на нерегулярные углы. В итоге свет выходит из объекта в выходной точке, отличной от точки вхождения в объект Screen-Space Percentage-Closer Soft Shadows

Какие практичные методики оптимизации кода OpenGl 3D движков кроме перечисленных ниже вы знаете?

#разработка_игр #3d #оптимизация #opengl



Вертексные буферные объекты.
Отрисовка треугольников одного материала для снижения количества переключений между
текстурами, цветом и компилированными шейдерами.
Удаление из кадра ненужных объектов. 
Рефакторинг кода стандартными методами.
Перенос матричных операций с мировыми координатами объектов в шейдеры.
Рендер спецэффектов в другой программе и отрисовка их из готового файла. (Используется
больше памяти, но быстрее так как не нужно проводить предварительные расчеты для отрисовки
спецэффекта.)
Использование diffuse карт для дешевого выбивания полигонов из модели без потери
качества.
Mipmapping.
Использование где это возможно заранее заготовленных карт освещения вместо real-time
расчетов
Использование triangle strips для экономии памяти.
Использование большего числа текстур текстур с размерами кратными степени двойки.
Перенос real-time расчета освещения в шейдеры.
Исключения из тела главной функции, которая отрисовывает кадр, всех сложных математических
операций, замена их заранее обсчитанными статичными объектами.
Перенос кода для детектирования столкновений, AI и других функций не связанных напрямую
с отрисовкой картинки в отдельный поток выполнения вызываемый с меньшей частотой чем FPS
Представление атрибутов вертексов в виде массива структур, а не структуры массивов(x1,y1,z1,x2,y2,z2,x3,y3,z3
вместо x1,x2,x3,y1,y2,y3,z1,z2,z3)

Под 3D движком понимается программа обертка над OpenGl, которая подготавливает массив
аттрибутов вертексов для подачи в трехмерный конвейер, естественно не поддерживающая
программный рендеринг при котором сам конвейер запрограммирован внутри кода движка.
Под оптимизацией понимается оптимизация по многим параметрам, быстродействию, качеству
картинки, экономии памяти, читабельности кода и.т.д
Интересуют только реальные методы легко и быстро реализуемые на практике прикладным
программистом.
Методы из советского ВТУЗовского курса вычислительной математики и численных методов,
а также алгоритмические-компиляторные методы вроде замены деления на два битовым сдвигом
повсюду внутри кода просьба не предлагать.    


Ответы

Ответ 1



Навскидку: Атласы - замена мелких текстур одной большой (что-то похожее видел в Вашем посте, но недопонял, о чём речь там). Occlusion query - отрисовываем простейшую модель вместо сложной, спрашиваем у видеокарты, сильно ли она перекроется, и узнаём, надо ли её рисовать. Использование временной когерентности для того же отбрасывания невидимых объектов. Instancing. Вообще говоря, Вы мешаете в кучу и графику, и игровую логику, так что конкретный ответ дать сложно. Более того, некоторые техники взаимоисключающие. Оптимизации применяются тогда, когда возникают узкие места, иначе толку от них нет. Например, если Вы упёрлись в fillrate, никакое применение VBO толку не даст, и наоборот, если основная проблема в диком количестве геометрии - можно не заморачиваться с атласами, оптимизацией шейдеров и тд,а сосредоточиться на отбрасывании невидимых треугольников и LOD. В общем случае, на неполностью загруженную видеокарту пытаются переложить все распараллеливающиеся задачи, а не только графику, в то время как процессору обычно отдают игровую логику(если видеокарта занята).

Ответ 2



к общему списку можно добавить использование лайтмапов для статичных объектов - и выглядит качественней, и ресурсы экономит