Jeg er i gang med at finde ud af, hvordan jeg pakker al den information, jeg har brug for til en fysisk baseret udskudt gengiver, i en G-buffer uden at bruge en uanstændig mængden af gengivelsesmål.
Det, jeg hidtil har, er 4 3-delte vektorer:
- Albedo / Diffuse
- Normal
- Tangent
- Position
Og 4 enkeltkomponenter
- Metallic
- Roughness
- Højde
- Omgivende okklusion
En naiv tilgang er at bundte en af de enkelte komponenter i alfa (fjerde) kanal med en af de tre-delte vektorer, hvilket er min nuværende undersøgelseslinje. I betragtning af at fire 4-kanals mål med fuld præcision med flydende punkt gengiver ikke er lille, forstår jeg, at det er almindeligt at bruge halv præcision og endnu mindre repræsentationer for at være mere hukommelsesbevidst.
Det, jeg spørger, er: hvilke komponenter kan jeg sikkert reducere præcisionen uden at miste kvalitet, og med hvor meget?
Svar
Først og fremmest behøver du slet ikke position i G-bufferen. Placeringen af en pixel kan rekonstrueres fra dybdebufferen under kendskab til kameraopsætningen og pixelens skærmplads xy-position. Så du kan slippe af med hele bufferen.
Desuden behøver du normalt ikke tangentvektorer i G-bufferen heller. De “er kun nødvendige for at konvertere normale kort fra tangentrum og til parallax-kortlægning; disse ville blive gjort under G-buffer-udfyldningskortet (når du har tangenter fra det maske, du gengiver), og G-bufferen ville kun gemme normaler i verden eller se plads.
Materielle egenskaber som farver, ruhed og metallisk er normalt kun 8-bit værdier i G-bufferen, da de kommer fra 8-bit teksturer. Samme for AO.
Højde er heller ikke nødvendig i G-bufferen, medmindre du vil lave en slags multi-pass-blanding, der afhænger af det, men hvis du har brug for det, er 8 bit sandsynligvis nok til det også.
Normaler kan have fordel af at blive gemt som 16-bit-værdier snarere end 8-bit. Half-float er okay, men 16-bit fixed-point er endnu bedre, da det giver dig mere ensartet præcision på tværs af alle retninger (halv-float er mere præcis nær akserne og mister noget præcision væk fra dem). Desuden kan du klippe dem fra 3 komponenter ned til 2 ved hjælp af oktaedrisk kortlægning .
Så i slutningen af dagen er en minimal G-buffer kan se ud som:
- Materiale farve + metallisk: RGBA8
- Oktahedrisk verdensrum normal + ruhed + AO: RGBA16
og det er alt! Kun 12 byte pr. pixel.
Alternativt kan du bruge en RG16-buffer til de normale og flytte ruhed + AO til en separat 8-bit buffer. Det ville give dig noget plads til at vokse, hvis du til sidst har brug for flere G-buffer komponenter i enten 8-bit eller 16-bit størrelser.
Kommentarer
- Også metalhed er ofte en binær værdi, og forudsat at du ikke bruger ruhedsgradienter (for at se virkningen af reduceret præcision), kan du gemme metal og ruhed i en enkelt 8-bit kanal (1 bit for metalhed og 7 for ruhed).