Hogyan generáljunk 3D telefonmodellt a böngészőben
Útmutató 3D telefonmodellhez a böngészőben Three.js-szel és CSG-vel: bevel élű ház, gomb- és hangszórókivágások, Web Worker és gyors lyukkivonás.

3D telefonmodellt úgy generálhat a böngészőben, hogy egy lekerekített sarkú téglalapot kihúz a készülék mélységére, majd logikai műveletekkel (CSG) kivágja belőle az előlapot, a gombokat, a hangszórókat és a csatlakozót. Az egész készüléket ezután néhány milliméterben megadott szám írja le, és egy új modell ezeknek a számoknak a módosítását jelenti, nem modellezést egy 3D programban.
Ez mindenhol hasznos, ahol sok hasonló készülékre van szükség, vagy a felhasználónak kell őket módosítania: konfigurátorok, mockupok, termékelőnézetek. Gyakorlati példa az Ecranify, egy eszköz 3D mockupokhoz App Store és Google Play képernyőképekhez, amelyben egyetlen kész 3D modell sincs. Alább lépésről lépésre olvashatja a folyamatot, egy méréssel együtt, amely megmutatja, hol lehet a számításon a legtöbbet spórolni.
Amire szüksége lesz
- Three.js a jelenethez, kamerákhoz, fényekhez és főleg a geometriához. A geometria a Three.js-ben mesh, vagyis háromszögek halmaza.
- A three-bvh-csg könyvtár a mesheken végzett logikai műveletekhez. Térbeli indexszel (BVH, bounding volume hierarchy) gyorsítja őket, így nem vet össze minden háromszöget minden másikkal.
- A készülék leírása adatként, például JSON a ház méreteivel, a sarkok sugarával, a bevel méretével és az oldalakon lévő elemek listájával. Minden pozíciót a készülék közepétől mért milliméterben adjon meg.
1. lépés: Húzza ki a téglalapot 3D-be
Rajzoljon egy lekerekített sarkú 2D téglalapot valós méretben, például 163,4 × 78 mm-eset, és húzza ki (extrudálás) 8,75 mm mélységre. Éles élű lapot kap. Ilyen telefon nincs, ezért a kihúzáskor kapcsolja be a bevelt is, vagyis az él lekerekítését. A Three.js mindkettőt egy lépésben elvégzi.


Egy dologra figyeljen: a bevel kifelé adódik hozzá. Ha pontos külső méretre van szüksége, csökkentse a 2D formát és a mélységet a bevel méretével.
b = min(bevel, mélység / 2)
forma = lekerekített téglalap(szélesség - 2b, magasság - 2b, saroksugár - b)
ház = kihúz(forma, mélység - 2b, bevel b)
Az ívek simaságát (tesszelláció) az határozza meg, hány szegmensre bontjuk az ívet. Több szegmens simább formát és több háromszöget jelent. Ez a szám később az egész számítás sebességét meghatározza, ezért a 7. lépésben visszatérünk rá.
2. lépés: Vágjon mélyedést a kijelzőnek
A CSG (constructive solid geometry) egyszerűbb testekből rak össze testeket három művelettel: unió, különbség és metszet. A különbség úgy működik, mint egy fúró: az egyik test anyagot vesz el a másikból.
A telefon kijelzője nem egy síkban van a kerettel, hanem egy sekély mélyedésben ül. Ehhez készítsen a házról egy második, 1,4 mm-rel kisebb másolatot, hagyja meg belőle csak a 0,7 mm vastag elülső részt (metszet egy nagy téglatesttel), és vonja ki ezt a részt a házból. A keletkezett mélyedésbe ezután tegyen egy sötét kijelzőfelületet.


Két gyakorlati részlet:
- A metszethez használt téglatestnek tényleg nagynak kell lennie. Elég, ha a mélységet vágja, de szélességben és magasságban túl kell nyúlnia az egész készüléken. Ne a mélységből számolja: például a mélység 20-szorosa egy vékony, magas telefonnál kisebb, mint a magassága, és fent meg lent vágatlan keret marad.
- Nagyítsa meg a vágótestet néhány ezrelékkel. Ha két testnek pontosan azonos lapja van, a CSG nem tudja eldönteni, melyik oldal van belül. Az 1,002-es lépték ezt megelőzi, és szemmel nem látszik.
3. lépés: Készítse elő az oldalsó elemeket fúróként
Minden oldalsó elem ugyanaz a recept más fúróval. Egy gomb például három testből áll: egy a gombnál kicsit mélyebb lekerekített téglalapot kivonunk a keretből, a nyílás széle kis letörést kap, a nyílásba pedig egy valamivel kisebb test kerül, amely kissé kiáll a keretből.


A hangszórók kis hengerek sorai, a csatlakozó egy lekerekített téglalap. Minden nyílásba tegyen valami sötétet: vékony korongot a rácsba, lapkát a csatlakozóba. Egy üres lyuk a vékony héjban hibának tűnik, a sötét kitöltésű lyuk hardvernek.

