Ako vygenerovať 3D model telefónu v prehliadači

Návod na 3D model telefónu v prehliadači cez Three.js a CSG: telo s bevel hranou, výrezy tlačidiel a reproduktorov, Web Worker a rýchle odčítanie otvorov.

Dva vygenerované 3D modely telefónu, jeden spredu s tmavým displejom a druhý zozadu

3D model telefónu vygenerujete v prehliadači tak, že obdĺžnik so zaoblenými rohmi vytiahnete do hĺbky a potom z neho booleovskými operáciami (CSG) vyrežete prednú stranu, tlačidlá, reproduktory a konektor. Celé zariadenie potom popisuje pár čísel v milimetroch a nový model je zmena týchto čísel, nie modelovanie v 3D programe.

Hodí sa to všade, kde potrebujete veľa podobných zariadení alebo ich má upravovať používateľ: konfigurátory, mockupy, náhľady produktov. Ako príklad z praxe slúži Ecranify, nástroj na 3D mockupy pre screenshoty do App Store a Google Play, v ktorom nie je ani jeden hotový 3D model. Nižšie je postup krok za krokom aj s meraním, ktoré ukazuje, kde sa dá na výpočte ušetriť najviac.

Čo budete potrebovať

  • Three.js na scénu, kamery, svetlá a hlavne geometriu. Geometria je v Three.js mesh, teda sieť trojuholníkov.
  • Knižnicu three-bvh-csg na booleovské operácie nad meshmi. Zrýchľuje ich priestorovým indexom (BVH, bounding volume hierarchy), vďaka ktorému netestuje každý trojuholník proti každému.
  • Popis zariadenia ako dáta, napríklad JSON s rozmermi tela, polomerom rohov, veľkosťou bevelu a zoznamom prvkov na bokoch. Všetky polohy zadávajte v milimetroch od stredu zariadenia.

Krok 1: Vytiahnite obdĺžnik do 3D

Nakreslite 2D obdĺžnik so zaoblenými rohmi v skutočných rozmeroch, napríklad 163,4 × 78 mm, a vytiahnite ho (extrúzia) do hĺbky 8,75 mm. Dostanete dosku s ostrými hranami. Žiadny telefón také nemá, preto pri vyťahovaní zapnite aj bevel, teda zaoblenie hrany. Three.js robí oboje v jednom kroku.

Len extrúziaHranatá doska bez zaoblených rohov a hrán
+ rohy a bevelRovnaká doska so zaoblenými rohmi aj hranami
Rovnaký tvar, iné dve čísla: polomer rohu a veľkosť bevelu.

Pozor na jednu vec: bevel sa pridáva navonok. Ak chcete presný vonkajší rozmer, zmenšite 2D tvar aj hĺbku o veľkosť bevelu.

b = min(bevel, hĺbka / 2)
tvar = zaoblený obdĺžnik(šírka - 2b, výška - 2b, polomer rohu - b)
telo = vytiahni(tvar, hĺbka - 2b, bevel b)

Hladkosť oblúkov (teseláciu) určuje počet segmentov, na ktoré sa oblúk rozdelí. Viac segmentov znamená hladší tvar a viac trojuholníkov. Toto číslo neskôr rozhodne o rýchlosti celého výpočtu, preto sa k nemu vrátime v kroku 7.

Krok 2: Vyrežte vaňu pre displej

CSG (constructive solid geometry) skladá telesá z jednoduchších telies pomocou troch operácií: zjednotenie, rozdiel a prienik. Rozdiel funguje ako vrták: jedno teleso odoberie materiál z druhého.

Displej telefónu nie je zarovno s rámom, sedí v plytkej vani. Tú vyrobíte tak, že spravíte druhú, o 1,4 mm menšiu kópiu tela, necháte z nej len prednú časť hrubú 0,7 mm (prienik s veľkým kvádrom) a túto časť odčítate od tela. Do vzniknutej vane potom vložíte tmavú plochu displeja.

Rezné telesoTelo telefónu s modrým priesvitným rezným telesom na prednej strane
Po odčítaníTelo s vyrezanou vaňou a tmavým displejom vo vnútri
Modré teleso je to, čo sa odčíta. Vpravo už je vo vani displej.

Dva praktické detaily:

  • Kváder na prienik musí byť naozaj veľký. Stačí mu orezávať hĺbku, ale v šírke a výške musí presahovať celé zariadenie. Neodvodzujte ho od hĺbky: napríklad 20-násobok hĺbky je pri tenkom vysokom telefóne menej ako jeho výška a hore a dole ostane neorezaný rám.
  • Zväčšite rezné teleso o pár promile. Keď majú dve telesá presne rovnakú plochu, CSG si nevie rady, ktorá strana je vnútri. Mierka 1,002 tomu predíde a okom ju nevidno.

Krok 3: Bočné prvky pripravte ako vrtáky

Každý prvok na boku je rovnaký recept s iným vrtákom. Tlačidlo napríklad vznikne z troch telies: zaoblený obdĺžnik o kúsok hlbší ako tlačidlo sa odčíta od rámu, okraj otvoru dostane malé skosenie a do otvoru sa vloží o niečo menšie teleso, ktoré z rámu trochu vytŕča.

VrtákyBok telefónu s dvoma modrými reznými telesami tlačidiel
Výrez a tlačidloBok telefónu s vyrezanými otvormi a vloženými tlačidlami
Dve tlačidlá na pravom boku pred odčítaním a po ňom.

Reproduktory sú rad malých valcov, konektor je zaoblený obdĺžnik. Do každého otvoru vložte niečo tmavé: tenký disk do mriežky, platničku do konektora. Prázdna diera v tenkej škrupine pôsobí ako chyba, diera s tmavou výplňou pôsobí ako hardvér.

