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> <use-vertex-attribute-aliasing>true</use-vertex-attribute-aliasing>
<!-- <!--
G-Buffer G-Buffer layout
......................................................... ..........................................................................
: Buffer : Red : Green : Blue : Alpha : : : Red : Green : Blue : Alpha :
:........:...........:...........:..........:...........: :.......................:...........:.........:............:.............:
: RT0 : albedo.r : albedo.g : albedo.b : AO/Cavity : : G-Buffer 0 (RGB10_A2) : Normal : Roughness : Material ID :
: RT1 : normal.x : normal.y : : G-Buffer 1 (RGBA8) : Base Color : Metallic :
: RT2 : Metalness : Roughness : Clearcoat : : G-Buffer 2 (RGBA8) : Material specific params : Occlusion :
: RT3 : Depth : : 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> <buffer>
<name>gbuffer0</name> <name>gbuffer0</name>
<type>2d</type> <type>2d</type>
<width>screen</width> <width>screen</width>
<height>screen</height> <height>screen</height>
<format>rgba8</format> <format>rgb10-a2</format>
</buffer> </buffer>
<buffer> <buffer>
<name>gbuffer1</name> <name>gbuffer1</name>
<type>2d</type> <type>2d</type>
<width>screen</width> <width>screen</width>
<height>screen</height> <height>screen</height>
<format>rg16f</format> <format>rgba8</format>
</buffer> </buffer>
<buffer> <buffer>
<name>gbuffer2</name> <name>gbuffer2</name>
@ -116,7 +129,7 @@
<type>cubemap</type> <type>cubemap</type>
<width>128</width> <width>128</width>
<height>128</height> <height>128</height>
<format>rgb16f</format> <format>r11f-g11f-b10f</format>
<min-filter>linear-mipmap-linear</min-filter> <min-filter>linear-mipmap-linear</min-filter>
<mag-filter>linear</mag-filter> <mag-filter>linear</mag-filter>
<wrap-s>clamp-to-edge</wrap-s> <wrap-s>clamp-to-edge</wrap-s>
@ -128,7 +141,7 @@
<type>cubemap</type> <type>cubemap</type>
<width>128</width> <width>128</width>
<height>128</height> <height>128</height>
<format>rgb16f</format> <format>r11f-g11f-b10f</format>
<min-filter>linear-mipmap-linear</min-filter> <min-filter>linear-mipmap-linear</min-filter>
<mag-filter>linear</mag-filter> <mag-filter>linear</mag-filter>
<wrap-s>clamp-to-edge</wrap-s> <wrap-s>clamp-to-edge</wrap-s>
@ -157,7 +170,7 @@
<type>2d</type> <type>2d</type>
<width>1024</width> <width>1024</width>
<height>1024</height> <height>1024</height>
<format>r16f</format> <format>r32f</format>
<min-filter>linear-mipmap-nearest</min-filter> <min-filter>linear-mipmap-nearest</min-filter>
<mag-filter>nearest</mag-filter> <mag-filter>nearest</mag-filter>
<mipmap-levels>10</mipmap-levels> <mipmap-levels>10</mipmap-levels>
@ -167,7 +180,7 @@
<type>2d</type> <type>2d</type>
<width>1</width> <width>1</width>
<height>1</height> <height>1</height>
<format>r16f</format> <format>r32f</format>
<min-filter>nearest</min-filter> <min-filter>nearest</min-filter>
<mag-filter>nearest</mag-filter> <mag-filter>nearest</mag-filter>
</buffer> </buffer>
@ -176,7 +189,7 @@
<type>2d</type> <type>2d</type>
<width>1</width> <width>1</width>
<height>1</height> <height>1</height>
<format>r16f</format> <format>r32f</format>
<min-filter>nearest</min-filter> <min-filter>nearest</min-filter>
<mag-filter>nearest</mag-filter> <mag-filter>nearest</mag-filter>
</buffer> </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 Generate the atmospheric scattering related LUTs
This is an implementation of Sébastien Hillaire's "A Scalable and This is an implementation of Sébastien Hillaire's "A Scalable and
@ -641,7 +679,7 @@
<pass include="csm-pass.xml"> <pass include="csm-pass.xml">
<name>csm0</name> <name>csm0</name>
<near-m>0.1</near-m> <near-m>0.1</near-m>
<far-m>3.0</far-m> <far-m>2.0</far-m>
<viewport> <viewport>
<x>0.0</x> <x>0.0</x>
<y>0.0</y> <y>0.0</y>
@ -651,8 +689,8 @@
</pass> </pass>
<pass include="csm-pass.xml"> <pass include="csm-pass.xml">
<name>csm1</name> <name>csm1</name>
<near-m>3.0</near-m> <near-m>2.0</near-m>
<far-m>70.0</far-m> <far-m>40.0</far-m>
<viewport> <viewport>
<x>0.5</x> <x>0.5</x>
<y>0.0</y> <y>0.0</y>
@ -662,8 +700,8 @@
</pass> </pass>
<pass include="csm-pass.xml"> <pass include="csm-pass.xml">
<name>csm2</name> <name>csm2</name>
<near-m>70.0</near-m> <near-m>40.0</near-m>
<far-m>300.0</far-m> <far-m>150.0</far-m>
<viewport> <viewport>
<x>0.0</x> <x>0.0</x>
<y>0.5</y> <y>0.5</y>
@ -673,8 +711,8 @@
</pass> </pass>
<pass include="csm-pass.xml"> <pass include="csm-pass.xml">
<name>csm3</name> <name>csm3</name>
<near-m>300.0</near-m> <near-m>150.0</near-m>
<far-m>1000.0</far-m> <far-m>500.0</far-m>
<viewport> <viewport>
<x>0.5</x> <x>0.5</x>
<y>0.5</y> <y>0.5</y>
@ -690,11 +728,11 @@
<effect>Effects/HDR/ao</effect> <effect>Effects/HDR/ao</effect>
<binding> <binding>
<unit>0</unit> <unit>0</unit>
<buffer>depth-stencil</buffer> <buffer>gbuffer0</buffer>
</binding> </binding>
<binding> <binding>
<unit>1</unit> <unit>1</unit>
<buffer>gbuffer1</buffer> <buffer>depth-stencil</buffer>
</binding> </binding>
<attachment> <attachment>
<component>color0</component> <component>color0</component>
@ -1198,36 +1236,36 @@
<!-- Debug passes --> <!-- Debug passes -->
<pass include="debug-pass.xml"> <pass include="debug-pass.xml">
<name>debug-albedo</name> <name>debug-color</name>
<effect>Effects/HDR/trivial</effect> <effect>Effects/HDR/gbuffer-debug-color</effect>
<geometry> <geometry>
<left>0.0</left> <left>0.0</left>
<bottom>0.0</bottom> <bottom>0.0</bottom>
<width>0.2</width> <width>0.2</width>
<height>0.2</height> <height>0.2</height>
</geometry> </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> <binding>
<unit>0</unit> <unit>0</unit>
<buffer>gbuffer1</buffer> <buffer>gbuffer1</buffer>
</binding> </binding>
</pass> </pass>
<pass include="debug-pass.xml"> <pass include="debug-pass.xml">
<name>debug-materials</name> <name>debug-normals</name>
<effect>Effects/HDR/trivial</effect> <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> <geometry>
<left>0.0</left> <left>0.0</left>
<bottom>0.8</bottom> <bottom>0.8</bottom>
@ -1236,9 +1274,31 @@
</geometry> </geometry>
<binding> <binding>
<unit>0</unit> <unit>0</unit>
<buffer>gbuffer0</buffer>
</binding>
<binding>
<unit>1</unit>
<buffer>gbuffer1</buffer>
</binding>
<binding>
<unit>2</unit>
<buffer>gbuffer2</buffer> <buffer>gbuffer2</buffer>
</binding> </binding>
</pass> </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"> <pass include="debug-pass.xml">
<name>debug-depth</name> <name>debug-depth</name>
<effect>Effects/HDR/visualize-depth</effect> <effect>Effects/HDR/visualize-depth</effect>

