WebGL i WebGPU u Three.js: što danas stvarno koči performanse

WebGL i WebGPU u Three.js: što danas stvarno koči performanse

WebGPU kao nasljednik WebGL‑a: teorija i stvarnost

WebGPU se u web zajednici pozicionira kao prirodni nasljednik WebGL‑a. Donosi moderniji grafički API, bolju kontrolu nad memorijom, naprednije shadere i mogućnost finog upravljanja pipelineom. Na papiru, to bi trebalo značiti više FPS‑ova, bolji frame pacing i veći vizualni raspon efekata u odnosu na klasični WebGLRenderer u Three.js‑u.

Međutim, iskustva iz stvarnih Three.js projekata pokazuju drukčiju sliku. U scenama s tisućama klasičnih mesh objekata, mnogi developeri danas bilježe 4x do 10x lošije performanse s WebGPURendererom u odnosu na WebGLRenderer. Posebno kada se radi o ne‑instanciranim objektima, složenijim uniform buffer layoutima i velikom broju draw poziva po frameu.

Time se otvara važno pitanje: gdje točno prestaje teorijska prednost WebGPU‑a, a počinju praktična ograničenja trenutne implementacije u Three.js‑u?

Zašto je WebGPURenderer često sporiji u Three.js‑u

Glavni razlog trenutačnih problema leži manje u samom WebGPU standardu, a više u načinu na koji Three.js implementira WebGPU backend. WebGPURenderer je još relativno mlad i prolazi kroz fazu agresivne optimizacije. WebGLRenderer, nasuprot tome, iza sebe ima godine iteracija i prilagodbi tipičnim web igrama, vizualizacijama i konfiguratorima.

U praksi, u scenama s puno objekata, presudna je CPU strana render pipelinea. Koliko brzo JavaScript kod može pripremiti render iteme, ažurirati UBO‑e, složiti batchove i poslati sve to GPU‑u. Upravo tu WebGPURenderer u trenutnoj fazi često gubi bitku.

Uloga render itema i UBO layouta

Three.js za svaku kombinaciju geometrije, materijala i transformacije formira tzv. render iteme. U WebGPURendereru svaki od tih render itema može povući sa sobom ažuriranje uniform buffer objekata (UBO‑a) i dodatnu CPU logiku oko bind grupa i pipeline statea.

Kada scena ima nekoliko desetaka ili stotina objekata, taj overhead je zanemariv. No u scenama s tisućama ne‑instanciranih mesh objekata, broj render itema eksplodira. Svaki frame CPU mora:

  • proći kroz veliki niz render itema
  • ažurirati ili validirati UBO‑e
  • pripremiti bind grupe i pipeline konfiguracije
  • izdati niz draw poziva prema GPU‑u

Upravo taj CPU dio pipelinea postaje usko grlo. GPU često miruje, dok JavaScript kod pokušava pripremiti sve podatke. Rezultat je niži FPS, nestabilan frame pacing i osjećaj da je WebGPU "sporiji", iako su njegove mogućnosti na GPU razini veće od WebGL‑a.

Zašto WebGLRenderer i dalje pobjeđuje u masovnim scenama

WebGLRenderer je godinama optimiziran za tipične game‑like scene: puno mesh objekata, jednostavniji UBO modeli i relativno predvidljiv tok podataka. Putanje u kodu su ispolirane, a mnoge optimizacije (poput sortiranja draw poziva, keširanja uniforma, efikasnog korištenja atributa) već su odavno na mjestu.

U takvim uvjetima, WebGLRenderer jednostavno ima prednost zrelosti. Njegov CPU overhead po render itemu je niži, a cijeli pipeline bolje prilagođen velikom broju klasičnih objekata. Zato se u realnim projektima često događa da ista scena u WebGLRendereru radi "glatko", dok WebGPURenderer pada na trećinu ili čak desetinu FPS‑a.

Kako WebGPU mijenja API u Three.js‑u

