×

Як я створив найкращий в світі алгоритм для 3D-текстурування

Всім привіт. Я Саша Каленюк, працюю на компанію Materialise, пишу книжку про геометрію для програмістів. Сьогодні я хотів би розказати вам історію свого особистого тріумфу і поділитися уроком, який мені пощастило з неї винести.

Насправді хотів написати цю історію ще три роки тому, ще до ковіда, до війни. Але радий, що не написав. Бо без цього нового досвіду, без надбаного за ці три роки розуміння, була б це геть інша історія. Та сама, але зовсім інакша.

Як я* створив** найкращий в світі*** алгоритм для 3D-текстурування****. Далі у тексті я пояснюю, що означають ці зірочки.

Історія

Отже, 24 травня 2019 року. Materialise проводить внутрішню конференцію у головному офісі в Льовені. Разом з колегами зі всього світу прибуває у головний офіс і наша делегація. Я випадково зустрічаю на сходах Курта, нашого найдосвідченішого і найповажнішого архітектора, і він з чимось мене вітає. «З чим-чим?» — перепитую — «Та ти знаєш».

Я не знаю.

Потім пленарка у великому залі. Розказують про ринок, партнерів, конкурентів, блакитний океан, обсяг продажів, прогнози і досягнення. Про те, як росте ЄБІТДА і курс акцій, які у нас офігєнні продукти і послуги. «А ще» — каже доповідач — «у нас тепер є найкращий у світі алгоритм для 3D-текстурування». І я бачу як голови колег повертаються в мою сторону.

Алгоритми не стають темою для пленарки тупо ніколи. Продукти — так. Послуги — звісно. Але алгоритм — це щось таке, що спершу загортається у API, потім — у користувацький інтерфейс, потім перейменовується у продукт чи послугу, і тільки тоді стає темою обговорень. Але щось сталося. Чомусь саме цей алгоритм опинився у проміні метафоричного прожектора. Мене насичує гордість і відчуття причетності до чогось екстраординарного.

Потім були доповіді за секціями. Я щось слухав, щось доповідав. Щось геть не пов’язане з 3D-текстурами, бо по цьому напрямку свою частину роботи я на той момент вже давно завершив і переключився на щось інше. Але відчуття тріумфу, відчуття перемоги не вщухало.

А ввечері, не повірите, був концерт. Збіг, звичайно. Просто наші колеги з Бельгії збирали гроші для чергової гуманітарної ініціативи в Африці, тож захотіли дати благодійний концерт «Rock 4 Benin». І дали.

І це все: музика, легкі напої, відкрите небо — все додавало святкової атмосфери. Особливо небо. Небо в Бельгії, насичене атлантичними вітрами, завжди таке драматичне, завжди просуває якісь свої наративи. В той вечір воно вирішило перетворитися на золото. Я стояв під цим золотим небом, пив, слухав музику, відчував себе переможцем.

Втім, жоден вечір, навіть найсвятковіший, не триватиме вічно. Небо почало темніти. І на вже не золотому, а темному вечірньому небі почали проступати зорі, як зірочки над заголовком статті. Що власне таке це 3D-текстурування? Чому це мій алгоритм раптом найкращий у світі? Що означає «створив»? І до чого тут власне я?

Хороші питання. Про них і поговоримо.

**** Що таке 3D-текстурування

Ну, тут все просто. Беремо 3D-модельку, беремо якийсь малюнок, ліпимо малюнок на модельку, натискаємо кнопку і якийсь алгоритм витискає чи витягує білі і чорні пікселі, створюючи відповідний рельєф на нашій модельці.

Картинка до:

Моделька після:

Концептуально так ніби зрозуміло, ніби нічого складного. Складність з’являється, коли цю кнопку починають тиснути справжні люди зі справжніми бізнес-потребами. Наприклад, якщо комусь треба витиснути QR-код на пласкій поверхні.

Картинка до:

Моделька після:

Тут просто потягати пікселі туди-сюди не вийде. Чорний піксель має лишатися пласким, і білий має лишатися пласким. А що тоді між ними? Ну, напевно якась стіночка, якась ще нова геометрія яку треба винайти самостійно, бо на картинці крім власне пікселів нічого немає.

Задача стає геть іншою, коли з’являються сірі пікселі, між якими жодної стіночки бути не має. Навпаки, текстурована поверхня має відображати градієнт з картинки, як чистий красивий нахил без жодних стінок і сходинок.

Картинка до:

Моделька після:




Або ще така задача. Намалювати квадратними пікселями шестикутний орнамент.

Картинка до:

Моделька після:

Отже, різні користувачі, різні примхи. А ще всі хочуть, щоб працювало швидко, точно, і без аварій. Тому, власне, концептуально проста задача і стає складною і цікавою. З необмеженими ресурсами можна було б наплодити мільярди трикутників, і всі неточності закидати деталізацією. З обмеженою пам’яттю, часом і встановленою точністю доводиться бути вигадливим.