View file

@ -9,12 +9,12 @@
<fragment-shader>Shaders/HDR/gbuffer-include.frag</fragment-shader> <fragment-shader>Shaders/HDR/gbuffer-include.frag</fragment-shader>
</program> </program>
<uniform> <uniform>
<name>depth_tex</name> <name>gbuffer0_tex</name>
<type>sampler-2d</type> <type>sampler-2d</type>
<value type="int">0</value> <value type="int">0</value>
</uniform> </uniform>
<uniform> <uniform>
<name>normal_tex</name> <name>depth_tex</name>
<type>sampler-2d</type> <type>sampler-2d</type>
<value type="int">1</value> <value type="int">1</value>
</uniform> </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> <wrap-t>clamp-to-edge</wrap-t>
<internal-format>normalized</internal-format> <internal-format>normalized</internal-format>
</texture> </texture>
<show-shadow-cascades>
<use>/sim/rendering/hdr/debug/show-shadow-cascades</use>
</show-shadow-cascades>
</parameters> </parameters>
<technique n="1"> <technique n="1">
<pass> <pass>
@ -61,6 +64,11 @@
<type>sampler-2d</type> <type>sampler-2d</type>
<value type="int">7</value> <value type="int">7</value>
</uniform> </uniform>
<uniform>
<name>debug_shadow_cascades</name>
<type>bool</type>
<value><use>show-shadow-cascades</use></value>
</uniform>
<!-- Shadows include --> <!-- Shadows include -->
<uniform> <uniform>
<name>shadow_tex</name> <name>shadow_tex</name>

