Ik ben bezig met het uitzoeken hoe ik alle informatie die ik nodig heb voor een fysiek gebaseerde uitgestelde renderer in een G-buffer kan verpakken zonder een obscene te gebruiken aantal rendertargets.

Wat ik tot nu toe heb, zijn 4 driedelige vectoren:

  • Albedo / Diffuus
  • Normaal
  • Tangent
  • Positie

En 4 afzonderlijke componenten

  • Metallic
  • Ruwheid
  • Hoogte
  • Ambient Occlusion

Een naïeve benadering is om een van de enkele componenten te bundelen in het alfa (vierde) kanaal met een van de driedelige vectoren, dat is mijn huidige onderzoekslijn. Maar aangezien vier 4-kanaals drijvende-kommaweergavedoelen met volledige precisie niet “klein zijn, begrijp ik dat het gebruikelijk is om halve precisie en zelfs kleinere representaties te gebruiken om meer geheugenbewust te zijn.

Wat ik vraag is: op welke componenten kan ik veilig de precisie verminderen zonder aan kwaliteit in te boeten, en met hoeveel?

Antwoord

Allereerst heb je helemaal geen positie in de G-buffer nodig. De positie van een pixel kan worden gereconstrueerd vanuit de dieptebuffer , waarbij u de camera-instellingen en de schermruimte xy-positie van de pixel kent. U kunt dus die hele buffer.

Ook heb je gewoonlijk ook geen tangensvectoren nodig in de G-buffer. Ze zijn alleen nodig voor het converteren van normale kaarten vanuit de raakruimte en voor parallax-mapping; deze zouden worden gedaan tijdens de G-buffer vulpas (wanneer je raaklijnen hebt van de mesh die je rendert), en de G-buffer zou alleen sla normalen op in wereld- of kijkruimte.

Materiaaleigenschappen zoals kleuren, ruwheid en metaalachtig zijn meestal slechts 8-bits waarden in de G-buffer, aangezien ze afkomstig zijn van 8-bits texturen. Hetzelfde geldt voor AO.

Hoogte is ook niet nodig in de G-buffer, tenzij je een soort van multi-pass blending gaat doen die ervan afhangt, maar als je het nodig hebt, is 8 bits waarschijnlijk ook daarvoor genoeg.

Normalen kunnen er baat bij hebben als ze worden opgeslagen als 16-bits waarden in plaats van 8-bits. Half-float is oké, maar een 16-bit fixed-point is zelfs nog beter, omdat het je meer uniforme precisie geeft in alle oriëntaties (half-float is nauwkeuriger bij de assen en verliest wat precisie daarbuiten). Bovendien kunt u ze van 3 componenten terugbrengen naar 2 met octaëdrische mapping .

Dus aan het eind van de dag is een minimale G-buffer kan er als volgt uitzien:

  • Materiaalkleur + metallic: RGBA8
  • Octaëdrische wereldruimte normaal + ruwheid + AO: RGBA16

en dat is alles! Slechts 12 bytes per pixel.

Als alternatief zou je een RG16-buffer kunnen gebruiken voor de normalen, en ruwheid + AO naar een aparte 8-bits buffer kunnen verplaatsen. Dat zou je wat ruimte om te groeien mocht je uiteindelijk meer G-buffer componenten nodig hebben van ofwel 8-bit of 16-bit grootten.

Reacties

  • Ook metalness is vaak een binaire waarde, en ervan uitgaande dat u geen ruwheidsgradiënten gebruikt (om de impact van verminderde precisie te zien), kunt u metalheid en ruwheid opslaan in een enkel 8-bit-kanaal (1 bit voor metalness en 7 voor ruwheid).

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *