Есть только Мику

Результат работы над библиотекой FSGL с OpenGL ES и код:

Дальше я опишу как это все программировалось, решались разные интересные проблемы.

Сначала мы проинициализируем OpenGL ES контекст, как это делается я писал в прошлой заметке. Дальше будет рассматриваться только отрисовка, краткое описание кода.

Матрица следит за тобой

Данная фигура Мику на видео состоит из треугольников. Чтобы нарисовать треугольник в OpenGL, нужно задать три точки к координатами x, y, z. в 2D координатах контекста OpenGL.
Так как нам нужно отрисовать фигуру содержащую 3D координаты, нам нужно использовать матрицу проекции (projection). Также нам нужно крутить, увеличивать, или что угодно делать с моделью – для этого используется матрица модели (model). Понятия камеры в OpenGL нет, на самом деле объекты крутятся, поворачиваются вокруг статичной камеры. Для этого используется матрица вида (view).

Для упрощения реализации OpenGL ES – в нем данные матрицы отсутствуют. Вы можете использовать библиотеки которые добавляют отсутствующий функционал, например GLM.

Шейдеры

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

Шейдеры я писал на языке GLSL. В моей текущей реализации шейдеры встроены прямо в основной код приложения как C-строки.

Буферы

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

Для того чтобы OpenGL знал в каком порядке отрисовывать точки для треугольников – вам понадобится индексный буфер (index). Индексный буфер содержит номер вертекса в массиве, с помощью трех таких индексов получается треугольник.

Текстуры

Для начала нужно прогрузить/сгенерировать текстуру для OpenGL. Для этого я использовал SDL_LoadBMP, загрузка текстуры происходит из bmp файла. Однако стоит отметить что годятся только 24-битные BMP, также цвета в них хранятся не в привычном порядке RGB, а в BGR. Тоесть после прогрузки нужно осуществить замену красного канала на синий.
Текстурные координаты задаются в формате UV, тоесть необходимо передать всего две координаты. Вывод текстуры осуществляется во фрагментном шейдере. Для этого необходимо осуществить биндинг текстуры во фрагментный шейдер.

Ничего лишнего

Так как, по нашему указанию, OpenGL рисует 3D через 2D – то для реализации глубины, и выборки невидимых треугольников – нужно использовать выборку (culling) и буфер глубины (Z-Buffer). В моей реализации удалось избежать ручной генерации буфера глубины, с помощью двух команд glEnable(GL_DEPTH_TEST); и выборки glEnable(GL_CULL_FACE);
Также обязательно проверьте что near plane для матрицы проекции больше нуля, т.к. проверка глубины с нулевым near plane работать не будет.

Рендеринг

Чтобы заполнить вертексный буфер, индексный буфер чем-то осознанным, например моделью Мику, нужно осуществить загрузку данной модели. Для этого я использовал библиотеку assimp. Мику была помещена в файл формата Wavefront OBJ, прогружена с помощью assimp, и реализована конвертация данных из assimp в вертексный, индексный буферы.

Рендеринг проходит в несколько этапов:

  1. Поворот Мику с помощью поворота матрицы модели
  2. Очистка экрана и буфера глубины
  3. Отрисовка треугольников с помощью команды glDrawElements.

Следующий этап – реализация рендеринга в WebGL с помощью Emscripten.

Исходный код:
https://github.com/demensdeum/OpenGLES3-Experiments/tree/master/8-sdl-gles-obj-textured-assimp-miku
Модель:
https://sketchfab.com/models/7310aaeb8370428e966bdcff414273e7

 

Проецируй это

Нарисовав красный чайник в 3D, я считаю своим долгом кратко описать как это делается.

Современный OpenGL не рисует 3D, он рисует только треугольники, точки, и пр. в 2D координатах экрана.
Чтобы вывести с помощью OpenGL хоть что-то, нужно предоставить вертексный буфер, написать вертексный шейдер, добавить в вертексный шейдер все необходимые матрицы (проекция, модель, вью), связать все входные данные с шейдером, вызвать метод отрисовки в OpenGL. Выглядит просто?


Ок, что такое вертексный буфер? Список координат которые необходимо отрисовать (x, y, z)
Вертексный шейдер говорит GPU какие координаты нужно рисовать.
Пиксельный шейдер говорит что рисовать (цвет, текстуру, блендинг и тд.)
Матрицы транслируют 3D координаты в 2D координаты OpenGL которые он может отрисовать

В следующих статьях я приведу примеры кода и результат.

SDL2 – OpenGL ES

