1
0
Fork 0

HDR: Optimize the G-Buffer and do not separate the occlusion texture

- The G-Buffer layout has been redesigned to be 96 bits per pixel. There are 24
unused bits that can be used for extra material parameters later (like
clearcoat).
- Add better debug views for the G-Buffer.
- Use octahedron normal encoding. This yields the same results as the previous
method but uses 16 bits less.
- Use rg11fb10f for the environment mapping cubemaps.
- Tweak the shadow mapping parameters and add a colored debug mode.
- Only render shadow maps for objects that inherit from model-default.eff or
model-pbr.eff instead of having a fallback Effect. Now transparent objects
should be ignored (if they are marked as such with model-transparent or
similar).
- Remove the separate occlusion texture. Now the PBR Effect expects a single
texture where R=occlusion, G=roughness and B=metallic.
This commit is contained in:
Fernando García Liñán 2021-08-26 22:51:46 +02:00
parent a789c24209
commit 9f39644199
34 changed files with 509 additions and 253 deletions

View file

@ -7,29 +7,42 @@
<use-vertex-attribute-aliasing>true</use-vertex-attribute-aliasing>
<!--
G-Buffer
.........................................................
: Buffer : Red : Green : Blue : Alpha :
:........:...........:...........:..........:...........:
: RT0 : albedo.r : albedo.g : albedo.b : AO/Cavity :
: RT1 : normal.x : normal.y :
: RT2 : Metalness : Roughness : Clearcoat :
: RT3 : Depth :
:........:...........:...........:..........:...........:
G-Buffer layout
..........................................................................
: : Red : Green : Blue : Alpha :
:.......................:...........:.........:............:.............:
: G-Buffer 0 (RGB10_A2) : Normal : Roughness : Material ID :
: G-Buffer 1 (RGBA8) : Base Color : Metallic :
: G-Buffer 2 (RGBA8) : Material specific params : Occlusion :
: Depth/Stencil : DEPTH32F_STENCIL8 (Reversed depth) :
:.......................:............:.........:...........:.............:
Notes:
- Two 10-bit channels is enough for normals, as long as we are using
octahedron normal encoding.
- Since the Material ID is stored in 2 bits, we can only have 4 different
material types. The maximum value (3 or 1.0) is reserved for the standard
PBR metallic-roughness material.
- In 'Material specific params' fancier materials can use up to 24 bits
to encode any information they might need (e.g. a clearcoat layer needs
to store the clearcoat amount and roughness).
- Materials that are very different from the standard should write
whatever they need in the G-Buffer without adhering to this layout and use
the stencil buffer and a separate render pass.
-->
<buffer>
<name>gbuffer0</name>
<type>2d</type>
<width>screen</width>
<height>screen</height>
<format>rgba8</format>
<format>rgb10-a2</format>
</buffer>
<buffer>
<name>gbuffer1</name>
<type>2d</type>
<width>screen</width>
<height>screen</height>
<format>rg16f</format>
<format>rgba8</format>
</buffer>
<buffer>
<name>gbuffer2</name>
@ -116,7 +129,7 @@
<type>cubemap</type>
<width>128</width>
<height>128</height>
<format>rgb16f</format>
<format>r11f-g11f-b10f</format>
<min-filter>linear-mipmap-linear</min-filter>
<mag-filter>linear</mag-filter>
<wrap-s>clamp-to-edge</wrap-s>
@ -128,7 +141,7 @@
<type>cubemap</type>
<width>128</width>
<height>128</height>
<format>rgb16f</format>
<format>r11f-g11f-b10f</format>
<min-filter>linear-mipmap-linear</min-filter>
<mag-filter>linear</mag-filter>
<wrap-s>clamp-to-edge</wrap-s>
@ -157,7 +170,7 @@
<type>2d</type>
<width>1024</width>
<height>1024</height>
<format>r16f</format>
<format>r32f</format>
<min-filter>linear-mipmap-nearest</min-filter>
<mag-filter>nearest</mag-filter>
<mipmap-levels>10</mipmap-levels>
@ -167,7 +180,7 @@
<type>2d</type>
<width>1</width>
<height>1</height>
<format>r16f</format>
<format>r32f</format>
<min-filter>nearest</min-filter>
<mag-filter>nearest</mag-filter>
</buffer>
@ -176,7 +189,7 @@
<type>2d</type>
<width>1</width>
<height>1</height>
<format>r16f</format>
<format>r32f</format>
<min-filter>nearest</min-filter>
<mag-filter>nearest</mag-filter>
</buffer>
@ -260,6 +273,31 @@
<!--=======================================================================-->
<!--
Clear the G-Buffer if we are debugging it to avoid the dreaded
'Solitaire Effect' :)
-->
<pass>
<name>debug-clear-gbuffer</name>
<type>quad</type>
<effect>Effects/HDR/gbuffer-debug-clear</effect>
<condition>
<property>/sim/rendering/hdr/debug/show-gbuffer</property>
</condition>
<attachment>
<component>color0</component>
<buffer>gbuffer0</buffer>
</attachment>
<attachment>
<component>color1</component>
<buffer>gbuffer1</buffer>
</attachment>
<attachment>
<component>color2</component>
<buffer>gbuffer2</buffer>
</attachment>
</pass>
<!--
Generate the atmospheric scattering related LUTs
This is an implementation of Sébastien Hillaire's "A Scalable and
@ -641,7 +679,7 @@
<pass include="csm-pass.xml">
<name>csm0</name>
<near-m>0.1</near-m>
<far-m>3.0</far-m>
<far-m>2.0</far-m>
<viewport>
<x>0.0</x>
<y>0.0</y>
@ -651,8 +689,8 @@
</pass>
<pass include="csm-pass.xml">
<name>csm1</name>
<near-m>3.0</near-m>
<far-m>70.0</far-m>
<near-m>2.0</near-m>
<far-m>40.0</far-m>
<viewport>
<x>0.5</x>
<y>0.0</y>
@ -662,8 +700,8 @@
</pass>
<pass include="csm-pass.xml">
<name>csm2</name>
<near-m>70.0</near-m>
<far-m>300.0</far-m>
<near-m>40.0</near-m>
<far-m>150.0</far-m>
<viewport>
<x>0.0</x>
<y>0.5</y>
@ -673,8 +711,8 @@
</pass>
<pass include="csm-pass.xml">
<name>csm3</name>
<near-m>300.0</near-m>
<far-m>1000.0</far-m>
<near-m>150.0</near-m>
<far-m>500.0</far-m>
<viewport>
<x>0.5</x>
<y>0.5</y>
@ -690,11 +728,11 @@
<effect>Effects/HDR/ao</effect>
<binding>
<unit>0</unit>
<buffer>depth-stencil</buffer>
<buffer>gbuffer0</buffer>
</binding>
<binding>
<unit>1</unit>
<buffer>gbuffer1</buffer>
<buffer>depth-stencil</buffer>
</binding>
<attachment>
<component>color0</component>
@ -1198,36 +1236,36 @@
<!-- Debug passes -->
<pass include="debug-pass.xml">
<name>debug-albedo</name>
<effect>Effects/HDR/trivial</effect>
<name>debug-color</name>
<effect>Effects/HDR/gbuffer-debug-color</effect>
<geometry>
<left>0.0</left>
<bottom>0.0</bottom>
<width>0.2</width>
<height>0.2</height>
</geometry>
<binding>
<unit>0</unit>
<buffer>gbuffer0</buffer>
</binding>
</pass>
<pass include="debug-pass.xml">
<name>debug-normals</name>
<effect>Effects/HDR/trivial</effect>
<geometry>
<left>0.8</left>
<bottom>0.0</bottom>
<width>0.2</width>
<height>0.2</height>
</geometry>
<binding>
<unit>0</unit>
<buffer>gbuffer1</buffer>
</binding>
</pass>
<pass include="debug-pass.xml">
<name>debug-materials</name>
<effect>Effects/HDR/trivial</effect>
<name>debug-normals</name>
<effect>Effects/HDR/gbuffer-debug-normal</effect>
<geometry>
<left>0.8</left>
<bottom>0.0</bottom>
<width>0.2</width>
<height>0.2</height>
</geometry>
<binding>
<unit>0</unit>
<buffer>gbuffer0</buffer>
</binding>
</pass>
<pass include="debug-pass.xml">
<name>debug-orm</name>
<effect>Effects/HDR/gbuffer-debug-orm</effect>
<geometry>
<left>0.0</left>
<bottom>0.8</bottom>
@ -1236,9 +1274,31 @@
</geometry>
<binding>
<unit>0</unit>
<buffer>gbuffer0</buffer>
</binding>
<binding>
<unit>1</unit>
<buffer>gbuffer1</buffer>
</binding>
<binding>
<unit>2</unit>
<buffer>gbuffer2</buffer>
</binding>
</pass>
<pass include="debug-pass.xml">
<name>debug-matid</name>
<effect>Effects/HDR/gbuffer-debug-matid</effect>
<geometry>
<left>0.0</left>
<bottom>0.57</bottom>
<width>0.2</width>
<height>0.2</height>
</geometry>
<binding>
<unit>0</unit>
<buffer>gbuffer0</buffer>
</binding>
</pass>
<pass include="debug-pass.xml">
<name>debug-depth</name>
<effect>Effects/HDR/visualize-depth</effect>

