HDR: Improve envmap pre-filtering
This commit is contained in:
parent
5c1c28c536
commit
526491790e
10 changed files with 177 additions and 62 deletions
|
@ -4,6 +4,7 @@
|
|||
<type>scene</type>
|
||||
<implicit-attachment-mask>depth</implicit-attachment-mask>
|
||||
<effect-scheme>hdr-envmap</effect-scheme>
|
||||
<clear-mask>depth</clear-mask>
|
||||
<!-- Only render the skydome and terrain -->
|
||||
<!-- TODO: Explicitly select the LOD level -->
|
||||
<cull-mask>0x800</cull-mask>
|
||||
|
|
|
@ -123,6 +123,18 @@
|
|||
<wrap-t>clamp-to-edge</wrap-t>
|
||||
<mipmap-levels>5</mipmap-levels>
|
||||
</buffer>
|
||||
<buffer>
|
||||
<name>prefiltered-envmap</name>
|
||||
<type>cubemap</type>
|
||||
<width>128</width>
|
||||
<height>128</height>
|
||||
<format>rgb16f</format>
|
||||
<min-filter>linear-mipmap-linear</min-filter>
|
||||
<mag-filter>linear</mag-filter>
|
||||
<wrap-s>clamp-to-edge</wrap-s>
|
||||
<wrap-t>clamp-to-edge</wrap-t>
|
||||
<mipmap-levels>5</mipmap-levels>
|
||||
</buffer>
|
||||
|
||||
<!-- Shadow map atlas -->
|
||||
<buffer>
|
||||
|
@ -305,7 +317,6 @@
|
|||
<component>color0</component>
|
||||
<buffer>envmap</buffer>
|
||||
<face>0</face>
|
||||
<level>0</level>
|
||||
</attachment>
|
||||
</pass>
|
||||
<pass include="env-capture-pass.xml">
|
||||
|
@ -315,7 +326,6 @@
|
|||
<component>color0</component>
|
||||
<buffer>envmap</buffer>
|
||||
<face>1</face>
|
||||
<level>0</level>
|
||||
</attachment>
|
||||
</pass>
|
||||
<pass include="env-capture-pass.xml">
|
||||
|
@ -325,7 +335,6 @@
|
|||
<component>color0</component>
|
||||
<buffer>envmap</buffer>
|
||||
<face>2</face>
|
||||
<level>0</level>
|
||||
</attachment>
|
||||
</pass>
|
||||
<pass include="env-capture-pass.xml">
|
||||
|
@ -335,7 +344,6 @@
|
|||
<component>color0</component>
|
||||
<buffer>envmap</buffer>
|
||||
<face>3</face>
|
||||
<level>0</level>
|
||||
</attachment>
|
||||
</pass>
|
||||
<pass include="env-capture-pass.xml">
|
||||
|
@ -345,7 +353,6 @@
|
|||
<component>color0</component>
|
||||
<buffer>envmap</buffer>
|
||||
<face>4</face>
|
||||
<level>0</level>
|
||||
</attachment>
|
||||
</pass>
|
||||
<pass include="env-capture-pass.xml">
|
||||
|
@ -355,7 +362,8 @@
|
|||
<component>color0</component>
|
||||
<buffer>envmap</buffer>
|
||||
<face>5</face>
|
||||
<level>0</level>
|
||||
<!-- Generate the mips after writing to the last face -->
|
||||
<mipmap-generation>true</mipmap-generation>
|
||||
</attachment>
|
||||
</pass>
|
||||
|
||||
|
@ -364,169 +372,207 @@
|
|||
We convolve the cubemap for five roughness values and store the results
|
||||
on the mipmap levels of the cubemap. Later passes will choose which mipmap
|
||||
level to use for reflections based on the roughness of the surface that's
|
||||
being lighted/rendered.
|
||||
being lighted/rendered. The first mipmap level can just be copied from the
|
||||
original envmap as we'd like it to contain perfect mirror reflections.
|
||||
Diffuse lighting is approximated by using the highest mipmap level
|
||||
(roughness=1).
|
||||
-->
|
||||
<pass include="env-prefilter-pass.xml">
|
||||
<name>env-prefilter0</name>
|
||||
<effect>Effects/HDR/envmap-copy</effect>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>0</face>
|
||||
<level>0</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color1</component>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>1</face>
|
||||
<level>0</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color2</component>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>2</face>
|
||||
<level>0</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color3</component>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>3</face>
|
||||
<level>0</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color4</component>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>4</face>
|
||||
<level>0</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color5</component>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>5</face>
|
||||
<level>0</level>
|
||||
</attachment>
|
||||
</pass>
|
||||
<pass include="env-prefilter-pass.xml">
|
||||
<name>env-prefilter1</name>
|
||||
<effect>Effects/HDR/envmap-prefilter1</effect>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>0</face>
|
||||
<level>1</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color1</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>1</face>
|
||||
<level>1</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color2</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>2</face>
|
||||
<level>1</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color3</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>3</face>
|
||||
<level>1</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color4</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>4</face>
|
||||
<level>1</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color5</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>5</face>
|
||||
<level>1</level>
|
||||
</attachment>
|
||||
</pass>
|
||||
|
||||
<pass include="env-prefilter-pass.xml">
|
||||
<name>env-prefilter2</name>
|
||||
<effect>Effects/HDR/envmap-prefilter2</effect>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>0</face>
|
||||
<level>2</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color1</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>1</face>
|
||||
<level>2</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color2</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>2</face>
|
||||
<level>2</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color3</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>3</face>
|
||||
<level>2</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color4</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>4</face>
|
||||
<level>2</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color5</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>5</face>
|
||||
<level>2</level>
|
||||
</attachment>
|
||||
</pass>
|
||||
|
||||
<pass include="env-prefilter-pass.xml">
|
||||
<name>env-prefilter3</name>
|
||||
<effect>Effects/HDR/envmap-prefilter3</effect>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>0</face>
|
||||
<level>3</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color1</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>1</face>
|
||||
<level>3</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color2</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>2</face>
|
||||
<level>3</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color3</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>3</face>
|
||||
<level>3</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color4</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>4</face>
|
||||
<level>3</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color5</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>5</face>
|
||||
<level>3</level>
|
||||
</attachment>
|
||||
</pass>
|
||||
|
||||
<pass include="env-prefilter-pass.xml">
|
||||
<name>env-prefilter4</name>
|
||||
<effect>Effects/HDR/envmap-prefilter4</effect>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>0</face>
|
||||
<level>4</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color1</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>1</face>
|
||||
<level>4</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color2</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>2</face>
|
||||
<level>4</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color3</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>3</face>
|
||||
<level>4</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color4</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>4</face>
|
||||
<level>4</level>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color5</component>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
<face>5</face>
|
||||
<level>4</level>
|
||||
</attachment>
|
||||
|
@ -662,7 +708,7 @@
|
|||
</binding>
|
||||
<binding>
|
||||
<unit>9</unit>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
</binding>
|
||||
<binding>
|
||||
<unit>10</unit>
|
||||
|
@ -695,7 +741,7 @@
|
|||
<effect-scheme>hdr-forward</effect-scheme>
|
||||
<binding>
|
||||
<unit>9</unit>
|
||||
<buffer>envmap</buffer>
|
||||
<buffer>prefiltered-envmap</buffer>
|
||||
</binding>
|
||||
<binding>
|
||||
<unit>11</unit>
|
||||
|
|
17
Effects/HDR/envmap-copy.eff
Normal file
17
Effects/HDR/envmap-copy.eff
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PropertyList>
|
||||
<name>Effects/HDR/envmap-copy</name>
|
||||
<technique n="1">
|
||||
<pass>
|
||||
<program>
|
||||
<vertex-shader>Shaders/HDR/envmap-prefilter.vert</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/envmap-copy.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>envmap</name>
|
||||
<type>sampler-cube</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
</PropertyList>
|
|
@ -3,6 +3,7 @@
|
|||
<name>Effects/HDR/envmap-prefilter</name>
|
||||
<parameters>
|
||||
<roughness type="float">0.0</roughness>
|
||||
<num-samples type="int">1</num-samples>
|
||||
</parameters>
|
||||
<technique n="1">
|
||||
<pass>
|
||||
|
@ -20,6 +21,11 @@
|
|||
<type>float</type>
|
||||
<value><use>roughness</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>num_samples</name>
|
||||
<type>int</type>
|
||||
<value><use>num-samples</use></value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
</PropertyList>
|
||||
|
|
|
@ -4,5 +4,6 @@
|
|||
<inherits-from>Effects/HDR/envmap-prefilter</inherits-from>
|
||||
<parameters>
|
||||
<roughness type="float">0.25</roughness>
|
||||
<num-samples type="int">8</num-samples>
|
||||
</parameters>
|
||||
</PropertyList>
|
||||
|
|
|
@ -4,5 +4,6 @@
|
|||
<inherits-from>Effects/HDR/envmap-prefilter</inherits-from>
|
||||
<parameters>
|
||||
<roughness type="float">0.5</roughness>
|
||||
<num-samples type="int">32</num-samples>
|
||||
</parameters>
|
||||
</PropertyList>
|
||||
|
|
|
@ -4,5 +4,6 @@
|
|||
<inherits-from>Effects/HDR/envmap-prefilter</inherits-from>
|
||||
<parameters>
|
||||
<roughness type="float">0.75</roughness>
|
||||
<num-samples type="int">64</num-samples>
|
||||
</parameters>
|
||||
</PropertyList>
|
||||
|
|
|
@ -4,5 +4,6 @@
|
|||
<inherits-from>Effects/HDR/envmap-prefilter</inherits-from>
|
||||
<parameters>
|
||||
<roughness type="float">1.0</roughness>
|
||||
<num-samples type="int">128</num-samples>
|
||||
</parameters>
|
||||
</PropertyList>
|
||||
|
|
27
Shaders/HDR/envmap-copy.frag
Normal file
27
Shaders/HDR/envmap-copy.frag
Normal file
|
@ -0,0 +1,27 @@
|
|||
#version 330 core
|
||||
|
||||
layout(location = 0) out vec3 fragColor0;
|
||||
layout(location = 1) out vec3 fragColor1;
|
||||
layout(location = 2) out vec3 fragColor2;
|
||||
layout(location = 3) out vec3 fragColor3;
|
||||
layout(location = 4) out vec3 fragColor4;
|
||||
layout(location = 5) out vec3 fragColor5;
|
||||
|
||||
in vec3 cubemapCoord0;
|
||||
in vec3 cubemapCoord1;
|
||||
in vec3 cubemapCoord2;
|
||||
in vec3 cubemapCoord3;
|
||||
in vec3 cubemapCoord4;
|
||||
in vec3 cubemapCoord5;
|
||||
|
||||
uniform samplerCube envmap;
|
||||
|
||||
void main()
|
||||
{
|
||||
fragColor0 = textureLod(envmap, cubemapCoord0, 0.0).rgb;
|
||||
fragColor1 = textureLod(envmap, cubemapCoord1, 0.0).rgb;
|
||||
fragColor2 = textureLod(envmap, cubemapCoord2, 0.0).rgb;
|
||||
fragColor3 = textureLod(envmap, cubemapCoord3, 0.0).rgb;
|
||||
fragColor4 = textureLod(envmap, cubemapCoord4, 0.0).rgb;
|
||||
fragColor5 = textureLod(envmap, cubemapCoord5, 0.0).rgb;
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
// Mostly based on 'Moving Frostbite to Physically Based Rendering'
|
||||
// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
|
||||
|
||||
#version 330 core
|
||||
|
||||
layout(location = 0) out vec3 fragColor0;
|
||||
|
@ -16,11 +19,11 @@ in vec3 cubemapCoord5;
|
|||
|
||||
uniform samplerCube envmap;
|
||||
uniform float roughness;
|
||||
|
||||
uniform int fg_CubemapFace;
|
||||
uniform int num_samples;
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
const uint NUM_SAMPLES = 64u;
|
||||
const float ENVMAP_SIZE = 128.0;
|
||||
const float ENVMAP_MIP_COUNT = 4.0;
|
||||
|
||||
float RadicalInverse_VdC(uint bits)
|
||||
{
|
||||
|
@ -37,57 +40,68 @@ vec2 Hammersley(uint i, uint N)
|
|||
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
|
||||
}
|
||||
|
||||
vec3 ImportanceSampleGGX(vec2 Xi, vec3 n, float r)
|
||||
vec3 ImportanceSampleGGX(vec2 Xi, vec3 n, float a)
|
||||
{
|
||||
float a = r*r;
|
||||
|
||||
float phi = 2.0 * PI * Xi.x;
|
||||
float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
|
||||
float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
|
||||
|
||||
vec3 h;
|
||||
h.x = sinTheta * cos(phi);
|
||||
h.y = sinTheta * sin(phi);
|
||||
h.z = cosTheta;
|
||||
return h;
|
||||
}
|
||||
|
||||
vec3 up = abs(n.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
|
||||
vec3 tangent = normalize(cross(up, n));
|
||||
vec3 bitangent = cross(n, tangent);
|
||||
|
||||
vec3 sampleVec = tangent * h.x + bitangent * h.y + n * h.z;
|
||||
return normalize(sampleVec);
|
||||
float D_GGX(float NdotH, float a2)
|
||||
{
|
||||
float f = (NdotH * a2 - NdotH) * NdotH + 1.0;
|
||||
return a2 / (PI * f * f);
|
||||
}
|
||||
|
||||
vec3 prefilter(vec3 n)
|
||||
{
|
||||
n = normalize(n);
|
||||
vec3 v = n; // n = v simplification
|
||||
float a = roughness*roughness;
|
||||
|
||||
vec3 prefilteredColor = vec3(0.0);
|
||||
float totalWeight = 0.0;
|
||||
|
||||
for (uint i = 0u; i < NUM_SAMPLES; ++i) {
|
||||
vec2 Xi = Hammersley(i, NUM_SAMPLES);
|
||||
vec3 h = ImportanceSampleGGX(Xi, n, roughness);
|
||||
vec3 up = abs(n.z) < 0.999f ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
|
||||
vec3 tangent = normalize(cross(up, n));
|
||||
vec3 bitangent = cross(n, tangent);
|
||||
mat3 tangentToWorld = mat3(tangent, bitangent, n);
|
||||
|
||||
uint sample_count = uint(num_samples);
|
||||
for (uint i = 0u; i < sample_count; ++i) {
|
||||
vec2 Xi = Hammersley(i, sample_count);
|
||||
vec3 h = tangentToWorld * ImportanceSampleGGX(Xi, n, a);
|
||||
vec3 l = normalize(2.0 * dot(v, h) * h - v);
|
||||
|
||||
float NdotL = max(dot(n, l), 0.0);
|
||||
if (NdotL > 0.0) {
|
||||
prefilteredColor += textureLod(envmap, l, 0.0).rgb * NdotL;
|
||||
float NdotH = clamp(dot(n, h), 0.0, 1.0);
|
||||
float VdotH = clamp(dot(v, h), 0.0, 1.0);
|
||||
|
||||
float pdf = D_GGX(NdotH, a) * NdotH / (4.0 * VdotH);
|
||||
float omegaS = 1.0 / (float(sample_count) * pdf);
|
||||
float omegaP = 4.0 * PI / (6.0 * ENVMAP_SIZE * ENVMAP_SIZE);
|
||||
float mipLevel = clamp(0.5 * log2(omegaS / omegaP) + 1.0,
|
||||
0.0, ENVMAP_MIP_COUNT);
|
||||
|
||||
prefilteredColor += textureLod(envmap, l, mipLevel).rgb * NdotL;
|
||||
totalWeight += NdotL;
|
||||
}
|
||||
}
|
||||
|
||||
prefilteredColor /= totalWeight;
|
||||
return prefilteredColor;
|
||||
return prefilteredColor / totalWeight;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
fragColor0 = prefilter(cubemapCoord0);
|
||||
fragColor1 = prefilter(cubemapCoord1);
|
||||
fragColor2 = prefilter(cubemapCoord2);
|
||||
fragColor3 = prefilter(cubemapCoord3);
|
||||
fragColor4 = prefilter(cubemapCoord4);
|
||||
fragColor5 = prefilter(cubemapCoord5);
|
||||
fragColor0 = prefilter(normalize(cubemapCoord0));
|
||||
fragColor1 = prefilter(normalize(cubemapCoord1));
|
||||
fragColor2 = prefilter(normalize(cubemapCoord2));
|
||||
fragColor3 = prefilter(normalize(cubemapCoord3));
|
||||
fragColor4 = prefilter(normalize(cubemapCoord4));
|
||||
fragColor5 = prefilter(normalize(cubemapCoord5));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue