Думаю, тут самое подходящее место, чтобы опубликовать мое новое творение Узнал я недавно о таком прекрасной модификации для любимой игры: OpenComputers. Разузнав подробности, решил попробовать что-нибудь для нее написать, ведь изучение нового яп всегда пойдет на пользу. И тут меня потянуло на графику. Но стандартные мониторы оставляют желать и искать лучшего. Благо, есть такое дополнение, как OpenPeripheral, расширяющее возможности OC, и, помимо прочего, добавляющее очки, через которые можно нарисовать на экране что-то четкое. Думаю, не стоит больше растягивать предисловие. Представляю вашему вниманию простенький низкоуровневый(пока) графический интерфейс: я назвал его Glass3D.
Что можно с ним сделать?
Добавить в список вершины по x,y,z
Создать полигоны по 3-м вершинам
Преобразовывать группы вершин при помощи матриц
Быстро все отрисовывать благодаря sync-функции из api моста очков(~30 fps может)
Зачем?
Отрисовывать красивые схемы, голлограммы из ваших программ, которые смогут быть всегда перед глазами
Исходники
https://raw.githubusercontent.com/Trientalis/OpenComputersProgramms/master/Glass3D.lua
Использование
Описание интерфейсов
addVertex3D(x,y,z,h):index -- создает новую вершину, параметр h пока не используется(вообще нужен для масштаба)
addVertices3D({x1,y1,z1,x2,y2,z2...,xn,yn,zn}):{index1,...indexn} -- принимает координаты точек, возвращает массив индексов
removeVertex3D(index) -- удаляет вершину, побочный эффект: смещение, будет решено в будующих версиях
addPolygon3D({index1,index2,index3},{color,opacity=1}):name -- добавляет полигон по трем точкам и цвету, возвращает имя полигона index1+"_"+index2+"_"+index3
removePolygon3D(name) -- удаляет полигон, без побочных эффектов
transform({index1,...,indexn},{number1,...,number16}) -- умножает текущую матрицу вершин на переданную
update() -- применяет матрицы вершин на их координаты, рисует полигоны
setFocalLenght(number) -- задает расстояние от глаз пользователя до экрана
демо:
--Тетраэдр, немного кривой, ну да ладно
local gl=dofile("Glass3D.lua")
--gl.setFocalLenght(200)
gl.addPolygon3D({gl.addVertex3D(-20,15,0),gl.addVertex3D(20,15,0),gl.addVertex3D(0,-20,0)},{color=0xff00ff,opacity=1})--Добавляет 3 вершины и полигон из них
gl.addPolygon3D({1,2,gl.addVertex3D(0,0,-25)},{color=0x00ff00,opacity=1})--2вершины у нас уже есть, нужна еще одна
gl.addPolygon3D({2,3,4},{color=0x0000ff,opacity=1})--остальные 2 грани
gl.addPolygon3D({3,1,4},{color=0xff0000,opacity=1})
local angle=-0.1*math.pi/180--угол поворота
for i=1,50 do--вращение по Y
gl.transform({1,2,3,4},{math.cos(angle),0,-math.sin(angle),0,
0,1,0,0,
math.sin(angle),0,math.cos(angle),0,
0,0,0,1})
gl.update()
os.sleep(0.03)
end
for i=1,50 do--вращение по Y+Z
gl.transform({1,2,3,4},{math.cos(angle),math.sin(angle),0,0,-math.sin(angle),math.cos(angle),0,0,0,0,1,0,0,0,0,1})
gl.update()
os.sleep(0.03)
end
for i=1,60 do--вращение по Y+X+Z
gl.transform({1,2,3,4},{1,0,0,0,
0,math.cos(angle),math.sin(angle),0,
0,-math.sin(angle),math.cos(angle),0,
0,0,0,1})
gl.update()
os.sleep(0.03)
end
О матрицах
матрица параллельного переноса:
[ 1 0 0 0 ] [ 0 1 0 0 ] [ 0 0 1 0 ] [ x y z 1 ]
матрица растяжения/сжатия:
[ z 0 0 0 ] [ 0 y 0 0 ] [ 0 0 x 0 ] [ 0 0 0 1 ]
матрица поворота вокруг оси x:
[ 1 0 0 0 ] [ 0 cos α sin α 0 ] [ 0 -sin α cos α 0 ] [ 0 0 0 1 ]
матрица поворота вокруг оси y:
[ cos α 0 -sin α 0 ] [ 0 1 0 0 ] [ sin α 0 cos α 0 ] [ 0 0 0 1 ]
матрица поворота вокруг оси z:
[ cos α sin α 0 0 ] [-sin α cos α 0 0 ] [ 0 0 1 0 ] [ 0 0 0 1 ]
Баги, ошибки
Сейчас уже можно нормально пользоваться этим api для простых целей, но имеется один старанный баг, и я никак не могу найти ошибочное место в коде: если применить матрицу поворота по одной оси, потом обновить экран(матрица сольется с вершиной), потом применить поворот по другой оси, эффект прежней матрицы остается А, может быть, это вообще не баг, с матрицы я раньше использовал только для одной из осей.
И еще подхрамывает постоянность частота кадров: увеличивается со временем.
Спасибо за внимание, надеюсь, вам понравилась моя работа.