View file

@ -9,12 +9,12 @@
<fragment-shader>Shaders/HDR/gbuffer-include.frag</fragment-shader>
</program>
<uniform>
<name>depth_tex</name>
<name>gbuffer0_tex</name>
<type>sampler-2d</type>
<value type="int">0</value>
</uniform>
<uniform>
<name>normal_tex</name>
<name>depth_tex</name>
<type>sampler-2d</type>
<value type="int">1</value>
</uniform>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<PropertyList>
<name>Effects/HDR/gbuffer-debug-clear</name>
<technique n="1">
<pass>
<program>
<vertex-shader>Shaders/HDR/trivial.vert</vertex-shader>
<fragment-shader>Shaders/HDR/gbuffer-debug-clear.frag</fragment-shader>
</program>
</pass>
</technique>
</PropertyList>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<PropertyList>
<name>Effects/HDR/gbuffer-debug-color</name>
<technique n="1">
<pass>
<program>
<vertex-shader>Shaders/HDR/trivial.vert</vertex-shader>
<fragment-shader>Shaders/HDR/gbuffer-debug-color.frag</fragment-shader>
</program>
<uniform>
<name>gbuffer1_tex</name>
<type>sampler-2d</type>
<value type="int">0</value>
</uniform>
</pass>
</technique>
</PropertyList>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<PropertyList>
<name>Effects/HDR/gbuffer-debug-matid</name>
<technique n="1">
<pass>
<program>
<vertex-shader>Shaders/HDR/trivial.vert</vertex-shader>
<fragment-shader>Shaders/HDR/gbuffer-debug-matid.frag</fragment-shader>
</program>
<uniform>
<name>gbuffer0_tex</name>
<type>sampler-2d</type>
<value type="int">0</value>
</uniform>
</pass>
</technique>
</PropertyList>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<PropertyList>
<name>Effects/HDR/gbuffer-debug-normal</name>
<technique n="1">
<pass>
<program>
<vertex-shader>Shaders/HDR/trivial.vert</vertex-shader>
<fragment-shader>Shaders/HDR/gbuffer-debug-normal.frag</fragment-shader>
</program>
<uniform>
<name>gbuffer0_tex</name>
<type>sampler-2d</type>
<value type="int">0</value>
</uniform>
</pass>
</technique>
</PropertyList>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<PropertyList>
<name>Effects/HDR/gbuffer-debug-orm</name>
<technique n="1">
<pass>
<program>
<vertex-shader>Shaders/HDR/trivial.vert</vertex-shader>
<fragment-shader>Shaders/HDR/gbuffer-debug-orm.frag</fragment-shader>
</program>
<uniform>
<name>gbuffer0_tex</name>
<type>sampler-2d</type>
<value type="int">0</value>
</uniform>
<uniform>
<name>gbuffer1_tex</name>
<type>sampler-2d</type>
<value type="int">1</value>
</uniform>
<uniform>
<name>gbuffer2_tex</name>
<type>sampler-2d</type>
<value type="int">2</value>
</uniform>
</pass>
</technique>
</PropertyList>