View file

@ -699,4 +699,21 @@
</pass> </pass>
</technique> </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> </PropertyList>

View file

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

View file

@ -12,18 +12,14 @@
<texture n="1"> <texture n="1">
<type>null-normalmap</type> <type>null-normalmap</type>
</texture> </texture>
<!-- Metallic and Roughness --> <!-- ORM Texture (Occlusion R, Roughness G and Metallic B) -->
<texture n="2"> <texture n="2">
<type>white</type> <type>white</type>
</texture> </texture>
<metallic-factor type="float">1.0</metallic-factor> <metallic-factor type="float">1.0</metallic-factor>
<roughness-factor type="float">1.0</roughness-factor> <roughness-factor type="float">1.0</roughness-factor>
<!-- Occlusion -->
<texture n="3">
<type>white</type>
</texture>
<!-- Emissive --> <!-- Emissive -->
<texture n="4"> <texture n="3">
<type>white</type> <type>white</type>
</texture> </texture>
<emissive-factor type="vec3d">0.0 0.0 0.0</emissive-factor> <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-s><use>texture[3]/wrap-s</use></wrap-s>
<wrap-t><use>texture[3]/wrap-t</use></wrap-t> <wrap-t><use>texture[3]/wrap-t</use></wrap-t>
</texture-unit> </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> <blend>0</blend>
<rendering-hint>opaque</rendering-hint> <rendering-hint>opaque</rendering-hint>
<cull-face><use>cull-face</use></cull-face> <cull-face><use>cull-face</use></cull-face>
@ -124,19 +111,14 @@
<value type="int">1</value> <value type="int">1</value>
</uniform> </uniform>
<uniform> <uniform>
<name>metallic_roughness_tex</name> <name>orm_tex</name>
<type>sampler-2d</type> <type>sampler-2d</type>
<value type="int">2</value> <value type="int">2</value>
</uniform> </uniform>
<uniform>
<name>occlusion_tex</name>
<type>sampler-2d</type>
<value type="int">3</value>
</uniform>
<uniform> <uniform>
<name>emissive_tex</name> <name>emissive_tex</name>
<type>sampler-2d</type> <type>sampler-2d</type>
<value type="int">4</value> <value type="int">3</value>
</uniform> </uniform>
<uniform> <uniform>
<name>base_color_factor</name> <name>base_color_factor</name>
@ -165,4 +147,21 @@
</uniform> </uniform>
</pass> </pass>
</technique> </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> </PropertyList>

View file

@ -5,16 +5,4 @@
<name>classic-shadow</name> <name>classic-shadow</name>
<fallback>Effects/Fallback/classic-shadow</fallback> <fallback>Effects/Fallback/classic-shadow</fallback>
</scheme> </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> </PropertyList>

View file

