[Direct3D] ID3DXEffect::SetTechnique() waneer je maar wilt?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Orwell
  • Registratie: December 2009
  • Laatst online: 08-09 22:11
Na wat geflans en gedoe heb 'k eens een 3D-engine gemaakt. Met OBJ-lezer, levellezer, programmeerbare shaders, dynamische camera, lost device-handling, en al de andere shiny termen die je eropaf kunt gooien.

Afbeeldingslocatie: http://img375.imageshack.us/img375/3593/kleink.png

Leuk allemaal met al die verschillende modellen, maar het is een beetje een straf om maar één technique tegelijk te kunnen(?) gebruiken. Laten we eens als voorbeeld zeggen dat we als techniquegeschut hebben:
  • Per Pixel Phong Fog Texture (voor modellen)
  • Per Vertex Diffuse No Fog Texture 'ZFunc = Always' (voor de skybox)
Nu gebruik ik voor elk model dezelfde shader, in de meeste gevallen Per Pixel Phong. Deze is wat zwaar, en geeft wat probleempjes. De skybox krijgt bijvoorbeeld, net zoals elk ander model, een normalenvergelijking en krijgt daardoor een shading wat er gaar uitziet:

Afbeeldingslocatie: http://img692.imageshack.us/img692/1573/skyboxz.png

Voor de duidelijkheid, de directionele lichtbron zit achter de camera, en laat nu net dit deel van skybox volgens dat Phongmodel goed reflecteren doordat de normaal overeenkomt met -lichtrichting. Slaat natuurlijk nergens op.

Ik wil dus die skybox een andere shader geven, de tweede uit de lijst, die alleen de texture als kleur op het model plakt zonder shading, maar ik heb echt geen idee hoe dat moet, en ik kan het ook nergens vinden. Even voor de duidelijkheid hoe ik de boel in elkaar heb zitten:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
SetSomeTechnique();

FX->Begin(0,0);
FX->BeginPass(0);

for(int a = 0;a < nummodels;a++) {
    /* WORLDSPACE EN SCREENSPACE EN TEXTURE EN COMMIT EN BUFFERS */
    d3ddev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 0, 0, models[a].numfaces);
}
    
FX->EndPass();
FX->End();


Globals worden geset, en model wordt getekend. Simpel. Alleen krijgt elk model zo wel dezelfde shader. En shaders veranderen mag binnen de pass niet meer(?), waardoor ik dan in principe voor elke shader een passloop moet maken, wat sterk wordt afgeraden door bijv. Frank Luna met zijn boek(je). Weet iemand hier hoe het wel netjes moet? Gebruikte bronnen:
  • Introduction to 3D Game Programming with DirectX 9.0c - A Shader Approach (blijft bij een enkele pass)
  • MSDN (prima in zoektocht naar vergeten functieparameters, verder niks hierover gevonden)
  • Microsoft DirectX SDK (June 2010) (kunnen niet van DXUT afblijven, dus nutteloze voorbeelden)

Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Je kan gewoon techniques switchen, elke draw call gebruikt de op dat moment actieve state (techniques beinvloeden state), dus je kan gewoon zoveel wisselen als je wilt per frame. Het is best mogelijk dat je honderden techniques gebruikt elk frame :)

Laad gewoon meerdere techniques in, en associeer elke "model" met een technique. Dan, wanneer je dat model rendert, activeer de juiste technique.

Voor goede performance kan je je modellen sorteren per effect wanneer je rendert, om de hoeveelheid shaderswitches te minimaliseren (maar ik zou eerst gewoon zorgen dat het werkt)

[ Voor 40% gewijzigd door MLM op 24-12-2010 15:56 ]

-niks-


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Je kunt ook gewoon meerdere shaders laden en die voor een draw call veranderen, hierdoor hoef je niet alles in een effect file te steken. Zoals je textures voor een object verandert geldt dat ook voor shaders en effecten.

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • Orwell
  • Registratie: December 2009
  • Laatst online: 08-09 22:11
MLM schreef op vrijdag 24 december 2010 @ 15:53:
Je kan gewoon techniques switchen, elke draw call gebruikt de op dat moment actieve state (techniques beinvloeden state), dus je kan gewoon zoveel wisselen als je wilt per frame. Het is best mogelijk dat je honderden techniques gebruikt elk frame :)

Laad gewoon meerdere techniques in, en associeer elke "model" met een technique. Dan, wanneer je dat model rendert, activeer de juiste technique.

