Poglavlje 42: Draw Calls i Batching
U ovom poglavlju ulazimo u jednu od najvaznijih tema optimizacije u real-time renderovanju: draw call-ove. Razumecete sta je draw call, zasto je skup, koliko ih je "previse", i koje tehnike -- instancing, mesh merging, auto-instancing, Nanite -- stoje na raspolaganju da ih drzite pod kontrolom. Ovo nije teoretsko poglavlje: ovo je poglavlje koje ce direktno odrediti da li vasa igra radi na 60 FPS ili na 20 FPS.
Uvod: Nevidljivi ubica performansi
Zamislite sledeci scenario. Napravili ste prekrasnu scenu u Unreal Engine 5. Imate lepe materijale, odlicno osvetljenje, sve izgleda fantasticno u editoru. Pokrenete igru, pogledate FPS counter -- 22 FPS. Otvorite GPU profiler -- GPU nije ni blizu maksimalnog opterecenja. Koristi mozda 40% svog kapaciteta. Pa gde je onda problem?
Otvorite CPU profiler. I tu vidite -- rendering thread je potpuno zagusljen. CPU provodi vecinu svog vremena pripremajuci i salajuci komande GPU-u. GPU ceka. CPU se gusi.
Dobrodosli u svet draw call-ova.
Draw call-ovi su jedan od onih problema koji su potpuno nevidljivi dok vas ne udare. Ne mozete ih videti u viewportu. Ne postoji crveno upozorenje koje iskoci i kaze "imate previse draw call-ova". Scena moze izgledati jednostavno -- par stotina objekata, nista spektakularno -- a opet da ima 15.000 draw call-ova koji guse vas CPU.
Ovo poglavlje je posveceno tome da razumete ovaj problem do kosti, i da naucite svaki alat koji UE5 nudi za njegovo resavanje. Ako ste procitali poglavlje 07 (Render Pipeline) i poglavlje 08 (GPU Arhitektura), vec imate solidne temelje. Sada cemo ih primeniti na jedan od najprakticnijih problema u game developmentu.
Krenimo.
42.1 Sta je Draw Call?
Definicija
Draw call je komanda koju CPU salje GPU-u sa instrukcijom: "Nacrtaj ovaj mesh, sa ovim materijalom, na ovoj poziciji u svetu."
To je to. Na najvisem nivou apstrakcije, draw call je upravo to -- jedna instrukcija za crtanje. Ali kao sto cemo videti, djavao je u detaljima.
Anatomija jednog draw call-a
Hajde da razlozimo sta se zapravo dogadja kada CPU treba da naredi GPU-u da nacrta jedan objekat -- recimo, jednu drvenu kutiju na podu vase scene.
Pre nego sto GPU moze da nacrta tu kutiju, CPU mora da uradi sledece:
- Postavi vertex buffer -- kaze GPU-u odakle da cita podatke o temenima (verteksima) tog mesh-a
- Postavi index buffer -- kaze GPU-u u kojem redosledu da povezuje ta temena u trouglove
- Postavi shader program -- kaze GPU-u koji vertex shader i pixel shader da koristi (tj. koji materijal da primeni)
- Postavi teksture -- binduje sve teksture koje taj materijal koristi (diffuse, normal, roughness, itd.) na odgovarajuce texture slot-ove
- Postavi uniform/constant buffer -- uploaduje parametre specifigne za ovaj objekat (World transformacija matrica, boja materijala, custom parametri, itd.)
- Postavi render state -- blending mode, depth testing, stencil state, face culling, itd.
- Izda draw komandu -- konacno, kaze GPU-u "nacrtaj"
CPU priprema za jedan draw call:
SetVertexBuffer(kutija_vertices) // Koji mesh?
SetIndexBuffer(kutija_indices) // Koji trouglovi?
SetShaderProgram(wood_shader) // Koji shader/materijal?
SetTexture(0, wood_diffuse) // Koja diffuse tekstura?
SetTexture(1, wood_normal) // Koja normal mapa?
SetTexture(2, wood_roughness) // Koja roughness mapa?
SetConstantBuffer(world_matrix, ...) // Gde u svetu?
SetRenderState(opaque, depth_test_on) // Kako crtati?
DrawIndexed(num_triangles) // NACRTAJ!
Vidite li obrazac? Sama komanda DrawIndexed na kraju je trivijalna -- to je bukvalno jedno pozivanje funkcije. Ali svih sedam koraka pre nje? To je ono sto kosta.
Draw call sam po sebi je jeftin -- state changes su skupi
Ovo je mozda najvaznija recenica u celom poglavlju, pa je ponovimo:
Sam draw call je brz. Promena stanja (state change) koja ga okruzuje je skupa.
Kada kazemo "draw call-ovi su skupi", mi zapravo mislimo na sav taj setup koji prethodi svakom draw call-u. Svaki put kada CPU menja koji mesh se koristi, ili koji shader, ili koje teksture -- to je state change. I svaki state change ima svoju cenu.
Zasto? Zato sto svaka promena stanja zahteva:
- Validaciju na strani drajvera -- graficki drajver (NVIDIA, AMD, Intel) mora da proveri da li je novo stanje validno, da li su svi resursi dostupni, da li postoji konflikt
- Azuriranje internih tabela -- GPU mora da azurira svoje interne reference na buffer-e, teksture, shader programe
- Potencijalni pipeline flush -- u nekim slucajevima, promena stanja zahteva da GPU zavrsi sav trenutni posao pre nego sto moze da prihvati novo stanje (ovo je najskuplja situacija)
Zamislite to kao fabriku za proizvodnju automobila. Sam proces montiranja jednog automobila je brz kada je linija podesnea. Ali ako za svaki automobil morate da promenite alate, boju, delove -- svaka ta promena zahteva zaustavljanje linije, zamenu opreme, i ponovo pokretanje. "Presvlacenje" linije je skupo, ne sama montaza.
CPU priprema, GPU izvrsava
Zapamtite ovo jasno (i ako ste procitali poglavlje 08, ovo ce vam biti poznato):
- CPU je odgovoran za pripremu draw call-ova -- odlucuje sta se crta, priprema podatke, puni command buffer
- GPU je odgovoran za izvrsavanje draw call-ova -- zapravo crta piksele na ekranu
Ovo znaci da problem sa draw call-ovima je CPU problem, ne GPU problem. Vas GPU moze biti najjaci na svetu, ali ako CPU ne moze da pripremi dovoljno draw call-ova na vreme, GPU ce sedeti i cekati.
U profajleru, ovo izgleda ovako:
CPU: ████████████████████████░░░░░░ (rendering thread zauzet 80% vremena)
GPU: ██████░░░░░░░░░░░░░░░░░░░░░░░ (GPU zauzet samo 25% vremena)
GPU CEKA CPU!
Ovo je klasicna slika CPU-bound scenarija uzrokovanog prevelikim brojem draw call-ova. GPU ima kapacitet da renderuje mnogo vise, ali CPU ga ne moze hraniti dovoljno brzo.
42.2 Zasto su Draw Calls skupi -- Detaljno
Sada kada znamo sta je draw call, hajde da detaljno razumemo zasto je skup. Ovo znanje je kljucno za razumevanje svih optimizacionih tehnika koje slede.
42.2.1 CPU overhead: Drajver kao posrednik
Izmedju vaseg koda (ili engine-a) i GPU-a stoji graficki drajver (graphics driver). Drajver je softverski sloj koji prevodi API pozive (DirectX, Vulkan, OpenGL) u instrukcije koje konkretni GPU razume.
Svaki put kada vas engine pozove neku DirectX ili Vulkan funkciju, drajver mora da:
- Validira parametre -- da li je ovaj buffer zaista alociiran? Da li je ovaj shader kompajliran? Da li su sve teksture u validnom stanju?
- Prevede poziv -- DirectX API je genricki, ali svaki GPU (NVIDIA GeForce, AMD Radeon, Intel Arc) ima razlicitu internu arhitekturu. Drajver mora da prevede genericke pozive u hardware-specifine komande.
- Puni command buffer -- drajver pakuje komande u buffer koji ce se poslati GPU-u. Ovaj buffer se zove command buffer (ili command list u DX12 terminologiji).
- Upravlja resursima -- prati koji resursi su u upotrebi, gde se nalaze u memoriji, da li treba nesto da se premesti iz sistemskog RAM-a u VRAM.
Sve ovo trosi CPU cikluse. I sto je kriticno -- u tradicionalnim API-jima kao sto su DirectX 11 i OpenGL, ovo se sve desava na jednoj niti (single-threaded). To znaci da bez obzira koliko CPU jezgara imate, sav ovaj posao ide kroz jedno usko grlo.
Tradicionalni API (DX11/OpenGL):
Thread 0 (Rendering): ████████████████████████████████ (100% zauzet)
Thread 1: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ (slobodan)
Thread 2: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ (slobodan)
Thread 3: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ (slobodan)
...
Samo jedna nit radi sav rendering posao!
42.2.2 State Changes: Pravi krivac
Kao sto smo vec pomenuli, draw call sam po sebi je brz. Promena stanja je skupa. Ali nisu sve promene stanja jednako skupe. Evo grubog rangiranja, od najskuplje do najjeftinije:
| Promena stanja | Relativna cena | Objasnjenje |
|---|---|---|
| Promena Render Target-a | ★★★★★ | GPU mora da flushuje pipeline, sacuva trenutni render target, ucita novi |
| Promena Shader programa | ★★★★ | GPU mora da ucita novi shader u izvrsne jedinice, resetuje registre |
| Promena tekstura | ★★★ | GPU mora da azurira texture descriptor-e, potencijalno ucita teksturu iz RAM-a u kes |
| Promena vertex/index buffer-a | ★★ | Relativno jeftino -- samo azurira pointer na podatke |
| Promena constant buffer-a (uniformi) | ★ | Najjeftinije -- mali transfer podataka |
Primetite nesto vazno: promena shader programa (tj. promena materijala) je medju najskupljim operacijama. Ovo je direktna veza sa temom ovog poglavlja -- svaki razlicit materijal u vasoj sceni potencijalno zahteva skup state change.
42.2.3 DX11 vs DX12/Vulkan: Razlika u overhead-u
Razlika izmedju "starijih" i "novijih" grafickih API-ja je fundamentalna za razumevanje draw call problematike.
DX11 / OpenGL -- Visok per-call overhead
DirectX 11 i OpenGL su high-level API-ji sa debelim slojem apstrakcije. Drajver radi ogroman posao za vas:
- Automatski upravlja memorijom (alokacije, dealokacije, transferi)
- Automatski prati zavisnosti izmedju resursa
- Automatski validira svaki poziv
- Automatski sinhronizuje CPU i GPU
Ovo je udobno za programera, ali ima cenu: svaki API poziv prolazi kroz debeo sloj drajverskog koda. Za 5.000 draw call-ova, to je 5.000 puta prolazak kroz ceo taj sloj. Na DX11, svaki draw call moze da kosta negde izmedju 5 i 20 mikrosekundi CPU vremena (zavisno od kompleksnosti state change-a i drajvera). Na prvi pogled to zvuci malo, ali:
5.000 draw calls x 10 us (mikrosekundi) prosecno = 50.000 us = 50 ms
Za 60 FPS, imate samo 16.67 ms po frejmu!
50 ms samo za pripremu draw call-ova = nemoguci 60 FPS.
DX12 / Vulkan -- Nizak per-call overhead
DirectX 12 i Vulkan su low-level API-ji koji prebacuju mnogo odgovornosti na programera (tj. na engine):
- Vi upravljate memorijom (alokacije, layouti, barijere)
- Vi pratite zavisnosti izmedju resursa
- Validacija je minimalna (greske u kodu = crash ili artefakti, bez lepih error poruka)
- Vi eksplicitno sinhronizujete CPU i GPU
Rezultat: drajverski overhead po draw call-u je dramaticno manji. Svaki draw call moze da kosta samo 1-3 mikrosekunde. Ali -- i ovo je kriticno -- overhead nije nula. Cak i sa DX12/Vulkan, 20.000 draw call-ova ce vas kostati:
20.000 draw calls x 2 us prosecno = 40.000 us = 40 ms
I dalje je to previse za 60 FPS!
Dakle, DX12/Vulkan vam daju vise prostora, ali ne eliminisu problem draw call-ova u potpunosti. Takodje, DX12 omogucava multithreaded command recording -- vise CPU niti moze paralelno da priprema komande, sto dramaticno poboljsava skalabilnost.
DX12/Vulkan multithreaded:
Thread 0: ████████░░░░░░░░ (25% zauzet -- priprema draw calls 0-2499)
Thread 1: ████████░░░░░░░░ (25% zauzet -- priprema draw calls 2500-4999)
Thread 2: ████████░░░░░░░░ (25% zauzet -- priprema draw calls 5000-7499)
Thread 3: ████████░░░░░░░░ (25% zauzet -- priprema draw calls 7500-9999)
Isti posao, ali podeljen na 4 niti!
UE5 koristi RHI (Rendering Hardware Interface) koji apstrahuje razlike izmedju API-ja. Na Windows-u, UE5 primarno koristi DX12 (mada podrzava i DX11 za stariji hardver). Na konzolama koristi native API-je. Poenta je -- UE5 vec koristi DX12 gde moze, ali vi i dalje morate paziti na broj draw call-ova.
42.2.4 Drajver vs Engine overhead
Vazno je razlikovati dva tipa overhead-a:
Drajver overhead -- vreme koje drajver (NVIDIA/AMD/Intel softver) trosi na validaciju, prevod i slanje komandi GPU-u. Ovo je ono sto DX12 smanjuje.
Engine overhead -- vreme koje sam Unreal Engine trosi na pripremu podataka za svaki draw call. Ovo ukljucuje:
- Frustum culling (provera da li je objekat u vidnom polju kamere)
- Occlusion culling (provera da li je objekat zaklonjen)
- Sortiranje objekata po materijalu i po dubini
- Priprema per-object constant buffer-a (matrice transformacije, parametri)
- Prolazak kroz scene graph i sakupljanje vidljivih objekata
Ovaj engine overhead postoji bez obzira koji API koristite. Cak i sa DX12, Unreal i dalje mora da prodje kroz svaki objekat i pripremi podatke. Ovo je razlog zasto Nanite (poglavlje 30) predstavlja tako radikalnu promenu -- on ne samo da smanjuje drajver overhead, vec eliminise i veliki deo engine overhead-a prebacivanjem posla na GPU.
42.3 Koliko je previse? Brojke i benchmarks
"Koliko draw call-ova je previse?" -- ovo je pitanje koje svaki developer postavi. I odgovor je, naravno: zavisi.
42.3.1 Faktori koji uticu na limit
Limit draw call-ova zavisi od:
- CPU brzine -- brzi CPU = vise draw call-ova moze da pripremi u 16.67 ms (za 60 FPS)
- Grafickog API-ja -- DX12/Vulkan imaju manji overhead po draw call-u nego DX11/OpenGL
- Kompleksnosti state change-ova -- mnogo razlicitih materijala = skuplje nego mnogo objekata sa istim materijalom
- Engine overhead-a -- koliko posla engine radi po objektu (culling, sorting, itd.)
- Ciljnog frame rate-a -- 30 FPS vam daje duplo vise vremena nego 60 FPS
- Sta jos CPU radi -- gameplay logika, fizika, AI, audio -- sve to deli CPU vreme sa rendering thread-om
42.3.2 Okvirne brojke
Evo nekih okvirnih smernica, ali zapamtite -- ovo su samo orijentacione vrednosti, ne apsolutna pravila:
| API / Platforma | Okvirni limit (60 FPS) | Komentar |
|---|---|---|
| DX11 (mid-range CPU) | ~2.000 - 4.000 | Tradicionalni limit, jednoniten rendering |
| DX11 (high-end CPU) | ~4.000 - 6.000 | Brzi CPU pomaze, ali jednoniten je i dalje problem |
| DX12 (mid-range CPU) | ~5.000 - 10.000 | Manji per-call overhead, multithreading pomaze |
| DX12 (high-end CPU) | ~10.000 - 20.000+ | Moze i vise, ali engine overhead i dalje postoji |
| Konzole (PS5, Xbox Series X) | ~5.000 - 15.000 | Native API, optimizovani drajveri |
| Mobilne platforme | ~500 - 2.000 | Veoma ograniceni CPU-ji, OpenGL ES overhead |
Za 30 FPS, mozete grube otprilike da udvostrucite ove brojke, posto imate duplo vise vremena po frejmu.
42.3.3 UE5 sa Nanite vs bez Nanite
Evo kljucne razlike koja je specificna za UE5:
Bez Nanite (tradicionalni pipeline):
- Svaki mesh u sceni = jedan ili vise draw call-ova (jedan po material slot-u)
- Mesh sa 3 materijala = 3 draw call-a
- 1.000 mesh-eva sa prosecno 2 materijala = 2.000 draw call-ova minimum
Sa Nanite:
- Nanite geometrija koristi GPU-driven rendering pipeline (detaljno obradjen u poglavlju 30)
- CPU salje minimalne podatke GPU-u -- u sustini, samo listu Nanite instanci
- GPU sam odlucuje sta je vidljivo, koliko detalja da prikaze, i sam izdaje interne "draw" komande
- Rezultat: hiljade Nanite mesh-eva moze da ima overhead od samo par draw call-ova sa CPU strane
- Ali: non-Nanite objekti (transparentni materijali, skeletal mesh-evi, VFX, itd.) i dalje koriste tradicionalni pipeline
Prakticna implikacija: u tipicnom UE5 projektu, Nanite vam resava problem draw call-ova za staticnu geometriju (zgrade, teren, kamenje, namestaj, itd.), ali morate i dalje paziti na draw call-ove od non-Nanite objekata.
42.3.4 Kako videti broj draw call-ova u UE5
Najbrzi nacin da vidite koliko draw call-ova vasa scena ima:
Metoda 1: stat scenerendering
Unesite u konzolu (tilde taster ~ ili apostof taster, zavisno od tastature):
stat scenerendering
Ovo prikazuje, izmedju ostalog:
Mesh draw calls: 3247 // <-- Ovo vas zanima
Num Primitives: 1203847
Metoda 2: stat RHI
stat RHI
Prikazuje:
DrawPrimitive calls: 4521
Triangles drawn: 2847291
Metoda 3: Viewport statistika
U editoru, kliknite na strelicu pored Lit u viewportu i izaberite Stat > Advanced > Draw Calls. Ovo prekriva viewport sa brojem draw call-ova.
Metoda 4: RenderDoc ili PIX
Za najdetaljniju analizu, mozete koristiti eksterne alate kao sto su RenderDoc (besplatan, open-source) ili PIX (Microsoft-ov alat za DX12). Oni vam omogucavaju da vidite svaki pojedinacni draw call, sa svim state change-ovima, i da izmerite koliko svaki kosta.
RenderDoc capture jednog frejma:
Draw Call #1: SetShader(M_Wood), SetTexture(T_Wood_D), Draw(Cube_01) -- 3.2 us
Draw Call #2: SetConstantBuffer(Transform_02), Draw(Cube_02) -- 0.8 us (isti shader!)
Draw Call #3: SetShader(M_Metal), SetTexture(T_Metal_D), Draw(Pipe_01) -- 4.1 us (shader change!)
Draw Call #4: SetConstantBuffer(Transform_04), Draw(Pipe_02) -- 0.9 us (isti shader)
...
Primetite u primeru iznad: draw call #2 je mnogo jeftiniji od #1 jer koristi isti shader -- nema skupe promene shader programa. Draw call #3 je skup jer menja shader. Ovo je razlog zasto je sortiranje po materijalu tako vazno -- ako grupisete sve objekte sa istim materijalom, smanjujete skupe state change-ove.
42.3.5 Pravilo palca
Ako vas zanima brza, pragmaticna smernica za UE5 projekte:
- Non-Nanite draw calls ispod 3.000 -- uglavnom ste bezbedni za 60 FPS na decent hardveru
- Izmedju 3.000 i 5.000 -- moguce je okej, ali profajlirajte na ciljnom hardveru
- Iznad 5.000 -- verovatno imate problem, narocito na konzolama i slabijim PC-jevima
- Iznad 10.000 -- definitivno problem, morate optimizovati
Ali ponavljam: uvek profajlirajte. Broj sam po sebi ne znaci nista bez konteksta. 5.000 draw call-ova sa istim materijalom moze biti brze od 2.000 draw call-ova sa 2.000 razlicitih materijala.
42.4 Instancing -- Isto nacrtaj mnogo puta, jeftino
Instancing je prva i jedna od najefektivnijih tehnika za smanjenje draw call-ova. Princip je jednostavan: ako imate isti mesh sa istim materijalom na vise mesta u sceni, umesto da izdajete zaseban draw call za svaki -- izdajete jedan draw call koji kaze GPU-u "nacrtaj ovaj mesh N puta, evo N transformacija (pozicija/rotacija/skala)".
42.4.1 Hardware Instancing -- Kako radi na GPU-u
Na najnizem nivou, hardware instancing koristi specijalne GPU feature-e koji omogucavaju efikasno ponavljanje iste geometrije.
Bez instancinga:
Draw Call 1: SetMesh(tree), SetMaterial(M_Tree), SetTransform(pos_1), Draw()
Draw Call 2: SetMesh(tree), SetMaterial(M_Tree), SetTransform(pos_2), Draw()
Draw Call 3: SetMesh(tree), SetMaterial(M_Tree), SetTransform(pos_3), Draw()
...
Draw Call 1000: SetMesh(tree), SetMaterial(M_Tree), SetTransform(pos_1000), Draw()
= 1000 draw calls, 1000 state setups
Sa instancingom:
Draw Call 1: SetMesh(tree), SetMaterial(M_Tree),
SetInstanceBuffer([pos_1, pos_2, ..., pos_1000]),
DrawInstanced(1000)
= 1 draw call, 1 state setup, 1000 instanci
GPU prima jedan draw call i interno pokrece vertex shader 1.000 puta, svaki put sa drugom transformacijom iz instance buffer-a. Ovo je izuzetno efikasno jer:
- Nema 999 dodatnih state change-ova -- mesh i materijal se postavljaju samo jednom
- Nema 999 dodatnih CPU-GPU komunikacija -- sve ide u jednom paketu
- GPU je dizajniran za ovo -- masovno paralelno izvrsavanje istog posla sa razlicitim podacima je upravo ono u cemu GPU briljira (vidite poglavlje 08, SIMD/SIMT model)
42.4.2 Per-Instance Data
Hardware instancing ne mora da se ogranici samo na transformaciju (pozicija/rotacija/skala). Svaka instanca moze imati custom per-instance data -- dodatne podatke koji se razlikuju od instance do instance:
- Boja -- svaka instanca drveta moze imati drugaciju nijansu zelene
- Wind offset -- svaka instanca moze drugacije reagovati na vetar
- Health/Damage -- svaka instanca moze prikazivati razlicit nivo ostecenja
- Custom float parametri -- bilo sta sto vam treba
U UE5, per-instance custom data se postavlja preko CustomDataFloat na HISM/ISM komponentama, i cita u materijalu preko PerInstanceCustomData node-a.
Material Graph:
[PerInstanceCustomData Index: 0] ---> [Lerp A: Green, B: Brown] ---> [Base Color]
Svaka instanca moze da ima razlicitu boju, a opet je to JEDAN draw call!
42.4.3 ISM -- Instanced Static Mesh Component
U UE5, InstancedStaticMeshComponent (ISM) je komponenta koja vam omogucava da dodate mnogo instanci istog static mesh-a u jednu komponentu. Sve instance se crtaju u jednom (ili malom broju) draw call-ova.
Kako koristiti ISM u Blueprint-u:
- Dodajte
InstancedStaticMeshComponentna vas Actor - U Blueprint-u ili C++-u pozovite
AddInstance(FTransform)za svaku instancu - Sve instance dele isti mesh i materijal
- Engine ih crta u jednom draw call-u (ili malom broju, zavisno od internog batching-a)
// C++ primer
UInstancedStaticMeshComponent* ISM = CreateDefaultSubobject<UInstancedStaticMeshComponent>("ISM");
ISM->SetStaticMesh(TreeMesh);
ISM->SetMaterial(0, TreeMaterial);
for (int32 i = 0; i < 1000; i++)
{
FTransform Transform;
Transform.SetLocation(FVector(FMath::RandRange(-5000, 5000),
FMath::RandRange(-5000, 5000), 0));
Transform.SetRotation(FRotator(0, FMath::RandRange(0, 360), 0).Quaternion());
ISM->AddInstance(Transform);
}
// Rezultat: 1000 drveca, ~1 draw call
Prednosti ISM-a:
- Drasticno smanjen broj draw call-ova
- Jednostavan za upotrebu
- Per-instance custom data
Ogranicenja ISM-a:
- Nema per-instance culling -- sve instance se crtaju ili nijedna (cela komponenta je jedna culling jedinica)
- Nema automatskog LOD-a -- sve instance koriste isti LOD nivo
- Ovo znaci da ako imate 10.000 instanci rasutih po velikom svetu, GPU ce crtati sve njih cak i ako je vecina van ekrana
Ovo ogranicenje je razlog zasto postoji HISM.
42.4.4 HISM -- Hierarchical Instanced Static Mesh Component
HierarchicalInstancedStaticMeshComponent (HISM) je napredna verzija ISM-a koja resava kljucna ogranicenja:
-
Hijerarhijski culling -- HISM organizuje instance u prostornu hijerarhiju (cluster tree). Engine moze da efikasno odbaci citave grupe instanci koje nisu vidljive, bez da proverava svaku pojedinacno.
-
Per-instance LOD -- svaka instanca moze da koristi drugaciji LOD nivo na osnovu svoje udaljenosti od kamere. Daleka drveca koriste LOD2, bliza LOD1, najbliza LOD0.
-
Per-instance occlusion -- instance koje su iza zida ili brda se ne crtaju.
ISM (Instanced Static Mesh):
CPU: "GPU, nacrtaj svih 10.000 instanci"
GPU: Crta svih 10.000, cak i one iza kamere
Problem: Mnogo nepotrebnog posla za GPU
HISM (Hierarchical Instanced Static Mesh):
CPU: Proverava cluster tree, odbacuje nevidljive grupe
CPU: "GPU, nacrtaj ovih 1.200 vidljivih instanci (sa razlicitim LOD-ovima)"
GPU: Crta samo 1.200, sa odgovarajucim LOD-ovima
Rezultat: Mnogo manje posla za GPU, a i dalje malo draw call-ova
Kako HISM interno radi
HISM organizuje instance u stablo klastera (cluster tree). Ovo stablo se gradi automatski kada dodate instance:
[Root Node]
/ \
[Cluster A] [Cluster B]
/ \ / \
[Leaf 1] [Leaf 2] [Leaf 3] [Leaf 4]
(250 inst) (250 inst) (250 inst) (250 inst)
Kada engine radi frustum culling, prolazi kroz ovo stablo odozgo nadole. Ako ceo Cluster A nije u vidnom polju kamere -- odmah odbacuje svih 500 instanci ispod njega, bez da proverava svaku pojedinacno. To je O(log N) kompleksnost umesto O(N).
Za LOD, HISM proverava udaljenost svake vidljive grupe od kamere i dodeljuje odgovarajuci LOD. Razliciti LOD nivoi se crtaju u zasebnim draw call-ovima (jer imaju razlicitu geometriju), ali broj draw call-ova je i dalje dramaticno manji od jednog po instanci.
42.4.5 Foliage System koristi HISM
Ako ste ikada koristili Foliage tool u UE5 (onaj kojim "slikate" travu, drveece, kamenje po terenu), vec ste koristili HISM a da to mozda niste ni znali!
Foliage system interno koristi HISM za svaki tip vegetacije koji dodate. Kada "naslikate" 50.000 busenja trave, engine ne pravi 50.000 zasebnih actor-a -- pravi jednu (ili nekoliko) HISM komponentu sa 50.000 instanci. To znaci umesto 50.000 draw call-ova, mozda imate 5-20, zavisno od broja LOD nivoa i vidljivosti.
Ovo je razlog zasto Foliage tool moze da podnese toliko vegetacije -- bez HISM-a, scena sa 100.000 busenja trave bi bila potpuno nerendabilna.
42.4.6 Kada instancing pomaze, a kada ne
Instancing je mocan, ali nije univerzalno resenje. Evo jasnih smernica:
Instancing POMAZE kada:
- Imate mnogo kopija istog mesh-a sa istim materijalom
- Razlike izmedju instanci su ogranicene na transformaciju i per-instance custom data
- Tipicni primeri: vegetacija, kamenje, stubovi, lampe, ograde, cepovi, municija, predmeti u inventaru
Instancing NE POMAZE (ili ne moze da se primeni) kada:
- Svaki objekat ima razlicit mesh -- ne mozete instancirati razlicite mesh-eve zajedno
- Svaki objekat ima razlicit materijal -- instance moraju deliti isti materijal (ukljucujuci iste teksture). Mozete koristiti per-instance custom data za varijacije, ali sam materijal (shader + teksture) mora biti identican
- Imate samo jednu ili dve kopije mesh-a -- overhead od postavljanja instancing sistema moze biti veci od usted od jednog manje draw call-a
- Objekti su dinamicni na nacin koji zahteva individual updates -- na primer, svaki objekat ima svoju fiziku, destrukciju, itd.
42.4.7 Prakticni primer: Pre i posle instancinga
Zamislite scenu: ulica u gradu, sa 200 ulicnih lampi. Svaka lampa je isti Static Mesh sa istim materijalom.
Bez instancinga:
200 zasebnih StaticMeshActor-a
= 200 draw call-ova (minimum, vise ako lampa ima vise material slot-ova)
+ 200 x frustum culling provera
+ 200 x occlusion culling provera
CPU: Tezak posao
Sa ISM (InstancedStaticMeshComponent):
1 Actor sa ISM komponentom, 200 instanci
= 1 draw call
- Nema per-instance culling (potencijalni problem ako su lampe rasute po velikom prostoru)
CPU: Minimalan posao
Sa HISM (HierarchicalInstancedStaticMeshComponent):
1 Actor sa HISM komponentom, 200 instanci
= 2-5 draw call-ova (zavisno od LOD nivoa i vidljivosti)
+ Efikasan hijerarhijski culling
+ Per-instance LOD
CPU: Minimalan posao, a i GPU radi samo ono sto mora
Za 200 ulicnih lampi, HISM je idealno resenje. Dobijate dramaticno smanjenje draw call-ova (od 200 na 2-5), a zadrzavate efikasan culling i LOD.
42.5 Mesh Merging / Actor Merging
Instancing radi samo kada imate vise kopija istog mesh-a sa istim materijalom. Ali sta ako imate mnogo razlicitih mesh-eva blizu jedan drugome? Tu na scenu stupa mesh merging (spajanje mesh-eva).
42.5.1 Koncept
Mesh merging uzima vise zasebnih static mesh-eva i kombinuje ih u jedan jedini mesh. Ovo je radikalan pristup: umesto da imate 50 razlicitih objekata koji generisu 50 draw call-ova, imate jedan objekat koji generise 1 draw call (ili onoliko draw call-ova koliko razlicitih materijala koristi).
Pre merge-a:
[Sto] [Stolica_1] [Stolica_2] [Stolica_3] [Vaza] [Tanjir_1] [Tanjir_2]
| | | | | | |
v v v v v v v
DC1 DC2 DC3 DC4 DC5 DC6 DC7
= 7 draw call-ova (minimum)
Posle merge-a:
[Merged_DiningSet]
|
v
DC1
= 1 draw call (ako svi dele isti materijal) ili 2-3 (ako imaju razlicite materijale)
42.5.2 Kako merge-ovati mesh-eve u UE5
UE5 nudi nekoliko nacina za mesh merging:
Metoda 1: Merge Actors tool
-
Selektujte vise actor-a u sceni
-
Idite na Window > Developer Tools > Merge Actors (ili pretrazite u meniju)
-
Izaberite jednu od opcija:
- Merge Meshes -- kombinuje mesh-eve u jedan, opciono kombinuje materijale
- Create Proxy Mesh -- pravi pojednostavljenu verziju (proxy) grupe objekata, ukljucujuci automatsko generisanje LOD-a
- Batch -- kombinuje u HISM komponentu umesto jednog mesh-a
-
Podesite opcije (merge materijale u texture atlas, generisi lightmap UV-ove, itd.)
-
Kliknite Merge
Metoda 2: HLOD (Hierarchical Level of Detail)
HLOD je automatiski sistem u UE5 koji merge-uje grupe objekata na velikom rastojanju. Kada se kamera udalji dovoljno, umesto da renderuje 100 zasebnih objekata, engine prikazuje jedan merged mesh sa pojednostavljenom geometrijom i kombinovanim materijalima.
HLOD je narocito koristan za otvorene svetove i koristi se zajedno sa World Partition sistemom (poglavlje 32).
Blizu kamere: [Kuca] [Drvo] [Ograda] [Bunar] = 4+ draw call-a, pun detalj
| | | |
v v v v
Individualni mesh-evi, puni LOD
Daleko od kamere: [HLOD_Proxy] = 1 draw call, smanjen detalj
|
v
Jedan merged mesh, uprosen materijal
42.5.3 Tradeoffs -- Sta dobijate i sta gubite
Mesh merging nije besplatan. Evo svih tradeoff-ova koje morate razumeti:
Prednosti:
- Drasticno manje draw call-ova -- to je ceo smisao
- Manje engine overhead-a -- manje objekata za culling, sorting, itd.
- Potencijalno bolji GPU cache performance -- vertex podaci jednog velikog mesh-a mogu bolje da se keshiraju
Mane:
-
Gubitak individualnog culling-a -- ako merge-ujete 50 objekata u jedan, i samo jedan je vidljiv, GPU i dalje mora da procesira vertex buffer celog merged mesh-a. Rasterizer ce odbaciti trouglove koji nisu na ekranu, ali vertex shader mora da ih obradi.
Merged mesh sa 50 objekata: Kamera vidi samo 5 objekata, ali GPU procesira vertekse svih 50. Nevidljivi trouglovi se odbacuju u clipping fazi, ali vertex shader je vec potrosio vreme na njih. 50 zasebnih objekata: Engine odbacuje 45 nevidljivih na CPU-u (frustum/occlusion culling). GPU procesira samo 5 vidljivih objekata.Ovo je fundamentalni tradeoff: manje draw call-ova (dobro za CPU) vs manje efikasan culling (potencijalno lose za GPU). Merge-ujte samo objekte koji su geografski blizu -- nemojte merge-ovati objekte sa razlicitih krajeva mape.
-
Veca memorija -- merged mesh koristi vise VRAM-a nego zbir originalnih mesh-eva, jer se ne mogu deliti vertex buffer-i izmedju instanci. Ako imate 10 istih stolica, zasebno su to 1 mesh (referenciran 10 puta). Merged -- to je 10 kopija mesh podataka u jednom buffer-u.
-
Nemogucnost pomeranja delova -- merged mesh je monolitan. Ne mozete pomeriti jednu stolicu bez da rebuild-ujete ceo mesh.
-
Komplikovaniji lightmap UV-ovi -- merged mesh treba jedan veliki lightmap koji pokriva sve objekte. Ovo moze zahtevati vecu lightmap rezoluciju ili moze dovesti do artefakata na granicama izmedju originalnih objekata.
-
Duze vreme rebuilda -- svaka promena u sceni zahteva ponovni merge.
42.5.4 Kada merge-ovati, a kada ne
Merge-ujte:
- Male objekte koji su fizicki blizu (npr. dekoracije na stolu, predmeti na polici, delovi ograde)
- Objekte koji se nikada ne pomeraju
- Objekte koji se uvek vide zajedno (ako vidite jedan, verovatno vidite i ostale)
- Interijere soba -- merge-ujte namestaj u sobi u jednu grupu
Ne merge-ujte:
- Objekte koji su rasuti po velikom prostoru (gubite culling efikasnost)
- Objekte koji se pomeraju ili imaju fiziku
- Objekte koji vec koriste instancing (vec imate mali broj draw call-ova)
- Nanite mesh-eve (Nanite ima svoju GPU-driven pipeline, merge nije potreban)
- Objekte sa potpuno razlicitim materijalima (merged mesh ce i dalje imati multiple draw call-ove, po jedan za svaki materijal)
42.5.5 Merge vs Instancing: Kada sta koristiti
| Kriterijum | Instancing (ISM/HISM) | Mesh Merging |
|---|---|---|
| Isti mesh, isti materijal | Idealno | Nepotrebno |
| Razliciti mesh-evi, isti materijal | Ne moze | Dobro |
| Razliciti mesh-evi, razliciti materijali | Ne moze | Ograniceno (merge materijale u atlas) |
| Objekti rasuti po velikom prostoru | HISM (ima culling) | Lose (gubi culling) |
| Objekti grupisani u malom prostoru | ISM dovoljno | Dobro |
| Potreba za pomeranjem delova | ISM (moze update instance) | Ne moze |
| Mnogo kopija (100+) | Idealno | Nepotrebno |
| Malo razlicitih objekata (5-20) | Ne moze (razliciti mesh-evi) | Idealno |
42.6 Nanite kao resenje za Draw Calls
O Nanite-u smo detaljno govorili u poglavlju 30. Ovde cemo se fokusirati iskljucivo na to kako Nanite utice na draw call problematiku.
42.6.1 GPU-Driven Rendering: Paradigmatska promena
Tradicionalni rendering pipeline radi ovako:
Tradicionalni pipeline:
CPU: [Traverse scene] -> [Cull objects] -> [Sort by material] -> [Submit draw calls]
|
v
GPU: [Execute draw calls] -> [Vertex shader] -> [Rasterize] -> [Pixel shader]
CPU radi OGROMNU kolicinu posla. Za 10.000 objekata, CPU mora da
prodje kroz svih 10.000, proveri vidljivost, sortira, pripremi draw calls.
Nanite koristi GPU-driven rendering koji fundamentalno menja ovu dinamiku:
Nanite GPU-driven pipeline:
CPU: [Upload instance list to GPU] (minimalan posao)
|
v
GPU: [GPU visibility test] -> [GPU LOD selection] -> [GPU clustering] -> [GPU rasterize]
CPU salje samo listu instanci (pozicije, materijali).
GPU SAM odlucuje sta je vidljivo, koji LOD da koristi, i kako da rastera.
Razlika u CPU overhead-u je ogromna. Umesto da CPU prolazi kroz svaki objekat i priprema draw call za njega, CPU samo kaze GPU-u "evo, ovo je lista svih Nanite objekata u sceni" -- i GPU preuzima sve ostalo.
42.6.2 Koliko draw call-ova generise Nanite?
Odgovor ce vas mozda iznenaditi: Nanite geometrija se ne renderuje kroz tradicionalne draw call-ove uopste!
Nanite koristi compute shader-e za visibility testing i rasterizaciju. Umesto DrawIndexed() poziva, Nanite koristi Dispatch() pozive za compute shader-e. Rezultat se renderuje u Visibility Buffer koji se zatim koristi u material evaluation fazi.
U praksi, Nanite moze da renderuje scenu sa milionima objekata uz svega nekoliko compute dispatch-ova sa CPU strane. Ovo je razlog zasto Nanite scene mogu imati ogromne kolicine geometrije bez CPU bottleneck-a.
Primer: Soba sa 500 komada namestaja
Bez Nanite:
- 500+ draw call-ova (vise ako mesh-evi imaju multiple material slotove)
- CPU: Frustum culling za svih 500, sortiranje, state setup za svaki
- Vreme: 2-5 ms na CPU (zavisno od kompleksnosti)
Sa Nanite:
- ~2-5 compute dispatch-a (nezavisno od broja objekata!)
- CPU: Minimalan posao -- upload instance data
- Vreme: ~0.1-0.3 ms na CPU
Usteda: 10-50x manje CPU vremena za rendering submission
42.6.3 Non-Nanite objekti: I dalje morate paziti
Nanite nije resenje za sve. Sledeci tipovi objekata i dalje prolaze kroz tradicionalni draw call pipeline:
- Skeletal Mesh-evi (animirani likovi, NPC-ji)
- Transparentni materijali (staklo, voda, VFX)
- Masked materijali sa dithered opacity (vegetacija sa alpha cutout-om -- mada novije verzije UE5 poboljsavaju podrsku za ovo)
- Niagara particle sistemi
- Decals (grafiti, ostecenja, mrlje)
- Dynamic mesh-evi koji se deformisu u runtime-u
Za ove objekte, sve tehnike koje smo diskutovali (instancing, merging, batching) su i dalje potpuno relevantne. U tipicnom projektu, cak i sa agresivnom upotrebom Nanite-a, mozete imati znacajan broj non-Nanite draw call-ova od VFX sistema, likova, transparentnih materijala, itd.
42.6.4 Prakticna strategija za UE5 projekte
Evo preporucene strategije za minimizaciju draw call-ova u UE5 projektu:
- Svu staticnu, opaque geometriju prebacite na Nanite -- zgrade, teren (Nanite podrzava Landscape od UE5.2+), kamenje, namestaj, dekoracije, industrijski elementi
- Za vegetaciju koristite HISM -- Foliage tool to vec radi automatski. Za Nanite-enabled vegetaciju, Nanite preuzima rendering. Za non-Nanite vegetaciju, HISM pruza efikasan instancing
- Transparentne objekte minimizujte -- svaki transparentni objekat je non-Nanite draw call. Gde mozete, koristite dithered opacity (masked) umesto prave transparencije
- Particle sisteme optimizujte -- koristite GPU particles (Niagara GPU Simulation) umesto CPU particles gde mozete. Merge-ujte slicne emittere
- Profajlirajte non-Nanite draw calls -- koristite
stat scenerenderingda vidite koliko draw call-ova dolazi od non-Nanite objekata, i ciljajte ta mesta za optimizaciju
42.7 Auto-Instancing u UE5
UE5 ima ugradjeni mehanizam koji automatski prepoznaje identicne mesh-eve sa identicnim materijalima i batch-uje ih u jednu instanced draw call -- bez ikakvog dodatnog rada sa vase strane. Ovo se zove auto-instancing.
42.7.1 Kako auto-instancing radi
Kada UE5 rendering sistem prolazi kroz listu objekata za renderovanje, on trazi grupe objekata koje imaju:
- Identican static mesh (ista geometrija)
- Identican materijal (isti parent materijal, iste teksture, isti parametri -- ili Material Instance istog parent-a sa istim parametrima koji nisu per-instance)
- Isti render state (isto osvetljenje, isti shadow settings, itd.)
Kada pronadje takvu grupu, umesto da izdaje zaseban draw call za svaki objekat, engine ih automatski batch-uje u jednu instanced draw.
42.7.2 Uslovi za auto-instancing
Auto-instancing nece raditi ako se objekti razlikuju u bilo cemu od sledeceg:
- Razlicit mesh -- ocigledno, razliciti mesh-evi se ne mogu instancirati zajedno
- Razlicit materijal (parent) -- dva razlicita materijala ne mogu biti u istom batch-u
- Razliciti Material Instance parametri -- ako jedan Material Instance ima Roughness=0.5 a drugi Roughness=0.8, ne mogu biti u istom batch-u (osim ako su ti parametri implementirani kao per-instance custom data)
- Razliciti mobility tipovi -- Static i Movable actor-i se ne batch-uju zajedno
- Razliciti shadow settings -- ako jedan objekat baca senku a drugi ne, ne mogu biti u istom batch-u
- Custom depth/stencil -- razliciti custom stencil setovi razbijaju batch
Auto-instancing primer:
Scena sa 100 StaticMeshActor-a:
- 50 koristi Mesh_A sa Material_1 -> Batch 1: 50 instanci, 1 draw call
- 30 koristi Mesh_A sa Material_2 -> Batch 2: 30 instanci, 1 draw call
- 10 koristi Mesh_B sa Material_1 -> Batch 3: 10 instanci, 1 draw call
- 10 koristi Mesh_B sa Material_3 -> Batch 4: 10 instanci, 1 draw call
Ukupno: 4 draw call-a umesto 100!
42.7.3 Kako verifikovati da auto-instancing radi
Postoji vise nacina da proverite da li auto-instancing radi u vasoj sceni:
Metoda 1: stat scenerendering
Ukljucite stat scenerendering i posmatrajte Mesh draw calls. Ako auto-instancing radi, ovaj broj ce biti znacajno manji od ukupnog broja mesh-eva u sceni.
Metoda 2: RenderDoc / PIX
Uhvatite jedan frejm u RenderDoc-u. Pronadjite draw call-ove i proverite InstanceCount parametar. Ako je veci od 1, znate da je instancing aktivan za taj draw call.
Metoda 3: Freeze rendering i brojanje
U editoru mozete koristiti FreezeRendering komandu da zamrznete rendering u trenutnom stanju, a zatim koristiti stat scenerendering da vidite brojeve.
Metoda 4: Konzolna promenljiva
r.MeshDrawCommands.DynamicInstancing 1 // Ukljuceno (default u UE5)
r.MeshDrawCommands.DynamicInstancing 0 // Iskljuceno (za poredjenje)
Probajte da iskljucite auto-instancing i uporedite broj draw call-ova sa i bez njega. Razlika ce vam jasno pokazati koliko auto-instancing pomaze.
42.7.4 Kako maksimizirati auto-instancing
Evo prakticnih saveta za maksimiziranje efikasnosti auto-instancinga:
-
Koristite Material Instances umesto zasebnih materijala. 10 Material Instance-a istog parent materijala sa istim parametarskim vrednostima ce se auto-instancirati. 10 zasebnih kopija materijala -- nece, cak i ako izgledaju identicno.
-
Standardizujte mesh-eve -- ako imate 5 varijacija jednog zida, a razlika je samo u teksturi, razmislite da koristite jedan mesh sa Material Instance parametrima za varijaciju, umesto 5 razlicitih mesh-eva.
-
Ujednacite settings -- pobrinite se da svi objekti istog tipa imaju iste shadow settings, mobility, i rendering options. Jedna stolica sa
Cast Shadow = truei druga saCast Shadow = falsenece biti u istom batch-u. -
Minimizujte per-object uniqueness -- svaka razlika izmedju dva naizgled identicna objekta moze da razbije batch. Pregledajte properties i uklonite nepotrebne razlike.
42.8 Uticaj materijala na Draw Calls
Materijali imaju direktan i ogroman uticaj na broj draw call-ova. Ovo je tema koja se direktno nadovezuje na poglavlje 22 (UE5 Material System), ali ovde je posmatramo iskljucivo kroz prizmu draw call optimizacije.
42.8.1 Fundamentalno pravilo: Razlicit materijal = Potencijalni state change
Svaki put kada GPU treba da predje sa jednog materijala na drugi, to zahteva state change:
- Ucitavanje novog shader programa
- Bindovanje novih tekstura
- Postavljanje novih parametara
Sto vise jedinstvenih materijala imate u sceni, to vise state change-ova, to vise draw call-ova (jer se objekti sa razlicitim materijalima ne mogu batch-ovati zajedno).
Scena A: 1.000 objekata, 5 materijala
- Prosecno 200 objekata po materijalu
- Auto-instancing + sortiranje: ~5-20 draw call-ova
- Efikasno!
Scena B: 1.000 objekata, 500 materijala
- Prosecno 2 objekta po materijalu
- Skoro nikakav batching: ~500-1.000 draw call-ova
- Vrlo neefikasno!
42.8.2 Material Instances: Varijacije bez dodatnih draw call-ova (uslovno)
Material Instance je varijacija parent materijala. Kljucna stvar: Material Instances istog parent materijala koriste ISTI shader program. Razlika je samo u parametrima (boja, roughness, teksture, itd.).
Ovo znaci da prelazak sa jednog Material Instance-a na drugi istog parent-a zahteva manji state change nego prelazak izmedju dva potpuno razlicita materijala:
Razliciti parent materijali:
M_Wood -> M_Metal
= Promena shader programa (SKUPO) + promena tekstura + promena parametara
Material Instances istog parent-a:
MI_Wood_Oak -> MI_Wood_Pine
= Promena tekstura + promena parametara (isti shader ostaje!)
Ali vazno upozorenje: cak i Material Instances sa razlicitim teksturama ili parametrima ne mogu biti u istom instanced draw call-u (auto-instancing). Oni mogu da smanje cenu state change-a, ali ne eliminisu draw call. Za pravi instancing, instance moraju imati identican materijal sa identicnim parametrima.
Izuzetak: parametri implementirani kao per-instance custom data mogu da variraju izmedju instanci bez razbijanja batch-a. Ovo je tehnika koju smo opisali u sekciji 42.4.2.
42.8.3 Texture Atlasing -- Vise tekstura u jednoj
Texture atlas je tehnika gde se vise manjih tekstura kombinuje u jednu veliku teksturu. Umesto da imate 10 zasebnih diffuse tekstura za 10 razlicitih materijala, imate jednu veliku teksturu koja sadrzi sve, a UV koordinate svakog mesh-a su pomerene da referenciraju odgovarajuci deo atlas-a.
Bez atlasa:
Materijal 1: [Drvo_Diffuse.png] [Drvo_Normal.png] -> Zaseban materijal
Materijal 2: [Kamen_Diffuse.png] [Kamen_Normal.png] -> Zaseban materijal
Materijal 3: [Metal_Diffuse.png] [Metal_Normal.png] -> Zaseban materijal
= 3 razlicita materijala, 3 draw call-a minimum
Sa atlasom:
Atlas materijal: [Atlas_Diffuse.png] [Atlas_Normal.png] -> JEDAN materijal
Drvo je na UV (0,0)-(0.33,1)
Kamen je na UV (0.33,0)-(0.66,1)
Metal je na UV (0.66,0)-(1,1)
= 1 materijal, 1 draw call!
Prednosti atlasinga:
- Drasticno manje materijala = manje draw call-ova
- Moguce da se batch-uje sve sa jednim draw call-om
Mane atlasinga:
- Manja rezolucija po teksturi -- delite prostor jedne teksture izmedju vise objekata
- Tiling ne radi -- ne mozete tile-ovati teksture unutar atlas-a jer bi prelazile u prostor susedne teksture (postoji resenje sa padding-om i clamp-om, ali je komplikovano)
- Bleeding artefakti -- na granicama tekstura unutar atlas-a mogu se pojaviti artefakti, narocito pri manjim mip nivoima. Padding izmedju tekstura ublazava ovo, ali ne eliminise potpuno
- Kompleksniji workflow -- zahteva dodatne alate za generisanje atlas-a i azuriranje UV-ova
- Manje fleksibilno -- promena jedne teksture zahteva regenerisanje celog atlas-a
UE5 Merge Actors tool ima opciju za automatsko kreiranje texture atlasa pri merge-ovanju mesh-eva. Ovo je najlaksi nacin za atlasing u UE5.
42.8.4 Strategija za minimizaciju materijala
Evo proverene strategije koja balansira vizuelni kvalitet i efikasnost draw call-ova:
-
Napravite "master" materijale -- kreirajte mali broj fleksibilnih parent materijala koji mogu da pokriju mnogo razlicitih izgleda. Na primer, jedan
M_Surface_Masterkoji podrzava drvo, kamen, metal, plastiku -- zavisno od tekstura i parametara. -
Koristite Material Instances za sve varijacije -- umesto da pravite novi materijal za svaku novu povrsinu, napravite Material Instance vaseg master materijala i promenite parametre.
-
Minimizujte broj aktivnih material slotova -- svaki material slot na mesh-u generise zaseban draw call. Mesh sa 5 material slotova = 5 draw call-ova. Gde mozete, kombinujte u jedan slot sa jednim atlasom.
-
Per-instance custom data za varijacije boja -- umesto zasebnih Material Instance-a za crvene, plave i zelene stolice, koristite jedan materijal sa per-instance custom data koji kontrolise boju. Sve stolice ostaju u istom batch-u.
-
Texture arrays za varijacije tekstura -- napredna tehnika gde koristite texture array umesto zasebnih tekstura. Per-instance custom data bira index u array-u. Ovo omogucava razlicite teksture bez razbijanja batch-a, ali zahteva da sve teksture imaju istu rezoluciju.
Primer "master" materijal pristupa:
Tradicionalno:
M_Wood_Floor -> Parent: M_Wood_Floor (zaseban shader)
M_Wood_Wall -> Parent: M_Wood_Wall (zaseban shader)
M_Stone_Floor -> Parent: M_Stone_Floor (zaseban shader)
M_Stone_Wall -> Parent: M_Stone_Wall (zaseban shader)
= 4 razlicita shader programa, nikakav batching
Master materijal pristup:
MI_Wood_Floor -> Parent: M_Surface_Master (ISTI shader)
MI_Wood_Wall -> Parent: M_Surface_Master (ISTI shader)
MI_Stone_Floor -> Parent: M_Surface_Master (ISTI shader)
MI_Stone_Wall -> Parent: M_Surface_Master (ISTI shader)
= 1 shader program, state change pri prelasku izmedju instance-a je jeftiniji
42.8.5 Material Slots na Mesh-u: Svaki slot = Draw Call
Ovo je detalj koji mnogi developeri previde: svaki material slot na mesh-u generise zaseban draw call. Mesh sa 3 material slota generise 3 draw call-a, bez obzira na to da li su svi slotovi isti materijal ili ne.
Mesh "Kuca":
Slot 0: M_Zidovi (cigla) -> Draw Call 1
Slot 1: M_Krov (crep) -> Draw Call 2
Slot 2: M_Prozori (staklo) -> Draw Call 3
Slot 3: M_Vrata (drvo) -> Draw Call 4
= 4 draw call-a po instanci kuce!
100 kuca = 400 draw call-ova (sa auto-instancingom moze biti manje,
ali i dalje 4x vise nego da je mesh imao 1 slot)
Preporuka: u fazi modelovanja, minimizujte broj material slotova. Koristite texture atlas da svedete sve povrsine na jedan materijal gde je to vizuelno prihvatljivo. Za props (manje objekte), ciljajte 1-2 material slota. Za vece objekte (zgrade), 3-4 slota je razumno.
42.9 Prakticna optimizacija -- Od problema do resenja
Sada kada razumemo sve alate koji nam stoje na raspolaganju, hajde da prodjemo kroz prakticni workflow za identifikaciju i resavanje draw call problema.
42.9.1 Korak 1: Identifikacija bottleneck-a
Pre nego sto bilo sta optimizujete, morate da potvrdite da su draw call-ovi zaista vas problem. Ako je GPU bottleneck (GPU je na 100%, CPU ceka), smanjenje draw call-ova nece pomoci -- problem je u slozenosti shadera, rezoluciji, overdraw-u, itd.
Kako proveriti:
-
Otvorite konzolu i unesite:
stat unitOvo prikazuje:
Frame: 28.5 ms Game: 3.2 ms Draw: 18.7 ms <-- Rendering thread (CPU strana renderinga) GPU: 8.1 ms <-- GPU stranaAko je
Drawznacajno veci odGPU, imate CPU-bound rendering -- draw call-ovi su verovatno problem. -
Unesite:
stat scenerenderingPronadjite
Mesh draw calls. Ako je broj veci od 3.000-5.000, imate potencijalnog krivca. -
Za detaljniju analizu:
stat initviewsPrikazuje vreme provedeno na visibility determination (frustum culling, occlusion culling). Ako je ovo vreme veliko, imate mnogo objekata za procesiranje.
42.9.2 Korak 2: Identifikacija izvora draw call-ova
Znate da imate previse draw call-ova. Sada morate da pronadjete odakle dolaze.
Tehnika 1: Wireframe mode
Prebacite viewport u Wireframe mode (Alt+3 u editoru ili konzolna komanda viewmode wireframe). Ovo vam daje vizuelni pregled koliko geometrije imate i gde. Gusti wireframe u odredjenoj oblasti = mnogo objekata = mnogo draw call-ova.
Tehnika 2: Selektivno sakrivanje
Selektujte grupe objekata i sakrijte ih (H taster u editoru). Posmatrajte stat scenerendering kako se menja. Kada sakrijete grupu koja dramaticno smanji draw call count -- pronasli ste krivca.
Tehnika 3: Scene Outliner analiza
Otvorite Scene Outliner i sortirajte po tipu. Pronadjite tipove actor-a koji imaju najvise instanci. Cest krivac su dekorativni objekti: kamencici, trava (ako nije Foliage), sitni props koji nisu instancirani.
Tehnika 4: Statistics window
Window > Statistics vam daje detaljan pregled scene, ukljucujuci broj primitiva, tekstura, materijala, i slicno.
42.9.3 Korak 3: Primena odgovarajuce strategije
Na osnovu onoga sto ste otkrili, primenite odgovarajucu strategiju:
| Situacija | Resenje | Ocekivano smanjenje |
|---|---|---|
| Mnogo kopija istog mesh-a (vegetacija, kamenje, dekoracije) | ISM/HISM ili Foliage tool | 90-99% smanjenje za te objekte |
| Mnogo malih razlicitih objekata grupisanih na malom prostoru | Mesh merging (Merge Actors) | 70-90% smanjenje za tu grupu |
| Mnogo razlicitih materijala na slicnim objektima | Master materijal + Material Instances, texture atlasing | 30-60% smanjenje materijala |
| Staticna opaque geometrija na DX12/DX11 | Konvertovanje u Nanite | Skoro potpuno eliminise CPU overhead za te objekte |
| Daleki objekti sa mnogo detalja | HLOD system | Dramaticno smanjenje na daljinu |
| Mesh-evi sa previse material slotova | Re-modelovanje sa manje slotova, atlas tekstura | Linearno smanjenje |
42.9.4 Primer iz prakse: Optimizacija gradske scene
Hajde da prodjemo kroz realistican primer. Imate scenu: mali gradski blok sa zgradama, ulicnim namestajem, vegetacijom.
Inicijalno stanje:
stat scenerendering:
Mesh draw calls: 8.743
stat unit:
Draw: 22.4 ms
GPU: 9.1 ms
Jasno CPU-bound! Draw call overhead je problem.
Analiza izvora:
Detaljni pregled:
- 24 zgrade, svaka sa 6-8 material slotova = ~170 draw calls
- 300 ulicnih lampi (isti mesh, isti materijal) = 300 draw calls
- 200 kanti za djubre (isti mesh, isti materijal) = 200 draw calls
- 150 klupa (isti mesh, isti materijal) = 150 draw calls
- 2.000 malih dekorativnih kamencica = 2.000 draw calls
- 500 zidnih dekoracija (razliciti mesh-evi) = 500 draw calls
- 5.000 busenja trave (nisu kroz Foliage tool) = 5.000 draw calls
- Ostalo (likovi, VFX, UI, itd.) = ~423 draw calls
Optimizacija, korak po korak:
Korak A: Prebacite travu na Foliage/HISM
5.000 zasebnih StaticMeshActor-a za travu -> 1 HISM komponenta
Pre: 5.000 draw calls
Posle: ~10-20 draw calls (zavisno od vidljivosti i LOD nivoa)
Usteda: ~4.980 draw calls
Korak B: Instancirajte ponavljajuce objekte
300 lampi -> 1 HISM (lampe)
200 kanti -> 1 HISM (kante)
150 klupa -> 1 HISM (klupe)
Pre: 650 draw calls
Posle: ~15 draw calls
Usteda: ~635 draw calls
Korak C: Merge-ujte male dekorativne kamencice u grupe
2.000 kamencica -> merge u 20 grupa po 100
Pre: 2.000 draw calls
Posle: ~20 draw calls
Usteda: ~1.980 draw calls
Korak D: Konvertujte zgrade u Nanite
24 zgrade sa 6-8 material slotova svaka
Pre: ~170 draw calls
Posle: Nanite GPU-driven, skoro 0 CPU draw call overhead
Usteda: ~170 draw calls
Korak E: Merge-ujte zidne dekoracije u grupe po zgradi
500 dekoracija -> merge u 24 grupe (po zgradi)
Pre: 500 draw calls
Posle: ~24-48 draw calls (zavisno od broja materijala)
Usteda: ~450 draw calls
Rezultat:
stat scenerendering:
Mesh draw calls: 556 (smanjeno sa 8.743!)
stat unit:
Draw: 4.8 ms (smanjeno sa 22.4 ms!)
GPU: 8.9 ms (skoro nepromenjeno -- GPU nije bio bottleneck)
CPU rendering overhead smanjen za 78%!
Scena sada radi na 60+ FPS umesto ~35 FPS.
42.9.5 Iterativni pristup
Optimizacija draw call-ova je iterativan proces. Ne morate (i ne treba) da radite sve odjednom. Preporuceni redosled:
- Prvo profajlirajte -- potvrdite da su draw calls zaista bottleneck
- Identifikujte najvece krivce -- pronadjite oblasti/objekte koji generisu najvise draw call-ova
- Primenite najlakse resenje prvo -- prebacivanje na Nanite, HISM za ponavljajuce objekte
- Ponovo profajlirajte -- vidite koliko ste usteli
- Ako treba vise -- mesh merging, texture atlasing, smanjenje material slotova
- Ponovo profajlirajte -- svaki put merite uticaj
- Zaustavite se kada je dovoljno -- optimizacija je balans izmedju performansi i fleksibilnosti. Ne unistavajte svoju scenu radi poslednjiheg 2% unapredjenja
42.10 Napredne teme
42.10.1 Sortiranje draw call-ova po stanju (State Sorting)
UE5 interno sortira draw call-ove da bi minimizovao skupe state change-ove. Redosled sortiranja je otprilike:
- Po render pass-u -- base pass, shadow pass, itd. (ovo je najgrublji nivo)
- Po shader programu -- grupisanje objekata sa istim shader-om zajedno
- Po material parametrima -- unutar istog shader-a, grupisanje po teksturama i parametrima
- Po vertex buffer-u -- grupisanje objekata sa istim mesh-om zajedno
- Po dubini (front-to-back za opaque, back-to-front za transparentne)
Optimalno sortiran rendering:
Shader A: [Obj1] [Obj5] [Obj12] [Obj7] // Svi koriste shader A
Shader B: [Obj2] [Obj8] [Obj14] // Svi koriste shader B
Shader C: [Obj3] [Obj9] [Obj4] [Obj15] // Svi koriste shader C
State changes: 2 (A->B, B->C)
Neoptimalno sortiran rendering:
[Obj1:A] [Obj2:B] [Obj3:C] [Obj5:A] [Obj8:B] [Obj9:C] ...
State changes: Svaki draw call menja shader! Uzasno neefikasno.
Vi kao developer ne morate rucno da sortirate -- UE5 to radi za vas. Ali mozete da pomognete engine-u tako sto koristite sto manje razlicitih materijala, sto daje engine-u manje state change-ova za sortiranje.
42.10.2 Draw Call Overhead u Shadow Pass-u
Ovde je cesta zamka: draw call-ovi se ne broje samo u main (base) rendering pass-u. Shadow pass takodje generise draw call-ove!
Za svako svetlo koje baca dinamicke senke, engine mora da renderuje shadow map -- a to znaci da prolazi kroz sve objekte koji bacaju senke i izdaje draw call-ove za svaki od njih, iz perspektive svetla.
Scena sa 1.000 objekata i 3 dinamicka svetla:
Base pass: ~1.000 draw calls (za ono sto kamera vidi)
Shadow pass 1: ~800 draw calls (za ono sto svetlo 1 vidi)
Shadow pass 2: ~600 draw calls (za ono sto svetlo 2 vidi)
Shadow pass 3: ~700 draw calls (za ono sto svetlo 3 vidi)
UKUPNO: ~3.100 draw calls!
Sama scena ima "samo" 1.000 objekata, ali shadow pass-ovi utrostrucuju
broj draw call-ova.
Resenja za shadow pass draw call-ove:
- Virtual Shadow Maps (VSM) -- UE5 podrazumevano koristi VSM koji smanjuje shadow rendering overhead (poglavlje 31)
- Cascade Shadow Maps sa ogranicenim rastojanjem -- ogranicite koliko daleko senke doscezu
- Iskljucite senke za objekte kojima ne trebaju -- mali dekorativni objekti cesto ne trebaju da bacaju senke
- Baked senke -- za staticna svetla, koristite baked lightmap senke umesto dinamickih (poglavlje 24)
- Nanite shadow rendering -- Nanite mesh-evi koriste GPU-driven shadow rendering sto smanjuje CPU overhead
42.10.3 Prepass / Early Z
UE5 koristi depth prepass (takodje poznat kao Early Z pass ili Z-prepass) koji renderuje dubinu (depth) scene pre main rendering pass-a. Ovo ima dva efekta na draw call-ove:
- Dodatan pass = dodatni draw call-ovi -- depth prepass generise svoje draw call-ove (mada su ovi jeftiniji jer ne koriste pune materijale)
- Smanjuje overdraw u main pass-u -- posto se dubina vec zna, pixel shader ne mora da se izvrsava za piksele koji su iza nesto drugog. Ovo smanjuje GPU rad u main pass-u.
Da li je net efekat pozitivan ili negativan zavisi od scene. Za scene sa mnogo overdraw-a (mnogo objekata koji se preklapaju), depth prepass je gotovo uvek koristan. Za scene sa malo preklapanja, moze da doda nepotreban overhead.
42.10.4 Batching transparentnih objekata
Transparentni objekti su posebna muka za draw call batching:
- Moraju se crtati back-to-front -- od najdaljeg ka najblizem, da bi blending radio ispravno
- Ne mogu se koristiti za depth prepass -- jer su prozirni, ne pisu u depth buffer
- Tesko se instanciraju -- sortiranje po dubini razbija instancing grupe
Rezultat: transparentni materijali su inherentno skupi u smislu draw call-ova. Svaki transparentni objekat je potencijalno zaseban draw call koji se ne moze optimizovati standardnim tehnikama.
Preporuke za transparentne objekte:
- Koristite transparenciju samo kada je zaista neophodna
- Razmotrite masked (alpha test) umesto translucent -- masked materijali mogu da koriste depth prepass i da se sortiraju sa opaque objektima
- Za particle efekte, smanjite broj emittera i koristite GPU particles
- Dithered opacity (screen-space dithering za fade-out) je jeftinija alternativa pravoj transparenciji
42.10.5 Dynamic vs Static Batching
UE5 razlikuje dva tipa batching-a:
Static batching -- objekti koji se nikada ne pomeraju mogu biti pre-batch-ovani. Engine zna unapred koji objekti mogu da budu zajedno i ne mora da ih sortira svaki frejm.
Dynamic batching -- objekti koji se pomeraju moraju biti ponovo sortirani i batch-ovani svaki frejm. Ovo zahteva vise CPU rada, ali omogucava batching za dinamicne objekte.
UE5 auto-instancing sistem radi kao hybrid -- koristi cached mesh draw commands za staticne objekte (koji se invalidiraju samo kada se objekat promeni) i dynamic instancing za objekte koji se menjaju.
Prakticna posledica: Movable objekti su nesto skupji od Static objekata u smislu batching overhead-a. Ako objekat nikada ne treba da se pomera, postavite njegov Mobility na Static.
42.11 Kompletna slika: Draw Call Lifecycle u UE5
Hajde da sumiramo ceo zivotni ciklus jednog draw call-a u UE5, od scene do piksela:
1. SCENE TRAVERSAL (CPU)
|
|- Engine prolazi kroz sve actor-e u sceni
|- Proverava vidljivost (frustum culling)
|- Proverava occlusion (occlusion culling)
|- Filtrira na osnovu distance culling i relevancy
|
v
2. MESH DRAW COMMAND GENERATION (CPU)
|
|- Za svaki vidljivi mesh, engine generise MeshDrawCommand
|- MeshDrawCommand sadrzi: mesh reference, materijal, transformaciju,
| render state, shader bindings
|- Commands se kesiraju za staticne objekte (ne regenerisu se svaki frejm)
|
v
3. SORTING & BATCHING (CPU)
|
|- Engine sortira MeshDrawCommands po state-u (shader, materijal, mesh)
|- Auto-instancing: identican commands se merge-uju u instanced draws
|- Sortiranje po dubini za opaque (front-to-back) i transparent (back-to-front)
|
v
4. COMMAND BUFFER FILLING (CPU)
|
|- Engine prevodi MeshDrawCommands u RHI (Rendering Hardware Interface) pozive
|- RHI pozivi se prevode u DX12/Vulkan/Metal komande
|- Komande se pakuju u command buffer (DX12 command list)
|
v
5. SUBMISSION TO GPU (CPU -> GPU)
|
|- Command buffer se submituje GPU-u za izvrsavanje
|- Na DX12, ovo moze biti multithreaded (vise command list-a paralelno)
|
v
6. GPU EXECUTION (GPU)
|
|- GPU izvrsava komande redom
|- Za svaki draw call: vertex fetch -> vertex shader -> rasterization -> pixel shader
|- State changes izmedju draw call-ova kostaju vreme
|
v
7. FRAMEBUFFER OUTPUT (GPU)
|
|- Rezultat se upisuje u framebuffer
|- Post-processing pass-ovi se primenjuju
|- Finalna slika se prikazuje na ekranu
Za Nanite objekte, koraci 2-5 su dramaticno pojednostavljeni:
1. SCENE TRAVERSAL (CPU) -- Samo za non-Nanite objekte
2. NANITE INSTANCE UPLOAD (CPU)
|- Minimalan posao: upload instance data (pozicije, materijali)
3. GPU-DRIVEN PIPELINE (GPU)
|- GPU sam radi visibility, LOD, clustering, rasterization
|- Nema tradicionalnih draw call-ova
|- Rezultat ide u Visibility Buffer
4. MATERIAL EVALUATION (GPU)
|- Na osnovu Visibility Buffer-a, evaluira materijale
|- Minimalan number of pixel shader invocations (tacno 1 po pikselu)
42.12 Ceste greske i anti-patterni
Evo najcescih gresaka koje developeri prave u vezi sa draw call-ovima:
Greska 1: "Imam Nanite, ne trebam da brinem o draw calls"
Zasto je greska: Nanite pokriva samo staticnu, opaque geometriju. Sve ostalo (likovi, VFX, transparentni objekti, skeletal mesh-evi) i dalje koristi tradicionalni pipeline.
Resenje: Profajlirajte non-Nanite draw calls. Koristite stat scenerendering i obratite paznju na koliko draw call-ova dolazi od non-Nanite objekata.
Greska 2: Stotine zasebnih actor-a za vegetaciju umesto Foliage tool-a
Zasto je greska: Svaki zasebni actor = zaseban draw call. 10.000 travki kao zasebni actor-i = 10.000 draw call-ova. Isti rezultat sa Foliage tool-om = 10-30 draw call-ova.
Resenje: Uvek koristite Foliage tool za vegetaciju. Ako vegetaciju generisite proceduralno (Blueprint, PCG), koristite HISM komponentu.
Greska 3: Previise material slotova na mesh-ovima
Zasto je greska: Svaki material slot = zaseban draw call. Mesh sa 8 material slotova generise 8 draw call-ova po instanci.
Resenje: Saradjujte sa 3D artistima da minimizuju material slotove. Koristite texture atlase. Ciljajte 1-2 slota za male objekte, 3-4 za velike.
Greska 4: Svaki objekat ima unikatan materijal
Zasto je greska: Unistava mogucnost batching-a. 500 objekata sa 500 razlicitih materijala = 500 draw call-ova, nema sanse za auto-instancing ili state sort optimizaciju.
Resenje: Master materijal pristup. Material Instances. Per-instance custom data za varijacije. Texture atlasing.
Greska 5: Ignorisanje shadow pass draw call-ova
Zasto je greska: Developeri cesto gledaju samo base pass draw calls. Shadow pass moze da generise jednako ili vise draw call-ova, narocito sa vise dinamickih svetala.
Resenje: Koristite Virtual Shadow Maps. Ogranicite shadow casting distance. Iskljucite senke za male objekte. Koristite baked senke gde mozete.
Greska 6: Premature optimization -- merge-ovanje svega
Zasto je greska: Preterano merge-ovanje unistava culling efikasnost, povecava memoriju, i otezava iteraciju. Merge-ovanje objekata koji nisu blizu jedan drugom moze zapravo pogorsati performanse.
Resenje: Merge-ujte samo objekte koji su geografski blizu i koji se uvek vide zajedno. Uvek profajlirajte pre i posle merge-a da potvrdite da je rezultat pozitivan.
Rezime poglavlja
Ovo poglavlje je pokrilo jedan od najkritcnijih aspekata optimizacije u real-time renderovanju. Hajde da sumiramo kljucne takeaway-e:
-
Draw call je komanda CPU-a ka GPU-u -- "nacrtaj ovaj mesh sa ovim materijalom". Sam call je jeftin; state changes koji ga okruzuju su skupi.
-
Draw call overhead je CPU problem -- ako imate previse draw call-ova, CPU se gusi pripremajuci komande, a GPU ceka.
-
DX12/Vulkan smanjuju per-call overhead, ali ne eliminisu ga. Nanite ga fundamentalno resava za staticnu geometriju prebacivanjem posla na GPU.
-
Instancing (ISM/HISM) je najefektivnija tehnika za ponavljajuce objekte. HISM dodaje hijerarhijski culling i per-instance LOD. Foliage system koristi HISM interno.
-
Mesh merging kombinuje razlicite mesh-eve u jedan, ali gubi individualni culling. Koristite ga za grupe malih objekata koji su blizu jedan drugom.
-
Materijali direktno uticu na draw calls -- vise jedinstvenih materijala = vise state change-ova = losiji batching. Master materijali, Material Instances, i texture atlasing su kljucne strategije.
-
Auto-instancing u UE5 automatski batch-uje identicne mesh+material kombinacije. Pomozite mu tako sto ujednacavate materijale i settings objekte.
-
Nanite eliminise CPU draw call overhead za staticnu opaque geometriju. Non-Nanite objekti i dalje zahtevaju tradicionalne optimizacije.
-
Uvek profajlirajte --
stat unit,stat scenerendering,stat RHI. Brojevi su jedini nacin da znate gde je problem i da li vasa optimizacija pomaze.
Kljucni pojmovi
| Termin | Objasnjenje |
|---|---|
| Draw Call | Komanda CPU-a ka GPU-u za crtanje jednog mesh-a sa jednim materijalom |
| State Change | Promena GPU stanja (shader, teksture, render state) izmedju draw call-ova; glavni izvor overhead-a |
| Command Buffer | Buffer u koji CPU pakuje komande za GPU; GPU ga izvrsava asinhrono |
| Instancing | Tehnika crtanja vise kopija istog mesh-a u jednom draw call-u |
| ISM | Instanced Static Mesh -- UE5 komponenta za instanciranje bez hijerarhijskog culling-a |
| HISM | Hierarchical Instanced Static Mesh -- ISM sa hijerarhijskim culling-om i per-instance LOD |
| Mesh Merging | Kombinovanje vise razlicitih mesh-eva u jedan, smanjuje draw calls ali gubi individualni culling |
| Auto-Instancing | UE5 mehanizam koji automatski batch-uje identicne mesh+material kombinacije |
| Texture Atlas | Jedna velika tekstura koja sadrzi vise manjih tekstura; omogucava jedan materijal umesto mnogo |
| Material Instance | Varijacija parent materijala sa promenjenim parametrima; koristi isti shader program |
| GPU-Driven Rendering | Paradigma gde GPU sam odlucuje sta i kako da crta, minimizujuci CPU overhead (Nanite) |
| RHI | Rendering Hardware Interface -- UE5 apstraktni sloj iznad DX11/DX12/Vulkan/Metal |
| Depth Prepass | Dodatni rendering pass koji popunjava depth buffer pre main pass-a; smanjuje overdraw |
| HLOD | Hierarchical Level of Detail -- automatsko merge-ovanje i pojednostavljivanje udaljenih objekata |
| Per-Instance Custom Data | Podaci koji variraju po instanci (boja, parametri) bez razbijanja instancing batch-a |
| Shadow Pass | Rendering pass za generisanje shadow mapa; generise dodatne draw call-ove |
| Batching | Grupisanje vise draw call-ova u jedan ili manji broj, smanjujuci CPU overhead |
Veze sa drugim poglavljima
-
Poglavlje 07 (Render Pipeline) -- Detaljan pregled rendering pipeline-a ukljucujuci Application Stage gde se draw calls pripremaju. Pogledajte sekciju o Application Stage za kontekst o tome kako CPU priprema podatke za GPU.
-
Poglavlje 08 (GPU Arhitektura) -- Razumevanje CPU vs GPU arhitekture je kljucno za razumevanje zasto su draw calls CPU problem. SIMD/SIMT model objasnjava zasto je instancing efikasan na GPU-u.
-
Poglavlje 22 (UE5 Material System) -- Material Instances, shader kompilacija i materijal optimizacija su direktno povezani sa draw call batching-om. Pogledajte sekcije o Material Instances i shader varijantama.
-
Poglavlje 30 (Nanite) -- GPU-driven rendering pipeline koji fundamentalno menja draw call paradigmu. Pogledajte sekcije o cluster-based renderingu i visibility buffer-u za tehnicke detalje.
-
Poglavlje 31 (Virtual Shadow Maps) -- VSM sistem koji smanjuje shadow pass draw call overhead. Relevantno za sekciju 42.10.2 ovog poglavlja.
-
Poglavlje 32 (World Partition) -- HLOD sistem koji automatski merge-uje daleke objekte. Kljucno za optimizaciju otvorenih svetova.
Preporuceno citanje i resursi
-
Epic Games dokumentacija: Rendering Optimization -- Zvanicna dokumentacija o rendering optimizaciji u UE5
-
"GPU Gems 2, Chapter 3: Inside GPU" -- Detaljno objasnjenje GPU pipeline-a i zasto su state changes skupi
-
"Real-Time Rendering, 4th Edition" (Akenine-Moller et al.) -- Poglavlje 18 pokriva pipeline optimization ukljucujuci batching i instancing
-
GDC Talk: "Optimizing the Graphics Pipeline with Compute" (Wihlidal, 2016) -- GPU-driven rendering koncepti koji su inspirisali Nanite
-
Epic Games: "Nanite - A Deep Dive" (Brian Karis, SIGGRAPH 2021) -- Tehnicko objasnjenje Nanite sistema
-
Unreal Engine Profiling Guide:
statkomande, Unreal Insights, i GPU profiling workflow -
RenderDoc dokumentacija: renderdoc.org -- Besplatan GPU debugger za analizu draw call-ova
-
Microsoft PIX: GPU profiling alat za DirectX 12 -- izuzetno koristan za draw call analizu na Windows-u