Paralelno s optimizacijama performansi, WebGPURenderer prolazi i kroz promjene u API‑ju. Cilj je pojednostaviti integraciju i učiniti inicijalizaciju transparentnijom. Jedna od ključnih promjena je uklanjanje niza "async" metoda.

Kraj renderAsync i clearAsync metoda

Ranije su developeri mogli koristiti metode poput renderAsync ili clearAsync kako bi eksplicitno sinkronizirali s GPU radom. U novijim verzijama Three.js‑a te su metode uklonjene. Umjesto toga, uvodi se jasniji model u kojem se asinkronost rješava primarno tijekom inicijalizacije renderera.

Preporučeni obrazac sada je eksplicitno pozivanje await renderer.init() prije prvog render pasa. Time Three.js dobiva priliku da pripremi sve WebGPU resurse, adapter, device, pipeline state i interne strukture, bez da se aplikacijski kod oslanja na skrivena "async" ponašanja tijekom samog renderiranja.

Posljedice za postojeće integracije i alate

Ova promjena nije samo kozmetička. Mnoge postojeće integracije i utility biblioteke oslanjale su se na staro ponašanje. Jedan od najčešće korištenih alata za praćenje performansi u WebGL projektima, stats-gl, više nije kompatibilan s novim WebGPU backendom.

Umjesto njega, Three.js zajednica se postupno okreće ugrađenim alatima:

  • Three.js Inspector, koji daje uvid u scenu, materijale, geometrije i render tok
  • GPU timestamp queryje, koji omogućuju precizno mjerenje vremena pojedinih render passova na GPU‑u

Za developere to znači promjenu navika. Umjesto jednostavnog FPS overlayja, potrebno je dublje razumjeti gdje nastaje usko grlo – na CPU ili GPU strani, u kojem render passu, s kojim shaderom ili kojim tipom objekta.

Kako danas birati između WebGLRenderer i WebGPURenderer

Za timove koji počinju novi 3D web projekt, dilema "WebGL ili WebGPU" više nije čisto ideološka. Umjesto da se WebGPU uzima zdravo za gotovo kao "brža" opcija, odluku bi trebalo temeljiti na profiliranju konkretne aplikacije.

Kada ostati na WebGL‑u

WebGLRenderer i dalje je najbolji izbor u sljedećim situacijama:

  • scene s jako velikim brojem ne‑instanciranih mesh objekata
  • projekti gdje je prioritet stabilan FPS na širokom spektru uređaja
  • postojeći kod koji masovno koristi provjerene WebGL ekstenzije i alate
  • aplikacije kojima je važna kompatibilnost sa starijim preglednicima i uređajima

U takvim slučajevima WebGL nudi predvidljiv pipeline i dobro razumljena ograničenja. Optimizacijske tehnike poput LOD sustava, frustum cullinga, smanjenja draw poziva i dalje su učinkovite i dobro dokumentirane.

Kada WebGPU ima smisla već danas

WebGPU se počinje isplatiti u projektima koji ciljaju modernije tehnike i kontrolu nad pipelineom, primjerice:

  • intenzivna upotreba instancinga (tisuće objekata istog mesh‑a u jednom draw pozivu)
  • batchevi geometrije i materijala, pažljivo dizajniran layout podataka
  • napredni shader pipelineovi s više render passova
  • clustered ili tiled rendering, napredno osvjetljenje i volumetrijski efekti

U takvim scenarijima WebGPURenderer može pokazati svoju snagu: manji broj draw poziva, bolja iskorištenost GPU‑a i veća fleksibilnost pri dizajnu render pipelinea. No preduvjet je da se arhitektura aplikacije od početka prilagodi tim principima.

Hibridni pristup: dvije putanje, jedan projekt

Najrealističnija strategija za današnje produkcijske projekte je hibridni pristup. Umjesto da se tim obveže na jedan renderer, isplati se paralelno održavati WebGL i WebGPU putanju, barem u ranoj fazi razvoja.