Voor goede performance kan je je modellen sorteren per effect wanneer je rendert, om de hoeveelheid shaderswitches te minimaliseren (maar ik zou eerst gewoon zorgen dat het werkt)
Ik snap best wel erg goed (denk ik), maar tegen de tijd dat de pass is begonnen kan de technique niet meer veranderen (voor zover ik weet).

Een heel rijtje techniques zijn inderdaad 'ingeladen', als je daarmee de handle setten bedoelt:

C++:
1
2
3
4
// Techniques 'inladen'?
FXPhongPointTex = FX->GetTechniqueByName("PhongPointTex");
FXPhongSpotTexInverse = FX->GetTechniqueByName("PhongSpotTexInverse");
...


Maar met dat wanneer technique setten kom ik niet verder. Tijdens de pass (ja, nog voor CommitChanges()) wordt er niets meer veranderd, hoeveel keer je ook SetTechnique() gebruikt. Erg vervelend. Even een overzicht:
  • Doe Pass(0) nog een netjes opnieuw, maar dan alleen met de skybox. Kan best. Alleen wordt de code lelijk als modellen ook eigen shaders krijgen.
  • Verander de technique binnenin de forloop zoals jullie zeggen. Gaat 'ie niet doen! :(
  • Maak van de passes een forloop, en zet op die manier alle modellen bij hun eigen shaders. Te doen, maar een hels karwei. Ook is multipassgedoe best sloom.
NC83 schreef op vrijdag 24 december 2010 @ 16:52:
Je kunt ook gewoon meerdere shaders laden en die voor een draw call veranderen, hierdoor hoef je niet alles in een effect file te steken. Zoals je textures voor een object verandert geldt dat ook voor shaders en effecten.
Klopt zeer zeker, doe ik ook redelijk. De redelijk veranderbare variabeles dan. Als ik bijvoorbeeld van Phong naar (zeg eens) Lambertian wil, moet ik toch echt een aparte shader maken. Maar daar zit nu net het probleem. Hoe gebruik ik beide? :/

Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Je kan toch eerst model 1 met technique A renderen (met hoeveel passes dat ook is) en dan model 2 met technique B (met hoeveel passes dat ook is).

-niks-


Acties:
  • 0 Henk 'm!

  • Orwell
  • Registratie: December 2009
  • Laatst online: 08-09 22:11
Ja, als je het zo bedoelt, maar dan wordt het verrekte lastig om van het hardcoded karakter af te komen.

Ik zou hooguit voor elke bekende shader een loop kunnen reserveren en elk model in zijn betreffende loop dumpen? :?

Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
Het klinkt als of je een forward-renderer hebt gemaakt. Het is dan niet (percee) de bedoeling dat je batches maakt van objecten met dezelfde shader maar dat je in 3 stappen renderd

-Skybox, met de skybox shader
-Geometry e.d. met per object de shader die bij het object hoort.
-HUD e.d.


Je krijgt dan zoiets:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
class  MyModel
{
    Effect myEffect;
    public void Draw(..)
    {
        SetTechnique(myEfect.technique);
       foreach (pass p in myEffect.technique)
       {
            SetPass(p);
            DrawVertices();
       }
    }
}

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • Orwell
  • Registratie: December 2009
  • Laatst online: 08-09 22:11
roy-t schreef op zaterdag 25 december 2010 @ 13:59:
Het klinkt als of je een forward-renderer hebt gemaakt. Het is dan niet (percee) de bedoeling dat je batches maakt van objecten met dezelfde shader maar dat je in 3 stappen renderd

-Skybox, met de skybox shader
-Geometry e.d. met per object de shader die bij het object hoort.
-HUD e.d.

Je krijgt dan zoiets: *Blabla*
Ja, een Deffered Renderer zou zeker leuk zijn, maar dat mag nog effies wachten van me. En als ik niet meer lichtbronnen ga maken, is forward nog even netzo best (al is Post-Processing wat lastig met Forward door dat gedoe met Surfaces). Maar goed, daar ging het niet over.

Verder lijkt het me handiger dat de skybox als laatste gaat, want dat scheelt geschrijf naar en geclean van de depth-buffer.

En dan blijft er nog steeds de vraag (blame die boeken waar het niet instaat), hoe dan de structuur van de code eruitziet. De code die je presenteert zet het inderdaad neer zoals ik dat in mijn bovenstaande post neerzette. Gewoon netjes elk model bij zijn shadermaatjes gooien, en zo per shader de daarbij behorende modellen tekenen. Maar ik zie echt nergens in al die boeken of waar dan ook hoe ik meerdere 'FX-passes' toepas. De boel loopt altijd in de zeik als ik nog eens (in functie of niet) weer aan Pass(0) begin met een andere Technique.