az oldalsó elemek listájának minden elemére:
fúró = az elem formája (henger, lekerekített téglalap, ...)
helyezd a fúrót az élre a mm-ben megadott pozíció szerint
add hozzá a fúrót a vágások listájához
ha az elemnek van kitöltése: add hozzá a kitöltést a jelenethez
Egy gomb hozzáadása így csak egy új bejegyzés az adatokban. Az elemek gyorsan szaporodnak: egy iPad Pro 13″ 58 hangszórólyukkal, 4 gombbal, 2 antennával és egy csatlakozóval rendelkezik, ez több mint 60 kivonás egyetlen házból.
4. lépés: Az előlap részleteit ne fúrja
A kamera kivágása, a kijelző tetején lévő sziget és a kezdőképernyő-jelző lapos. Geometriát vágni hozzájuk felesleges munka. Helyezze fel őket decalként, vagyis felületre vetített képként. Vetítse egy rejtett síkra, amely az egész előlapot lefedi, és a pozíciót ugyanabban a milliméterben adja meg, mint minden mást. Kivétel a régebbi iPhone-ok kerek kezdőgombja. Ennek valódi mélysége van, ami oldalról látszik, ezért CSG-n megy keresztül.
5. lépés: Tegye át a számítást Web Workerbe
A böngészőben a JavaScript egyetlen szálon fut. Ugyanez a szál számol, rajzolja az oldalt és reagál a kattintásokra. Amíg a CSG fut, az oldal megáll, és egy spinner sem segít, mert annak is ugyanez a szál kell.
Ezért az egész készülék összeállítását futtassa Web Workerben, vagyis egy külön háttérszálon. A worker megkapja a készülék leírását, kész csúcstömböket ad vissza, és az oldal folyamatos marad. Ha egy paraméter megváltozik, állítsa le a régi workert, és indítson újat, hogy ne számoljon végig egy elavult állapotot.
A worker eredménye eltart egy ideig, ezért adjon hozzá azonnali előnézetet. A szerkesztett elemet mutassa kék, áttetsző „szellemként”: egyszerű téglatestként vagy hengerként néhány tucat háromszöggel, amely a fő szálon azonnal felépíthető. Amikor a worker végez, a szellem eltűnik.
6. lépés: Vonja ki az összes lyukat egyszerre
A legegyenesebb út az elemek egymás utáni kivonása: az 1. lyukat a házból, aztán a 2.-at az eredményből és így tovább. Minden kivonás azonban újraépíti az egész ház térbeli indexét, ami a számítás legdrágább része. Több tucat elemnél az idő nagyon gyorsan nő.
Jobb, ha előbb összegyűjti az adott test összes fúróját, egyetlen mesh-be egyesíti őket, és egyszer vonja ki.
vágások = []
minden elemre: add hozzá a fúróját a vágásokhoz
egyesített = egyesítsd az összes vágást egy mesh-be
ház = ház mínusz egyesített
ha az egyesítés nem sikerül: vond ki a vágásokat egyenként
Mérés a folyamat egyszerűsített másolatán (Three.js 0.170, three-bvh-csg 0.0.17, Node 22, felhőszerver 2 Intel Xeon 2,1 GHz-es maggal, 5 futás mediánja):
| Test | Lyukak | Egyenként | Egyszerre |
|---|---|---|---|
| telefon, 17 676 háromszög | 25 | 2,47 s | 0,26 s |
| tablet, 17 676 háromszög | 58 | 5,55 s | 0,89 s |
| tablet, 68 108 háromszög | 58 | 22,8 s | 3,1 s |
Egy feltétel: az egyesítés és egyetlen kivonás csak akkor adja ugyanazt az eredményt, mint a fokozatos kivonás, ha a fúrók nem fedik egymást. Az elemek különböző helyeken vannak, így ez általában teljesül. Ha viszont a felhasználó két elemet egymásra tol, az átfedés helyén apró hiba keletkezhet.
7. lépés: A szegmensszámot tartsa paraméterként
A megjelenítéshez elég tesszelláció a CSG-hez gyakran feleslegesen sűrű. Saroknként 64 és a bevelen 32 szegmenssel a ház 68 108 háromszögből áll. A felét (32 és 16) egy 2 mm-es élen nem látni, de a ház így csak 17 676 háromszög, és a táblázat harmadik sora mutatja, mit jelent ez az időben.


A legfeljebb 2 mm sugarú kis elemek (hangszórólyukak, csavarok) kapják a szegmensek felét, a galéria előnézetei még kevesebbet. A minőséget ezért ne konstansként írja a kódba, hanem az összeállítás paramétereként adja meg.
Renderelés szerveren videokártya nélkül
Ha ugyanazt a jelenetet szerveren is renderelni kell, például az exportok tartalékaként, az képernyő nélküli (headless) Chrome-ban fut, amely videokártya híján szoftveresen rajzol. Ott minden pazarlás megsokszorozódik. Az Ecranifyban a legnehezebb tablet a fenti módosítások nélkül elérte a 15 perces időkorlátot. Egyesített vágásokkal, kisebb textúrákkal, alacsonyabb tesszellációval és a kész geometria cache-ével, amelynek kulcsa a készülékleírás hashe, egy renderelés nagyjából fél percig tart, egy ismételt pedig körülbelül 5 másodpercig. A részletek interaktív példákkal az ecranify.com angol nyelvű cikkében olvashatók.
Ha hasonló 3D-s problémát old meg a böngészőben, vagy egyedi alkalmazásra van szüksége, írjon nekünk.