Praktičan workflow za timove

Jedan mogući workflow izgleda ovako:

  1. Implementirati osnovnu scenu i ključne značajke koristeći WebGLRenderer.
  2. Dodati eksperimentalnu WebGPURenderer putanju iza feature flaga ili konfiguracijske opcije.
  3. Na ciljanim uređajima mjeriti FPS, frame time i GPU vrijeme za obje putanje.
  4. Identificirati dijelove scene gdje WebGPU pokazuje jasnu prednost (npr. masivni instancing, kompleksni efekti).
  5. Postupno prilagođavati podatkovni model (instancing, batchevi, UBO layouti) kako bi se ti dijelovi maksimalno iskoristili u WebGPU modu.

Na taj način projekt već danas može eksperimentirati s budućnošću web renderinga, bez da žrtvuje stabilne performanse u produkciji.

Primjer: vizualizacija grada

Zamislimo vizualizaciju grada s desecima tisuća zgrada, vozila i senzora. U klasičnoj WebGL postavci, svaka zgrada je zaseban mesh objekt. WebGLRenderer će to podnijeti bolje od trenutnog WebGPURenderera, jer je CPU overhead po objektu manji.

No, ako se scena premodelira tako da zgrade dijele istu geometriju i materijal te se crtaju kao instancirani mesh, WebGPU može preuzeti vodstvo. Umjesto tisuća draw poziva, dobivamo nekoliko pažljivo dizajniranih batcheva. U tom slučaju, hibridni pristup omogućuje:

  • WebGL kao zadanu opciju za sve korisnike
  • WebGPU kao "high performance" mod za moderne preglednike, s optimiziranim instancing pipelineom

Što slijedi u Three.js ekosustavu

Three.js tim već najavljuje daljnje promjene u organizaciji renderera. Cilj je jasnije odvojiti apstraktni pojam "renderer" od konkretnog backend API‑ja (WebGL, WebGPU ili nešto treće u budućnosti). To bi trebalo olakšati održavanje više backendova i omogućiti fleksibilnije prebacivanje između njih.

Dok se ta tranzicija ne dovrši, realan je pristup tretirati WebGPU kao naprednu, ali još uvijek djelomično pokusnu opciju. Posebno u kontekstu Three.js‑a, gdje je WebGPURenderer još u intenzivnoj fazi optimizacije CPU‑overheada, UBO layouta i načina upravljanja render itemima.

Za developere to znači dvije ključne stvari:

  • ne očekivati automatski boost performansi samo prelaskom na WebGPU
  • ulagati vrijeme u profiliranje i redizajn podatkovnog modela, posebno oko instancinga i batchiranja

Zaključak: WebGPU nije čarobni štapić, ali jest budućnost

WebGPU u Three.js‑u donosi novu razinu kontrole nad render pipelineom, ali i novu razinu odgovornosti za arhitekturu aplikacije. Trenutačno, u mnogim realnim scenama s velikim brojem ne‑instanciranih mesh objekata, WebGLRenderer i dalje ostvaruje bolje performanse. Razlog nije slabost WebGPU standarda, nego mladi status WebGPURenderera i CPU uska grla u načinu na koji Three.js trenutno upravlja render itemima i UBO‑ima.

Umjesto da WebGPU doživljavamo kao instant zamjenu za WebGL, isplativije je na njega gledati kao na platformu za dizajn modernih, instanciranih i batchiranih scena. Hibridni pristup – profiliranje obje putanje, ciljano korištenje WebGPU‑a tamo gdje donosi stvarnu korist i zadržavanje WebGL‑a za masivne klasične scene – danas je najzrelija strategija za ozbiljne 3D web projekte.

Budućnost web renderinga vjerojatno pripada WebGPU‑u, ali put do tamo vodi kroz pažljivu optimizaciju, realna mjerenja performansi i spremnost da se mijenja način na koji modeliramo i iscrtavamo 3D svjetove u pregledniku.

Natrag na vrh