View file

@ -11,6 +11,9 @@
<wrap-t>clamp-to-edge</wrap-t>
<internal-format>normalized</internal-format>
</texture>
<show-shadow-cascades>
<use>/sim/rendering/hdr/debug/show-shadow-cascades</use>
</show-shadow-cascades>
</parameters>
<technique n="1">
<pass>
@ -61,6 +64,11 @@
<type>sampler-2d</type>
<value type="int">7</value>
</uniform>
<uniform>
<name>debug_shadow_cascades</name>
<type>bool</type>
<value><use>show-shadow-cascades</use></value>
</uniform>
<!-- Shadows include -->
<uniform>
<name>shadow_tex</name>

View file

@ -699,4 +699,21 @@
</pass>
</technique>
<technique n="119">
<scheme>hdr-shadow</scheme>
<pass>
<color-mask type="vec4d">0 0 0 0</color-mask>
<cull-face>back</cull-face>
<blend>0</blend>
<polygon-offset>
<factor>1.1</factor>
<units>4.0</units>
</polygon-offset>
<program>
<vertex-shader>Shaders/HDR/geometry-shadow.vert</vertex-shader>
<fragment-shader>Shaders/HDR/geometry-shadow.frag</fragment-shader>
</program>
</pass>
</technique>
</PropertyList>

View file

@ -68,15 +68,6 @@
<wrap-s><use>texture[3]/wrap-s</use></wrap-s>
<wrap-t><use>texture[3]/wrap-t</use></wrap-t>
</texture-unit>
<texture-unit>
<unit>4</unit>
<type><use>texture[4]/type</use></type>
<image><use>texture[4]/image</use></image>
<filter><use>texture[4]/filter</use></filter>
<mag-filter><use>texture[4]/mag-filter</use></mag-filter>
<wrap-s><use>texture[4]/wrap-s</use></wrap-s>
<wrap-t><use>texture[4]/wrap-t</use></wrap-t>
</texture-unit>
<texture-unit>
<unit>8</unit>
<image><use>texture[8]/image</use></image>
@ -117,19 +108,14 @@
<value type="int">1</value>
</uniform>
<uniform>
<name>metallic_roughness_tex</name>
<name>orm_tex</name>
<type>sampler-2d</type>
<value type="int">2</value>
</uniform>
<uniform>
<name>occlusion_tex</name>
<type>sampler-2d</type>
<value type="int">3</value>
</uniform>
<uniform>
<name>emissive_tex</name>
<type>sampler-2d</type>
<value type="int">4</value>
<value type="int">3</value>
</uniform>
<uniform>
<name>base_color_factor</name>

View file

@ -12,18 +12,14 @@
<texture n="1">
<type>null-normalmap</type>
</texture>
<!-- Metallic and Roughness -->
<!-- ORM Texture (Occlusion R, Roughness G and Metallic B) -->
<texture n="2">
<type>white</type>
</texture>
<metallic-factor type="float">1.0</metallic-factor>
<roughness-factor type="float">1.0</roughness-factor>
<!-- Occlusion -->
<texture n="3">
<type>white</type>
</texture>
<!-- Emissive -->
<texture n="4">
<texture n="3">
<type>white</type>
</texture>
<emissive-factor type="vec3d">0.0 0.0 0.0</emissive-factor>
@ -88,15 +84,6 @@
<wrap-s><use>texture[3]/wrap-s</use></wrap-s>
<wrap-t><use>texture[3]/wrap-t</use></wrap-t>
</texture-unit>
<texture-unit>
<unit>4</unit>
<type><use>texture[4]/type</use></type>
<image><use>texture[4]/image</use></image>
<filter><use>texture[4]/filter</use></filter>
<mag-filter><use>texture[0]/mag-filter</use></mag-filter>
<wrap-s><use>texture[4]/wrap-s</use></wrap-s>
<wrap-t><use>texture[4]/wrap-t</use></wrap-t>
</texture-unit>
<blend>0</blend>
<rendering-hint>opaque</rendering-hint>
<cull-face><use>cull-face</use></cull-face>
@ -124,19 +111,14 @@
<value type="int">1</value>
</uniform>
<uniform>
<name>metallic_roughness_tex</name>
<name>orm_tex</name>
<type>sampler-2d</type>
<value type="int">2</value>
</uniform>
<uniform>
<name>occlusion_tex</name>
<type>sampler-2d</type>
<value type="int">3</value>
</uniform>
<uniform>
<name>emissive_tex</name>
<type>sampler-2d</type>
<value type="int">4</value>
<value type="int">3</value>
</uniform>
<uniform>
<name>base_color_factor</name>
@ -165,4 +147,21 @@
</uniform>
</pass>
</technique>
<technique n="119">
<scheme>hdr-shadow</scheme>
<pass>
<color-mask type="vec4d">0 0 0 0</color-mask>
<cull-face>back</cull-face>
<blend>0</blend>
<polygon-offset>
<factor>1.1</factor>
<units>4.0</units>
</polygon-offset>
<program>
<vertex-shader>Shaders/HDR/geometry-shadow.vert</vertex-shader>
<fragment-shader>Shaders/HDR/geometry-shadow.frag</fragment-shader>
</program>
</pass>
</technique>
</PropertyList>

View file

@ -5,16 +5,4 @@
<name>classic-shadow</name>
<fallback>Effects/Fallback/classic-shadow</fallback>
</scheme>
<!-- HDR -->
<!--
<scheme>
<name>hdr-geometry</name>
<fallback>Effects/Fallback/hdr-geometry</fallback>
</scheme>
-->
<scheme>
<name>hdr-shadow</name>
<fallback>Effects/Fallback/hdr-shadow</fallback>
</scheme>
</PropertyList>