*** Чому мій алгоритм «найкращий у світі»

Ну, тут вже дійсно просто. Тому що насправді, ні. Немає жодних міжнародних змагань з 3D-текстурування, ніхто не проводив вичерпний аналіз всього, що є на ринку, отже «найкращий у світі» — це не встановлений факт. Втім, принаймні це справжній відгук одного з наших клієнтів.

Можливо, вони просто намагалися бути ввічливими, але ми дали їм демку, вони сказали: «вау! Найкращий у світі! Берем.» І це перетворилося на своєрідний мемчик. Хтось із продажів переказав комусь з продуктової команди, хтось із команди переказав комусь в маркетингу, хтось з маркетингу переказав менеджменту, так воно, власне, і попало на пленарку.

Вибачте, якщо розчарував.

** Що означає «створив»

Почнемо з того, що алгоритм для 3D-текстурування був у нас вже багато років. І я його підтримував. Фіксив баги, додавав кнопки. Матюкався під ніс, як заведено, мріяв переписати з нуля.

Найбільшою його проблемою було те, що в нього не було найбільшої проблеми. Були баги, були проблеми з перформансом, але він якось працював, якось заробляв нам гроші, тож нагальної потреби переписувати його ніколи насправді не існувало.

Все раптом зсунулось з мертвої точки, коли начальник департаменту вирішив проявити ініціативу і відкрити у нас дослідницьку інтернатуру. Ідея мала кілька недоліків. Так, наприклад, інтернів було вирішено брати з-поміж студентів академії, які не пройшли відбір у дійсні команди. Ну тобто якщо ти добре вчишся і наполегливо працюєш, то перший рік фікситимеш баги у коді, який 20 років як в компанії ніхто не супортить, а якщо забиваєш на роботу і навчання — попадаєш одразу на новий блискучий дослідницький проєкт. Трохи несправедливо, але менш з тим.

Звісно, як тільки в мене з’явився інтерн і обов’язок придумати йому дослідження, я тут же дістав з ментальної полиці свій проєкт нового 3D-текстурщика і запустив його під маркою інтернатури.

В ході проєкту виявилося, що всі геніальні ідеї що я складав в стіл кілька років виявились безплідними мареннями. Ніщо не спрацювало так, як треба, а те, що якимось чудом спрацювало — взагалі ніколи не було передбачено.

Як в справжньому дослідницькому проєкті, все пішло не так з першого рядка коду, але, як в справжньому дослідницькому проєкті ж, останній рядок завершував який-не-який, але робочий прототип. Сам собою він був геть негідний, але свою справу зробив: дозволив запустити вже девелопмент-проєкт без жодних інтернатур.

Далі на мене вже працював investment bias. Це коли в проєкт вкладається все більше і більше ресурсів, і, попри видимий брак прогресу, закривати його стає нібито все дорожче і дорожче. А прогресу не було. Був прототип за прототипом, були якісь дрібні ідеї, якісь локальні покращення. Кожен раз, коли якась ідея не спрацьовувала, я скидав її, код і опис, в окрему папочку і йшов до свого проджект-менеджера з покаянням. «Саш, ні пса не працює, треба все переписати з нуля.» «Як, знов? Ну, гаразд, піду поговорю з продукт-менеджером, щось придумаємо.»

Зрештою, сума помилок стала такою, що не навчитися на них було б неможливо. Я почав робити успіхи. Одна за одною, великі концептуальні проблеми розчинялися самі собою, а маленькі заполіровувались одне переписування за іншим. За декілька місяців безперервних спроб різного ступеню марності, алгоритм почав мати непоганий вигляд.

Вже після того, як алгоритм було завершено, після того, як він попав у продукт і почав приносити гроші, я наважився підрахувати файли у своїй лузерській папочці. Їх було 42.

* Я

І отут ми підходимо до найголовнішого. Дивіться. Як запустити проєкт, придумав начальник департаменту. Відповідальність за проєкт взяв на себе проджект-менеджер. Продуктовий менеджер взяв на себе ризик, а ризик був і, зважаючи на перші місяці без успіхів, не маленький. Далі, аналітик налагодив роботу з реальними користувачами так, щоб я працював над реальними, а не вигаданими проблемами. А тестер ще і вигаданих проблем додав. Все, що робив власне я — це приходив щодня на роботу і розважався з пікселями і трикутниками. Ха! Мені ще за це і платили!

Я абсолютно певен, що в моєму особистому тріумфі моя власна роль парадоксально мінімальна. Мені пощастило опинитися в команді, яка відкрита до ризиків, відкрита до нових ідей, яка дозволяє робити достатньо помилок. В мене вірили, мене підтримували, мене захищали, а я просто робив те, що навчений робити.

Власне, тому я і радий що не написав цей текст три роки тому. Бо тоді це було б порожнім вихвалянням. Тільки тепер, на одинадцятому місяці війни, я готовий зробити зі свого колишнього досвіду гідний урок.

