How much precision do I need in my G-Buffer? I'm in the process of working out how to pack all the information I need for a Physically Based Deferred Renderer into a G-Buffer without using an obscene amount of render targets. 

What I have so far is 4 3-part vectors: 


Albedo/Diffuse
Normal
Tangent
Position


And 4 single components


Metallic
Roughness
Height
Ambient Occlusion


A naive approach is to bundle one of the single components into the alpha (fourth) channel with one of the 3-part vectors, which is my current line of investigation. However, given that four 4-channel full precision floating point render targets isn't small I understand it's common to use half precision and even smaller representations to be more memory conscious. 

What I'm asking is: which components can I safely cut precision down on without losing quality, and by how much?
First of all, you don't need position in the G-buffer at all. The position of a pixel can be reconstructed from the depth buffer, knowing the camera setup and the pixel's screen-space xy position. So you can get rid of that whole buffer.

Also, you don't ordinarily need tangent vectors in the G-buffer either. They're only needed for converting normal maps from tangent space, and for parallax mapping; these would be done during the G-buffer fill pass (when you have tangents from the mesh you're rendering), and the G-buffer would only store normals in world or view space.

Material properties like colors, roughness, and metallic are usually just 8-bit values in the G-buffer, since they're sourced from 8-bit textures. Same for AO.

Height is also not needed in the G-buffer unless you're going to be doing some kind of multi-pass blending that depends on it, but if you do need it, 8 bits is probably enough for that too.

Normals can be benefit from being stored as 16-bit values rather than 8-bit. Half-float is okay, but 16-bit fixed-point is even better, as it gives you more uniform precision across all orientations (half-float is more precise near the axes and loses some precision away from them). Moreover, you can cut them from 3 components down to 2 using octahedral mapping.

So, at the end of the day, a minimal G-buffer might look like:


Material color + metallic: RGBA8
Octahedral world-space normal + roughness + AO: RGBA16


and that's all! Only 12 bytes per pixel.

Alternatively, you could use an RG16 buffer for the normals, and move roughness + AO into a separate 8-bit buffer. That would give you some room to grow should you eventually need more G-buffer components of either 8-bit or 16-bit sizes.