PDA

View Full Version : Deferred PBR materials



Neuroticheeze
05-22-2017, 03:34 AM
Hey, 1st time posting so sorry in advance if I put this thread in the wrong spot or whatever but,

I'd like to get some advice and opinions from you guys about something I've implemented so far.
People are saying that the less gl state changes your renderer makes, the less of a bottleneck it will be.
So, I wanna remove much of the texture switching and binding that goes on behind the scenes as muich as possible.

I've actually put a system in place to do this and it works like a charm but I'm not sure if it's actually beneficial.
So far I'm using Mipmapped Texture2D Arrays. Which is an array of mip textures 0-n, and each mip level is an array of equal sized textures, My engine utilises each mip level as an extra place to store a unique texture.
For example,
Given just the albedo texture-array:

ALBEDO:
Mip 0 = { A(512x512), B(512x512), C(512x512), ... }
Mip 1 = { D(256x256), F(256x256), H(256x256), ... }
Mip 2 = { E(128x128), G(128x128), ...}
etc, etc

This way, each texture fits together sort of like a 2-dimensional jagged array.
Therefore to reference a single texture we need 2 numbers ("MipLevel" and "LayerIndex"). I store these numbers as a uvec2 in glsl.

Each material (eg, for a chair, or a character) is made up of 5 textures so far:
Albedo
Normals
Roughness
Metalness
and Additive (glowmap)

I plan to restructure the definition of a PBR material for my engine in the future but this is it for now.


Inside the shader that writes to the vertex info buffer, The material is known as a single integer. When it is time to sample from these texture arrays using textureLod, that int is used in a lookup which returns 10 numbers, these tell us where each texture in the texture-arrays that make up a material can be found.

textureLod for texture arrays takes in a vec3, as well as LOD. So ultimately 4 parameters [TexCoord.u, TexCoord.v, LayerIndex, MipLevel].

So, in summary:

materialID + texCoord ->
[Material Lookup] ->
5x uvec2's (5 pbr textures) ->
5x textureLod(sampler2DArray, vec3(texCoord, layerIndex), mipLevel) ->
5x sampled vec4's from the textures that make up the PBR material;

There's some drawbacks ofc,
LOD Mipmapping isn't possible,
All textures must be resized to the nearest power-of-2 square texture dimensions beforehand (Done when the game starts up)

But, performance is good, by eye; Haven't measured it yet.
Texture detail is still kept and visible which is good.
No artifacts that I can see.
And the used texture units + samplers inside a shader is kept to a few, bound once and that's it for the life of the program.

All that said, I see potential for this approach but there are just so many caveats. Should I abandon this technique altogether for something better? Or is what I have going a pretty solid approach from a design perspective?
I just wanna ask you guys if there's a tried and true technique for keeping texture switching and binding to a minimum in the update loop, or any thoughts you guys might have on where I can make improvements.

Thanks, sorry if this is all vague nonsense. I'd be happy to elaborate.

TL:DR Looking for a system that will drastically limit the number of texture swaps, allowing for a PBR material system by design.

Dark Photon
05-22-2017, 06:07 PM
All that said, I see potential for this approach but there are just so many caveats. Should I abandon this technique altogether for something better? Or is what I have going a pretty solid approach from a design perspective?
I just wanna ask you guys if there's a tried and true technique for keeping texture switching and binding to a minimum in the update loop, or any thoughts you guys might have on where I can make improvements.

It's a good start, but you may also want to look at using bindless textures instead or in addition as they get rid of some of the cons (obvious and definitely not obvious) for using texture arrays to minimize binds, particularly when you are dynamically subloading some of these textures at runtime.

For more on eliminating state changes in general (texture binds included), even if you're not targeting NVidia GPUs specifically (but especially if you are), be sure and read the various "AZDO" (Approaching Zero Driver Overhead) presentations that NVidia has put out in the last 5 years or so. Also, this page is a useful read: OpenGL like Vulkan (https://developer.nvidia.com/opengl-vulkan) (NVidia)