Ми всі набагато менш автономніші ніж здається. Ми не можемо існувати відокремлено, принаймні, існувати як інженери. Навіть генератор треба чимось заправляти, навіть «Старлінк» треба ремонтувати. Нам потрібні інші люди. Кур’єри, адміни, електрики, сантехніки і лікарі швидкої допомоги.

Втім, ми теж комусь потрібні. Навіть, якщо наша роль наразі — робити п’ятсоттисячне онлайн-казино або турецький клон Facebook, якщо в процесі нам вдається закачувати в країну валюту — це вже робить нашу роль гідною.

А наш особистий успіх — це лише показник того, наскільки вдало ми інтегровані у людську мережу. Показник лише того, наскільки вдало ми відповідаємо своєму місцю, а не наскільки ми сильні, розумні чи самостійні самі по собі.

У мене все, дякую за увагу.

👍ПодобаєтьсяСподобалось26
До обраногоВ обраному6
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Классно, поздравляю с интересной работой! У нас есть тоже рнд отдел на работе, завидую что занимаются интереснотой фултайм :)

Sounds like that Nobel prize need to divide between others too. But...
Напевне це все тобі за ініціативу, бо якщо пам’ятаєш те славнозвісне прислів’я...
До речі, якщо ми модель тривимірну трикутниками, то може і реальність трикутна?
І ще, де, в біса, середина у числа 4 ?
Я ось думаю, що деякі числа двійні. Як Флеш Гордон, коли розпливається по швидкості у полосу.
1,2,3,4,5
1,11,111,1111,11111

Фактори, які сприяли професійному досягненню автора і команди/компанії, можна описати терміном «культура». Згодні? Бажаю автору; його колегам і роботодавцю подальших успіхів.

Ми не можемо існувати відокремлено, принаймні, існувати як інженери.

Тим не менше, Нобелівську премію, Премію тьюринга дають індивідуально.
Звісно без сторонніх людей важко досягти успіху. Але, умовно кажучи, завжди є той один крок який дає тектонічний зсув.
Умовно кажучи — алгоритм можна покращити різними оптимізаціями, але автор принципово нового підходу один.

Я когда-то в детстве придумал алгоритм быстрой проверки на столкновение спрайтов для КР580.
Классический метод базировался на стандартной сетке координат, которые проверяются математически. Сложность алгоритма в том, что чем больше спрайтов — тем больше проверок. Мой метод был основан на слиянии текстур при условии что на каждую итерацию спрайты перемещаются на один пиксель.
Например, есть спрайт героя, есть спрайты стен и есть спрайты врагов. Задача — не перемещать героя сквозь стены и получать урон при столкновении с врагами. Также нужно чтоб враг при столкновении менял вектор движения.
Алгоритм был такой — при перемещении спрайта мы берем будущие по вектору массив пикселей(2) бекграунда того места, куда планируется перемещение, и отрисовываем закадровку — в одну итерацию. При этом если у нас на будущем месте будет искажение, значит на бекграунде уже есть объект.
Так как спрайты двигаются ровно на 1 пиксель, то мы уже можем понимать по состоянию массива пикселей, с чем сталкивается спрайт —
Если искажения пошли на половину массива пикселей — значит это спрайт стены, так как он статичный. А вот если у нас изменения на полный массив — значит нам на встречу двигается объект с вектором движения в 1 пиксель (1+1 = 2).
Соотвественно спрайт врага получает указание сменить вектор, а герой — получает урон.
Потом отображается закадровка и цикл повторяется.

Такой алгоритм упрощал сложность, так как надо было выполнить XOR пикселей объекта на закадровке и если там были искажения с оригинальным спрайтом — зааффектить логику.

Минусом алгоритма было создание некоторых артефактов в зоне стыка спрайтов на один кадр, что вполне допустимо по сравнению с выгодой, которую оно давало.

Если обычно для программ на КР580 было 2-6 объектов, а потом частота кадров стопалась и играть было нельзя. У меня можно было поместить больше объектов.

И бонус — как переоптимизация сыграла в минус для моей игры. Логично было, что проверку надо начинать с первого совпадения с объектом, и останавливать сразу, чтоб экономить процессор.

Да, но — нет! Потому что такая экономия делала неравномерную задержку и вызывала нестабильность частоты кадров.

Ну, а то что получилось — можно посмотреть тут: youtu.be/zs2HA6eQY88

Відкрили очі... До цього моменту був впевнений, що Львів — це клон Спектрума, а отже побудований на Z80, а не на ВМ80.

Дуже нетипова стаття для DOU. Видно, що і сама технічна проблема заслуговує уваги і контекст важливий.

Дякую за ковток свіжого повітря! (На противагу копірайтерському крінжу, якого багацько з’явилося, та вічному скигленню місцевої авдиторії.)

Сподіваюсь, колись і деталі імплементації можна буде викласти і хтось щось там навіть зрозуміє )

Підписатись на коментарі