Я люблю Panda3D. Однако этот игровой движок слишком сложен в компиляции/поддержке для платформы Microsoft Windows. Поэтому я решил заняться разработкой собственной графической библиотеки на OpenGL ES и SDL2.
В этой статье я опишу как инициализировать OpenGL контекст. Мы выведем пустое окно.

King Nothing

Для начала установим библиотеки OpenGL ES3 – GLES 3. На убунте это делается легко, командой sudo apt-get install libgles2-mesa-dev. Для работы с OpenGL, необходимо проинициализировать контекст. Для решения данной задачи есть много вспомогательных библиотек – SDL2, GLFW, GLFM и тд. На самом деле, единственного варианта инициализации для всех платформ не существует, я выбрал SDL2 т.к. код будет един для Windows/*nix/HTML5/iOS/Android/и тд.

Установить SDL2 на убунте можно командой sudo apt-get install libsdl2-dev

Код для инициализации контекста OpenGL с помощью SDL2:

    SDL_Window *window = SDL_CreateWindow(
            "SDL2 - OGLES",
            SDL_WINDOWPOS_UNDEFINED,
            SDL_WINDOWPOS_UNDEFINED,
            640,
            480,
            SDL_WINDOW_OPENGL
            );
	    

    SDL_GLContext glContext = SDL_GL_CreateContext(window);

После этого можно делать вызовы OpenGL, которые будут отрабатывать в данном контексте.

Пример с выводом окна на OpenGL ES с синей заливкой:
https://github.com/demensdeum/OpenGLES3-Experiments/tree/master/3sdl-gles
https://github.com/demensdeum/OpenGLES3-Experiments/blob/master/3sdl-gles/sdlgles.cpp

Собрать и проверить можно с помощью команды cmake . && make && ./SDLGles

Flame Steel Core

Скриншот из последней версии Death Mask:

Выглядит на миллион долларов да?

Переименование, разбиение

Библиотека Flame Steel Engine переименована в Flame Steel Core, Game Toolkit разбит на SDL, Panda3D (Desktop) и Web (ThreeJS) библиотеки. Если в наличии есть стальные шары для сборки с помощью библиотек Flame Steel, тогда нужно сначала выбрать и собрать нужные.

Github:

https://github.com/demensdeum/Death-Mask
https://github.com/demensdeum/FlameSteelCore
https://github.com/demensdeum/FlameSteelEngineGameToolkit
https://github.com/demensdeum/FlameSteelEngineGameToolkitDesktop

Устаревшие:

https://github.com/demensdeum/FlameSteelEngineGameToolkitSDL
https://github.com/demensdeum/FlameSteelEngineGameToolkitWeb

Квантовый взлом RSA

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

Не все так страшно

На самом деле на первом этапе создания ключей мы берем два случайных числа, но числа должны делиться только на себя и единицу – простые числа.
Назовем их p и q. Далее мы должны получить число n = p *q. Оно будет использоваться для дальнейшей генерации ключей, ключи в свою очередь будут использоваться для шифрования, дешифровки сообщений. В итоговом варианте приватного и публичного ключа число n будет передано без изменений.
Допустим у нас на руках один из ключей RSA и зашифрованное сообщение. Вытаскиваем из ключа число n и начинаем его хакать.

Факторизуем n

Факторизация – разложение числа на простые множители. Сначала вытаскиваем из ключа число n (на настоящих ключах можно сделать с помощью openssl), допустим n = 35. Тогда раскладываем на простые множители n = 35 = 5 * 7, это и есть наши p и q. Теперь можно перегенерить ключи с помощью полученных p, q, дешифровать сообщение и шифровать обеспечивая видимость оригинального автора.

С кубитами не все так просто

Неужели можно поломать любой RSA так просто? На самом деле нет, числа p, q берут заведомо большими, чтобы задача факторизации на классических компьютерах заняла очень продолжительное время (10 лет в какой-то там степени)
Однако, используя квантовый алгоритм Шора, факторизовать число можно за очень малое время. На данный момент в статьях на эту тему заявлено время перемножения данного числа, тоесть фактически моментально. Для работы алгоритма Шора необходимо реализовать квантовые компьютеры, с большим количеством кубит. В 2001 году IBM разложили на простые множители число 15 с помощью 7 кубит. Так что этого момента придется ждать еще долго, к тому времени мы перейдем на пост-квантовые алгоритмы шифрования.

Потрогать Шора

Питер Шор рассказывает про свой алгоритм факторизации

Чтобы опробовать алгоритм Шора на квантовом симуляторе, вы можете установить ProjectQ, в его примеры входит реализация shor.py, позволяющая факторизовать число вводимое пользователем. На симуляторе время выполнения удручает, но вроде весело и задорно симулирует работу квантового компьютера.

Статьи:
http://www.pagedon.com/rsa-explained-simply/my_programming/
http://southernpacificreview.com/2014/01/06/rsa-key-generation-example/
https://0day.work/how-i-recovered-your-private-key-or-why-small-keys-are-bad/

Реализация RSA на Python:
https://github.com/demensdeum/RSA-Python

Квантовый генератор чисел и хак IBM Quantum Experience

Эта заметка увеличит длину вашего резюме на 5 см!

Без лишних слов о крутости квантовых компьютеров и всего такого, сегодня я покажу как сделать генератор чисел на реальном квантовом процессоре IBM.
Для этого мы будем использовать всего один кубит, фреймворк для разработки квантового ПО для python – ProjectQ, и 16 кубитовый процессор от IBM, онлайн доступ к которому открыт любому желающему по программе IBM Quantum Experience.

Установка ProjectQ

Для начала у вас должен быть Linux, Python и pip. Какие либо инструкции по установке этих базовых вещей приводить бесполезно, т.к. в любом случае инструкции устареют через неделю, поэтому просто найдите гайд по установке на официальном сайте. Далее устанавливаем ProjectQ, гайд по установке приведен в документации. На данный момент все свелось к установке пакета ProjectQ через pip, одной командой: python -m pip install –user projectq

Ставим кубит в суперпозицию

Создаем файл quantumNumberGenerator.py и берем пример генератора бинарного числа из документации ProjectQ, просто добавляем в него цикл на 32 шага, собираем бинарную строку и переводим в 32-битное число:

import projectq.setups.ibm
from projectq.ops import H, Measure
from projectq import MainEngine
from projectq.backends import IBMBackend

binaryString = ""

eng = MainEngine()

for i in range(1, 33):

 qubit = eng.allocate_qubit()

 H | qubit

 Measure | qubit

 eng.flush()

 binaryString = binaryString + str(int(qubit))

 print("Step " + str(i))

number = int(binaryString, 2)

print("\n--- Quantum 32-Bit Number Generator by demensdeum@gmail.com (2017) ---\n")
print("Binary: " + binaryString)
print("Number: " + str(number))
print("\n---")

Запускаем и получаем число из квантового симулятора с помощью команды python quantumNumberGenerator.py

Незнаю как вы, но я получил вывод и число 3974719468:

--- Quantum 32-Bit Number Generator by demensdeum@gmail.com (2017) ---

Binary: 11101100111010010110011111101100
Number: 3974719468

---

Хорошо, теперь мы запустим наш генератор на реальном квантовом процессоре IBM.

Хакаем IBM

Проходим регистрацию на сайте IBM Quantum Experience, подтверждаем email, в итоге должен остаться email и пароль для доступа.
Далее включаем айбиэмовский движок, меняем строку eng = MainEngine() -> eng = MainEngine(IBMBackend())
В теории после этого вы запускаете код снова и теперь он работает на реальном квантовом процессоре, используя один кубит. Однако после запуска вам придется 32 раза набрать свой email и пароль при каждой аллокации реального кубита. Обойти это можно прописав свой email и пароль прямо в библиотеки ProjectQ.

Заходим в папку где лежит фреймворк ProjectQ, ищем файл с помощью grep по строке IBM QE user (e-mail).
В итоге я исправил строки в файле projectq/backends/_ibm/_ibm_http_client.py:

email = input_fun('IBM QE user (e-mail) > ') -> email = "quantumPsycho@aport.ru"

password = getpass.getpass(prompt='IBM QE password > ') -> password = "ilovequbitsandicannotlie"

Напишите свой email и password со-но.

После этого IBM будет отправлять результаты работы с кубитом онлайн прямо в ваш скрипт, процесс генерации занимает около 20 секунд.

Возможно в дальнейшем я доберусь до работы квантового регистра, и возможно будет туториал, но это не обязательно.
Да прибудет с вами запутанность.

Статья на похожую тему:
Introducing the world’s first game for a quantum computer

Зачем делать игровой движок в 2017 году?

Много людей меня спрашивают, зачем делать игровой движок в 2017? Ведь на рынке уже столько готовых решений забесплатно.

Я подготовил отдельную статью с обзором текущего рынка геймдева, описал причины сподвигнувшие меня на создание Flame Steel Engine:

https://demensdeum.com/blog/ru/reasons-to-make-new-game-engine-in-2017/