@ -5,8 +5,8 @@ out float fragColor;
in vec2 texCoord; in vec2 texCoord;
uniform sampler2D gbuffer0_tex;
uniform sampler2D depth_tex; uniform sampler2D depth_tex;
uniform sampler2D normal_tex;
uniform mat4 fg_ProjectionMatrix; uniform mat4 fg_ProjectionMatrix;
@ -22,11 +22,11 @@ const vec2 kernel[4] = vec2[](
vec2( 0.0, -1.0), // bottom vec2( 0.0, -1.0), // bottom
vec2(-1.0, 0.0)); // left vec2(-1.0, 0.0)); // left
vec3 decodeNormal(vec2 f);
vec3 positionFromDepth(vec2 pos, float depth); vec3 positionFromDepth(vec2 pos, float depth);
vec3 decodeNormal(vec2 enc);
float rand(vec2 co) { 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) float sampleAO(vec3 fragPos, vec3 normal, vec2 coords)
@ -46,10 +46,12 @@ float sampleAO(vec3 fragPos, vec3 normal, vec2 coords)
void main() void main()
{ {
float fragDepth = texture(depth_tex, texCoord).r; vec4 gbuffer0 = texture(gbuffer0_tex, texCoord);
vec3 fragPos = positionFromDepth(texCoord, fragDepth); 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, vec2 randomVec = normalize(vec2(rand(texCoord) * 2.0 - 1.0,
rand(texCoord+1.0) * 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 mat4 fg_ProjectionMatrixInverse;
uniform vec2 fg_NearFar; uniform vec2 fg_NearFar;
// https://aras-p.info/texts/CompactNormalStorage.html // Octahedron normal encoding
// Method #4: Spheremap Transform // https://knarkowicz.wordpress.com/2014/04/16/octahedron-normal-vector-encoding/
// Lambert Azimuthal Equal-Area projection vec2 msign(vec2 v)
vec2 encodeNormal(vec3 n)
{ {
float p = sqrt(n.z * 8.0 + 8.0); return vec2((v.x >= 0.0) ? 1.0 : -1.0,
return vec2(n.xy / p + 0.5); (v.y >= 0.0) ? 1.0 : -1.0);
} }
vec3 decodeNormal(vec2 enc) vec2 encodeNormal(vec3 n)
{ {
vec2 fenc = enc * 4.0 - 2.0; n /= (abs(n.x) + abs(n.y) + abs(n.z));
float f = dot(fenc, fenc); n.xy = (n.z >= 0) ? n.xy : (1.0 - abs(n.yx)) * msign(n.xy);
float g = sqrt(1.0 - f * 0.25); n.xy = n.xy * 0.5 + 0.5;
vec3 n; return n.xy;
n.xy = fenc * g; }
n.z = 1.0 - f * 0.5;
return n; 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 // 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 #version 330 core
layout(location = 0) out vec4 gbuffer0; layout(location = 0) out vec4 outGBuffer0;
layout(location = 1) out vec2 gbuffer1; layout(location = 1) out vec4 outGBuffer1;
layout(location = 2) out vec4 gbuffer2; layout(location = 2) out vec4 outGBuffer2;
in vec3 normalVS; in vec3 normalVS;
const float CHROME_METALNESS = 1.0;
const float CHROME_ROUGHNESS = 0.1;
vec2 encodeNormal(vec3 n); vec2 encodeNormal(vec3 n);
void main() void main()
{ {
gbuffer0 = vec4(1.0); outGBuffer0.rg = encodeNormal(normalVS);
gbuffer1 = encodeNormal(normalVS); outGBuffer0.b = CHROME_ROUGHNESS;
gbuffer2 = vec4(1.0, 0.1, 0.0, 0.0); 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 #version 330 core
layout(location = 0) out vec4 gbuffer0; layout(location = 0) out vec4 outGBuffer0;
layout(location = 1) out vec2 gbuffer1; layout(location = 1) out vec4 outGBuffer1;
layout(location = 2) out vec4 gbuffer2; layout(location = 2) out vec4 outGBuffer2;
in vec2 texCoord; in vec2 texCoord;
in mat3 TBN; in mat3 TBN;
@ -21,8 +21,7 @@ vec3 decodeSRGB(vec3 screenRGB);
void main() void main()
{ {
gbuffer0.rgb = decodeSRGB(texture(color_tex, texCoord).rgb); vec3 color = decodeSRGB(texture(color_tex, texCoord).rgb);
gbuffer0.a = 1.0;
vec3 normal = vec3(0.0, 0.0, 1.0); vec3 normal = vec3(0.0, 0.0, 1.0);
if (normalmap_enabled > 0) { if (normalmap_enabled > 0) {
@ -32,10 +31,12 @@ void main()
normal = -normal; normal = -normal;
} }
normal = normalize(TBN * normal); normal = normalize(TBN * normal);
gbuffer1 = encodeNormal(normal);
gbuffer2 = vec4(DEFAULT_COMBINED_METALNESS, outGBuffer0.rg = encodeNormal(normal);
DEFAULT_COMBINED_ROUGHNESS, outGBuffer0.b = DEFAULT_COMBINED_ROUGHNESS;
0.0, outGBuffer0.a = 1.0;
0.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 base_color_tex;
uniform sampler2D normal_tex; uniform sampler2D normal_tex;
uniform sampler2D metallic_roughness_tex; uniform sampler2D orm_tex;
uniform sampler2D occlusion_tex;
uniform sampler2D emissive_tex; uniform sampler2D emissive_tex;
uniform vec4 base_color_factor; uniform vec4 base_color_factor;
uniform float metallic_factor; uniform float metallic_factor;
@ -29,8 +28,6 @@ vec3 evaluateLight(
vec3 baseColor, vec3 baseColor,
float metallic, float metallic,
float roughness, float roughness,
float clearcoat,
float clearcoatRoughness,
vec3 f0, vec3 f0,
vec3 intensity, vec3 intensity,
float occlusion, float occlusion,
@ -59,13 +56,13 @@ void main()
if (baseColor.a < alpha_cutoff) if (baseColor.a < alpha_cutoff)
discard; discard;
float occlusion = texture(occlusion_tex, texCoord).r;
vec3 n = texture(normal_tex, texCoord).rgb * 2.0 - 1.0; vec3 n = texture(normal_tex, texCoord).rgb * 2.0 - 1.0;
n = normalize(TBN * n); n = normalize(TBN * n);
vec4 metallicRoughness = texture(metallic_roughness_tex, texCoord); vec3 orm = texture(orm_tex, texCoord).rgb;
float metallic = metallicRoughness.r * metallic_factor; float occlusion = orm.r;
float roughness = metallicRoughness.g * roughness_factor; float roughness = orm.g * roughness_factor;
float metallic = orm.b * metallic_factor;
vec3 emissive = texture(emissive_tex, texCoord).rgb * emissive_factor; vec3 emissive = texture(emissive_tex, texCoord).rgb * emissive_factor;
@ -83,8 +80,6 @@ void main()
vec3 color = evaluateLight(baseColor.rgb, vec3 color = evaluateLight(baseColor.rgb,
metallic, metallic,
roughness, roughness,
0.0,
0.0,
f0, f0,
sunIlluminance, sunIlluminance,
shadowFactor, shadowFactor,

View file

@ -1,16 +1,15 @@
#version 330 core #version 330 core
layout(location = 0) out vec4 gbuffer0; layout(location = 0) out vec4 outGBuffer0;
layout(location = 1) out vec2 gbuffer1; layout(location = 1) out vec4 outGBuffer1;
layout(location = 2) out vec4 gbuffer2; layout(location = 2) out vec4 outGBuffer2;
in vec2 texCoord; in vec2 texCoord;
in mat3 TBN; in mat3 TBN;
uniform sampler2D base_color_tex; uniform sampler2D base_color_tex;
uniform sampler2D normal_tex; uniform sampler2D normal_tex;
uniform sampler2D metallic_roughness_tex; uniform sampler2D orm_tex;
uniform sampler2D occlusion_tex;
uniform sampler2D emissive_tex; uniform sampler2D emissive_tex;
uniform vec4 base_color_factor; uniform vec4 base_color_factor;
uniform float metallic_factor; uniform float metallic_factor;
@ -22,22 +21,24 @@ vec3 decodeSRGB(vec3 screenRGB);
void main() void main()
{ {
vec4 baseColorTexel = texture(base_color_tex, texCoord); vec3 baseColorTexel = texture(base_color_tex, texCoord).rgb; // Ignore alpha
vec4 baseColor = vec4(decodeSRGB(baseColorTexel.rgb), baseColorTexel.a) vec3 baseColor = decodeSRGB(baseColorTexel.rgb) * base_color_factor.rgb;
* base_color_factor;
gbuffer0.rgb = baseColor.rgb;
float occlusion = texture(occlusion_tex, texCoord).r;
gbuffer0.a = occlusion;
vec3 normal = texture(normal_tex, texCoord).rgb * 2.0 - 1.0; vec3 normal = texture(normal_tex, texCoord).rgb * 2.0 - 1.0;
normal = normalize(TBN * normal); normal = normalize(TBN * normal);
gbuffer1 = encodeNormal(normal);
vec4 metallicRoughness = texture(metallic_roughness_tex, texCoord); vec3 orm = texture(orm_tex, texCoord).rgb;
float metallic = metallicRoughness.r * metallic_factor; float occlusion = orm.r;
float roughness = metallicRoughness.g * roughness_factor; float roughness = orm.g * roughness_factor;
gbuffer2 = vec4(metallic, roughness, 0.0, 0.0); float metallic = orm.b * metallic_factor;
vec3 emissive = texture(emissive_tex, texCoord).rgb * emissive_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 #version 330 core
layout(location = 0) out vec4 fragColor; out vec4 fragColor;
in vec2 texCoord;
uniform sampler2D color_tex;
const float ALPHA_THRESHOLD = 0.5;
void main() void main()
{ {
fragColor = vec4(1.0); 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 #version 330 core
layout(location = 0) in vec4 pos; layout(location = 0) in vec4 pos;
layout(location = 3) in vec4 multiTexCoord0;
out vec2 texCoord;
uniform mat4 osg_ModelViewProjectionMatrix; uniform mat4 osg_ModelViewProjectionMatrix;
void main() void main()
{ {
gl_Position = osg_ModelViewProjectionMatrix * pos; gl_Position = osg_ModelViewProjectionMatrix * pos;
texCoord = multiTexCoord0.st;
} }

View file

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

View file

@ -1,7 +1,7 @@
#version 330 core #version 330 core
layout(location = 0) out vec4 gbuffer0; layout(location = 0) out vec4 outGBuffer0;
layout(location = 1) out vec2 gbuffer1; layout(location = 1) out vec4 outGBuffer1;
in vec4 waterTex1; in vec4 waterTex1;
in vec4 waterTex2; in vec4 waterTex2;
@ -207,8 +207,9 @@ void main()
N0.g += (ddy + ddy1 + ddy2 + ddy3); N0.g += (ddy + ddy1 + ddy2 + ddy3);
vec3 N = normalize(mix(N0, N1, mixFactor) * waveRoughness); vec3 N = normalize(mix(N0, N1, mixFactor) * waveRoughness);
gbuffer1 = encodeNormal(TBN * N);
vec3 floorColor = decodeSRGB(texture(water_colormap, TopoUV).rgb); 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 #version 330 core
layout(location = 0) out vec4 gbuffer0; layout(location = 0) out vec4 outGBuffer0;
layout(location = 1) out vec2 gbuffer1; layout(location = 1) out vec4 outGBuffer1;
layout(location = 2) out vec4 gbuffer2; layout(location = 2) out vec4 outGBuffer2;
in vec3 normalVS; in vec3 normalVS;
in vec2 texCoord; in vec2 texCoord;
@ -11,7 +11,7 @@ in vec4 materialColor;
uniform sampler2D color_tex; uniform sampler2D color_tex;
const float DEFAULT_METALNESS = 0.0; const float DEFAULT_METALNESS = 0.0;
const float DEFAULT_ROUGHNESS = 0.8; const float DEFAULT_ROUGHNESS = 0.5;
vec2 encodeNormal(vec3 n); vec2 encodeNormal(vec3 n);
vec3 decodeSRGB(vec3 screenRGB); vec3 decodeSRGB(vec3 screenRGB);
@ -20,11 +20,12 @@ void main()
{ {
vec3 texel = texture(color_tex, texCoord).rgb; vec3 texel = texture(color_tex, texCoord).rgb;
vec3 color = decodeSRGB(texel) * materialColor.rgb; // Ignore transparency vec3 color = decodeSRGB(texel) * materialColor.rgb; // Ignore transparency
gbuffer0.rgb = color;
gbuffer0.a = 1.0; outGBuffer0.rg = encodeNormal(normalVS);
gbuffer1 = encodeNormal(normalVS); outGBuffer0.b = DEFAULT_ROUGHNESS;
gbuffer2 = vec4(DEFAULT_METALNESS, outGBuffer0.a = 1.0;
DEFAULT_ROUGHNESS, outGBuffer1.rgb = color;
0.0, outGBuffer1.a = DEFAULT_METALNESS;
0.0); 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); 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) * Normal distribution function (NDF) (specular D)
* Trowbridge-Reitz/GGX microfacet distribution. Includes Disney's * Trowbridge-Reitz/GGX microfacet distribution. Includes Disney's
@ -137,8 +142,6 @@ vec3 evaluateLight(
vec3 baseColor, vec3 baseColor,
float metallic, float metallic,
float roughness, float roughness,
float clearcoat,
float clearcoatRoughness,
vec3 f0, // Use getF0Reflectance() to obtain this vec3 f0, // Use getF0Reflectance() to obtain this
vec3 intensity, vec3 intensity,
float occlusion, float occlusion,
@ -169,14 +172,13 @@ vec3 evaluateLight(
float D = D_GGX(NdotH, a2); float D = D_GGX(NdotH, a2);
float G = G_SmithGGX(NdotV, NdotL, a2); float G = G_SmithGGX(NdotV, NdotL, a2);
// Diffuse term // Diffuse term: Lambertian diffuse model
// Lambertian diffuse model vec3 f_diffuse = (vec3(1.0) - F) * Fd_Lambert(c_diff);
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);
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; vec3 color = material * intensity * occlusion;
return color; return color;

View file

@ -1,6 +1,6 @@
#version 330 core #version 330 core
out vec3 fragHdrColor; out vec3 fragColor;
in vec2 texCoord; in vec2 texCoord;
@ -10,20 +10,21 @@ uniform sampler2D gbuffer2_tex;
uniform sampler2D depth_tex; uniform sampler2D depth_tex;
uniform sampler2D ao_tex; uniform sampler2D ao_tex;
uniform bool debug_shadow_cascades;
uniform mat4 fg_ViewMatrixInverse; uniform mat4 fg_ViewMatrixInverse;
uniform mat4 fg_ProjectionMatrix; uniform mat4 fg_ProjectionMatrix;
uniform vec3 fg_SunDirection; uniform vec3 fg_SunDirection;
vec3 decodeNormal(vec2 enc); vec3 decodeNormal(vec2 f);
vec3 positionFromDepth(vec2 pos, float depth); vec3 positionFromDepth(vec2 pos, float depth);
float getShadowing(vec3 p, vec3 n, vec3 l, mat4 viewToClip); 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 getF0Reflectance(vec3 baseColor, float metallic);
vec3 evaluateLight( vec3 evaluateLight(
vec3 baseColor, vec3 baseColor,
float metallic, float metallic,
float roughness, float roughness,
float clearcoat,
float clearcoatRoughness,
vec3 f0, vec3 f0,
vec3 intensity, vec3 intensity,
float occlusion, float occlusion,
@ -46,26 +47,27 @@ vec3 getSunIntensity();
void main() void main()
{ {
float depth = texture(depth_tex, texCoord).r;
vec4 gbuffer0 = texture(gbuffer0_tex, texCoord); 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); 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 pos = positionFromDepth(texCoord, depth);
vec3 v = normalize(-pos); vec3 v = normalize(-pos);
vec3 n = decodeNormal(gbuffer1);
vec3 l = fg_SunDirection; vec3 l = fg_SunDirection;
float NdotL = dot(n, l); float NdotL = dot(n, l);
float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0); float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
vec3 baseColor = gbuffer0.rgb; float ao = texture(ao_tex, texCoord).r;
float cavity = gbuffer0.a;
float metallic = gbuffer2.r;
float roughness = gbuffer2.g;
float clearcoat = gbuffer2.b;
float clearcoatRoughness = gbuffer2.a;
vec3 f0 = getF0Reflectance(baseColor, metallic); vec3 f0 = getF0Reflectance(baseColor, metallic);
@ -75,15 +77,13 @@ void main()
vec3 color = evaluateLight(baseColor, vec3 color = evaluateLight(baseColor,
metallic, metallic,
roughness, roughness,
clearcoat,
clearcoatRoughness,
f0, f0,
sunIlluminance, sunIlluminance,
shadowFactor, shadowFactor,
n, l, v, n, l, v,
NdotL, NdotV); NdotL, NdotV);
float ambientOcclusion = ao * cavity; float ambientOcclusion = ao * occlusion;
vec3 worldNormal = (fg_ViewMatrixInverse * vec4(n, 0.0)).xyz; vec3 worldNormal = (fg_ViewMatrixInverse * vec4(n, 0.0)).xyz;
vec3 worldReflected = (fg_ViewMatrixInverse * vec4(reflect(-v, 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)); 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 vec2 uv_factor = vec2(0.5, 0.5);
const float SSS_THICKNESS = 0.1; 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 float SSS_MAX_DISTANCE = 0.05;
const vec3 DITHER_MAGIC = vec3(0.06711056, 0.00583715, 52.9829189); 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); 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) vec2 s = smoothstep(vec2(0.0), bottomLeft, uv)
- smoothstep(BAND_TOP_RIGHT, vec2(1.0), p1.xy); - smoothstep(topRight, vec2(1.0), uv);
float blend = 1.0 - s.x * s.y; return 1.0 - s.x * s.y;
return mix(sampleCascade(p1, s1, mapSize),
sampleCascade(p2, s2, mapSize),
blend);
} }
bool checkWithinBounds(vec2 coords, vec2 bottomLeft, vec2 topRight) 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; float dz = samplePos.z - sampleDepth;
if (dz > 0.00001 && dz < SSS_THICKNESS) { if (dz > 0.00001 && dz < SSS_THICKNESS) {
shadow = 1.0; 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; break;
} }
t += dt; 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 // We test if we are inside the cascade bounds to find the tightest
// map that contains the fragment. // map that contains the fragment.
if (isInsideCascade(lightSpacePos[i])) { if (isInsideCascade(lightSpacePos[i])) {
if (isInsideBand(lightSpacePos[i]) && ((i+1) < 4)) { if (isInsideBand(lightSpacePos[i])) {
// Blend between cascades if the fragment is near the // Blend between cascades if the fragment is near the
// next cascade to avoid abrupt transitions. // next cascade to avoid abrupt transitions.
visibility = clamp(sampleAndBlendBand(lightSpacePos[i], float blend = getBlendFactor(lightSpacePos[i].xy,
lightSpacePos[i+1], BAND_BOTTOM_LEFT,
uv_shifts[i], BAND_TOP_RIGHT);
uv_shifts[i+1], float cascade0 = sampleCascade(lightSpacePos[i],
mapSize), uv_shifts[i],
0.0, 1.0); 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 { } else {
// We are far away from the borders of the cascade, so // We are far away from the borders of the cascade, so
// we skip the blending to avoid the performance cost // we skip the blending to avoid the performance cost
// of sampling the shadow map twice. // of sampling the shadow map twice.
visibility = clamp(sampleCascade(lightSpacePos[i], visibility = sampleCascade(lightSpacePos[i],
uv_shifts[i], uv_shifts[i],
mapSize), mapSize);
0.0, 1.0);
} }
break; break;
} }
} }
visibility = clamp(visibility, 0.0, 1.0);
if (visibility > 0.0) if (visibility > 0.0)
visibility *= getContactShadow(p, l, viewToClip); visibility *= getContactShadow(p, l, viewToClip);
return visibility; 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 float MAX_PREFILTERED_LOD = 4.0;
const vec3 EXTRATERRESTRIAL_SOLAR_ILLUMINANCE = vec3(128.0); const vec3 EXTRATERRESTRIAL_SOLAR_ILLUMINANCE = vec3(128.0);
vec3 decodeNormal(vec2 enc); vec3 decodeNormal(vec2 f);
vec3 positionFromDepth(vec2 pos, float depth); vec3 positionFromDepth(vec2 pos, float depth);
vec3 addAerialPerspective(vec3 color, vec2 coord, float depth); vec3 addAerialPerspective(vec3 color, vec2 coord, float depth);
@ -36,11 +36,17 @@ float D_GGX(float NdotH, float a2)
void main() void main()
{ {
vec4 gbuffer0 = texture(gbuffer0_tex, texCoord);
vec4 gbuffer1 = texture(gbuffer1_tex, texCoord);
float depth = texture(depth_tex, texCoord).r; 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 pos = positionFromDepth(texCoord, depth);
vec3 v = normalize(-pos); vec3 v = normalize(-pos);
vec3 n = decodeNormal(texture(gbuffer1_tex, texCoord).rg);
vec3 l = fg_SunDirection; vec3 l = fg_SunDirection;
vec3 reflected = reflect(-v, n); vec3 reflected = reflect(-v, n);
@ -62,7 +68,6 @@ void main()
float fresnel = F_Schlick(NdotV, f0); float fresnel = F_Schlick(NdotV, f0);
// Refracted light // Refracted light
vec3 seaColor = texture(gbuffer0_tex, texCoord).rgb;
vec3 Esky = textureLod(prefiltered_envmap, worldNormal, MAX_PREFILTERED_LOD).rgb; vec3 Esky = textureLod(prefiltered_envmap, worldNormal, MAX_PREFILTERED_LOD).rgb;
vec3 refracted = seaColor * Esky * RECIPROCAL_PI; vec3 refracted = seaColor * Esky * RECIPROCAL_PI;

View file

@ -1,8 +1,8 @@
#version 330 core #version 330 core
layout(location = 0) out vec4 gbuffer0; layout(location = 0) out vec4 outGBuffer0;
layout(location = 1) out vec2 gbuffer1; layout(location = 1) out vec4 outGBuffer1;
layout(location = 2) out vec4 gbuffer2; layout(location = 2) out vec4 outGBuffer2;
in vec3 normalVS; in vec3 normalVS;
in vec2 texCoord; in vec2 texCoord;
@ -44,11 +44,14 @@ void main()
st = -st; st = -st;
} }
vec3 texel = texture(atlas, vec3(st, lc)).rgb; vec3 texel = decodeSRGB(texture(atlas, vec3(st, lc)).rgb);
gbuffer0.rgb = decodeSRGB(texel);
gbuffer0.a = 1.0;
gbuffer1 = encodeNormal(normalVS);
float specularity = clamp(dot(specular.rgb, vec3(0.333)), 0.0, 1.0); 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-magnitude type="float">0.5</bloom-magnitude>
<bloom-threshold type="float">8.0</bloom-threshold> <bloom-threshold type="float">8.0</bloom-threshold>
<debug> <debug>
<show-gbuffer type="bool">false</show-gbuffer>
<display-ev100 type="bool">false</display-ev100> <display-ev100 type="bool">false</display-ev100>
<show-gbuffer type="bool">false</show-gbuffer>
<show-shadow-cascades type="bool">false</show-shadow-cascades>
</debug> </debug>
</hdr> </hdr>
<composite-viewer-enabled type="bool">true</composite-viewer-enabled> <composite-viewer-enabled type="bool">true</composite-viewer-enabled>