Spodná hrana telefónu s dvoma radmi otvorov reproduktora a konektorom uprostred
Otvory reproduktora a konektor. Všetko sú odčítané valce a zaoblené obdĺžniky.
pre každý prvok v zozname prvkov boku:
    vrták = tvar prvku (valec, zaoblený obdĺžnik, ...)
    umiestni vrták na hranu podľa polohy v mm
    pridaj vrták do zoznamu rezov
    ak má prvok výplň: pridaj výplň do scény

Pridať tlačidlo je potom zápis do dát. Prvkov rýchlo pribúda: iPad Pro 13″ má 58 otvorov reproduktora, 4 tlačidlá, 2 antény a konektor, teda vyše 60 odčítaní od jedného tela.

Krok 4: Predné detaily nevŕtajte

Výrez pre kameru, ostrovček v hornej časti displeja alebo indikátor domovskej obrazovky sú ploché. Rezať pre ne geometriu je zbytočná práca. Nalepte ich ako decal, teda obrázok premietnutý na povrch. Premietajte ho na skrytú rovinu cez celú prednú stranu a polohu zadávajte v rovnakých milimetroch ako všetko ostatné. Výnimkou je okrúhle domovské tlačidlo starších iPhonov. To má skutočnú hĺbku, ktorú vidno zboku, a preto ide cez CSG.

Krok 5: Presuňte výpočet do Web Workera

JavaScript v prehliadači beží v jednom vlákne. To isté vlákno počíta, kreslí stránku a reaguje na kliky. Kým beží CSG, stránka stojí a nepomôže ani spinner, lebo aj ten potrebuje to isté vlákno.

Celé zostavenie zariadenia preto spustite vo Web Workeri, teda v samostatnom vlákne na pozadí. Worker dostane popis zariadenia, vráti hotové polia vrcholov a stránka ostane plynulá. Pri zmene parametra starý worker ukončite a spustite nový, nech nedopočítava zastaraný stav.

Výsledok z workera chvíľu trvá, preto pridajte okamžitý náhľad. Upravovaný prvok ukážte ako modrý priesvitný „duch“, jednoduchý kváder alebo valec s pár desiatkami trojuholníkov, ktorý sa dá postaviť v hlavnom vlákne hneď. Keď worker skončí, duch zmizne.

Krok 6: Odčítajte všetky otvory naraz

Najpriamočiarejší spôsob je odčítať prvky postupne: otvor 1 od tela, potom otvor 2 od výsledku a tak ďalej. Každé odčítanie však znova postaví priestorový index celého tela, čo je najdrahšia časť výpočtu. Pri desiatkach prvkov čas rastie veľmi rýchlo.

Lepšie je najprv zozbierať všetky vrtáky pre dané teleso, spojiť ich do jedného meshu a odčítať raz.

rezy = []
pre každý prvok: pridaj jeho vrták do rezy
spojený = spoj všetky rezy do jedného meshu
telo = telo mínus spojený
ak spojenie zlyhá: odčítaj rezy po jednom

Meranie na zjednodušenej kópii postupu (Three.js 0.170, three-bvh-csg 0.0.17, Node 22, cloudový server s 2 jadrami Intel Xeon 2,1 GHz, medián z 5 behov):

Teleso Otvory Po jednom Naraz
telefón, 17 676 trojuholníkov 25 2,47 s 0,26 s
tablet, 17 676 trojuholníkov 58 5,55 s 0,89 s
tablet, 68 108 trojuholníkov 58 22,8 s 3,1 s

Jedna podmienka: spojenie a jedno odčítanie dá rovnaký výsledok ako postupné odčítanie, len ak sa vrtáky neprekrývajú. Prvky sú na rôznych miestach, takže to bežne platí. Ak ale používateľ posunie dva prvky na seba, v mieste prekrytia môže vzniknúť drobná chyba.

Krok 7: Počet segmentov majte ako parameter

Teselácia, ktorá stačí na zobrazenie, je pre CSG často zbytočne hustá. Pri 64 segmentoch na roh a 32 na bevel má telo 68 108 trojuholníkov. Polovicu (32 a 16) na 2 mm hrane nevidno, ale telo má len 17 676 trojuholníkov a tretí riadok tabuľky ukazuje, čo to robí s časom.

64 a 32 segmentovDrôtený model rohu telefónu s veľmi hustou sieťou trojuholníkov
32 a 16 segmentovDrôtený model rovnakého rohu s polovičným počtom segmentov
Roh tela zhora. Vpravo je štvrtina trojuholníkov.

Malým prvkom s polomerom do 2 mm (otvory reproduktora, skrutky) dajte polovicu segmentov, náhľadom v galérii ešte menej. Kvalitu preto nedávajte ako konštantu do kódu, ale ako parameter zostavenia.

Render na serveri bez grafickej karty

Ak potrebujete rovnakú scénu vykresliť aj na serveri, napríklad ako zálohu exportu, beží v Chrome bez obrazovky (headless), ktorý bez grafickej karty kreslí softvérovo. Tam sa každá neefektivita znásobí. V Ecranify najťažší tablet bez spomenutých úprav narazil na limit 15 minút. So spojenými rezmi, menšími textúrami, nižšou teseláciou a cache hotovej geometrie podľa hashu popisu zariadenia trvá render okolo pol minúty a opakovaný okolo 5 sekúnd. Podrobnosti aj s interaktívnymi ukážkami sú v anglickom článku na ecranify.com.

Ak riešite podobný problém s 3D v prehliadači alebo potrebujete appku na zákazku, napíšte nám.

← Ďalšie v kategórii Ecranify