[ Voor 4% gewijzigd door Orwell op 26-12-2010 21:46 ]


Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

uit de losse hand, om een frame te renderen, kun je iets doen als

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1) zoek een lijst met alle objecten (modellen) die je wilt renderen. gebruik culling om alles buiten je camera-frustrum uit te sluiten
2) splits lijst uit stap 1) in groepen. dat gebruik je om bepaalde modellen later te doen. bijvoorbeeld, groep 1 = alle non-transparante modellen, groep 2 = skybox, groep 3 = transparente modellen
3) clear depth + render target, begin scene
foreach(groep)
{
  4) splits de modellen in de groep per technique
  foreach(technique)
  {
    5) begin technique
    6) foreach(pass in technique)
    {
       7) begin pass
       8) render alle geometry voor modellen met deze technique
       9) end pass
    }
    10) end technique
  }
}
11) post-processing
12) HUD/GUI/andere overlays etc.
13) end scene, present


voor deferred rendering is het vrijwel hetzelfde, alleen moeten je techniques naar de deferred buffer renderen, en is je eerste post-process je deferred lighting

-niks-


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
Forward rendering post-processing is niet moeilijk. Zolang je alles eerst maar naar een render target rendered, kun je dan bij je laatste stap (rendertarget->screen) een postprocessing shader gebruiken, zoiets als blur is dan perfect te doen. (Sommige andere technieken zoals diepte-gebaseerde blur zijn idd wat moeilijker, maar met MRT is ook daar wel wat aan te doen).

Verder chapeau dat je zo ff een forward renderer in elkaar hebt gezet, uit je start post lijkt het alsof je dat zo even in een paar middagjes hebt gedaan, en dat is toch wel erg tof!

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • Orwell
  • Registratie: December 2009
  • Laatst online: 08-09 22:11
roy-t schreef op maandag 27 december 2010 @ 19:25:
Forward rendering post-processing is niet moeilijk. Zolang je alles eerst maar naar een render target rendered, kun je dan bij je laatste stap (rendertarget->screen) een postprocessing shader gebruiken, zoiets als blur is dan perfect te doen. (Sommige andere technieken zoals diepte-gebaseerde blur zijn idd wat moeilijker, maar met MRT is ook daar wel wat aan te doen).
Wie zei hier Post Process (met een dot blur en B&W)?

Afbeeldingslocatie: http://img232.imageshack.us/img232/2262/klein.png

Eerst rendere men met een viewport naar een eigen texture, en dan zette men die texture pal voor de camera. Maar goed, inderdaad, je moet het doen met de uiteindelijk berekende kleuren, de uiteindelijke kleuren. Geen specular, diepte, normals en al die data. Maar daar gaat het even niet over
Verder chapeau dat je zo ff een forward renderer in elkaar hebt gezet, uit je start post lijkt het alsof je dat zo even in een paar middagjes hebt gedaan, en dat is toch wel erg tof!
Dat van die paar middagjes valt op zich mee, het is al twee weken geleden dat ik de FFP in de prul heb gegooid en zo goed als overnieuw ben begonnen. Maar het tempo komt vooral door ervaring met modden, van Mount&Blade welteverstaan. Daardoor was 'k al bekend met 3D, HLSL en cpp. Dus ja, valt best mee. Wilde alleen weten hoe het nu eigenlijk werkte achter de schermen. ;)

En laten jullie nu eens een geniaal idee hebben! Waarom zet ik niet gewoon een shader in het levelformaat?

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
P -2957.6 1513.3 65.8 // Positional
D 1 1 0.5 // Directional
S 1.0 // Diffuse
A 0.3 // Ambient
C 0 25 0 0 0 // Camera xyz angleH angleV

m Conifer.obj // model
t Conifer.dds // texture
p 91 0 1073 // worldpos
r 0 324 0 // rotate
s 0.85335 0.85335 0.85335 // scale

m *idem* // instance van bovenstaande
t *idem* // instance van bovenstaande
p -33 0 -1331
r 0 284 0
s 1.55272 1.55272 1.55272

(mtprs...)


Hierzo het formaat op het moment. Als ik nu is voor elk model een f toevoeg en daarachter de naam van de shader? En als ik daarna eens die hele pass in een functie dump en zo elke shader langsga (die ik in een array dump)? Geniaal plan.
Pagina: 1