Андроиды в дельфинарии

    Приветствую всех любителей тех устройств, что помещаются в карман, а также тех, кто держит свой карман шире 7". Сейчас мы займемся искусством программирования кросс-платформенных графических приложений, то есть таких приложений, которые работают на мобильной платформе (смартфоны и планшеты Android) и под Windows (стационарные PC, ноутбуки, нетбуки, планшеты). При этом наши приложения будут графическими, графика основана на OpenGL (OGL) и его мобильном варианте OpenGL ES (GLES). Я использую Embarcadero Delphi XE7. Важная особенность – в этом проекте я не использую платформу FM (FireMonkey), мы будем писать все сами и с нуля, как в старые добрые времена.

    image

    Предлагаю сразу разделить работу пополам:
    — я пишу кросс-платформенную графическую библиотеку, рассматриваю примеры её использования, расписываю детали реализации, отвечаю на вопросы;
    — ваша часть не менее ответственна: от вас мне нужен тест демок на различных мобильных устройствах, рапорты о выполнении, отзывы и критика, новые идеи и свежее мясо новые пользователи как библиотеки так и собственно приложений.

    1. Первая демка
    Android mc.apk 3.8 MB yadi.sk/d/n1wDuX1RhC4QX
    Windows mc.zip 1.9 MB yadi.sk/d/tBKQxaV7ff8KW
    Исходные тексты в репо: sourceforge.net/p/delphioga/code/ci/default/tree
    В первой версии программа не хитрая – она просто выводит на экран 4096 угловатых разноцветных шариков и позволяет полетать мимо них в режиме “свободной камеры”. Сферы я раскрасила по принципу цветового пространства RGB, ещё они вращаются. На этом примере я хочу рассмотреть методы построения 3D примитивов (в частности сфер) и приёмы оптимизации отрисовки (Frustum сulling, детализация объектов).
    Но нам никак не обойтись без небольшой вводной части.

    2. Инструкция по эксплуатации, смартфон/планшет Android
    1. Устанавливаем mc.apk, это архив инсталляции программы. Если у вас есть вопросы как это сделать, я готова помочь.
    2. При установке apk возможно предупреждение, что программа требует доступа к Internet. На самом деле программа скомпилирована в режиме Debug, поэтому ей потенциально нужен доступ к локальной сети для возможности работы отладчика (gdbserver) и консоли логов logcat. Логи нам еще потребуются. Из самой программы к сети я не обращаюсь никак, там есть только рисование графики на экране.
    3. После установки у вас добавится новый ярлычок на Рабочем столе “mc”. Запускаем программу. Любуемся на заставку — огонек FM (я пока не меняла иконки мобильного проекта Delphi по умолчанию). Обращаем внимание на время запуска приложения, сколько оно у вас приблизительно в секундах и их долях? Мы можем сравнить это с временем загрузки примеров FM приложений, пока что сравнение в нашу пользу.
    4. Вот вы и на месте, добро пожаловать. Используйте ваши пальцы и тачскрин для изменения направления взгляда и направления движения. Справа вверху есть парочка экранных кнопок – вперед и назад. Если у вас 2 руки, вы можете одновременно двигаться и поворачиваться. Для этого потребуется определенная сноровка, уж чего-чего, а простой жизни я не обещала.
    5. При переключении в другое приложение или “засыпании” планшета (давайте мобильное устройство именовать планшетом, потому что у меня планшет) программа приостановит отрисовку графики (контекст GLES и само окно приложения удаляются, так положено делать на Android), однако сама программа не прекратит работу. При переключении обратно в приложение или “пробуждении” планшета окно и контекст будут созданы заново, мы продолжим наше путешествие с места остановки. Следует обращать внимание на этот нюанс при тестировании, некоторые игры не умеют корректно “восстанавливаться”, мы же должны уметь.
    6. Поверните планшет горизонтально, потом вертикально. Работу приложения следует проверять в каждом из этих двух режимов. Разумеется такой фокус сработает, только если у вас ориентация дисплея устройства установлена в “авто”.
    7. Выйти из демки просто – нажмите системную кнопку “назад”.
    8. Напишите в комментариях к статье тип мобильного устройства, которое вы применяли (фирма-производитель, модель), я постараюсь отыскать его характеристики, типы CPU и GPU, версию OS. Эти данные я включаю в файл hardware.txt в репо.

    image

    3. Инструкция по эксплуатации, Windows
    1. Распаковываем архив zip. Не удивляемся объему exe файла, демка скомпилирована в режиме Debug, в релизе exe весит 1.5 MB. Запускаем mc.exe.
    Никаких системных предупреждений о использовании сети, как в Android не будет, потому что сеть в демке не используется, на PC отладчик и логи работают локально.
    2. Вот вы и на месте, добро пожаловать. Для изменения направления взгляда и направления движения “потащите” экран при нажатой левой кнопке мышки (ЛКМ). Для перемещения в пространстве работают клавиши [WASD] на клавиатуре (либо стрелки, либо стрелки на NumPad). Экранные кнопки для движения вперед-назад тоже есть, они кликабельны. [F1] выводит справку, [ESC] позволяет выйти из программы.
    3. Обратите внимание на второе окно (при запуске программы на панели управления появляется два окна), это консоль отладки. Подобную консоль для Android (logcat) мы рассмотрим позже. После GPU Vendor, Renderer (фирма/тип вашей видеокарты) там пишет Open GL version. Скажем так, если версия OpenGL ниже 3.0, то некоторые будущие возможности библиотеки не пойдут на вашей старой видеокарте. Впрочем, прикладное приложение может содержать 2 ветки реализации таких возможностей и работать в любом случае.
    4. VSYNC в этом примере выключен, FPS может быть куда больше 60 Гц (попробуйте отвернуться от видимых объектов), нагрузка на GPU и CPU максимальна. Я так делаю для тестирования скорости отрисовки фрейма, если включить VSYNC нагрузка станет нормальной.

    4. Отладочный вывод на экран
    На скриншотах слева вверху есть некоторые желтые буквы и цифры.
    FPS – среднее число кадров в секунду, наш главный инструмент в оценке быстродействия рисования. Под Android VSYNC включен, FPS лимитирован частотой обновления экрана (60 Гц), впрочем я так подогнала нагрузку на GPU в демо, что на большинстве мобильных устройств FPS будет “проседать”. Это не страшно пока управление и анимация остаются адекватными. Под Windows же VSYNC выключен, FPS не имеет лимита;
    TDF – среднее время отрисовки одного фрейма в миллисекундах, по сути величина обратная FPS; она нужна чтобы понимать “тайминг” — какого порядка интервалы времени у нас фигурируют для рисования кадра; при FPS 60 Гц это время около 17 мс;
    NFR – число отрисованных фреймов от старта приложения; при FPS 60 Гц в первую же секунду эта цифра достигнет 60;
    T – время в мс от старта приложения, его я использую как аргумент для функций анимации, в примере от него зависит вращение сфер;
    POS — координаты камеры в 3D мире XYZ, при старте оси расположены так: X направо, Y вверх, Z на нас;
    AH, AV — углы поворота камеры относительно горизонтали и вертикали в градусах; об угле крена лучше поговорить отдельно;
    N – общее число объектов во Вселенной;
    NV – столько объектов целиком или частично попадают в область видимости (фрустум, усеченная пирамида поля зрения камеры);
    HD – столько ближних объектов отображаются с несколько лучшим качеством отрисовки, дальние объекты рисуются попроще;
    SCR — разрешение экрана.

    5. Как выглядит процесс разработки
    Я подключаю планшет к PC под Windows USB-кабелем (можно и через Wi-Fi). Сначала пишу платформенно-зависимый код неких функций для Android, запускаю программу на планшете. Эта часть работы требует много терпения, приложение сравнительно долго компилируется и запускается на планшете. Отладка доступна (точки остановки, пошаговое выполнение, просмотр состояния переменных). Также использую отладочный вывод приложения в logcat, смотреть логи могу прямо на PC в реальном времени. Когда на планшете заработало, я пишу платформенно-зависимый вариант кода функций для Windows, это уже проще. После этого начинается самое интересное – основную часть программы я пишу универсальным кодом вызывая одноименные платформенные функции, проверяю на PC и лишь изредка заливаю на планшет, как правило, там все работает.

    6. Под капотом
    Заглянем немного в исходные тексты. В папке common у меня лежит собственно библиотека. Начнем с файла Draw.pas.
    На чем основана кросс-платформенная графика? Под Windows я использую модуль OpenGL.pas, но только те функции, которые имеют аналоги в GLES под Android (модули Androidapi.Egl.pas, Androidapi.Gles.pas, Androidapi.Gles2.pas).
    uses
      Types,SysUtils,
    {$IFDEF Android}
      Androidapi.Egl, Androidapi.Gles, Androidapi.Gles2,
    {$ENDIF}
    {$IFDEF MSWINDOWS}
      Winapi.OpenGL,
    {$ENDIF}
      Vectors, Colors, Textures, DrawPolyhedron, DrawSphere;
    

    Там где OGL и GLES совпадают разницы в синтаксисе мало, вот разве что glOrtho пришлось подровнять. При помощи директив условной компиляции типа {$IFDEF ANDROID} и {$IFDEF MSWINDOWS} мы будем описывать платформенно-зависимую реализацию.
    {$IFDEF ANDROID}
    procedure glOrtho (left, right, bottom, top, zNear, zFar: GLfloat);
    begin
      glOrthof(left, right, bottom, top, zNear, zFar);
    end;
    {$ENDIF} 

    Что ещё не совпадает? На GLES нет glBegin/glEnd и соответственно всего связанного с ними семейства функций. Это не страшно, будем рисовать в стиле OGL 2.0 передавая за один раз указатели на массивы вершин (нормалей, цветов, текстурных координат). Например, один простейший треугольник можно нарисовать так (цвет текущий, нормалей и текстур нет):
    procedure Triangle(p1, p2, p3: TV3); overload;
    begin
      SetLength(ap3, 3);
      ap3[0] := p1;
      ap3[1] := p2;
      ap3[2] := p3;
      glVertexPointer(3, GL_FLOAT, 0, @ap3[0]);
      glDrawArrays(GL_TRIANGLES, 0, Length(ap3));
    end;

    Чтобы нарисовать множество треугольников 3D фигуры не следует вызывать процедуру Triangle много раз. Следует сложить все вершины всех треугольников в один массив и нарисовать их единственным вызовом glDrawArrays. Эта функция используется в текущем демо для рисования каждой сферы, как с GL_TRIANGLES так и с GL_TRIANGLE_STRIP:
    // отобразить готовый массив вершин c нормалями 
    procedure DrawAVNT(avn: TAVertexN; met:GLenum; Position,Rotation,Scale: TV3);
    begin
     glPushMatrix;
     Transform(Position,Rotation,Scale);
     glVertexPointer(3, GL_FLOAT, SizeOf(TVertexN), @avn[0].V);
     glNormalPointer(GL_FLOAT, SizeOf(TVertexN), @avn[0].N);
     glDrawArrays(met,0,Length(avn));// GL_TRIANGLES
     glPopMatrix;
    end;


    На этом мы прервемся, для первого знакомства такой вводной части должно хватить. Если понравится — у меня уже есть наброски продолжения статьи.

    PS/05.06.2015
    В библиотеку добавлена загрузка 3D моделей в формате obj.

    image

    Дополнительный источник информации по теме: forum.sources.ru/index.php?showtopic=401121
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 28

      +2
      А нельзя кат перенести выше? Ужасно ленту загромождает, сократите текст до ката раза в 3-4, пожалуйста.
        0
        То чувство, когда до ката контента больше, чем после...)
          +1
          Поправилась, текст сократила. Если надо ещё меньше — подумаю над заменой картинки.
            +1
            Если понравится — у меня уже есть наброски продолжения статьи

            Интересно, что будет дальше. Продолжайте.
              +1
              Материала у меня хватает. По тематическим хабам и тегам сложились определенные ленты, я не стану их заспамливать частыми статьями. Все-таки моя тема несколько нестандартная, еще немного и можно её в «Ненормальное программирование» помещать. Сами посудите: разработка приложений для Android не на Java — это уже некая альтернативщина. А тут я беру Embarcadero Delphi XE7 у которого разработка мобильных приложений определена через платформу FireMonkey. Там эти самые приложения можно печь как пирожки. А мне не хочется пирожков из готовых полуфабрикатов, домашняя кухня вкуснее, хотя и требует гораздо больших усилий.
              +5
              Проект любопытный, но статья абсолютно неинформативна. Если соберетесь писать следующую часть, расскажите больше о самой структуре приложения, тонкостях и потенциальных подводных камнях — как в разделе «под капотом», но более детально и пошагово.
                +1
                Не волнуйтесь, уж если мы залезли «под капот», то не не вылезем оттуда пока не разберем «движок» до гайки. Если идти последовательно, то начать наверное придется с создания окна, инициализации EGL, создания и настройки контекста GLES. Можно подойти с другой стороны и начать с рисования — треугольник, плоские фигуры, 3D примитивы, поверхности, текстурирование, меши. Я как раз собиралась написать в первой версии фигуры вращения и хоть простенькие частицы. Вообще-то начинать принято с выбора среды разработки, но это скользкая тема. А мне бы хотелось начать сразу с тестирования мобильной демки, вон какие подробные инструкции написала. В общем главное начать :))
                  +1
                  Про рисование на низком уровне уже была фундаментальная серия статей. А вот настройка окружения до минимальной рабочей версии, с которой можно было бы поиграться самостоятельно — это было бы интересно.
                    0
                    Та серия статей от haqreu была про «софт-рендер» (кроме «аддендума» про GLSL шейдеры).
                    В шейдерах можно делать многое, на ffp можно делать разное, на CPU (софт-рендер) можно сделать всё © Б.Т.' 2015.

                    «Настройка окружения до минимальной рабочей версии» — так это же и есть моя «Первая демка» предъявленная в статье. Этот вопрос уже доступен тем, кто скачал из репо исходники, я там на комментарии и ссылки не поскупилась (модули AppWindow.pas, AppForm.pas).
                    Разбирать такое построчно выйдет длинновато и скучновато, не факт что решусь.

                    То ли дело рисование граф. примитивов. Вот, фигуры вращения сделала. Вчера было «500 лет граненному стакану», как никак :))

                    image
                +1
                У haqreu в его «Кратком курсе...» рассмотрено рисование на предельно низком уровне (в хорошем смысле этого слова) — вообще без OpenGL драйвера, чистый софт рендеринг. Я же могу написать о практическом рисовании в реальном времени на экране средствами GPU, только GPU будет мобильный, а полученный текст на GLES будет полностью совместим с OpenGL на PC. Дело в том, что у меня на GLES нет чего-то подобного glu или glut (графической библиотеки), начинать приходится с вывода треугольника. Там даже квада нет (на GL_QUADS круто секономили), я квады из 2-х треугольников рисую.
                Ладно, графика никуда от меня не убежит, надеюсь. ОК, принято. Разберу работу программы от старта (что создаём, что и как инициализируем и зачем) до цикла рисования и обработки тачскрина.
                Еще момент: тексты с OpenGL хорошо переносятся на другие языки программирования. Но под мобильную платформу нужно еще иметь компилятор, который выдаст бинарный .so и архивчик с инсталляцией apk на выходе (Delphi пошел по пути ndk). Поэтому я не даю гарантий, что моя последовательность действий при старте приложения прямо применима для Java (Java это sdk и там несколько иная кухня на машине Dalvik).
                  +1
                  Мне повезло и у меня есть две руки, это позволило найти один баг — если сначала начать вращать камеру, а потом не отрывая пальца начать двигаться (стрелочками), после чего оторвать палец от вращения камерой — состояние поворота камеры сбросится на предыдущее.
                  Еще один момент — у вас при смене ориентации экрана то ли меняется fov у камеры то ли ее центровка — в общем при вращение наблюдаются явные искажения. Заметил это, запустив демку в вертикальном режиме, потом повернув в горизонтальный.
                  Фпс при обзоре всех шариков — около 12.
                  Телефон Samsung Galaxy Note 3 n9000, gpu Mali-T628MP6
                    0
                    Зачет, вот что значит прямые руки. Оба замечания поставила на первое месте в моём todo, после фикса отпишусь.
                    Я замечала перескоки камеры при «двуручном» управлении, но срабатывает «синдром разработчика» — как-то так жму что летаю без глюка.
                    Поэтому и нужен объективный сторонний тест. Хотелось бы нормально отладить все нюансы простой демки и только потом двигаться дальше. Лично я выступаю за качество софта, функциональность мы еще успеем расширить, потом и статьи хорошие напишем.
                    Сам принцип управления полетом следует обсудить. На PC это допустим клавиши WASD + мышь, а как сделать на тачскрине?

                    У меня задаётся фиксированный FOVY=90 градусов, по горизонтали это выходит больше * AspectRatio (соотношение сторон дисплея). Угол конечно широковат, тестирую так, такие вещи как угол обзора камеры принято выносить в настройки. При смене ориентации экрана… то же самое, FOVY=90, только теперь Y другой. На практике поворот устройства в вертикальную ориентацию приводит в итоге к «приближению» изображения (перескок координат в сторону стал виден только на низком FPS, он связан с тем, что я тороплюсь применить новые длину и ширину дисплея, они в EGL должны еще «устаканится»). Вывод — при повороте нужно корректировать FOV, точнее считать AspectRatio как обратную величину.

                    Модуль Camera.pas, здесь будут правки.
                    procedure TCamera3D.Apply(aWidth, aHeight: Single);
                    begin
                    Aspect := aWidth / aHeight;
                    glMatrixMode(GL_PROJECTION);
                    glLoadIdentity;
                    gluPerspective(FieldOfView, Aspect, zNear, zFar);
                    glMatrixMode(GL_MODELVIEW);
                    glLoadIdentity;

                    glRotatef(Pitch, -1, 0, 0);
                    glRotatef(Yaw, 0, 1, 0);
                    with Position do
                    glTranslatef(-x, -y, -z);

                    glLightfv(GL_LIGHT0, GL_POSITION, @LightPosition); // in current GL_MODELVIEW projection
                    end;


                    Еще я явно перестаралась с нагрузкой на GPU в демке. 4096 сфер * 80 треугольников в каждой = 327680 треугольников. Смысл теста был такой — в центре шаро-куба FPS выше, так как в один момент можно наблюдать только часть объектов, фрустум кулинг проверяла.

                    Еще раз спасибо за грамотный репорт. Если у Вас есть соображения что можно сделать полезного из моих скромных наработок — напишите, именно Ваше мнение мне будет ценно.
                      +1
                      На тачскрине можно сделать так же как и на PC — кнопочки WASD + палец для обзора. WASD можно заменить на виртуальный стик.
                        0
                        Виртуальный стик? У меня примитивный GUI (что впрочем, даёт простор для творчества), кнопки рисую сама, координаты касания на тачскрине определяю, попадание в кнопку вычисляю. Кнопка может быть не квадратной. Пока думалось так — окружность, 4 сектора, повернуть на 45 градусов — получится 4 кнопки, как на пульте телевизора. Стик вижу иначе — круглая область, где в зависимости от точки касания сразу будет направление перемещения по 2 осям (в локальной системе координат камеры). Это все надо пробовать. Юзабилити управления — одна из важнейших задач для меня.
                        Свой скайп и VK написала в Диалог.
                        +1
                        Попробуйте фиксировать диагональный FOV. В этом случае размеры останутся прежними и на вид никаких изменений не произойдёт.
                        Хотя, всё зависит от задач. В некоторых случаях лучше горизонтальный FOV фиксировать.
                          0
                          Правильно, диагональный FOV у меня на планшете постоянный. Сейчас фиксирован FOVY, эта традиция идёт от
                          OpenGL.pas procedure gluPerspective(fovy, aspect, zNear, zFar: GLdouble); stdcall;
                          В результате под Windows, если сделать широкое низкое окно можно получить FOVX до 180 градусов. Может это и не баг, а полезная фича, если например сидишь в засаде:)) Думаю перейти на фиксировнный FOVX, так будет понятнее. Библиотеки glu на GLES у меня нет, поэтому имитирую известную функцию вот так:
                          procedure gluPerspective(fovy, aspect, zNear, zFar: double);
                          var m: TM4x4; sn,cs,c,dz,ar: Double;
                          begin
                           if aspect = 0 then Exit;
                           dz:=zFar- zNear;
                           if dz = 0 then Exit;
                           ar:=fovy*g2r2; //Pi/360
                           SinCos(ar,sn,cs);
                           if sn=0 then Exit;
                           c:=cs/sn;  //cotangent
                           FillChar(m, SizeOf(m), 0);
                           m[0,0]:=c/aspect;
                           m[1,1]:=c;
                           m[2,2]:=-(zFar+zNear)/dz;
                           m[2,3]:=-1;
                           m[3,2]:=-2*zNear*zFar/dz;
                           glMultMatrixf(@m);
                          end;
                          

                        +1
                        Ура, у меня появилась некая «карма» и я поставила свой первый +1 на Хабре. Вот за что поставила: за внимательное чтение статьи и точное выполнение условий авторского эксперимента, за корректный баг-репорт, разумный юмор и позитивное отношение.
                        И это хорошо.
                          +1
                          Главное не упоминать особо о карме, здесь за это её минусуют :/
                            0
                            Логично, учту. А о контекстной рекламе на сайте упоминать можно?
                            Мегафон пишет прямо под моей статьей, предлагает купить их китайский Android-смартфон. Я не советую.
                            Для разработки программ под Android нужно иметь устройство на базе Android. Эмуляторы Android на PC слишком медленны и неуклюжи. Для тестирования софта я применяю недорогие 7" планшеты: Samsung GALAXY Tab3 Lite SM-T110 и Nomi A07000 (последний вообще пародия на планшет, впрочем для тестирования как раз отлично, это моя «нижняя планка»). Еще задумываюсь о приобретении смарта, что-то вроде старенького HTC мне бы подошло. Тестировала и на навороченных дорогих моделях — разницы никакой. CPU и GPU пишут изрядно круче, на практике прирост производительности невелик.
                        +1
                        Пожалуйста, используйте для кода теги:
                        <source lang=«delphi»>
                        </source>
                          0
                          Спасибо, я искала эту возможность. Сейчас проверю. Рассмотрим функцию поворота камеры в пространстве которая используется в текущем демо. Это тот же модуль Camera.pas.
                          // такой поворот имеет вырожденные точки сверху и снизу
                          procedure TCamera3D.MoveForvard(V:Single);
                          var i:Integer; ah,av: Single; rz,rh,rv,dr:TV3;
                          begin
                           ah:=Yaw*g2r;   // horizontal angle in XZ plane
                           av:=Pitch*g2r; // vertical angle
                           // polar to decart from -Z
                           dr.x:=cos(av)*sin(ah);
                           dr.y:=sin(av);
                           dr.z:=-cos(av)*cos(ah);
                           Position:=Position+dr*V;
                          end;
                          

                          Для поворота камеры в итоге я планирую использовать другой вариант.
                          Вот тут лежит моя предыдущая демка под Win, камера заметно лучше — bionica-game.tumblr.com
                          Там есть вопрос с нарастающим креном, углы Эйлера — поворот по 2-м осям непременно даст поворот по 3-й оси.
                          Придется выбрать из двух зол, либо ввести управление креном.

                            +1
                            А для того чтобы проверить — есть кнопочка предпросмотра.
                            вот тут

                              0
                              Прошу прощения, про камеру я хотела рассказать Torvald3d, вышла путаница. С другой стороны, это комментарии к моей статье, я тут стараюсь отвечать оптом на все на вопросы читателей. У меня могут быть и встречные вопросы. Я совсем не разбираюсь в хабро-рейтингах, кармах и т.п.
                              Задачка: статью выложила сегодня после обеда, сразу получила минуса за неправильно поставленный кат (в ленте смотрелось некрасиво), это справедливо. 17 человек добавили статью в избранное, за проголосовало 4, против проголосовало 6 (кажется все из за ката). Я понимаю что в минусах.
                              Вопрос 1: нужно ли писать продолжение статьи при таких раскладах?
                              Вопрос 2: может нужно заменить картинку над катом, чтобы в ленте никому не мешало?
                              Вопрос 3: те 17 что добавили в избранное, они не все имели возможность голосовать, или имели?
                                0
                                Вопрос 4: сколько мне надо набрать кармы, чтобы, например, поставить + Torvald3d, его репорт попал в точку.
                                  +1
                                  Делайте продолжение!
                                    0
                                    Работаю над продолжением статьи.
                                    Основная проблема — длинные ступни у NPC. Никак не могу подобрать им подходящие ботинки :))

                                    image
                                    +1
                                    Да не заморачивайтесь вы этими хабарейтингами. Я обычно прислушиваюсь к комментариям и стараюсь их учесть в следующих статьях.
                                    Писать нужно, учтя все, за что огребли в предыдущих статьях)
                                    На счет картинки — всегда стараюсь писать поменьше текста до ката и выставить покруче картинку — это привлекает внимание. Из-за большого количества постов, на сплошном тексте обычно взгляд не задерживается.
                                      +1
                                      Уфф, я сделала-таки фигуры вращения. Еще оптимизировать надо, импорт path с SVG надо бы, сечения solid фигур с «крышками», но это уже детали. Придумала: следующая моя демка (и, возможно, статья) будет посвящена проблеме космического полицейского мусора. Знаете ли Вы, что только с начала этого года 40% аварий НЛО произошло при их столкновении с неопознанными орбитальными мусорными объектами (рус.«НОМО», англ.«UOTO»). Что там только не летает — страшно подумать. Гринпис, спасем орбиту!

                            Only users with full accounts can post comments. Log in, please.