Global Illumination Research Pt 6
A "roughness" property has been added in the material editor. This is a simple slider with a value from zero to one. (The default material roughness value is 0.5, so all your existing materials won't turn into mirrors when the update comes). Changing the roughness value will have no visible effect unless an environment probe is visible in the scene, although I could modify the lighting shaders to make this control gloss in the specular calculation:
Two new commands have also been added, Material::SetRoughness and Material::GetRoughness.
All of the channels in our 4-texture gbuffer are already in use. To avoid allocating an additional texture to store the per-pixel roughness value, I used two flags in the materials flags value to make a simple 2-bit float. This is encoded in the geometry pass as follows:
if (materialroughness>=0.5) { materialflags += 32; if (materialroughness>=0.75) materialflags += 64; } else { if (materialroughness>=0.25) materialflags += 64; }
The probe shader then decodes it into a "roughness" integer:
int roughness=1; if ((32 & materialflags)!=0) roughness += 4; if ((64 & materialflags)!=0) roughness += 2;
The reflection cubemap lookup is then performed as follows:
miplevel = max(int(textureQueryLod(texture5,shadowcoord).y),roughness); vec4 specular = textureLod(texture5,shadowcoord,miplevel) * specularity * lightspecular;
This allows us to pack the roughness value into the gbuffer while avoiding additional texture memory use. We also have one final unused flag in the material flags value we can allocate in the future for additional functionality. Although this only allows four possible roughness values, I think it is a good solution. Just remember that "rough surface" equals "blurry reflection". The image below corresponds to a low roughness value and the reflections are sharp and clear.
Notice that the reflections do not appear on the directly lit spheres, due to the "maximum" blend mode described here. While not technically accurate, this is a good way of dealing with the limitations of 8-bit color until ultrabright 10-bit monitors (or more) become the norm.
Here is a shot using a medium roughness value, around 0.5:
Finally, a very rough surface gives indistinct reflections that still look great because they correspond to the surrounding environment:
Shader Updates
To solve the problem described here, all shaders have been updated so that gbuffer normals are stored in world space instead of camera space. If you are using the beta branch, you must update your project to get the new shaders or lighting will not appear correctly.
Any third party shaders must be updated for this change. Most model shaders will have a section of code in the vertex program that looks something like this:
mat3 nmat = mat3(camerainversematrix[0].xyz,camerainversematrix[1].xyz,camerainversematrix[2].xyz); nmat *= mat3(entitymatrix[0].xyz,entitymatrix[1].xyz,entitymatrix[2].xyz);
The camera matrix multiplication can be removed and the code simplified to that below:
mat3 nmat = mat3(entitymatrix);
Some post-processing shaders retrieve the pixel normal with a piece of code like this in the fragment program:
vec3 normal = normalize(normaldata.xyz*2.0-1.0);
To update these shaders, first declare a new uniform before the main function:
uniform mat3 camerainversenormalmatrix;
And multiply the world normal by this to get the screen normal:
vec3 normal = camerainversenormalmatrix * normalize(normaldata.xyz*2.0-1.0);
Leadwerks Game Engine 4.1
The new global illumination feature will be released in Leadwerks Game Engine 4.1. For comparison you can see a screenshot below of the Leadwerks 4.0 renderer, which looks good:
But the Leadwerks 4.1 render of the same scene looks absolutely fantastic:
Until now, directly illuminated surfaces in Leadwerks looked the best, and now shaded areas look equally beautiful, or even better. Remaining tasks include testing on AMD and Intel hardware, which I have not done yet. I also have to do more work to selectively render objects in the GI reflection render. Objects that cast dynamic shadows are presently skipped, but I need to actually re-render all shadows so their shadows aren't visible in the reflection. I also need to remove entities like particle emitters and adjust quality settings so the GI render isn't rendering reflective water and other unnecessary things. Finally, the probe shader needs more work so it can handle rotation of the probe entity, which it presently does not do.
- 15
9 Comments
Recommended Comments