Zobrazit předchozí téma :: Zobrazit následující téma |
Autor |
Zpráva |
MD
Založen: 29. 07. 2007 Příspěvky: 437 Bydliště: Praha
|
Zaslal: 28. duben 2008, 17:40:13 Předmět: Krkal: engine s rovnobeznou projekci, shadery pro osvetleni |
|
|
Pote co jsem na podzim dodelal kompilator se chci venovat dalsi casti, tentokrat grafickemu enginu. V Hardwarove grafice jsem zacatecnik (a to i presto ze z toho mam statnice), tak bych vas rad pozadal o nejaky ty rady.
Tak jak to bude vypadat:
Jedna se o hru ve stylu Krkal (http://www.krkal.org/cs/screenshots.html) nebo o 3D hru ve stylu UFO 1,2, ale i Prince of Persia 1,2
Je to tedy neco mezi 2D a 3D.
Zakladem jsou objekty ("tiles"), na rozdil od beznych 2D her maji treti rozmer, ktery je vykreslovan v nejakem rovnobeznem promitani. Z objektu je poskladan level, na obrazovce jich muze byt velke mnozstvi (Krkal), mohou byt poskladany v prostoru do vice vrstev a pater (UFO)
Objekt ma 3D souradnice a sadu textur (Barva, Normala, Vyskova mapa, ...) Tedy z 2D spritu delam 3D zalezitost!! Navic potrebuju obalove teleso. (Abych mohl pocitat viditelnostni trideni celych objektu a dalsi veci)
Prosim vynechte otazky, proc objekty reprezentuju 2D bitmapou a ne 3D modelem. Oba pristupy maji sve a diskuse o tom by byla na dalsi thread.
A ted problemy:
1) Viditelnostni trideni. Tohle uz mame vychytane ze stareho Krkala. Objekty jsou setrideny a pak vykreslovany odzadu dopredu. Tento smer je potreba kvuli casto pouzivane pruhlednosti.
2) Svetla. Jsou pocitana presne v kazdem pixelu (Phong). Puvodni Krkal to pocital softwarove (jen diffusni slozku) a pak vysledky uchovaval v Cachi.
Nyni bych to chtel predelat do shaderu -> moznost pocitat to realtime, mit hodne dynamicke levely, mit specularni slozku a dalsi coool efekty.
Tenhle vikend jsem se ucil se shadery a mam tu takovy prototip: www.krkal.org/download/KrkalShader.zip - je to shader 3.0 pro Render Monkey. Davam to sem pro ilustraci a budu rad kdyz to zhodnoti nekdo zkuseny.
Taky jsem potreboval vyzkouset jak budou shadery rychle. No bude to jen tak tak Ten muj shader pocita 1+5 svetel a uz mirne ztraci plynulost u vetsich rozliseni (Ja mam GeForce 6600GT) A to se tam nic neprekryva! Nejake navrhy jak to delat rychle?
Tech svetel muze byt v levelu velke mnozstvi (v Krkalovi treba 50), takze to chce umet rychle zjistit ktera svetla sviti na ktery objekt.
a) Otazka: Jak resit situaci, kdyz na objekt sviti opravdu hodne svetel? (Shader ma problemy uz s peti) Ty mene vyznamna zanedbat? Rendrovat ve vice pruchodech a barvu scitat? Co pak s pruhlednosti?
b) Otazka jak efektivne zamezit kresleni zakrytych objektu ci pixelu? (vypocet svetla na pixelu je drahy) Muzu implementovat nejaky hruby softwarovy algoritmus ktery eliminuje objekty (napriklad objekty za velkou stenou, objekty pod podlahou). Problem je ze ve stene mohou byt diry a podlaha muze byt pruhledna. Taky me napadlo vyuzit ZBuffer (ten jsme v puvodnim Krkalovi nepotrebovali) Ze bych v prvnim pruchodu kreslil odpredu dozadu a do ZBufferu zapsal souradnici prvniho nepruhledneho pixelu (Barvu bych v tomto pruchodu nepocital). V druhem pruchodu bych kreslil klasicky odzadu do predu s pouzitim ZBufferu. Jde to takhle udelat?
3) Rychle vykreslovani objektu (tohle rozvedu priste, ted jen strucne). Kazdy objekt je pouze ctyruhelnik, ale muze jich byt hodne, tak bych je chtel kreslit co nejvic "Hromadne" Jak na to? Jak predavat informace o posunu, svetlech, texture (skoro si rikam ze se nam vsechna grafika vejde do jedne textury) atd? Nejake napady na chytre vyuziti VertexBufferu? _________________ - play with objects - www.krkal.org - |
|
Návrat nahoru |
|
|
Augi
Založen: 28. 07. 2007 Příspěvky: 782 Bydliště: Čerčany
|
Zaslal: 28. duben 2008, 20:01:45 Předmět: |
|
|
0) Jak děláš ze spritů 3D objekty? Jen tím, že použiješ normal mapu a 3D osvětlení? Nic proti, jen se ptám...
1) Obecně v dnešní 3D grafice platí pravidlo, že je nejvýhodnější vykreslovat objekty odpředu dozadu. Výhodnější je to proto, protože pak se v ideálním případě vypočte barva jen tolika pixelů, kolik pixelů má obrazovka. Prostě se tím eliminuje to, že bys vykreslil nějaký pixel a ten by byl přepsán jiným pixelem bližšího objektu. Toto použití předpokládá použití Z-bufferu (v dnešní době žádnej problém). Samozřejmě pro korektní alpha-průhlednost je potřeba přesně opačné pořadí vykreslování, což v reálných aplikacích ústí ve dvě "fronty objektů k vykreslení". Ale některý druhy blendingu se dají snad ošéfovat i bez nutnosti řazení. Zkus zagooglovat "Order-Independent Transparency", "Sort-Independent Alpha Blending" apod. (sám o tomhle nic nevím)
2) Tvoje zadání je dost specifické a upočítání většího počtu světel je opravdu trošku problém (samozřejmě existují dema, která renderují s použitím X-světel, ale reálné nasazení...). Dnešní CPU jsou imho dost rychlé a pokud máš nějaký systém, který je schopen to upočítat na CPU, co zkusit ho trošku oprášit a nezanášet si do projektu další jazyk (HLSL/GLSL/Cg)? Jen takové zamyšlení...
2a) Více světel by šlo vypočítat třeba tak, že bys sis vypočítal objekt někde vedle do nějaký menší textury a tu by jsi pak vykreslil do back-bufferu (momentální nápad). Jinak bych to viděl na nějaké předzpracování na CPU, např. použít pár nejbližších světel a ostatní ignorovat nebo je nějak chytře zprůměrovat do jednoho. Při počítání nejbližších světel bych tu vzdálenost objekt-světlo určitě vážil intenzitou světla (trošku vzdálenější ale silnější světlo bude mít větší vliv na osvětlení než blízké ale slabé světlo).
2b) Jak jsem psal v bodě 1, vykreslování odpředu dozadu s použitím Z-bufferu je v pohodě. Iniciální průchod jen pro nastavení Z-bufferu se taky používá, otázka je, jestli by to nebylo rychlejší bez něj.
3) Odpověď je jednoduchá - geometry instancing. Můžeš to udělat tak, že budeš vykreslovat hromadu stejných čtverců najednou, každý čtverec bude znát svůj index, a v konstantních registrech shaderů budeš mít pro každý čtverec uloženy souřadnice, barvu, whatever... Počet konstatních registrů je ale omezen (řádově stovky), takže velikost jedné dávky čtverců je dána tímto počtem. Dále lze místo konstatních registrů použít texturu (načítat si parametry čtverců z textury), ale některé grafické karty buď vůbec neumí nebo nemají rády čtení z textury ve vertex shaderu - takže osobně bych použil raději ty konstantní registry. Dále myslím od shader modelu 3.0 je podporován hardware instancing, který spočívá v tom, že máš dva buffery - v Tvém případě bys měl v jednom bufferu čtverec a ve druhém bufferu data pro jednotlivé čtverce. No a v SM4 jsou možnosti ještě daleko širší. Ale pokud chceš, aby to chodilo i lidem se starším železem, naprgal bych aspoň geometry instancing před konstantní registry. Jinak tomuhle tématu (instancingu) se teď snad věnoval Eosie, tak Ti určitě něco k tomu napíše |
|
Návrat nahoru |
|
|
MD
Založen: 29. 07. 2007 Příspěvky: 437 Bydliště: Praha
|
Zaslal: 28. duben 2008, 21:56:24 Předmět: |
|
|
Ano vypocitam to z textury. Z, Y mam, Z si vezmu z vyskove mapy, trosoku to upravim (napr perspektivni zkoseni: X+=Z*shX; Y+=Z*shY; Z+= Z0) a mam svetove souradnice bodu. Dale z textury vezmu normalu, muzu spocitat vektor ke kamere, ke svetlu, vzdalenost ke svetlu, svetlo podle vzdalenosti utlumit a spocitat osvetleni (diffusni a specularni slozku)
-> Vyseldek je potom naprosto super, je to hladce nasviceny highpoly 3D model , kdyby nebylo te nevyhody, ze se s nim neda otacet, tak by nikdo nepoznal ze jde o sprite.
Tyhle vypocty uz jsem si vyzkousel v tom mem testovacim shaderu, takze kdo chce, muze se na to kouknout. Jinak tohle se opravdu musi pocitat pro kazdy bod a jedine mozne optimalizace jsou: Mit cache (napriklad renderovat do textury a ulozit si to na pozdeji (ve starem enginu jsme delali to same jen softwarove)), nepocitat to pro body, ktere jsou momentalne zakryte ( to bude dost nutnost), omezit pocet svetel, pro mene vyznamna svetla zjednodusit shader.
K te cachi, zkusil bych se tomu vyhnout, pokud to pujde. Aby cache fungovala, tak to vyzaduje hodne staticky level. Nesmi se tam moc hybat(animovat) objekty, ale hlavne svetla. Tak uvidime.
K mnozstvi svetel: Je tam jedno "slunce", ktere sviti na vsechno a pak lokalni svetla a omezenym radiusem. Diky tomu, prestoze je v levlu treba 50 svetel, by v prumeru mel byt kazdy objekt nasvicen tak 4mi lokalnimi svetly. To by se snad melo dat zvladat pocitat.
K poradi vykreslovani. My jsme driv nepouzivali ZBuffer, protoze to nebylo potrba. Poradi objektu si umime urcit softwarove. Problem je v tom, ze vsechny objekty maji alfa kanal. A i ty ktere nejsou pruhledne samy o sobe, tak maji alfu alespon na obrysu. (Super vec, Krkal vubec netrpi roztrepenymi hranami! ). Takze tohle chce nak poresit. ZBuffer asi bude treba <= ted je drahy vypocet pixelu a navic pocitam s daleko vic 3D levly (patra, vrstvy).
Tu trojku si vygoogluju, ale budu i rad, kdyz se k tomu nekdo jeste vyjadri. Pokud musim objekty kreslit v urcitem poradi, tak nemusi byt vzdy mozne sgrupovat ty objekty se stejnymy vlastnostmi (stejna textura, stejna svetla)
Pocitam s tim ze textury sloucim do jedne velke, abych je nemusel moc prepinat. V soucasnosti by se mi dokonce veskera grafika vesla do jedny textury! (obrazky byly jen 54x54, temer zadne animace)
Pak pocitam ze informace pro ctverce zadam pres VB, muzu tam napriklad vyplnit indexy svetel, ktere na ctverec sviti a vlastni popis svetla pak mit treba v texture.
Jak funguje indexovani tech konstantnich registru? Resp daji se indexovat?. Jak se shader dozvi ktery index ma pouzit? Posila se to, tak jak to chapu ja (z Vertex Bufferu do Vertex Shaderu a z nej pak do Pixel Shaderu) nebo je to uplne jinak?
Diky moc za odpovedi.
PS target hardwere je pixel shader 3.0, minimum je moje soucasna karta (dnes uz maj vsichni lepsi), tedy GeForce6600GT
PS2 Jeste poznamka k tem objektum - jejich tvar a velikost neni omezena, takze tam muzou byt steny, kostky, veze, drobne objektiky ... _________________ - play with objects - www.krkal.org - |
|
Návrat nahoru |
|
|
Marek
Založen: 28. 07. 2007 Příspěvky: 1782 Bydliště: Velká Morava
|
Zaslal: 28. duben 2008, 22:42:01 Předmět: |
|
|
Přihodím svoje názory. Reakce na první 2 příspěvky.
1) Raději to seřaď vždycky sortem, i ty průhledné. Techniky na order-independent transparency jsou trochu trikovější a o dost pomalejší + mají další omezení.
2) Seš si jistý, že to chceš mít SM3.0? Omezuješ se na ATI X1000+ a GF6+, nikde jinde to není. K tomu tvému efektu: SM3.0 oproti SM2.0 má výhodu v tom, že můžeš použít podmínky, takže by bylo rozumné udělat něco jako if (svítí na tomto pixelu světlo?) { result += přidej světlo; }, u SM2.0 to nemá smysl takhle dělat. Používej power-of-two textury (rozměry 2^m x 2^n), jakékoliv jiné se negativně projeví na výkonu a mají další omezení (nefunguje u nich např. opakování textur na některém hw).
Zdá se mi, že tam toho počítáš nějak moc. Přesuň do vertex shaderu vše, co můžeš, např. počítání útlumu světla, prostě všechno, co netrpí při lineární interpolaci hodnot mezi vertex a pixel shaderem. Obecně tím trpí veškeré vektory a výpočty na nich závislé, protože při interpolaci se mění jejich délka. Všechny výpočty, jejichž hodnota je konstantní při renderingu spritu, přesuň na cpu (v RM to samozřejmě nejde, tak tam do VS).
Používej kvadratický útlum, je rychlejší. Při počítání osvětlení použij funkci lit; saturate( output ) je zbytečné. Jindy místo funkcí min,max použij saturate, je rychlejší. Snaž se víc používat intrinsic funkce, 4 skaláry sčítat přes dot(float4(a,b,c,d),1), instrukce dot se dá využít častěji (třeba to perspektivní zkosení). Modifikátor " : COLOR" se používá jen u vstupních a výstupních registrů, na normální funkce to nemá vliv. Celé to jde udělat rozhodně rychleji a efektivněji, ale 50 světel je trochu moc, na každý objekt bys měl aplikovat max. 4, většinou by to ale mělo být méně. SM2.0 má limit 64 ALU instrukcí, takže tam jich moc nenacpeš. Pokud se rozhodneš renderovat světla ve více průchodech a sčítat to, tak aby tohle fungovalo i na průhledných objektech, budeš muset nastudovat trik nazvaný "premultiplied alpha", bez toho to nebude fungovat. Využití zbufferu na výkonu nic neubere, může jenom pomoct.
3) Geometry instancing řeším tak, že si do vertex bufferu uložím objekt třeba 30x za sebe, do position.w si dám index objektu. Ve vertex shaderu si definuju strukturu jedné instance objektu a udělám z toho pole o velikosti 30. Position.w pak používám na indexaci - SM2.0 vertex shader má jeden adresavací registr. Pozor - pixel shader adresovat neumí, takže per-instance data si tam budeš muset poslat přes interpolátory (= přes výstup z vertex shaderu, stejně jak koordináty), ale většinou to není potřeba. Výhoda tohoto přístupu je, že od HW nepotřebuješ žádnou funkci navíc, z toho důvodu se tomu taky někdy říká shader instancing. Jeden draw call, 30 objektů, velmi efektivní. Nicméně nepěkně to znemožňuje kompletní seřazení objektů, pokud je víc objektů jiného typu. Konstantních registrů je na VS2.0 256x float4.
Později budu pokračovat... _________________ AMD Open Source Graphics Driver Developer |
|
Návrat nahoru |
|
|
xtopi
Založen: 11. 08. 2007 Příspěvky: 24 Bydliště: La republica Checa
|
Zaslal: 29. duben 2008, 01:16:31 Předmět: |
|
|
ja bych jenom poradil k tomu instancovani, to je hezky ze ti tady nepisou lidi postup, ale podle mě je daleko lepší příklad, a v SDK DirectX 9 je zrovna jeden výbornej s nazvem (překvapivě) "Instancing", kde máš hned 4 předvedený metody (constant-, shader-, hardware- a stream-instancing), můžeš si ho i spustit a porovnat rychlost (taky se tam kreslej krychle ). Začni tím nejjednodušším (constant instancing). Uvidíš že i ten je hodně rychlej, a až ti to bude renderovat tak můžeš kdykoliv přejít na nějakej víc advanced, ale ani nemusíš . |
|
Návrat nahoru |
|
|
MD
Založen: 29. 07. 2007 Příspěvky: 437 Bydliště: Praha
|
Zaslal: 29. duben 2008, 08:56:01 Předmět: |
|
|
Dekuji za nasmerovani.
2.0 vs 3.0, samozrejme bych byl rad kompatibilni i se starsimi kartami, ale co jsem si to zkusil, tak jsem zjistil, ze 2.0 nestaci - jednak potrebuju hodne instrukci a jednak se bude hodit vetveni (if). Takze primarni target musi byt 3.0, pro 2.0 muzu zkusit udelat podporu dodatecne, s tim ze orezu funkcionalitu.
Vzdalenost ke svetlu se da pocitat ve VS? Myslim, ze ji pak nebudu umet interpolovat na jednotlivy pixel. Zavislost neni linearni (jestli jsem se nesplet). Navic tam mam tu vyskovou mapu, ktera se souradnicema umi pekne zamichat. Nicmene rada zkusit co mozna nejvice veci presunout na VS je spravna.
Ja misto saturate pouzival max, protoze tam mohly byt hodnoty vetsi nez jedna, ale kouknu jestli se to neda udelat nak jinak. Shader se samozrejme optimalizovat da, diky moc za rady, je to muj prvni
U svetel mam takovyto utlum: 2 * Radius / (Radius + k*Distance^2). (Dvojka, aby to svitilo vic , Raduis je vlastnost svetla (v mem prototipu ulozana v alfe) ) Muzes sem napsat vzorec toho, co jsi myslel ty?
3) Skoda ze ten pixel shader neumi adresovat, kdyz mam vetsinu vypoctu na nem. Jak pomale je predavani parametru z VS na PS, jsou parametry vzdy interpolovane, nebo u nektereho typu to je vypnute?
S tim razenim si nejak poradim, v podstate buduju acyklicky orientovany graf (Hrana AB znamena, ze musim A vykreslit pred B), pak tento graf topologicky setridim (DFS). Ne vsude je hrana a obcas muzu kreslit neco drive a neco pozdeji. Mozna bude stacit pridat nejakou heuristiku, ktera ovlivni poradi prochazeni grafu. _________________ - play with objects - www.krkal.org - |
|
Návrat nahoru |
|
|
Augi
Založen: 28. 07. 2007 Příspěvky: 782 Bydliště: Čerčany
|
Zaslal: 29. duben 2008, 09:09:27 Předmět: |
|
|
MD napsal: |
Vzdalenost ke svetlu se da pocitat ve VS? |
K výpočtu vzdálenosti Ti stačí znát pozici vertexu (tu máš) a pozici světla (dodáš přes konstantní registr).
MD napsal: |
Navic tam mam tu vyskovou mapu, ktera se souradnicema umi pekne zamichat. Nicmene rada zkusit co mozna nejvice veci presunout na VS je spravna. |
Pak budeš asi muset použít per-pixel osvětlení, tedy počítat onu vzdálenost až v pixel shaderu.
MD napsal: |
Jak pomale je predavani parametru z VS na PS, jsou parametry vzdy interpolovane, nebo u nektereho typu to je vypnute? |
Předávání hodnot z VS do PS přes texcoords by mělo být v pohodě a na výkonu by se to snad podepsat nemělo (to si jen myslím, nikdy jsem to nezkoušel). Interpolaci lze částečně vypnout (ovlivní to myslím jen COLOR) tím, že zapneš tzv. flat shading - pak se pro všechny pixely trojúhelníku použije barva prvního vertexu (nebo tak nějak). |
|
Návrat nahoru |
|
|
Marek
Založen: 28. 07. 2007 Příspěvky: 1782 Bydliště: Velká Morava
|
Zaslal: 29. duben 2008, 13:46:21 Předmět: |
|
|
Ve VS:
kód: |
lightVecAtt = (lightPos.xyz - vertexPos.xyz) / lightRadius; |
Délka vektoru určuje útlum. Díky lineární povaze interpolátorů je můžeme použít.
V PS:
kód: |
float4 phong(float3 normal, float3 lightVecAtt, float3 viewVec, float4 matDiffuse, float4 matSpecular, float shininess)
{
float3 lightVec = normalize(lightVecAtt);
// Diffuse a specular
float2 L;
L.x = dot(lightVec, normal);
L.y = dot(viewVec, reflect(lightVec, normal));
L = lit(L.x, L.y, shininess).yz;
// Utlum svetla
L *= saturate(1 - dot(lightVecAtt, lightVecAtt));
// Ted se to da vsechno dohromady a obarvi
return matDiffuse * L.x + matSpecular * L.y;
} |
Jak vidíš, vzorec na útlum je hodně jednoduchej.
Ne vždy potřebuješ "if", místo toho můžeš udělat víc verzí shaderů, třeba mít shader na jedno světlo, pak na 2 světla atd.
Jen si dej pozor, ať ti to hraní si s shaderama nepřeroste přes hlavu. _________________ AMD Open Source Graphics Driver Developer |
|
Návrat nahoru |
|
|
MD
Založen: 29. 07. 2007 Příspěvky: 437 Bydliště: Praha
|
Zaslal: 29. duben 2008, 14:22:06 Předmět: |
|
|
Pekne, takhle se mi ten kod moc libi, zkusim to upravit pro tu svou vyskovou mapu.
Jeste dotaz k intrinsic funkcim:
Funkci reflect jsem objevil uz driv a zkusil jsem ji. Kdyz jsem se pak ale podival do assembleru, melo to vic instrukci, nez muj puvodni kod:
kód: |
float fNDotL = dot( fvNormal, fvLightDirection );
float3 fvReflection = normalize( ( ( 2.0f * fvNormal ) * ( fNDotL ) ) - fvLightDirection );
|
Co je teda lepsi? Zalezi na kompilatoru? Ze nektery to prelozi do neceho pomalejsiho, nez mam ja, protoze napriklad umim vyuzit mezivysledek z predchoziho kroku? Naopak na novejsich kartach muze byt intrinsic vyhodnejsi, ze bude opravdu realizovan jednou instrukci? _________________ - play with objects - www.krkal.org - |
|
Návrat nahoru |
|
|
Marek
Založen: 28. 07. 2007 Příspěvky: 1782 Bydliště: Velká Morava
|
Zaslal: 29. duben 2008, 14:37:38 Předmět: |
|
|
To je divný - optimizér by ten druhý stejný výpočet měl eliminovat. Asi bude lepší to dělat tak, jak jsi to dělal doposud. Funkce reflect nejspíš nikdy jednou instrukcí realizována nebude, je to moc specifický případ. Jo a ještě takovej detail - ten asm kód je furt mezikód. Driver provádí další optimalizace a ve výsledku to může vypadat jinak, třeba instrukce inteligentně párovat (některý gpu umí provádět jednu vektorovou a jednu skalární instrukci zároveň). Taky se může stát, že některé instrukce driver rozloží na více, protože je neumí (i když to by se stávat moc nemělo). Raději sleduj fps než počet instrukcí. _________________ AMD Open Source Graphics Driver Developer |
|
Návrat nahoru |
|
|
|