View file

@ -5,8 +5,8 @@ out float fragColor;
in vec2 texCoord;
uniform sampler2D gbuffer0_tex;
uniform sampler2D depth_tex;
uniform sampler2D normal_tex;
uniform mat4 fg_ProjectionMatrix;
@ -22,11 +22,11 @@ const vec2 kernel[4] = vec2[](
vec2( 0.0, -1.0), // bottom
vec2(-1.0, 0.0)); // left
vec3 decodeNormal(vec2 f);
vec3 positionFromDepth(vec2 pos, float depth);
vec3 decodeNormal(vec2 enc);
float rand(vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453);
}
float sampleAO(vec3 fragPos, vec3 normal, vec2 coords)
@ -46,10 +46,12 @@ float sampleAO(vec3 fragPos, vec3 normal, vec2 coords)
void main()
{
float fragDepth = texture(depth_tex, texCoord).r;
vec3 fragPos = positionFromDepth(texCoord, fragDepth);
vec4 gbuffer0 = texture(gbuffer0_tex, texCoord);
float depth = texture(depth_tex, texCoord).r;
vec3 normal = normalize(decodeNormal(texture(normal_tex, texCoord).rg));
vec3 normal = decodeNormal(gbuffer0.rg);
vec3 fragPos = positionFromDepth(texCoord, depth);
vec2 randomVec = normalize(vec2(rand(texCoord) * 2.0 - 1.0,
rand(texCoord+1.0) * 2.0 - 1.0));

View file

@ -0,0 +1,12 @@
#version 330 core
layout(location = 0) out vec4 outGBuffer0;
layout(location = 1) out vec4 outGBuffer1;
layout(location = 2) out vec4 outGBuffer2;
void main()
{
outGBuffer0 = vec4(0.0);
outGBuffer1 = vec4(0.0);
outGBuffer2 = vec4(0.0);
}

View file

@ -0,0 +1,12 @@
#version 330 core
out vec4 fragColor;
in vec2 texCoord;
uniform sampler2D gbuffer1_tex;
void main()
{
fragColor = vec4(texture(gbuffer1_tex, texCoord).rgb, 1.0);
}

View file

@ -0,0 +1,12 @@
#version 330 core
out vec4 fragColor;
in vec2 texCoord;
uniform sampler2D gbuffer0_tex;
void main()
{
fragColor = vec4(vec3(texture(gbuffer0_tex, texCoord).a), 1.0);
}

View file

@ -0,0 +1,12 @@
#version 330 core
out vec4 fragColor;
in vec2 texCoord;
uniform sampler2D gbuffer0_tex;
void main()
{
fragColor = vec4(texture(gbuffer0_tex, texCoord).rg, 0.0, 1.0);
}

View file

@ -0,0 +1,17 @@
#version 330 core
out vec4 fragColor;
in vec2 texCoord;
uniform sampler2D gbuffer0_tex;
uniform sampler2D gbuffer1_tex;
uniform sampler2D gbuffer2_tex;
void main()
{
fragColor = vec4(texture(gbuffer2_tex, texCoord).a,
texture(gbuffer0_tex, texCoord).b,
texture(gbuffer1_tex, texCoord).a,
1.0);
}

View file

@ -3,24 +3,30 @@
uniform mat4 fg_ProjectionMatrixInverse;
uniform vec2 fg_NearFar;
// https://aras-p.info/texts/CompactNormalStorage.html
// Method #4: Spheremap Transform
// Lambert Azimuthal Equal-Area projection
vec2 encodeNormal(vec3 n)
// Octahedron normal encoding
// https://knarkowicz.wordpress.com/2014/04/16/octahedron-normal-vector-encoding/
vec2 msign(vec2 v)
{
float p = sqrt(n.z * 8.0 + 8.0);
return vec2(n.xy / p + 0.5);
return vec2((v.x >= 0.0) ? 1.0 : -1.0,
(v.y >= 0.0) ? 1.0 : -1.0);
}
vec3 decodeNormal(vec2 enc)
vec2 encodeNormal(vec3 n)
{
vec2 fenc = enc * 4.0 - 2.0;
float f = dot(fenc, fenc);
float g = sqrt(1.0 - f * 0.25);
vec3 n;
n.xy = fenc * g;
n.z = 1.0 - f * 0.5;
return n;
n /= (abs(n.x) + abs(n.y) + abs(n.z));
n.xy = (n.z >= 0) ? n.xy : (1.0 - abs(n.yx)) * msign(n.xy);
n.xy = n.xy * 0.5 + 0.5;
return n.xy;
}
vec3 decodeNormal(vec2 f)
{
f = f * 2.0 - 1.0;
vec3 n = vec3(f, 1.0 - abs(f.x) - abs(f.y));
float t = max(-n.z, 0.0);
n.x += (n.x > 0.0) ? -t : t;
n.y += (n.y > 0.0) ? -t : t;
return normalize(n);
}
// Given a 2D coordinate in the range [0,1] and a depth value from a depth

View file

@ -1,16 +1,23 @@
#version 330 core
layout(location = 0) out vec4 gbuffer0;
layout(location = 1) out vec2 gbuffer1;
layout(location = 2) out vec4 gbuffer2;
layout(location = 0) out vec4 outGBuffer0;
layout(location = 1) out vec4 outGBuffer1;
layout(location = 2) out vec4 outGBuffer2;
in vec3 normalVS;
const float CHROME_METALNESS = 1.0;
const float CHROME_ROUGHNESS = 0.1;
vec2 encodeNormal(vec3 n);
void main()
{
gbuffer0 = vec4(1.0);
gbuffer1 = encodeNormal(normalVS);
gbuffer2 = vec4(1.0, 0.1, 0.0, 0.0);
outGBuffer0.rg = encodeNormal(normalVS);
outGBuffer0.b = CHROME_ROUGHNESS;
outGBuffer0.a = 1.0;
outGBuffer1.rgb = vec3(1.0);
outGBuffer1.a = CHROME_METALNESS;
outGBuffer2.rgb = vec3(0.0);
outGBuffer2.a = 1.0;
}

View file

@ -1,8 +1,8 @@
#version 330 core
layout(location = 0) out vec4 gbuffer0;
layout(location = 1) out vec2 gbuffer1;
layout(location = 2) out vec4 gbuffer2;
layout(location = 0) out vec4 outGBuffer0;
layout(location = 1) out vec4 outGBuffer1;
layout(location = 2) out vec4 outGBuffer2;
in vec2 texCoord;
in mat3 TBN;
@ -21,8 +21,7 @@ vec3 decodeSRGB(vec3 screenRGB);
void main()
{
gbuffer0.rgb = decodeSRGB(texture(color_tex, texCoord).rgb);
gbuffer0.a = 1.0;
vec3 color = decodeSRGB(texture(color_tex, texCoord).rgb);
vec3 normal = vec3(0.0, 0.0, 1.0);
if (normalmap_enabled > 0) {
@ -32,10 +31,12 @@ void main()
normal = -normal;
}
normal = normalize(TBN * normal);
gbuffer1 = encodeNormal(normal);
gbuffer2 = vec4(DEFAULT_COMBINED_METALNESS,
DEFAULT_COMBINED_ROUGHNESS,
0.0,
0.0);
outGBuffer0.rg = encodeNormal(normal);
outGBuffer0.b = DEFAULT_COMBINED_ROUGHNESS;
outGBuffer0.a = 1.0;
outGBuffer1.rgb = color;
outGBuffer1.a = DEFAULT_COMBINED_METALNESS;
outGBuffer2.rgb = vec3(0.0);
outGBuffer2.a = 1.0;
}

View file

@ -8,8 +8,7 @@ in vec3 ecPos;
uniform sampler2D base_color_tex;
uniform sampler2D normal_tex;
uniform sampler2D metallic_roughness_tex;
uniform sampler2D occlusion_tex;
uniform sampler2D orm_tex;
uniform sampler2D emissive_tex;
uniform vec4 base_color_factor;
uniform float metallic_factor;
@ -29,8 +28,6 @@ vec3 evaluateLight(
vec3 baseColor,
float metallic,
float roughness,
float clearcoat,
float clearcoatRoughness,
vec3 f0,
vec3 intensity,
float occlusion,
@ -59,13 +56,13 @@ void main()
if (baseColor.a < alpha_cutoff)
discard;
float occlusion = texture(occlusion_tex, texCoord).r;
vec3 n = texture(normal_tex, texCoord).rgb * 2.0 - 1.0;
n = normalize(TBN * n);
vec4 metallicRoughness = texture(metallic_roughness_tex, texCoord);
float metallic = metallicRoughness.r * metallic_factor;
float roughness = metallicRoughness.g * roughness_factor;
vec3 orm = texture(orm_tex, texCoord).rgb;
float occlusion = orm.r;
float roughness = orm.g * roughness_factor;
float metallic = orm.b * metallic_factor;
vec3 emissive = texture(emissive_tex, texCoord).rgb * emissive_factor;
@ -83,8 +80,6 @@ void main()
vec3 color = evaluateLight(baseColor.rgb,
metallic,
roughness,
0.0,
0.0,
f0,
sunIlluminance,
shadowFactor,

View file

@ -1,16 +1,15 @@
#version 330 core
layout(location = 0) out vec4 gbuffer0;
layout(location = 1) out vec2 gbuffer1;
layout(location = 2) out vec4 gbuffer2;
layout(location = 0) out vec4 outGBuffer0;
layout(location = 1) out vec4 outGBuffer1;
layout(location = 2) out vec4 outGBuffer2;
in vec2 texCoord;
in mat3 TBN;
uniform sampler2D base_color_tex;
uniform sampler2D normal_tex;
uniform sampler2D metallic_roughness_tex;
uniform sampler2D occlusion_tex;
uniform sampler2D orm_tex;
uniform sampler2D emissive_tex;
uniform vec4 base_color_factor;
uniform float metallic_factor;
@ -22,22 +21,24 @@ vec3 decodeSRGB(vec3 screenRGB);
void main()
{
vec4 baseColorTexel = texture(base_color_tex, texCoord);
vec4 baseColor = vec4(decodeSRGB(baseColorTexel.rgb), baseColorTexel.a)
* base_color_factor;
gbuffer0.rgb = baseColor.rgb;
float occlusion = texture(occlusion_tex, texCoord).r;
gbuffer0.a = occlusion;
vec3 baseColorTexel = texture(base_color_tex, texCoord).rgb; // Ignore alpha
vec3 baseColor = decodeSRGB(baseColorTexel.rgb) * base_color_factor.rgb;
vec3 normal = texture(normal_tex, texCoord).rgb * 2.0 - 1.0;
normal = normalize(TBN * normal);
gbuffer1 = encodeNormal(normal);
vec4 metallicRoughness = texture(metallic_roughness_tex, texCoord);
float metallic = metallicRoughness.r * metallic_factor;
float roughness = metallicRoughness.g * roughness_factor;
gbuffer2 = vec4(metallic, roughness, 0.0, 0.0);
vec3 orm = texture(orm_tex, texCoord).rgb;
float occlusion = orm.r;
float roughness = orm.g * roughness_factor;
float metallic = orm.b * metallic_factor;
vec3 emissive = texture(emissive_tex, texCoord).rgb * emissive_factor;
outGBuffer0.rg = encodeNormal(normal);
outGBuffer0.b = roughness;
outGBuffer0.a = 1.0;
outGBuffer1.rgb = baseColor;
outGBuffer1.a = metallic;
outGBuffer2.rgb = vec3(0.0);
outGBuffer2.a = occlusion;
}

View file

@ -1,17 +1,8 @@
#version 330 core
layout(location = 0) out vec4 fragColor;
in vec2 texCoord;
uniform sampler2D color_tex;
const float ALPHA_THRESHOLD = 0.5;
out vec4 fragColor;
void main()
{
fragColor = vec4(1.0);
float alpha = texture(color_tex, texCoord).a;
if (alpha <= ALPHA_THRESHOLD)
discard;
}

View file

@ -1,14 +1,10 @@
#version 330 core
layout(location = 0) in vec4 pos;
layout(location = 3) in vec4 multiTexCoord0;
out vec2 texCoord;
uniform mat4 osg_ModelViewProjectionMatrix;
void main()
{
gl_Position = osg_ModelViewProjectionMatrix * pos;
texCoord = multiTexCoord0.st;
}

View file

@ -14,6 +14,7 @@ uniform mat4 osg_ProjectionMatrix;
uniform vec4 fg_Viewport;
uniform vec3 fg_SunDirection;
const float DEFAULT_TRANSPARENT_METALNESS = 0.0;
const float DEFAULT_TRANSPARENT_ROUGHNESS = 0.1;
vec3 decodeSRGB(vec3 screenRGB);
@ -23,8 +24,6 @@ vec3 evaluateLight(
vec3 baseColor,
float metallic,
float roughness,
float clearcoat,
float clearcoatRoughness,
vec3 f0,
vec3 intensity,
float occlusion,
@ -64,10 +63,8 @@ void main()
float shadowFactor = getShadowing(ecPos, n, l, osg_ProjectionMatrix);
vec3 color = evaluateLight(baseColor,
0.0,
DEFAULT_TRANSPARENT_METALNESS,
DEFAULT_TRANSPARENT_ROUGHNESS,
0.0,
0.0,
f0,
sunIlluminance,
shadowFactor,
@ -78,7 +75,7 @@ void main()
vec3 worldReflected = (osg_ViewMatrixInverse * vec4(reflect(-v, n), 0.0)).xyz;
color += evaluateIBL(baseColor,
0.0,
DEFAULT_TRANSPARENT_METALNESS,
DEFAULT_TRANSPARENT_ROUGHNESS,
f0,
1.0,

View file

@ -1,7 +1,7 @@
#version 330 core
layout(location = 0) out vec4 gbuffer0;
layout(location = 1) out vec2 gbuffer1;
layout(location = 0) out vec4 outGBuffer0;
layout(location = 1) out vec4 outGBuffer1;
in vec4 waterTex1;
in vec4 waterTex2;
@ -207,8 +207,9 @@ void main()
N0.g += (ddy + ddy1 + ddy2 + ddy3);
vec3 N = normalize(mix(N0, N1, mixFactor) * waveRoughness);
gbuffer1 = encodeNormal(TBN * N);
vec3 floorColor = decodeSRGB(texture(water_colormap, TopoUV).rgb);
gbuffer0.rgb = floorColor;
outGBuffer0.rg = encodeNormal(TBN * N);
outGBuffer1.rgb = floorColor;
}

View file

@ -1,8 +1,8 @@
#version 330 core
layout(location = 0) out vec4 gbuffer0;
layout(location = 1) out vec2 gbuffer1;
layout(location = 2) out vec4 gbuffer2;
layout(location = 0) out vec4 outGBuffer0;
layout(location = 1) out vec4 outGBuffer1;
layout(location = 2) out vec4 outGBuffer2;
in vec3 normalVS;
in vec2 texCoord;
@ -11,7 +11,7 @@ in vec4 materialColor;
uniform sampler2D color_tex;
const float DEFAULT_METALNESS = 0.0;
const float DEFAULT_ROUGHNESS = 0.8;
const float DEFAULT_ROUGHNESS = 0.5;
vec2 encodeNormal(vec3 n);
vec3 decodeSRGB(vec3 screenRGB);
@ -20,11 +20,12 @@ void main()
{
vec3 texel = texture(color_tex, texCoord).rgb;
vec3 color = decodeSRGB(texel) * materialColor.rgb; // Ignore transparency
gbuffer0.rgb = color;
gbuffer0.a = 1.0;
gbuffer1 = encodeNormal(normalVS);
gbuffer2 = vec4(DEFAULT_METALNESS,
DEFAULT_ROUGHNESS,
0.0,
0.0);
outGBuffer0.rg = encodeNormal(normalVS);
outGBuffer0.b = DEFAULT_ROUGHNESS;
outGBuffer0.a = 1.0;
outGBuffer1.rgb = color;
outGBuffer1.a = DEFAULT_METALNESS;
outGBuffer2.rgb = vec3(0.0);
outGBuffer2.a = 1.0;
}

View file

@ -29,6 +29,11 @@ vec3 F_Schlick(float VdotH, vec3 F0)
return F0 + (vec3(1.0) - F0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);
}
float F_Schlick(float VdotH, float F0)
{
return F0 + (1.0 - F0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);
}
/**
* Normal distribution function (NDF) (specular D)
* Trowbridge-Reitz/GGX microfacet distribution. Includes Disney's
@ -137,8 +142,6 @@ vec3 evaluateLight(
vec3 baseColor,
float metallic,
float roughness,
float clearcoat,
float clearcoatRoughness,
vec3 f0, // Use getF0Reflectance() to obtain this
vec3 intensity,
float occlusion,
@ -169,14 +172,13 @@ vec3 evaluateLight(
float D = D_GGX(NdotH, a2);
float G = G_SmithGGX(NdotV, NdotL, a2);
// Diffuse term
// Lambertian diffuse model
vec3 diffuse = (vec3(1.0) - F) * Fd_Lambert(c_diff);
// Specular term
// Cook-Torrance specular microfacet model
vec3 specular = ((D * G) * F) / (4.0 * NdotV * NdotL);
// Diffuse term: Lambertian diffuse model
vec3 f_diffuse = (vec3(1.0) - F) * Fd_Lambert(c_diff);
vec3 material = diffuse + specular;
// Specular term: Cook-Torrance specular microfacet model
vec3 f_specular = ((D * G) * F) / (4.0 * NdotV * NdotL);
vec3 material = f_diffuse + f_specular;
vec3 color = material * intensity * occlusion;
return color;

View file

@ -1,6 +1,6 @@
#version 330 core
out vec3 fragHdrColor;
out vec3 fragColor;
in vec2 texCoord;
@ -10,20 +10,21 @@ uniform sampler2D gbuffer2_tex;
uniform sampler2D depth_tex;
uniform sampler2D ao_tex;
uniform bool debug_shadow_cascades;
uniform mat4 fg_ViewMatrixInverse;
uniform mat4 fg_ProjectionMatrix;
uniform vec3 fg_SunDirection;
vec3 decodeNormal(vec2 enc);
vec3 decodeNormal(vec2 f);
vec3 positionFromDepth(vec2 pos, float depth);
float getShadowing(vec3 p, vec3 n, vec3 l, mat4 viewToClip);
vec3 debugShadowColor(vec3 p, vec3 n, vec3 l);
vec3 getF0Reflectance(vec3 baseColor, float metallic);
vec3 evaluateLight(
vec3 baseColor,
float metallic,
float roughness,
float clearcoat,
float clearcoatRoughness,
vec3 f0,
vec3 intensity,
float occlusion,
@ -46,26 +47,27 @@ vec3 getSunIntensity();
void main()
{
float depth = texture(depth_tex, texCoord).r;
vec4 gbuffer0 = texture(gbuffer0_tex, texCoord);
vec2 gbuffer1 = texture(gbuffer1_tex, texCoord).rg;
vec4 gbuffer1 = texture(gbuffer1_tex, texCoord);
vec4 gbuffer2 = texture(gbuffer2_tex, texCoord);
float ao = texture(ao_tex, texCoord).r;
float depth = texture(depth_tex, texCoord).r;
// Unpack G-Buffer
vec3 n = decodeNormal(gbuffer0.rg);
float roughness = gbuffer0.b;
uint matId = uint(gbuffer0.a * 4.0);
vec3 baseColor = gbuffer1.rgb;
float metallic = gbuffer1.a;
float occlusion = gbuffer2.a;
vec3 pos = positionFromDepth(texCoord, depth);
vec3 v = normalize(-pos);
vec3 n = decodeNormal(gbuffer1);
vec3 l = fg_SunDirection;
float NdotL = dot(n, l);
float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
vec3 baseColor = gbuffer0.rgb;
float cavity = gbuffer0.a;
float metallic = gbuffer2.r;
float roughness = gbuffer2.g;
float clearcoat = gbuffer2.b;
float clearcoatRoughness = gbuffer2.a;
float ao = texture(ao_tex, texCoord).r;
vec3 f0 = getF0Reflectance(baseColor, metallic);
@ -75,15 +77,13 @@ void main()
vec3 color = evaluateLight(baseColor,
metallic,
roughness,
clearcoat,
clearcoatRoughness,
f0,
sunIlluminance,
shadowFactor,
n, l, v,
NdotL, NdotV);
float ambientOcclusion = ao * cavity;
float ambientOcclusion = ao * occlusion;
vec3 worldNormal = (fg_ViewMatrixInverse * vec4(n, 0.0)).xyz;
vec3 worldReflected = (fg_ViewMatrixInverse * vec4(reflect(-v, n), 0.0)).xyz;
@ -98,5 +98,8 @@ void main()
color = addAerialPerspective(color, texCoord, length(pos));
fragHdrColor = color;
if (debug_shadow_cascades)
color *= debugShadowColor(pos, n, l);
fragColor = color;
}

View file

@ -20,7 +20,7 @@ const vec2 uv_shifts[4] = vec2[4](
const vec2 uv_factor = vec2(0.5, 0.5);
const float SSS_THICKNESS = 0.1;
const uint SSS_NUM_STEPS = 32u;
const uint SSS_NUM_STEPS = 16u;
const float SSS_MAX_DISTANCE = 0.05;
const vec3 DITHER_MAGIC = vec3(0.06711056, 0.00583715, 52.9829189);
@ -76,14 +76,11 @@ float sampleCascade(vec4 p, vec2 shift, vec2 mapSize)
return sampleOptimizedPCF(pos, mapSize);
}
float sampleAndBlendBand(vec4 p1, vec4 p2, vec2 s1, vec2 s2, vec2 mapSize)
float getBlendFactor(vec2 uv, vec2 bottomLeft, vec2 topRight)
{
vec2 s = smoothstep(vec2(0.0), BAND_BOTTOM_LEFT, p1.xy)
- smoothstep(BAND_TOP_RIGHT, vec2(1.0), p1.xy);
float blend = 1.0 - s.x * s.y;
return mix(sampleCascade(p1, s1, mapSize),
sampleCascade(p2, s2, mapSize),
blend);
vec2 s = smoothstep(vec2(0.0), bottomLeft, uv)
- smoothstep(topRight, vec2(1.0), uv);
return 1.0 - s.x * s.y;
}
bool checkWithinBounds(vec2 coords, vec2 bottomLeft, vec2 topRight)
@ -151,7 +148,9 @@ float getContactShadow(vec3 p, vec3 l, mat4 viewToClip)
float dz = samplePos.z - sampleDepth;
if (dz > 0.00001 && dz < SSS_THICKNESS) {
shadow = 1.0;
// TODO: Add screen fading
vec2 screenFade = smoothstep(vec2(0.0), vec2(0.07), samplePos.xy)
- smoothstep(vec2(0.93), vec2(1.0), samplePos.xy);
shadow *= screenFade.x * screenFade.y;
break;
}
t += dt;
@ -184,30 +183,62 @@ float getShadowing(vec3 p, vec3 n, vec3 l, mat4 viewToClip)
// We test if we are inside the cascade bounds to find the tightest
// map that contains the fragment.
if (isInsideCascade(lightSpacePos[i])) {
if (isInsideBand(lightSpacePos[i]) && ((i+1) < 4)) {
if (isInsideBand(lightSpacePos[i])) {
// Blend between cascades if the fragment is near the
// next cascade to avoid abrupt transitions.
visibility = clamp(sampleAndBlendBand(lightSpacePos[i],
lightSpacePos[i+1],
uv_shifts[i],
uv_shifts[i+1],
mapSize),
0.0, 1.0);
float blend = getBlendFactor(lightSpacePos[i].xy,
BAND_BOTTOM_LEFT,
BAND_TOP_RIGHT);
float cascade0 = sampleCascade(lightSpacePos[i],
uv_shifts[i],
mapSize);
float cascade1;
if (i == 3) {
// Handle special case of the last cascade
cascade1 = 1.0;
} else {
cascade1 = sampleCascade(lightSpacePos[i+1],
uv_shifts[i+1],
mapSize);
}
visibility = mix(cascade0, cascade1, blend);
} else {
// We are far away from the borders of the cascade, so
// we skip the blending to avoid the performance cost
// of sampling the shadow map twice.
visibility = clamp(sampleCascade(lightSpacePos[i],
uv_shifts[i],
mapSize),
0.0, 1.0);
visibility = sampleCascade(lightSpacePos[i],
uv_shifts[i],
mapSize);
}
break;
}
}
visibility = clamp(visibility, 0.0, 1.0);
if (visibility > 0.0)
visibility *= getContactShadow(p, l, viewToClip);
return visibility;
}
vec3 debugShadowColor(vec3 p, vec3 n, vec3 l)
{
float NdotL = clamp(dot(n, l), 0.0, 1.0);
vec4 lightSpacePos[4];
lightSpacePos[0] = getLightSpacePosition(p, n, NdotL, fg_LightMatrix_csm0);
lightSpacePos[1] = getLightSpacePosition(p, n, NdotL, fg_LightMatrix_csm1);
lightSpacePos[2] = getLightSpacePosition(p, n, NdotL, fg_LightMatrix_csm2);
lightSpacePos[3] = getLightSpacePosition(p, n, NdotL, fg_LightMatrix_csm3);
if (isInsideCascade(lightSpacePos[0]))
return vec3(1.0, 0.0, 0.0);
else if (isInsideCascade(lightSpacePos[1]))
return vec3(0.0, 1.0, 0.0);
else if (isInsideCascade(lightSpacePos[2]))
return vec3(0.0, 0.0, 1.0);
else if (isInsideCascade(lightSpacePos[3]))
return vec3(1.0, 0.0, 1.0);
return vec3(0.0);
}

View file

@ -19,7 +19,7 @@ const float RECIPROCAL_PI = 0.31830988618;
const float MAX_PREFILTERED_LOD = 4.0;
const vec3 EXTRATERRESTRIAL_SOLAR_ILLUMINANCE = vec3(128.0);
vec3 decodeNormal(vec2 enc);
vec3 decodeNormal(vec2 f);
vec3 positionFromDepth(vec2 pos, float depth);
vec3 addAerialPerspective(vec3 color, vec2 coord, float depth);
@ -36,11 +36,17 @@ float D_GGX(float NdotH, float a2)
void main()
{
vec4 gbuffer0 = texture(gbuffer0_tex, texCoord);
vec4 gbuffer1 = texture(gbuffer1_tex, texCoord);
float depth = texture(depth_tex, texCoord).r;
// Unpack G-Buffer
vec3 n = decodeNormal(gbuffer0.rg);
vec3 seaColor = gbuffer1.rgb;
vec3 pos = positionFromDepth(texCoord, depth);
vec3 v = normalize(-pos);
vec3 n = decodeNormal(texture(gbuffer1_tex, texCoord).rg);
vec3 l = fg_SunDirection;
vec3 reflected = reflect(-v, n);
@ -62,7 +68,6 @@ void main()
float fresnel = F_Schlick(NdotV, f0);
// Refracted light
vec3 seaColor = texture(gbuffer0_tex, texCoord).rgb;
vec3 Esky = textureLod(prefiltered_envmap, worldNormal, MAX_PREFILTERED_LOD).rgb;
vec3 refracted = seaColor * Esky * RECIPROCAL_PI;

View file

@ -1,8 +1,8 @@
#version 330 core
layout(location = 0) out vec4 gbuffer0;
layout(location = 1) out vec2 gbuffer1;
layout(location = 2) out vec4 gbuffer2;
layout(location = 0) out vec4 outGBuffer0;
layout(location = 1) out vec4 outGBuffer1;
layout(location = 2) out vec4 outGBuffer2;
in vec3 normalVS;
in vec2 texCoord;
@ -44,11 +44,14 @@ void main()
st = -st;
}
vec3 texel = texture(atlas, vec3(st, lc)).rgb;
gbuffer0.rgb = decodeSRGB(texel);
gbuffer0.a = 1.0;
gbuffer1 = encodeNormal(normalVS);
vec3 texel = decodeSRGB(texture(atlas, vec3(st, lc)).rgb);
float specularity = clamp(dot(specular.rgb, vec3(0.333)), 0.0, 1.0);
gbuffer2 = vec4(0.0, 1.0-specularity, 0.0, 0.0);
outGBuffer0.rg = encodeNormal(normalVS);
outGBuffer0.b = 1.0 - specularity;
outGBuffer0.a = 1.0;
outGBuffer1.rgb = texel;
outGBuffer1.a = 0.0;
outGBuffer2.rgb = vec3(0.0);
outGBuffer2.a = 1.0;
}

View file

@ -389,8 +389,9 @@ Started September 2000 by David Megginson, david@megginson.com
<bloom-magnitude type="float">0.5</bloom-magnitude>
<bloom-threshold type="float">8.0</bloom-threshold>
<debug>
<show-gbuffer type="bool">false</show-gbuffer>
<display-ev100 type="bool">false</display-ev100>
<show-gbuffer type="bool">false</show-gbuffer>
<show-shadow-cascades type="bool">false</show-shadow-cascades>
</debug>
</hdr>
<composite-viewer-enabled type="bool">true</composite-viewer-enabled>