HDR: Significant update
- New atmosphering rendering technique based on my own work. - Attempt to fix some remaining transparency issues. - Use a luminance histogram for auto exposure. - Add support for clustered shading. - Add WS 2.0 shaders. - Add 3D cloud shaders. - Add orthoscenery support.
This commit is contained in:
parent
85771b2863
commit
c4d19877cf
52 changed files with 1765 additions and 669 deletions
|
@ -83,18 +83,7 @@
|
|||
<type>2d</type>
|
||||
<width>256</width>
|
||||
<height>64</height>
|
||||
<format>rgb16f</format>
|
||||
<min-filter>linear</min-filter>
|
||||
<mag-filter>linear</mag-filter>
|
||||
<wrap-s>clamp-to-edge</wrap-s>
|
||||
<wrap-t>clamp-to-edge</wrap-t>
|
||||
</buffer>
|
||||
<buffer>
|
||||
<name>multiple-scattering</name>
|
||||
<type>2d</type>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
<format>rgb16f</format>
|
||||
<format>rgba16f</format>
|
||||
<min-filter>linear</min-filter>
|
||||
<mag-filter>linear</mag-filter>
|
||||
<wrap-s>clamp-to-edge</wrap-s>
|
||||
|
@ -104,8 +93,8 @@
|
|||
<name>sky-view</name>
|
||||
<type>2d</type>
|
||||
<width>256</width>
|
||||
<height>128</height>
|
||||
<format>rgb16f</format>
|
||||
<height>256</height>
|
||||
<format>rgba16f</format>
|
||||
<min-filter>linear</min-filter>
|
||||
<mag-filter>linear</mag-filter>
|
||||
<wrap-s>repeat</wrap-s>
|
||||
|
@ -164,19 +153,27 @@
|
|||
<shadow-comparison>true</shadow-comparison>
|
||||
</buffer>
|
||||
|
||||
<!-- Average luminance -->
|
||||
<!-- Histogram for automatic exposure -->
|
||||
<buffer>
|
||||
<name>luminance</name>
|
||||
<name>histogram-partial</name>
|
||||
<type>2d</type>
|
||||
<width>1024</width>
|
||||
<height>1024</height>
|
||||
<format>r32f</format>
|
||||
<min-filter>linear-mipmap-nearest</min-filter>
|
||||
<width>screen</width>
|
||||
<height>256</height>
|
||||
<format>r32ui</format>
|
||||
<min-filter>nearest</min-filter>
|
||||
<mag-filter>nearest</mag-filter>
|
||||
<mipmap-levels>10</mipmap-levels>
|
||||
</buffer>
|
||||
<buffer>
|
||||
<name>prev-luminance</name>
|
||||
<name>histogram</name>
|
||||
<type>2d</type>
|
||||
<width>256</width>
|
||||
<height>1</height>
|
||||
<format>r32ui</format>
|
||||
<min-filter>nearest</min-filter>
|
||||
<mag-filter>nearest</mag-filter>
|
||||
</buffer>
|
||||
<buffer>
|
||||
<name>histogram-luminance</name>
|
||||
<type>2d</type>
|
||||
<width>1</width>
|
||||
<height>1</height>
|
||||
|
@ -185,7 +182,7 @@
|
|||
<mag-filter>nearest</mag-filter>
|
||||
</buffer>
|
||||
<buffer>
|
||||
<name>adapted-luminance</name>
|
||||
<name>prev-luminance</name>
|
||||
<type>2d</type>
|
||||
<width>1</width>
|
||||
<height>1</height>
|
||||
|
@ -296,14 +293,7 @@
|
|||
</pass>
|
||||
|
||||
<!--
|
||||
Generate the atmospheric scattering related LUTs
|
||||
This is an implementation of Sébastien Hillaire's "A Scalable and
|
||||
Production Ready Sky and Atmosphere Rendering Technique".
|
||||
As a small summary, the sky-view and aerial perspective LUTs are used by
|
||||
later passes to apply atmospheric scattering to the skydome and
|
||||
opaque/transparent objects respectively. These two LUTs also rely on
|
||||
another pair of LUTs (transmittance and multiple scattering) to speed up
|
||||
the computations.
|
||||
Atmospheric scattering.
|
||||
-->
|
||||
<pass>
|
||||
<name>atmos-transmittance</name>
|
||||
|
@ -314,19 +304,6 @@
|
|||
<buffer>transmittance</buffer>
|
||||
</attachment>
|
||||
</pass>
|
||||
<pass>
|
||||
<name>atmos-multiple-scattering</name>
|
||||
<type>quad</type>
|
||||
<effect>Effects/HDR/atmos-multiple-scattering</effect>
|
||||
<binding>
|
||||
<unit>0</unit>
|
||||
<buffer>transmittance</buffer>
|
||||
</binding>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
<buffer>multiple-scattering</buffer>
|
||||
</attachment>
|
||||
</pass>
|
||||
<pass>
|
||||
<name>atmos-sky-view</name>
|
||||
<type>quad</type>
|
||||
|
@ -335,10 +312,6 @@
|
|||
<unit>0</unit>
|
||||
<buffer>transmittance</buffer>
|
||||
</binding>
|
||||
<binding>
|
||||
<unit>1</unit>
|
||||
<buffer>multiple-scattering</buffer>
|
||||
</binding>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
<buffer>sky-view</buffer>
|
||||
|
@ -352,10 +325,6 @@
|
|||
<unit>0</unit>
|
||||
<buffer>transmittance</buffer>
|
||||
</binding>
|
||||
<binding>
|
||||
<unit>1</unit>
|
||||
<buffer>multiple-scattering</buffer>
|
||||
</binding>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
<buffer>aerial-perspective</buffer>
|
||||
|
@ -650,6 +619,15 @@
|
|||
<clear-mask>depth stencil</clear-mask>
|
||||
<clear-depth>0.0</clear-depth>
|
||||
<cull-mask>0xfffff7ff</cull-mask>
|
||||
<clustered-shading>
|
||||
<tile-size>128</tile-size>
|
||||
<depth-slices>1</depth-slices>
|
||||
<num-threads>1</num-threads>
|
||||
<max-pointlights>1024</max-pointlights>
|
||||
<max-spotlights>1024</max-spotlights>
|
||||
<pbr-lights>true</pbr-lights>
|
||||
<expose-uniforms>false</expose-uniforms>
|
||||
</clustered-shading>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
<buffer>gbuffer0</buffer>
|
||||
|
@ -771,6 +749,13 @@
|
|||
<use-shadow-pass>csm1</use-shadow-pass>
|
||||
<use-shadow-pass>csm2</use-shadow-pass>
|
||||
<use-shadow-pass>csm3</use-shadow-pass>
|
||||
<use-clustered-uniforms>
|
||||
<pass>geometry</pass>
|
||||
<clusters-bind-unit>5</clusters-bind-unit>
|
||||
<indices-bind-unit>6</indices-bind-unit>
|
||||
<pointlights-bind-unit>14</pointlights-bind-unit>
|
||||
<spotlights-bind-unit>15</spotlights-bind-unit>
|
||||
</use-clustered-uniforms>
|
||||
<binding>
|
||||
<unit>0</unit>
|
||||
<buffer>gbuffer0</buffer>
|
||||
|
@ -918,45 +903,62 @@
|
|||
</pass>
|
||||
|
||||
<!--
|
||||
Average luminance calculation
|
||||
1. Convert the RGB values to luminance values and store them on a fixed
|
||||
size texture.
|
||||
2. Generate mipmaps for this texture until we are left with a 1x1 texture
|
||||
at the highest mipmap level. This downsampling process effectively
|
||||
calculates the geometric mean of luminance.
|
||||
3. Simulate eye adaptation by smoothing out the transition between
|
||||
different exposures.
|
||||
4. Update the previous frame average luminance value for next frame.
|
||||
Auto exposure using a luminance histogram
|
||||
Based on the article by Alex Tardif:
|
||||
https://www.alextardif.com/HistogramLuminance.html
|
||||
|
||||
Instead of using a compute shader, we run two fragment shaders. The first
|
||||
calculates a partial histogram of the rows of the input HDR texture, and
|
||||
the second aggregates them together to obtain a single histogram.
|
||||
|
||||
The last step, which calculates the average scene luminance from the
|
||||
histogram, is identical even though it is implemented as a fragment shader.
|
||||
|
||||
This technique will find the average luminance after multiplication by the
|
||||
albedo. This is not correct, but the alternative (keeping a luminance
|
||||
texture) is too expensive and not worth the trouble.
|
||||
-->
|
||||
<pass>
|
||||
<name>luminance</name>
|
||||
<name>histogram-column</name>
|
||||
<type>quad</type>
|
||||
<effect>Effects/HDR/luminance</effect>
|
||||
<effect>Effects/HDR/histogram-column</effect>
|
||||
<binding>
|
||||
<unit>0</unit>
|
||||
<buffer>hdr-result</buffer>
|
||||
</binding>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
<buffer>luminance</buffer>
|
||||
<mipmap-generation>true</mipmap-generation>
|
||||
<buffer>histogram-partial</buffer>
|
||||
</attachment>
|
||||
</pass>
|
||||
<pass>
|
||||
<name>adapt-luminance</name>
|
||||
<name>histogram-aggregate</name>
|
||||
<type>quad</type>
|
||||
<effect>Effects/HDR/adapt-luminance</effect>
|
||||
<effect>Effects/HDR/histogram-aggregate</effect>
|
||||
<binding>
|
||||
<unit>0</unit>
|
||||
<buffer>prev-luminance</buffer>
|
||||
</binding>
|
||||
<binding>
|
||||
<unit>1</unit>
|
||||
<buffer>luminance</buffer>
|
||||
<buffer>histogram-partial</buffer>
|
||||
</binding>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
<buffer>adapted-luminance</buffer>
|
||||
<buffer>histogram</buffer>
|
||||
</attachment>
|
||||
</pass>
|
||||
<pass>
|
||||
<name>histogram-luminance</name>
|
||||
<type>quad</type>
|
||||
<effect>Effects/HDR/histogram-luminance</effect>
|
||||
<binding>
|
||||
<unit>0</unit>
|
||||
<buffer>histogram</buffer>
|
||||
</binding>
|
||||
<binding>
|
||||
<unit>1</unit>
|
||||
<buffer>prev-luminance</buffer>
|
||||
</binding>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
<buffer>histogram-luminance</buffer>
|
||||
</attachment>
|
||||
</pass>
|
||||
<pass>
|
||||
|
@ -965,7 +967,7 @@
|
|||
<effect>Effects/HDR/copy-prev-luminance</effect>
|
||||
<binding>
|
||||
<unit>0</unit>
|
||||
<buffer>adapted-luminance</buffer>
|
||||
<buffer>histogram-luminance</buffer>
|
||||
</binding>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
|
@ -990,7 +992,7 @@
|
|||
</binding>
|
||||
<binding>
|
||||
<unit>1</unit>
|
||||
<buffer>adapted-luminance</buffer>
|
||||
<buffer>histogram-luminance</buffer>
|
||||
</binding>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
|
@ -1152,7 +1154,7 @@
|
|||
</binding>
|
||||
<binding>
|
||||
<unit>1</unit>
|
||||
<buffer>adapted-luminance</buffer>
|
||||
<buffer>histogram-luminance</buffer>
|
||||
</binding>
|
||||
<binding>
|
||||
<unit>4</unit>
|
||||
|
|
|
@ -14,11 +14,6 @@
|
|||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>multiscattering_lut</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">1</value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
</PropertyList>
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PropertyList>
|
||||
<name>Effects/HDR/atmos-multiple-scattering</name>
|
||||
<technique n="1">
|
||||
<pass>
|
||||
<program>
|
||||
<vertex-shader>Shaders/HDR/trivial.vert</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/atmos-multiple-scattering.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/HDR/atmos-include.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>transmittance_lut</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
</PropertyList>
|
|
@ -13,11 +13,6 @@
|
|||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>multiscattering_lut</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">1</value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
</PropertyList>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<fragment-shader>Shaders/HDR/copy-prev-luminance.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>lum_tex</name>
|
||||
<name>tex</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PropertyList>
|
||||
<name>Effects/HDR/luminance</name>
|
||||
<name>Effects/HDR/histogram-aggregate</name>
|
||||
<technique n="1">
|
||||
<pass>
|
||||
<program>
|
||||
<vertex-shader>Shaders/HDR/trivial.vert</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/luminance.frag</fragment-shader>
|
||||
<vertex-shader>Shaders/HDR/trivial-notexcoord.vert</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/histogram-aggregate.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>hdr_tex</name>
|
||||
<name>partial_histogram_tex</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
18
Effects/HDR/histogram-column.eff
Normal file
18
Effects/HDR/histogram-column.eff
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PropertyList>
|
||||
<name>Effects/HDR/histogram-column</name>
|
||||
<technique n="1">
|
||||
<pass>
|
||||
<program>
|
||||
<vertex-shader>Shaders/HDR/trivial-notexcoord.vert</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/histogram-column.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/HDR/histogram-include.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>hdr_tex</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
</PropertyList>
|
|
@ -1,19 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PropertyList>
|
||||
<name>Effects/HDR/adapt-luminance</name>
|
||||
<name>Effects/HDR/histogram-luminance</name>
|
||||
<technique n="1">
|
||||
<pass>
|
||||
<program>
|
||||
<vertex-shader>Shaders/HDR/trivial-notexcoord.vert</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/adapt-luminance.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/HDR/histogram-luminance.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/HDR/histogram-include.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>prev_lum_tex</name>
|
||||
<name>histogram_tex</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>current_lum_tex</name>
|
||||
<name>prev_lum_tex</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">1</value>
|
||||
</uniform>
|
|
@ -41,6 +41,7 @@
|
|||
<fragment-shader>Shaders/HDR/shadows-include.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/HDR/lighting-include.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/HDR/aerial-perspective-include.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/HDR/clustered-include.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>gbuffer0_tex</name>
|
||||
|
|
|
@ -234,4 +234,50 @@
|
|||
<vertex-program-two-side>true</vertex-program-two-side>
|
||||
</pass>
|
||||
</technique>
|
||||
|
||||
<technique n="109">
|
||||
<scheme>hdr-geometry</scheme>
|
||||
</technique>
|
||||
<technique n="129">
|
||||
<scheme>hdr-forward</scheme>
|
||||
<pass>
|
||||
<!-- Reverse floating point depth buffer -->
|
||||
<depth>
|
||||
<function>gequal</function>
|
||||
<near>1.0</near>
|
||||
<far>0.0</far>
|
||||
<write-mask>false</write-mask>
|
||||
</depth>
|
||||
<texture-unit>
|
||||
<unit>0</unit>
|
||||
<type>2d</type>
|
||||
<image><use>texture[0]/image</use></image>
|
||||
<wrap-s>clamp-to-border</wrap-s>
|
||||
<wrap-t>clamp-to-border</wrap-t>
|
||||
</texture-unit>
|
||||
<blend>1</blend>
|
||||
<rendering-hint>transparent</rendering-hint>
|
||||
<program>
|
||||
<vertex-shader>Shaders/HDR/cloud-static.vert</vertex-shader>
|
||||
<vertex-shader>Shaders/HDR/aerial-perspective-include.frag</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/3dcloud.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>baseTexture</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
<!-- Aerial perspective include -->
|
||||
<uniform>
|
||||
<name>aerial_perspective_lut</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">11</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>transmittance_lut</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">12</value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
</PropertyList>
|
||||
|
|
|
@ -154,4 +154,50 @@
|
|||
<vertex-program-two-side>true</vertex-program-two-side>
|
||||
</pass>
|
||||
</technique>
|
||||
|
||||
<technique n="109">
|
||||
<scheme>hdr-geometry</scheme>
|
||||
</technique>
|
||||
<technique n="129">
|
||||
<scheme>hdr-forward</scheme>
|
||||
<pass>
|
||||
<!-- Reverse floating point depth buffer -->
|
||||
<depth>
|
||||
<function>gequal</function>
|
||||
<near>1.0</near>
|
||||
<far>0.0</far>
|
||||
<write-mask>false</write-mask>
|
||||
</depth>
|
||||
<texture-unit>
|
||||
<unit>0</unit>
|
||||
<type>2d</type>
|
||||
<image><use>texture[0]/image</use></image>
|
||||
<wrap-s>clamp-to-border</wrap-s>
|
||||
<wrap-t>clamp-to-border</wrap-t>
|
||||
</texture-unit>
|
||||
<blend>1</blend>
|
||||
<rendering-hint>transparent</rendering-hint>
|
||||
<program>
|
||||
<vertex-shader>Shaders/HDR/cloud-static.vert</vertex-shader>
|
||||
<vertex-shader>Shaders/HDR/aerial-perspective-include.frag</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/3dcloud.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>baseTexture</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
<!-- Aerial perspective include -->
|
||||
<uniform>
|
||||
<name>aerial_perspective_lut</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">11</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>transmittance_lut</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">12</value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
</PropertyList>
|
||||
|
|
|
@ -362,4 +362,50 @@
|
|||
<vertex-program-two-side>true</vertex-program-two-side>
|
||||
</pass>
|
||||
</technique>
|
||||
|
||||
<technique n="109">
|
||||
<scheme>hdr-geometry</scheme>
|
||||
</technique>
|
||||
<technique n="129">
|
||||
<scheme>hdr-forward</scheme>
|
||||
<pass>
|
||||
<!-- Reverse floating point depth buffer -->
|
||||
<depth>
|
||||
<function>gequal</function>
|
||||
<near>1.0</near>
|
||||
<far>0.0</far>
|
||||
<write-mask>false</write-mask>
|
||||
</depth>
|
||||
<texture-unit>
|
||||
<unit>0</unit>
|
||||
<type>2d</type>
|
||||
<image><use>texture[0]/image</use></image>
|
||||
<wrap-s>clamp-to-border</wrap-s>
|
||||
<wrap-t>clamp-to-border</wrap-t>
|
||||
</texture-unit>
|
||||
<blend>1</blend>
|
||||
<rendering-hint>transparent</rendering-hint>
|
||||
<program>
|
||||
<vertex-shader>Shaders/HDR/cloud-static.vert</vertex-shader>
|
||||
<vertex-shader>Shaders/HDR/aerial-perspective-include.frag</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/3dcloud.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>baseTexture</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
<!-- Aerial perspective include -->
|
||||
<uniform>
|
||||
<name>aerial_perspective_lut</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">11</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>transmittance_lut</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">12</value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
</PropertyList>
|
||||
|
|
|
@ -475,4 +475,68 @@
|
|||
<!--<vertex-program-two-side>true</vertex-program-two-side>-->
|
||||
</pass>
|
||||
</technique>
|
||||
|
||||
<technique n="109">
|
||||
<scheme>hdr-geometry</scheme>
|
||||
</technique>
|
||||
<technique n="129">
|
||||
<scheme>hdr-forward</scheme>
|
||||
<pass>
|
||||
<!-- Reverse floating point depth buffer -->
|
||||
<depth>
|
||||
<function>gequal</function>
|
||||
<near>1.0</near>
|
||||
<far>0.0</far>
|
||||
<write-mask>false</write-mask>
|
||||
</depth>
|
||||
<texture-unit>
|
||||
<unit>0</unit>
|
||||
<type>2d</type>
|
||||
<image><use>texture[0]/image</use></image>
|
||||
<wrap-s>clamp-to-border</wrap-s>
|
||||
<wrap-t>clamp-to-border</wrap-t>
|
||||
</texture-unit>
|
||||
<blend>1</blend>
|
||||
<rendering-hint>transparent</rendering-hint>
|
||||
<program>
|
||||
<vertex-shader>Shaders/HDR/3dcloud.vert</vertex-shader>
|
||||
<vertex-shader>Shaders/HDR/aerial-perspective-include.frag</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/3dcloud.frag</fragment-shader>
|
||||
<attribute>
|
||||
<name>usrAttr1</name>
|
||||
<index>10</index>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>usrAttr2</name>
|
||||
<index>11</index>
|
||||
</attribute>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>baseTexture</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>range</name>
|
||||
<type>float</type>
|
||||
<value><use>range</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>detail_range</name>
|
||||
<type>float</type>
|
||||
<value><use>detail</use></value>
|
||||
</uniform>
|
||||
<!-- Aerial perspective include -->
|
||||
<uniform>
|
||||
<name>aerial_perspective_lut</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">11</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>transmittance_lut</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">12</value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
</PropertyList>
|
||||
|
|
|
@ -93,4 +93,46 @@
|
|||
</polygon-offset>
|
||||
</pass>
|
||||
</technique>
|
||||
|
||||
<technique n="107">
|
||||
<scheme>hdr-geometry</scheme>
|
||||
<pass>
|
||||
<!-- Reverse floating point depth buffer -->
|
||||
<depth>
|
||||
<function>gequal</function>
|
||||
<near>1.0</near>
|
||||
<far>0.0</far>
|
||||
</depth>
|
||||
<stencil>
|
||||
<function>always</function>
|
||||
<value>9</value>
|
||||
<pass>replace</pass>
|
||||
</stencil>
|
||||
<texture-unit>
|
||||
<unit>0</unit>
|
||||
<type><use>texture[0]/type</use></type>
|
||||
<image><use>texture[0]/image</use></image>
|
||||
<filter><use>texture[0]/filter</use></filter>
|
||||
<wrap-s><use>texture[0]/wrap-s</use></wrap-s>
|
||||
<wrap-t><use>texture[0]/wrap-t</use></wrap-t>
|
||||
</texture-unit>
|
||||
<blend>0</blend>
|
||||
<rendering-hint>opaque</rendering-hint>
|
||||
<cull-face>back</cull-face>
|
||||
<program>
|
||||
<vertex-shader>Shaders/HDR/geometry-lfeat.vert</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/geometry-lfeat.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/HDR/gbuffer-include.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>color_tex</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
<polygon-offset>
|
||||
<factor>2.0</factor>
|
||||
<units>1.0</units>
|
||||
</polygon-offset>
|
||||
</pass>
|
||||
</technique>
|
||||
</PropertyList>
|
||||
|
|
|
@ -5,5 +5,5 @@ It's kept for backwards compatibility and should not be used on new projects.
|
|||
-->
|
||||
<PropertyList>
|
||||
<name>Effects/model-combined-transparent</name>
|
||||
<inherits-from>Effects/model-combined</inherits-from>
|
||||
<inherits-from>Effects/model-transparent</inherits-from>
|
||||
</PropertyList>
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
<!-- DIFFUSE -->
|
||||
</material>
|
||||
<material-id>0</material-id>
|
||||
<render-bin>
|
||||
<bin-number>1</bin-number>
|
||||
<bin-name>RenderBin</bin-name>
|
||||
</render-bin>
|
||||
<write-depth type="bool">true</write-depth>
|
||||
<!-- BEGIN fog include -->
|
||||
<visibility><use>/environment/ground-visibility-m</use></visibility>
|
||||
<avisibility><use>/environment/visibility-m</use></avisibility>
|
||||
|
@ -87,6 +92,9 @@
|
|||
</predicate>
|
||||
<pass>
|
||||
<lighting>true</lighting>
|
||||
<depth>
|
||||
<write-mask><use>write-depth</use></write-mask>
|
||||
</depth>
|
||||
<material>
|
||||
<active><use>material/active</use></active>
|
||||
<ambient><use>material/ambient</use></ambient>
|
||||
|
@ -103,11 +111,10 @@
|
|||
</blend>
|
||||
<shade-model><use>shade-model</use></shade-model>
|
||||
<cull-face><use>cull-face</use></cull-face>
|
||||
<!--<render-bin>
|
||||
<bin-number>1</bin-number>
|
||||
<bin-name>RenderBin</bin-name>
|
||||
</render-bin>-->
|
||||
<rendering-hint><use>rendering-hint</use></rendering-hint>
|
||||
<render-bin>
|
||||
<bin-number><use>render-bin/bin-number</use></bin-number>
|
||||
<bin-name><use>render-bin/bin-name</use></bin-name>
|
||||
</render-bin>
|
||||
<texture-unit>
|
||||
<!-- The texture unit is always active because the shaders expect
|
||||
that. -->
|
||||
|
@ -408,6 +415,9 @@
|
|||
</predicate>
|
||||
<pass>
|
||||
<lighting>true</lighting>
|
||||
<depth>
|
||||
<write-mask><use>write-depth</use></write-mask>
|
||||
</depth>
|
||||
<material>
|
||||
<active>
|
||||
<use>material/active</use>
|
||||
|
@ -448,9 +458,10 @@
|
|||
<cull-face>
|
||||
<use>cull-face</use>
|
||||
</cull-face>
|
||||
<rendering-hint>
|
||||
<use>rendering-hint</use>
|
||||
</rendering-hint>
|
||||
<render-bin>
|
||||
<bin-number><use>render-bin/bin-number</use></bin-number>
|
||||
<bin-name><use>render-bin/bin-name</use></bin-name>
|
||||
</render-bin>
|
||||
<texture-unit>
|
||||
<!-- The texture unit is always active because the shaders expect
|
||||
that. -->
|
||||
|
@ -572,6 +583,9 @@
|
|||
<technique n="13">
|
||||
<pass>
|
||||
<lighting>true</lighting>
|
||||
<depth>
|
||||
<write-mask><use>write-depth</use></write-mask>
|
||||
</depth>
|
||||
<material>
|
||||
<active>
|
||||
<use>material/active</use>
|
||||
|
@ -612,9 +626,10 @@
|
|||
<cull-face>
|
||||
<use>cull-face</use>
|
||||
</cull-face>
|
||||
<rendering-hint>
|
||||
<use>rendering-hint</use>
|
||||
</rendering-hint>
|
||||
<render-bin>
|
||||
<bin-number><use>render-bin/bin-number</use></bin-number>
|
||||
<bin-name><use>render-bin/bin-name</use></bin-name>
|
||||
</render-bin>
|
||||
<texture-unit>
|
||||
<active>
|
||||
<use>texture[0]/active</use>
|
||||
|
|
|
@ -4,6 +4,12 @@
|
|||
<inherits-from>Effects/model-default</inherits-from>
|
||||
|
||||
<parameters>
|
||||
<render-bin>
|
||||
<bin-number>111</bin-number>
|
||||
<bin-name>DepthSortedBin</bin-name>
|
||||
</render-bin>
|
||||
<write-depth type="bool">false</write-depth>
|
||||
|
||||
<texture n="8">
|
||||
<image>Textures/PBR/dfg_lut.dds</image>
|
||||
<type>2d</type>
|
||||
|
|
|
@ -886,4 +886,64 @@
|
|||
</alpha-test>
|
||||
</pass>
|
||||
</technique>
|
||||
|
||||
<technique n="108">
|
||||
<scheme>hdr-geometry</scheme>
|
||||
<pass>
|
||||
<!-- Reverse floating point depth buffer -->
|
||||
<depth>
|
||||
<function>gequal</function>
|
||||
<near>1.0</near>
|
||||
<far>0.0</far>
|
||||
</depth>
|
||||
<stencil>
|
||||
<function>always</function>
|
||||
<value>9</value>
|
||||
<pass>replace</pass>
|
||||
</stencil>
|
||||
<texture-unit>
|
||||
<unit>0</unit>
|
||||
<type><use>texture[0]/type</use></type>
|
||||
<image><use>texture[0]/image</use></image>
|
||||
<filter><use>texture[0]/filter</use></filter>
|
||||
<wrap-s><use>texture[0]/wrap-s</use></wrap-s>
|
||||
<wrap-t><use>texture[0]/wrap-t</use></wrap-t>
|
||||
</texture-unit>
|
||||
<texture-unit>
|
||||
<unit>1</unit>
|
||||
<type><use>texture[4]/type</use></type>
|
||||
<image><use>texture[4]/image</use></image>
|
||||
<filter><use>texture[4]/filter</use></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>2</unit>
|
||||
<type>noise</type>
|
||||
</texture-unit>
|
||||
<blend>0</blend>
|
||||
<rendering-hint>opaque</rendering-hint>
|
||||
<cull-face>back</cull-face>
|
||||
<program>
|
||||
<vertex-shader>Shaders/HDR/geometry-runway.vert</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/geometry-runway.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/HDR/gbuffer-include.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>color_tex</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>normal_tex</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">1</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>noise_tex</name>
|
||||
<type>sampler-3d</type>
|
||||
<value type="int">2</value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
</PropertyList>
|
||||
|
|
|
@ -1669,7 +1669,6 @@
|
|||
</pass>
|
||||
</technique>
|
||||
|
||||
<!-- Just for ocean tiles. For actual terrain we use ws30.eff. -->
|
||||
<technique n="109">
|
||||
<scheme>hdr-geometry</scheme>
|
||||
<pass>
|
||||
|
@ -1696,8 +1695,8 @@
|
|||
<rendering-hint>opaque</rendering-hint>
|
||||
<cull-face>back</cull-face>
|
||||
<program>
|
||||
<vertex-shader>Shaders/HDR/geometry.vert</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/geometry.frag</fragment-shader>
|
||||
<vertex-shader>Shaders/HDR/geometry-terrain.vert</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/geometry-terrain.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/HDR/gbuffer-include.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
|
@ -1705,16 +1704,11 @@
|
|||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
<!-- Orthophoto include -->
|
||||
<uniform>
|
||||
<name>color_mode</name>
|
||||
<type>int</type>
|
||||
<value>2</value>
|
||||
<!-- AMBIENT_AND_DIFFUSE -->
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>material_diffuse</name>
|
||||
<type>float-vec4</type>
|
||||
<value><use>material/diffuse</use></value>
|
||||
<name>orthophoto_tex</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">15</value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
|
|
61
Shaders/HDR/3dcloud.frag
Normal file
61
Shaders/HDR/3dcloud.frag
Normal file
|
@ -0,0 +1,61 @@
|
|||
#version 330 core
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
in vec2 texCoord;
|
||||
in vec4 cloudColor;
|
||||
|
||||
uniform sampler2D baseTexture;
|
||||
|
||||
uniform mat4 osg_ProjectionMatrix;
|
||||
uniform vec4 fg_Viewport;
|
||||
uniform vec3 fg_SunDirection;
|
||||
|
||||
const int STEPS = 8;
|
||||
|
||||
uniform float density = 30.0;
|
||||
uniform float max_sample_dist = 0.05;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 base = texture(baseTexture, texCoord);
|
||||
|
||||
// Directly discard fragments below a threshold
|
||||
if (base.a < 0.02)
|
||||
discard;
|
||||
|
||||
// Pixel position in screen space [-1, 1]
|
||||
vec2 screen_uv = ((gl_FragCoord.xy - fg_Viewport.xy) / fg_Viewport.zw) * 2.0 - 1.0;
|
||||
|
||||
// XXX: Sun's screen-space position. This should be passed as an uniform
|
||||
vec4 sun_dir_screen = osg_ProjectionMatrix * vec4(fg_SunDirection, 0.0);
|
||||
sun_dir_screen.xyz /= sun_dir_screen.w;
|
||||
sun_dir_screen.xyz = normalize(sun_dir_screen.xyz);
|
||||
|
||||
// Direction from pixel to Sun in screen space
|
||||
vec2 sun_dir = screen_uv - sun_dir_screen.xy;
|
||||
// Flip the x axis
|
||||
sun_dir.x = -sun_dir.x;
|
||||
|
||||
float dt = max_sample_dist / STEPS;
|
||||
|
||||
// 2D ray march along the Sun's direction to estimate the transmittance
|
||||
float T = 1.0;
|
||||
for (int i = 0; i < STEPS; ++i) {
|
||||
float t = (float(i) + 0.5) * dt;
|
||||
vec2 uv_t = texCoord - sun_dir * t;
|
||||
vec4 texel = texture(baseTexture, uv_t);
|
||||
// Beer-Lambert's law
|
||||
T *= exp(-texel.a * dt * density);
|
||||
}
|
||||
|
||||
// When the camera is facing perpendicularly to the Sun, the Sun's
|
||||
// screen-space location can tend toward infinity. Fade the effect toward
|
||||
// the perpendicular.
|
||||
float fade = smoothstep(0.1, 0.5, dot(vec3(0.0, 0.0, -1.0), fg_SunDirection));
|
||||
|
||||
vec4 color = base * cloudColor;
|
||||
color.rgb *= base.a * mix(1.0, T, fade);
|
||||
|
||||
fragColor = color;
|
||||
}
|
116
Shaders/HDR/3dcloud.vert
Normal file
116
Shaders/HDR/3dcloud.vert
Normal file
|
@ -0,0 +1,116 @@
|
|||
#version 330 core
|
||||
|
||||
layout(location = 0) in vec4 pos;
|
||||
layout(location = 2) in vec4 vertexColor;
|
||||
layout(location = 3) in vec4 multiTexCoord0;
|
||||
layout(location = 10) in vec4 usrAttr1;
|
||||
layout(location = 11) in vec4 usrAttr2;
|
||||
|
||||
out vec2 texCoord;
|
||||
out vec4 cloudColor;
|
||||
|
||||
uniform float range;
|
||||
uniform float detail_range;
|
||||
|
||||
uniform mat4 osg_ModelViewMatrix;
|
||||
uniform mat4 osg_ModelViewProjectionMatrix;
|
||||
uniform mat4 osg_ViewMatrixInverse;
|
||||
uniform vec3 fg_SunDirectionWorld;
|
||||
|
||||
// aerial-perspective-include.frag
|
||||
vec3 add_aerial_perspective(vec3 color, vec2 coord, float depth);
|
||||
vec3 get_sun_radiance(vec3 p);
|
||||
|
||||
void main()
|
||||
{
|
||||
float alpha_factor = usrAttr1.r;
|
||||
float shade_factor = usrAttr1.g;
|
||||
float cloud_height = usrAttr1.b;
|
||||
float bottom_factor = usrAttr2.r;
|
||||
float middle_factor = usrAttr2.g;
|
||||
float top_factor = usrAttr2.b;
|
||||
|
||||
texCoord = multiTexCoord0.st;
|
||||
|
||||
// XXX: Should be sent as an uniform
|
||||
mat4 inverseModelViewMatrix = inverse(osg_ModelViewMatrix);
|
||||
|
||||
vec4 ep = inverseModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0);
|
||||
vec4 l = inverseModelViewMatrix * vec4(0.0, 0.0, 1.0, 1.0);
|
||||
vec3 u = normalize(ep.xyz - l.xyz);
|
||||
|
||||
// Find a rotation matrix that rotates 1,0,0 into u. u, r and w are
|
||||
// the columns of that matrix.
|
||||
vec3 absu = abs(u);
|
||||
vec3 r = normalize(vec3(-u.y, u.x, 0.0));
|
||||
vec3 w = cross(u, r);
|
||||
|
||||
// Do the matrix multiplication by [ u r w pos]. Assume no
|
||||
// scaling in the homogeneous component of pos.
|
||||
vec4 final_pos = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
final_pos.xyz = pos.x * u;
|
||||
final_pos.xyz += pos.y * r;
|
||||
final_pos.xyz += pos.z * w;
|
||||
// Apply Z scaling to allow sprites to be squashed in the z-axis
|
||||
final_pos.z = final_pos.z * vertexColor.w;
|
||||
|
||||
// Now shift the sprite to the correct position in the cloud.
|
||||
final_pos.xyz += vertexColor.xyz;
|
||||
|
||||
// Determine the position - used for fog and shading calculations
|
||||
float fogCoord = length(vec3(osg_ModelViewMatrix * vec4(vertexColor.xyz, 1.0)));
|
||||
float center_dist = length(vec3(osg_ModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)));
|
||||
|
||||
if ((fogCoord > detail_range) && (fogCoord > center_dist) && (shade_factor < 0.7)) {
|
||||
// More than detail_range away, so discard all sprites on opposite side of
|
||||
// cloud center by shifting them beyond the view fustrum
|
||||
gl_Position = vec4(0.0, 0.0, 10.0, 1.0);
|
||||
cloudColor = vec4(0.0);
|
||||
} else {
|
||||
gl_Position = osg_ModelViewProjectionMatrix * final_pos;
|
||||
|
||||
vec4 final_view_pos = osg_ModelViewMatrix * final_pos;
|
||||
vec4 final_world_pos = osg_ViewMatrixInverse * final_view_pos;
|
||||
|
||||
// Determine a lighting normal based on the vertex position from the
|
||||
// center of the cloud, so that sprite on the opposite side of the cloud
|
||||
// to the sun are darker.
|
||||
vec3 n = normalize(vec3(osg_ViewMatrixInverse *
|
||||
osg_ModelViewMatrix * vec4(-final_pos.xyz, 0.0)));
|
||||
float NdotL = dot(-fg_SunDirectionWorld, n);
|
||||
|
||||
// Determine the shading of the vertex. We shade it based on it's position
|
||||
// in the cloud relative to the sun, and it's vertical position in the cloud.
|
||||
float shade = mix(shade_factor, top_factor, smoothstep(-0.3, 0.3, NdotL));
|
||||
|
||||
if (final_pos.z < 0.5 * cloud_height) {
|
||||
shade = min(shade, mix(bottom_factor, middle_factor,
|
||||
final_pos.z * 2.0 / cloud_height));
|
||||
} else {
|
||||
shade = min(shade, mix(middle_factor, top_factor,
|
||||
final_pos.z * 2.0 / cloud_height - 1.0));
|
||||
}
|
||||
|
||||
cloudColor.rgb = shade * get_sun_radiance(final_world_pos.xyz);
|
||||
|
||||
// Perspective division and scale to [0, 1] to get the screen position
|
||||
// of the vertex.
|
||||
vec2 coord = (gl_Position.xy / gl_Position.w) * 0.5 + 0.5;
|
||||
cloudColor.rgb = add_aerial_perspective(
|
||||
cloudColor.rgb, coord, length(final_view_pos));
|
||||
|
||||
if ((fogCoord > (0.9 * detail_range))
|
||||
&& (fogCoord > center_dist)
|
||||
&& (shade_factor < 0.7)) {
|
||||
// cloudlet is almost at the detail range, so fade it out.
|
||||
cloudColor.a = 1.0 - smoothstep(0.9 * detail_range, detail_range, fogCoord);
|
||||
} else {
|
||||
// As we get within 100m of the sprite, it is faded out.
|
||||
// Equally at large distances it also fades out.
|
||||
cloudColor.a = min(smoothstep(10.0, 100.0, fogCoord),
|
||||
1.0 - smoothstep(0.9 * range, range, fogCoord));
|
||||
}
|
||||
|
||||
cloudColor.a *= alpha_factor;
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#version 330 core
|
||||
|
||||
out float adaptedLum;
|
||||
|
||||
uniform sampler2D prev_lum_tex;
|
||||
uniform sampler2D current_lum_tex;
|
||||
|
||||
uniform float osg_DeltaFrameTime;
|
||||
|
||||
// Higher values give faster eye adaptation times
|
||||
const float TAU = 4.0;
|
||||
|
||||
void main()
|
||||
{
|
||||
float prevLum = texelFetch(prev_lum_tex, ivec2(0), 0).r;
|
||||
float currentLum = exp(textureLod(current_lum_tex, vec2(0.5), 10.0).r);
|
||||
adaptedLum = prevLum + (currentLum - prevLum) *
|
||||
(1.0 - exp(-osg_DeltaFrameTime * TAU));
|
||||
}
|
|
@ -3,71 +3,91 @@
|
|||
uniform sampler2D aerial_perspective_lut;
|
||||
uniform sampler2D transmittance_lut;
|
||||
|
||||
uniform float fg_SunZenithCosTheta;
|
||||
uniform vec3 fg_SunDirectionWorld;
|
||||
uniform float fg_CameraDistanceToEarthCenter;
|
||||
uniform float fg_SunZenithCosTheta;
|
||||
uniform float fg_EarthRadius;
|
||||
|
||||
const float AERIAL_SLICES = 32.0;
|
||||
const float AERIAL_LUT_TILE_SIZE = 1.0 / AERIAL_SLICES;
|
||||
const float AERIAL_LUT_TEXEL_SIZE = 1.0 / 1024.0;
|
||||
const float AERIAL_MAX_DEPTH = 128000.0;
|
||||
const vec3 EXTRATERRESTRIAL_SOLAR_ILLUMINANCE = vec3(128.0);
|
||||
const float AP_SLICE_COUNT = 32.0;
|
||||
const float AP_MAX_DEPTH = 128000.0;
|
||||
const float AP_SLICE_WIDTH_PIXELS = 32.0;
|
||||
const float AP_SLICE_SIZE = 1.0 / AP_SLICE_COUNT;
|
||||
const float AP_TEXEL_WIDTH = 1.0 / (AP_SLICE_COUNT * AP_SLICE_WIDTH_PIXELS);
|
||||
|
||||
const float ATMOSPHERE_RADIUS = 6471e3;
|
||||
|
||||
vec4 sampleAerialPerspectiveSlice(vec2 coord, int slice)
|
||||
//-- BEGIN spectral include
|
||||
|
||||
// Extraterrestial Solar Irradiance Spectra, units W * m^-2 * nm^-1
|
||||
// https://www.nrel.gov/grid/solar-resource/spectra.html
|
||||
const vec4 sun_spectral_irradiance = vec4(1.679, 1.828, 1.986, 1.307);
|
||||
|
||||
const mat4x3 M = mat4x3(
|
||||
137.672389239975, -8.632904716299537, -1.7181567391931372,
|
||||
32.549094028629234, 91.29801417199785, -12.005406444382531,
|
||||
-38.91428392614275, 34.31665471469816, 29.89044807197628,
|
||||
8.572844237945445, -11.103384660054624, 117.47585277566478
|
||||
);
|
||||
|
||||
vec3 linear_srgb_from_spectral_samples(vec4 L)
|
||||
{
|
||||
// Sample at the pixel center
|
||||
float offset = slice * AERIAL_LUT_TILE_SIZE + AERIAL_LUT_TEXEL_SIZE * 0.5;
|
||||
float x = coord.x * (AERIAL_LUT_TILE_SIZE - AERIAL_LUT_TEXEL_SIZE) + offset;
|
||||
return texture(aerial_perspective_lut, vec2(x, coord.y));
|
||||
return M * L;
|
||||
}
|
||||
|
||||
vec4 sampleAerialPerspective(vec2 coord, float depth)
|
||||
//-- END spectral include
|
||||
|
||||
vec4 sample_aerial_perspective_slice(sampler2D lut, vec2 coord, float slice)
|
||||
{
|
||||
// Sample at the pixel center
|
||||
float offset = slice * AP_SLICE_SIZE + AP_TEXEL_WIDTH * 0.5;
|
||||
float x = coord.x * (AP_SLICE_SIZE - AP_TEXEL_WIDTH) + offset;
|
||||
return texture(lut, vec2(x, coord.y));
|
||||
}
|
||||
|
||||
vec4 sample_aerial_perspective(sampler2D lut, vec2 coord, float depth)
|
||||
{
|
||||
vec4 color;
|
||||
// Map to [0,1]
|
||||
float w = depth / AERIAL_MAX_DEPTH;
|
||||
// Squared distribution
|
||||
w = sqrt(clamp(w, 0.0, 1.0));
|
||||
w *= AERIAL_SLICES;
|
||||
if (w <= 1.0) {
|
||||
float w = sqrt(clamp(depth / AP_MAX_DEPTH, 0.0, 1.0));
|
||||
float x = w * AP_SLICE_COUNT;
|
||||
if (x <= 1.0) {
|
||||
// Handle special case of fragments behind the first slice
|
||||
color = mix(vec4(0.0, 0.0, 0.0, 1.0),
|
||||
sampleAerialPerspectiveSlice(coord, 0),
|
||||
w);
|
||||
sample_aerial_perspective_slice(lut, coord, 0),
|
||||
x);
|
||||
} else {
|
||||
w -= 1.0;
|
||||
// Manually interpolate between slices
|
||||
color = mix(sampleAerialPerspectiveSlice(coord, int(floor(w))),
|
||||
sampleAerialPerspectiveSlice(coord, int(ceil(w))),
|
||||
sqrt(fract(w)));
|
||||
x -= 1.0;
|
||||
color = mix(sample_aerial_perspective_slice(lut, coord, floor(x)),
|
||||
sample_aerial_perspective_slice(lut, coord, ceil(x)),
|
||||
fract(x));
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
vec3 addAerialPerspective(vec3 color, vec2 coord, float depth)
|
||||
vec3 add_aerial_perspective(vec3 color, vec2 coord, float depth)
|
||||
{
|
||||
vec4 aerialPerspective = sampleAerialPerspective(coord, depth);
|
||||
return color * aerialPerspective.a + aerialPerspective.rgb
|
||||
* EXTRATERRESTRIAL_SOLAR_ILLUMINANCE;
|
||||
vec4 ap = sample_aerial_perspective(aerial_perspective_lut, coord, depth);
|
||||
return color * ap.a + ap.rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the illuminance of the Sun for a surface perpendicular to the Sun
|
||||
* direction. The illuminance is calculated at the altitude of the viewer,
|
||||
* which might or might not be correct in certain circumstances. If the object
|
||||
* being illuminated is not too far from the viewer it's a good enough
|
||||
* approximation.
|
||||
/*
|
||||
* Get the Sun radiance at a point 'p' in world space.
|
||||
* We cannot use the Sun extraterrestial irradiance directly because it will be
|
||||
* attenuated by the transmittance of the atmospheric medium.
|
||||
*/
|
||||
vec3 getSunIntensity()
|
||||
vec3 get_sun_radiance(vec3 p)
|
||||
{
|
||||
float normalizedHeight = (fg_CameraDistanceToEarthCenter - fg_EarthRadius)
|
||||
float distance_to_earth_center = length(p);
|
||||
float normalized_altitude = (distance_to_earth_center - fg_EarthRadius)
|
||||
/ (ATMOSPHERE_RADIUS - fg_EarthRadius);
|
||||
|
||||
vec2 coord = vec2(fg_SunZenithCosTheta * 0.5 + 0.5,
|
||||
clamp(normalizedHeight, 0.0, 1.0));
|
||||
vec3 transmittance = texture(transmittance_lut, coord).rgb;
|
||||
vec3 zenith_dir = p / distance_to_earth_center;
|
||||
float sun_cos_theta = dot(zenith_dir, fg_SunDirectionWorld);
|
||||
|
||||
return EXTRATERRESTRIAL_SOLAR_ILLUMINANCE * transmittance;
|
||||
float u = sun_cos_theta * 0.5 + 0.5;
|
||||
float v = clamp(normalized_altitude, 0.0, 1.0);
|
||||
vec4 transmittance = texture(transmittance_lut, vec2(u, v));
|
||||
|
||||
vec4 L = sun_spectral_irradiance * transmittance;
|
||||
return linear_srgb_from_spectral_samples(L);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
// An implementation of Sébastien Hillaire's "A Scalable and Production Ready
|
||||
// Sky and Atmosphere Rendering Technique".
|
||||
// Render the aerial perspective LUT, similar to
|
||||
// "A Scalable and Production Ready Sky and Atmosphere Rendering Technique"
|
||||
// by Sébastien Hillaire (2020).
|
||||
//
|
||||
// This shader generates the aerial perspective LUT. This LUT is used by opaque
|
||||
// and transparent objects to apply atmospheric scattering. In-scattering is
|
||||
// stored in the RGB channels, while transmittance is stored in the alpha
|
||||
// channel.
|
||||
// Unlike the paper, we are using a tiled 2D texture instead of a true 3D
|
||||
// texture. For some reason the overhead of rendering to a texture a lot of
|
||||
// times (the depth of the 3D texture) seems to be too high, probably because
|
||||
// OSG is not sharing state between those passes.
|
||||
// texture. For some reason the overhead of rendering to a texture many times
|
||||
// (the depth of the 3D texture) seems to be too high, probably because OSG is
|
||||
// not sharing state between those passes.
|
||||
|
||||
#version 330 core
|
||||
|
||||
|
@ -17,112 +14,73 @@ out vec4 fragColor;
|
|||
in vec2 texCoord;
|
||||
|
||||
uniform sampler2D transmittance_lut;
|
||||
uniform sampler2D multiscattering_lut;
|
||||
|
||||
uniform mat4 fg_ViewMatrixInverse;
|
||||
uniform vec3 fg_CameraPositionCart;
|
||||
uniform vec3 fg_SunDirectionWorld;
|
||||
uniform float fg_SunZenithCosTheta;
|
||||
uniform float fg_CameraDistanceToEarthCenter;
|
||||
uniform float fg_EarthRadius;
|
||||
|
||||
const float PI = 3.141592653;
|
||||
const float ATMOSPHERE_RADIUS = 6471e3;
|
||||
const float TOTAL_SLICES = 32.0;
|
||||
const float DEPTH_RANGE = 128000.0;
|
||||
const int AERIAL_PERSPECTIVE_SAMPLES = 20;
|
||||
const vec3 ONE_OVER_THREE = vec3(1.0 / 3.0);
|
||||
const float AP_SLICE_COUNT = 32.0;
|
||||
const float AP_MAX_DEPTH = 128000.0;
|
||||
const int AERIAL_PERSPECTIVE_STEPS = 20;
|
||||
|
||||
// gbuffer-include.frag
|
||||
vec3 positionFromDepth(vec2 pos, float depth);
|
||||
|
||||
float raySphereIntersection(vec3 ro, vec3 rd, float radius);
|
||||
vec3 sampleMedium(in float height,
|
||||
out float mieScattering, out float mieAbsorption,
|
||||
out vec3 rayleighScattering, out vec3 ozoneAbsorption);
|
||||
float miePhaseFunction(float cosTheta);
|
||||
float rayleighPhaseFunction(float cosTheta);
|
||||
vec3 getValueFromLUT(sampler2D lut, float sunCosTheta, float normalizedHeight);
|
||||
// atmos-include.frag
|
||||
vec4 compute_inscattering(in vec3 ray_origin,
|
||||
in vec3 ray_dir,
|
||||
in float t_max,
|
||||
in vec3 sun_dir,
|
||||
in int steps,
|
||||
in sampler2D transmittance_lut,
|
||||
out vec4 transmittance);
|
||||
|
||||
//-- BEGIN spectral include
|
||||
|
||||
// Extraterrestial Solar Irradiance Spectra, units W * m^-2 * nm^-1
|
||||
// https://www.nrel.gov/grid/solar-resource/spectra.html
|
||||
const vec4 sun_spectral_irradiance = vec4(1.679, 1.828, 1.986, 1.307);
|
||||
|
||||
const mat4x3 M = mat4x3(
|
||||
137.672389239975, -8.632904716299537, -1.7181567391931372,
|
||||
32.549094028629234, 91.29801417199785, -12.005406444382531,
|
||||
-38.91428392614275, 34.31665471469816, 29.89044807197628,
|
||||
8.572844237945445, -11.103384660054624, 117.47585277566478
|
||||
);
|
||||
|
||||
vec3 linear_srgb_from_spectral_samples(vec4 L)
|
||||
{
|
||||
return M * L;
|
||||
}
|
||||
|
||||
//-- END spectral include
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
// Account for the depth layer we are currently in
|
||||
float x = texCoord.x * TOTAL_SLICES;
|
||||
// Account for the depth slice we are currently in. Depth goes from 0 to
|
||||
// DEPTH_RANGE in a squared distribution. The first slice is not 0 since
|
||||
// that would waste a slice.
|
||||
float x = texCoord.x * AP_SLICE_COUNT;
|
||||
float slice = ceil(x);
|
||||
float w = slice / AP_SLICE_COUNT; // [0,1]
|
||||
float depth = w*w * AP_MAX_DEPTH;
|
||||
|
||||
vec2 coord = vec2(fract(x), texCoord.y);
|
||||
// Depth goes from the 0 to DEPTH_RANGE in a squared distribution.
|
||||
// The first slice is not at 0 since that would waste a slice.
|
||||
float w = ceil(x) / TOTAL_SLICES;
|
||||
w *= w;
|
||||
float depth = w * DEPTH_RANGE;
|
||||
|
||||
vec3 fragPos = positionFromDepth(coord, 1.0);
|
||||
vec3 rayDir = vec4(fg_ViewMatrixInverse * vec4(normalize(fragPos), 0.0)).xyz;
|
||||
vec3 frag_pos = positionFromDepth(coord, 1.0);
|
||||
vec3 ray_dir = vec4(fg_ViewMatrixInverse * vec4(normalize(frag_pos), 0.0)).xyz;
|
||||
|
||||
vec3 rayOrigin = fg_CameraPositionCart;
|
||||
|
||||
// Handle the camera being underground
|
||||
float earthRadius = min(fg_EarthRadius, fg_CameraDistanceToEarthCenter);
|
||||
|
||||
float atmosDist = raySphereIntersection(rayOrigin, rayDir, ATMOSPHERE_RADIUS);
|
||||
float groundDist = raySphereIntersection(rayOrigin, rayDir, earthRadius);
|
||||
|
||||
float tmax;
|
||||
if (fg_CameraDistanceToEarthCenter < ATMOSPHERE_RADIUS) {
|
||||
// We are inside the atmosphere
|
||||
if (groundDist < 0.0) {
|
||||
// No ground collision, use the distance to the outer atmosphere
|
||||
tmax = atmosDist;
|
||||
} else {
|
||||
// Use the distance to the ground
|
||||
tmax = groundDist;
|
||||
}
|
||||
} else {
|
||||
// We are in outer space, skip
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
return;
|
||||
}
|
||||
// Clip the max distance to the depth of this slice
|
||||
tmax = min(tmax, depth);
|
||||
|
||||
float cosTheta = dot(rayDir, fg_SunDirectionWorld);
|
||||
float miePhase = miePhaseFunction(cosTheta);
|
||||
float rayleighPhase = rayleighPhaseFunction(cosTheta);
|
||||
|
||||
vec3 L = vec3(0.0);
|
||||
vec3 throughput = vec3(1.0);
|
||||
float t = 0.0;
|
||||
|
||||
for (int i = 0; i < AERIAL_PERSPECTIVE_SAMPLES; ++i) {
|
||||
float newT = ((float(i) + 0.3) / AERIAL_PERSPECTIVE_SAMPLES) * tmax;
|
||||
float dt = newT - t;
|
||||
t = newT;
|
||||
|
||||
vec3 samplePos = rayOrigin + rayDir * t;
|
||||
float height = length(samplePos) - fg_EarthRadius;
|
||||
float normalizedHeight = height / (ATMOSPHERE_RADIUS - fg_EarthRadius);
|
||||
|
||||
float mieScattering, mieAbsorption;
|
||||
vec3 rayleighScattering, ozoneAbsorption;
|
||||
vec3 extinction = sampleMedium(height, mieScattering, mieAbsorption,
|
||||
rayleighScattering, ozoneAbsorption);
|
||||
|
||||
vec3 sampleTransmittance = exp(-dt*extinction);
|
||||
|
||||
vec3 sunTransmittance = getValueFromLUT(
|
||||
transmittance_lut, fg_SunZenithCosTheta, normalizedHeight);
|
||||
vec3 multiscattering = getValueFromLUT(
|
||||
multiscattering_lut, fg_SunZenithCosTheta, normalizedHeight);
|
||||
|
||||
vec3 S =
|
||||
rayleighScattering * (rayleighPhase * sunTransmittance + multiscattering) +
|
||||
mieScattering * (miePhase * sunTransmittance + multiscattering);
|
||||
|
||||
vec3 Sint = (S - S * sampleTransmittance) / extinction;
|
||||
L += throughput * Sint;
|
||||
throughput *= sampleTransmittance;
|
||||
}
|
||||
|
||||
// Instead of storing an entire vec3, store the mean of its components
|
||||
float transmittance = dot(throughput, ONE_OVER_THREE);
|
||||
|
||||
fragColor = vec4(L, transmittance);
|
||||
vec4 transmittance;
|
||||
vec4 L = compute_inscattering(fg_CameraPositionCart,
|
||||
ray_dir,
|
||||
depth,
|
||||
fg_SunDirectionWorld,
|
||||
AERIAL_PERSPECTIVE_STEPS,
|
||||
transmittance_lut,
|
||||
transmittance);
|
||||
// In-scattering
|
||||
fragColor.rgb = linear_srgb_from_spectral_samples(L * sun_spectral_irradiance);
|
||||
// Transmittance
|
||||
fragColor.a = dot(transmittance, vec4(0.25));
|
||||
}
|
||||
|
|
|
@ -1,28 +1,99 @@
|
|||
// An implementation of Sébastien Hillaire's "A Scalable and Production Ready
|
||||
// Sky and Atmosphere Rendering Technique".
|
||||
|
||||
#version 330 core
|
||||
|
||||
const float PI = 3.141592653;
|
||||
|
||||
// Atmosphere parameters
|
||||
// Section 2.1 of [Bruneton08], units are inverse meters
|
||||
const float mie_density_height_scale = 8.33333e-4; // Hm=1.2km
|
||||
const float rayleigh_density_height_scale = 1.25e-4; // Hr=8km
|
||||
const float mie_scattering = 3.996e-6;
|
||||
const float mie_absorption = 4.4e-6;
|
||||
const vec3 rayleigh_scattering = vec3(5.802, 13.558, 33.1) * vec3(1e-6);
|
||||
const vec3 ozone_absorption = vec3(0.650, 1.881, 0.085) * vec3(1e-6);
|
||||
|
||||
const float PI = 3.14159265358979323846;
|
||||
const float INV_PI = 0.31830988618379067154;
|
||||
const float INV_4PI = 0.25 * INV_PI;
|
||||
const float PHASE_ISOTROPIC = INV_4PI;
|
||||
const float RAYLEIGH_PHASE_SCALE = (3.0 / 16.0) * INV_PI;
|
||||
const float g = 0.8;
|
||||
const float gg = g*g;
|
||||
const float mie_phase_scale = 3.0/(8.0*PI);
|
||||
const float rayleigh_phase_scale = 3.0/(16.0*PI);
|
||||
|
||||
// Returns the distance between ro and the first intersection with the sphere
|
||||
// or -1.0 if there is no intersection.
|
||||
// -1.0 is also returned if the ray is pointing away from the sphere.
|
||||
float raySphereIntersection(vec3 ro, vec3 rd, float radius)
|
||||
const float ATMOSPHERE_RADIUS = 6471e3;
|
||||
|
||||
// Rayleigh scattering coefficient at sea level, units m^-1
|
||||
// "Rayleigh-scattering calculations for the terrestrial atmosphere"
|
||||
// by Anthony Bucholtz (1995).
|
||||
const vec4 molecular_scattering_coefficient_base =
|
||||
vec4(6.605e-6, 1.067e-5, 1.842e-5, 3.156e-5);
|
||||
|
||||
// Ozone absorption cross section, units m^2 / molecules
|
||||
// "High spectral resolution ozone absorption cross-sections"
|
||||
// by V. Gorshelev et al. (2014).
|
||||
const vec4 ozone_cross_section =
|
||||
vec4(3.472e-21, 3.914e-21, 1.349e-21, 11.03e-23) * 1e-4f;
|
||||
|
||||
const float ozone_mean_monthly_dobson[] = float[](
|
||||
347.0, // January
|
||||
370.0, // February
|
||||
381.0, // March
|
||||
384.0, // April
|
||||
372.0, // May
|
||||
352.0, // June
|
||||
333.0, // July
|
||||
317.0, // August
|
||||
298.0, // September
|
||||
285.0, // October
|
||||
290.0, // November
|
||||
315.0 // December
|
||||
);
|
||||
const float ozone_height_distribution[] = float[](
|
||||
9.0 / 210.0,
|
||||
14.0 / 210.0,
|
||||
111.0 / 210.0,
|
||||
64.0 / 210.0,
|
||||
6.0 / 210.0,
|
||||
6.0 / 210.0,
|
||||
0.0
|
||||
);
|
||||
|
||||
/*
|
||||
* Every aerosol type expects 5 parameters:
|
||||
* - Scattering cross section
|
||||
* - Absorption cross section
|
||||
* - Base density (km^-3)
|
||||
* - Background density (km^-3)
|
||||
* - Height scaling parameter
|
||||
* These parameters can be sent as uniforms.
|
||||
*
|
||||
* This model for aerosols and their corresponding parameters come from
|
||||
* "A Physically-Based Spatio-Temporal Sky Model"
|
||||
* by Guimera et al. (2018).
|
||||
*/
|
||||
// Urban
|
||||
uniform vec4 aerosol_absorption_cross_section =
|
||||
vec4(2.8722e-24, 4.6168e-24, 7.9706e-24, 1.3578e-23);
|
||||
uniform vec4 aerosol_scattering_cross_section =
|
||||
vec4(1.5908e-22, 1.7711e-22, 2.0942e-22, 2.4033e-22);
|
||||
uniform float aerosol_base_density = 1.3681e20;
|
||||
uniform float aerosol_relative_background_density = 2e6 / 1.3681e20;
|
||||
uniform float aerosol_height_scale = 0.73;
|
||||
|
||||
uniform float aerosol_turbidity = 1.0;
|
||||
|
||||
uniform int month_of_the_year = 0;
|
||||
uniform vec4 ground_albedo = vec4(0.3);
|
||||
|
||||
uniform float fg_EarthRadius;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Helper function to obtain the transmittance to the top of the atmosphere
|
||||
* from Buffer A.
|
||||
*/
|
||||
vec4 transmittance_from_lut(sampler2D lut, float cos_theta, float normalized_altitude)
|
||||
{
|
||||
float u = clamp(cos_theta * 0.5 + 0.5, 0.0, 1.0);
|
||||
float v = clamp(normalized_altitude, 0.0, 1.0);
|
||||
return texture(lut, vec2(u, v));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the distance between ro and the first intersection with the sphere
|
||||
* or -1.0 if there is no intersection. The sphere's origin is (0,0,0).
|
||||
* -1.0 is also returned if the ray is pointing away from the sphere.
|
||||
*/
|
||||
float ray_sphere_intersection(vec3 ro, vec3 rd, float radius)
|
||||
{
|
||||
float b = dot(ro, rd);
|
||||
float c = dot(ro, ro) - radius*radius;
|
||||
|
@ -33,46 +104,205 @@ float raySphereIntersection(vec3 ro, vec3 rd, float radius)
|
|||
return (-b-sqrt(d));
|
||||
}
|
||||
|
||||
// Sample the sky medium properties at a height in meters, 0 being the ground
|
||||
// and ~100km being the top of the atmosphere.
|
||||
// Returns the total atmospheric extinction.
|
||||
vec3 sampleMedium(in float height,
|
||||
out float mieScattering, out float mieAbsorption,
|
||||
out vec3 rayleighScattering, out vec3 ozoneAbsorption)
|
||||
/*
|
||||
* Rayleigh phase function.
|
||||
*/
|
||||
float molecular_phase_function(float cos_theta)
|
||||
{
|
||||
float densityMie = exp(-mie_density_height_scale * height);
|
||||
float densityRayleigh = exp(-rayleigh_density_height_scale * height);
|
||||
float densityOzone = max(0.0, 1.0 - abs(height-25.0e3)/15.0e3);
|
||||
|
||||
mieScattering = mie_scattering * densityMie;
|
||||
mieAbsorption = mie_absorption * densityMie;
|
||||
|
||||
rayleighScattering = rayleigh_scattering * densityRayleigh;
|
||||
|
||||
ozoneAbsorption = ozone_absorption * densityOzone;
|
||||
|
||||
return mieScattering + mieAbsorption + rayleighScattering + ozoneAbsorption;
|
||||
return RAYLEIGH_PHASE_SCALE * (1.0 + cos_theta*cos_theta);
|
||||
}
|
||||
|
||||
// Approximation of the Mie phase function with the Cornette-Shanks phase function
|
||||
float miePhaseFunction(float cosTheta)
|
||||
/*
|
||||
* Henyey-Greenstrein phase function.
|
||||
*/
|
||||
float aerosol_phase_function(float cos_theta)
|
||||
{
|
||||
float num = (1.0 - gg) * (1.0 + cosTheta*cosTheta);
|
||||
float den = (2.0 + gg) * pow((1.0 + gg - 2.0 * g * cosTheta), 1.5);
|
||||
return mie_phase_scale * num / den;
|
||||
float den = 1.0 + gg + 2.0 * g * cos_theta;
|
||||
return INV_4PI * (1.0 - gg) / (den * sqrt(den));
|
||||
}
|
||||
|
||||
float rayleighPhaseFunction(float cosTheta)
|
||||
/*
|
||||
* Get the approximated multiple scattering contribution for a given point
|
||||
* within the atmosphere.
|
||||
*/
|
||||
vec4 get_multiple_scattering(sampler2D transmittance_lut,
|
||||
float cos_theta,
|
||||
float normalized_height,
|
||||
float d)
|
||||
{
|
||||
return rayleigh_phase_scale * (1.0 + cosTheta*cosTheta);
|
||||
// Solid angle subtended by the planet from a point at d distance
|
||||
// from the planet center.
|
||||
float omega = 2.0 * PI * (1.0 - sqrt(d*d - fg_EarthRadius*fg_EarthRadius) / d);
|
||||
omega = max(0.0, omega);
|
||||
|
||||
vec4 T_to_ground = transmittance_from_lut(transmittance_lut, cos_theta, 0.0);
|
||||
|
||||
vec4 T_ground_to_sample =
|
||||
transmittance_from_lut(transmittance_lut, 1.0, 0.0) /
|
||||
transmittance_from_lut(transmittance_lut, 1.0, normalized_height);
|
||||
|
||||
// 2nd order scattering from the ground
|
||||
vec4 L_ground = PHASE_ISOTROPIC * omega * (ground_albedo * INV_PI)
|
||||
* T_to_ground * T_ground_to_sample * max(0.0, cos_theta);
|
||||
|
||||
// Fit of Earth's multiple scattering coming from other points in the atmosphere
|
||||
vec4 L_ms = 0.02 * vec4(0.217, 0.347, 0.594, 1.0)
|
||||
* (1.0 / (1.0 + 5.0 * exp(-17.92 * cos_theta)));
|
||||
|
||||
return L_ms + L_ground;
|
||||
}
|
||||
|
||||
// Sample one of the LUTs (transmittance or multiple scattering) for a given
|
||||
// normalized height inside the atmosphere [0,1] and the cosine of the Sun
|
||||
// zenith angle.
|
||||
vec3 getValueFromLUT(sampler2D lut, float sunCosTheta, float normHeight)
|
||||
/*
|
||||
* Return the molecular volume scattering coefficient (m^-1) for a given altitude
|
||||
* in kilometers.
|
||||
*/
|
||||
vec4 get_molecular_scattering_coefficient(float h)
|
||||
{
|
||||
float x = clamp(sunCosTheta * 0.5 + 0.5, 0.0, 1.0);
|
||||
float y = clamp(normHeight, 0.0, 1.0);
|
||||
return texture(lut, vec2(x, y)).rgb;
|
||||
return molecular_scattering_coefficient_base
|
||||
* exp(-0.07771971 * pow(h, 1.16364243));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the molecular volume absorption coefficient (km^-1) for a given altitude
|
||||
* in kilometers.
|
||||
*/
|
||||
vec4 get_molecular_absorption_coefficient(float h)
|
||||
{
|
||||
int i = int(clamp(h / 9.0, 0.0, 6.0));
|
||||
float density = ozone_height_distribution[i] *
|
||||
ozone_mean_monthly_dobson[month_of_the_year] * 2.6867e20f; // molecules / m^2
|
||||
density /= 9e3; // m^-3
|
||||
return ozone_cross_section * density; // m^-1
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the aerosol density for a given altitude in kilometers.
|
||||
*/
|
||||
float get_aerosol_density(float h)
|
||||
{
|
||||
return aerosol_base_density * (exp(-h / aerosol_height_scale)
|
||||
+ aerosol_relative_background_density);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the collision coefficients (scattering and absorption) of the
|
||||
* atmospheric medium for a given point at an altitude h.
|
||||
*/
|
||||
void get_atmosphere_collision_coefficients(in float h,
|
||||
out vec4 aerosol_absorption,
|
||||
out vec4 aerosol_scattering,
|
||||
out vec4 molecular_absorption,
|
||||
out vec4 molecular_scattering,
|
||||
out vec4 extinction)
|
||||
{
|
||||
h = max(h, 0.0); // In case height is negative
|
||||
float aerosol_density = get_aerosol_density(h * 1e-3) * aerosol_turbidity;
|
||||
aerosol_absorption = aerosol_absorption_cross_section * aerosol_density * 1e-3;
|
||||
aerosol_scattering = aerosol_scattering_cross_section * aerosol_density * 1e-3;
|
||||
molecular_absorption = get_molecular_absorption_coefficient(h * 1e-3);
|
||||
molecular_scattering = get_molecular_scattering_coefficient(h * 1e-3);
|
||||
extinction =
|
||||
aerosol_absorption + aerosol_scattering +
|
||||
molecular_absorption + molecular_scattering;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the in-scattering integral of the volume rendering equation (VRE)
|
||||
*
|
||||
* The integral is solved numerically by ray marching. The final in-scattering
|
||||
* returned by this function is a 4D vector of the spectral radiance sampled for
|
||||
* the 4 wavelengths at the top of this file. To obtain an RGB triplet, the
|
||||
* spectral radiance must be multiplied by the spectral irradiance of the Sun
|
||||
* and converted to sRGB.
|
||||
*/
|
||||
vec4 compute_inscattering(in vec3 ray_origin,
|
||||
in vec3 ray_dir,
|
||||
in float t_max,
|
||||
in vec3 sun_dir,
|
||||
in int steps,
|
||||
in sampler2D transmittance_lut,
|
||||
out vec4 transmittance)
|
||||
{
|
||||
// Any given ray inside the atmospheric medium can end in one of 3 places:
|
||||
// 1. The Earth's surface.
|
||||
// 2. Outer space. We define the boundary between space and the atmosphere
|
||||
// at the Kármán line.
|
||||
// 3. Any object within the atmosphere.
|
||||
float ray_altitude = length(ray_origin);
|
||||
// Handle the camera being underground
|
||||
float earth_radius = min(ray_altitude, fg_EarthRadius);
|
||||
float atmos_dist = ray_sphere_intersection(ray_origin, ray_dir, ATMOSPHERE_RADIUS);
|
||||
float ground_dist = ray_sphere_intersection(ray_origin, ray_dir, earth_radius);
|
||||
float t_d;
|
||||
if (ray_altitude < ATMOSPHERE_RADIUS) {
|
||||
// We are inside the atmosphere
|
||||
if (ground_dist < 0.0) {
|
||||
// No ground collision, use the distance to the outer atmosphere
|
||||
t_d = atmos_dist;
|
||||
} else {
|
||||
// We have a collision with the ground, use the distance to it
|
||||
t_d = ground_dist;
|
||||
}
|
||||
} else {
|
||||
// We are in outer space
|
||||
// XXX: For now this is a flight simulator, not a space simulator
|
||||
transmittance = vec4(1.0);
|
||||
return vec4(0.0);
|
||||
}
|
||||
|
||||
// Clip by the maximum distance
|
||||
t_d = min(t_d, t_max);
|
||||
|
||||
float cos_theta = dot(-ray_dir, sun_dir);
|
||||
|
||||
float molecular_phase = molecular_phase_function(cos_theta);
|
||||
float aerosol_phase = aerosol_phase_function(cos_theta);
|
||||
|
||||
float dt = t_d / float(steps);
|
||||
|
||||
vec4 L_inscattering = vec4(0.0);
|
||||
transmittance = vec4(1.0);
|
||||
|
||||
for (int i = 0; i < steps; ++i) {
|
||||
float t = (float(i) + 0.5) * dt;
|
||||
vec3 x_t = ray_origin + ray_dir * t;
|
||||
|
||||
float distance_to_earth_center = length(x_t);
|
||||
vec3 zenith_dir = x_t / distance_to_earth_center;
|
||||
float altitude = distance_to_earth_center - fg_EarthRadius;
|
||||
float normalized_altitude = altitude / (ATMOSPHERE_RADIUS - fg_EarthRadius);
|
||||
|
||||
float sample_cos_theta = dot(zenith_dir, sun_dir);
|
||||
|
||||
vec4 aerosol_absorption, aerosol_scattering;
|
||||
vec4 molecular_absorption, molecular_scattering;
|
||||
vec4 extinction;
|
||||
get_atmosphere_collision_coefficients(
|
||||
altitude,
|
||||
aerosol_absorption, aerosol_scattering,
|
||||
molecular_absorption, molecular_scattering,
|
||||
extinction);
|
||||
|
||||
vec4 transmittance_to_sun = transmittance_from_lut(
|
||||
transmittance_lut, sample_cos_theta, normalized_altitude);
|
||||
|
||||
vec4 ms = get_multiple_scattering(
|
||||
transmittance_lut, sample_cos_theta, normalized_altitude,
|
||||
distance_to_earth_center);
|
||||
|
||||
vec4 S =
|
||||
molecular_scattering * (molecular_phase * transmittance_to_sun + ms) +
|
||||
aerosol_scattering * (aerosol_phase * transmittance_to_sun + ms);
|
||||
|
||||
vec4 step_transmittance = exp(-dt * extinction);
|
||||
|
||||
// Energy-conserving analytical integration
|
||||
// "Physically Based Sky, Atmosphere and Cloud Rendering in Frostbite"
|
||||
// by Sébastien Hillaire
|
||||
vec4 S_int = (S - S * step_transmittance) / max(extinction, 1e-7);
|
||||
L_inscattering += transmittance * S_int;
|
||||
transmittance *= step_transmittance;
|
||||
}
|
||||
|
||||
return L_inscattering;
|
||||
}
|
||||
|
|
|
@ -1,133 +0,0 @@
|
|||
// An implementation of Sébastien Hillaire's "A Scalable and Production Ready
|
||||
// Sky and Atmosphere Rendering Technique".
|
||||
//
|
||||
// This shader generates the multiple scattering LUT.
|
||||
|
||||
#version 330 core
|
||||
|
||||
out vec3 fragColor;
|
||||
|
||||
in vec2 texCoord;
|
||||
|
||||
uniform sampler2D transmittance_lut;
|
||||
|
||||
uniform float fg_EarthRadius;
|
||||
|
||||
const float PI = 3.141592653;
|
||||
const float ATMOSPHERE_RADIUS = 6471e3;
|
||||
const int SQRT_SAMPLES = 4;
|
||||
const float INV_SAMPLES = 1.0 / float(SQRT_SAMPLES*SQRT_SAMPLES);
|
||||
const int MULTIPLE_SCATTERING_SAMPLES = 20;
|
||||
|
||||
const vec3 ground_albedo = vec3(0.3);
|
||||
|
||||
float raySphereIntersection(vec3 ro, vec3 rd, float radius);
|
||||
vec3 sampleMedium(in float height,
|
||||
out float mieScattering, out float mieAbsorption,
|
||||
out vec3 rayleighScattering, out vec3 ozoneAbsorption);
|
||||
float miePhaseFunction(float cosTheta);
|
||||
float rayleighPhaseFunction(float cosTheta);
|
||||
vec3 getValueFromLUT(sampler2D lut, float sunCosTheta, float normalizedHeight);
|
||||
|
||||
vec3 generateRayDir(float theta, float phi)
|
||||
{
|
||||
float cosPhi = cos(phi);
|
||||
float sinPhi = sin(phi);
|
||||
float cosTheta = cos(theta);
|
||||
float sinTheta = sin(theta);
|
||||
return vec3(cosTheta * sinPhi, sinTheta * sinPhi, cosPhi);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
float sunCosTheta = texCoord.x * 2.0 - 1.0;
|
||||
vec3 sunDir = vec3(-sqrt(1.0 - sunCosTheta*sunCosTheta), 0.0, sunCosTheta);
|
||||
|
||||
float altitude = mix(fg_EarthRadius, ATMOSPHERE_RADIUS, texCoord.y);
|
||||
vec3 rayOrigin = vec3(0.0, 0.0, altitude);
|
||||
|
||||
vec3 Ltotal = vec3(0.0);
|
||||
vec3 LMStotal = vec3(0.0);
|
||||
|
||||
for (int i = 0; i < SQRT_SAMPLES; ++i) {
|
||||
for (int j = 0; j < SQRT_SAMPLES; ++j) {
|
||||
float theta = 2.0 * PI * (float(i) + 0.5) / float(SQRT_SAMPLES);
|
||||
float phi = PI * (float(j) + 0.5) / float(SQRT_SAMPLES);
|
||||
vec3 rayDir = generateRayDir(theta, phi);
|
||||
|
||||
float atmosDist = raySphereIntersection(rayOrigin, rayDir, ATMOSPHERE_RADIUS);
|
||||
float groundDist = raySphereIntersection(rayOrigin, rayDir, fg_EarthRadius);
|
||||
|
||||
float tmax;
|
||||
if (groundDist < 0.0) {
|
||||
// No ground collision, use the distance to the outer atmosphere
|
||||
tmax = atmosDist;
|
||||
} else {
|
||||
// Use the distance to the ground
|
||||
tmax = groundDist;
|
||||
}
|
||||
|
||||
float cosTheta = dot(rayDir, sunDir);
|
||||
float miePhase = miePhaseFunction(cosTheta);
|
||||
float rayleighPhase = rayleighPhaseFunction(-cosTheta);
|
||||
|
||||
vec3 L = vec3(0.0);
|
||||
vec3 LMS = vec3(0.0);
|
||||
vec3 throughput = vec3(1.0);
|
||||
float t = 0.0;
|
||||
|
||||
for (int k = 0; k < MULTIPLE_SCATTERING_SAMPLES; ++k) {
|
||||
float newT = ((float(k) + 0.3) / MULTIPLE_SCATTERING_SAMPLES) * tmax;
|
||||
float dt = newT - t;
|
||||
t = newT;
|
||||
|
||||
vec3 samplePos = rayOrigin + rayDir * t;
|
||||
float height = length(samplePos) - fg_EarthRadius;
|
||||
float normalizedHeight = height / (ATMOSPHERE_RADIUS - fg_EarthRadius);
|
||||
|
||||
float mieScattering, mieAbsorption;
|
||||
vec3 rayleighScattering, ozoneAbsorption;
|
||||
vec3 extinction = sampleMedium(height, mieScattering, mieAbsorption,
|
||||
rayleighScattering, ozoneAbsorption);
|
||||
|
||||
vec3 sampleTransmittance = exp(-dt*extinction);
|
||||
|
||||
vec3 sunTransmittance = getValueFromLUT(
|
||||
transmittance_lut, sunCosTheta, normalizedHeight);
|
||||
|
||||
vec3 S = (rayleighScattering * rayleighPhase +
|
||||
mieScattering * miePhase) * sunTransmittance;
|
||||
|
||||
// Not using the power serie
|
||||
vec3 MS = mieScattering + rayleighScattering;
|
||||
vec3 MSint = (MS - MS * sampleTransmittance) / extinction;
|
||||
LMS += throughput * MSint;
|
||||
|
||||
vec3 Sint = (S - S * sampleTransmittance) / extinction;
|
||||
L += throughput * Sint;
|
||||
throughput *= sampleTransmittance;
|
||||
}
|
||||
|
||||
if (groundDist >= 0.0) {
|
||||
// Account for bounced light off the Earth
|
||||
vec3 p = rayOrigin + rayDir * groundDist;
|
||||
float pHeight = length(p);
|
||||
vec3 up = p / pHeight;
|
||||
|
||||
float normHeight = (pHeight - fg_EarthRadius)
|
||||
/ (ATMOSPHERE_RADIUS - fg_EarthRadius);
|
||||
float sunZenithCosTheta = dot(sunDir, up);
|
||||
|
||||
vec3 transmittanceFromGround = getValueFromLUT(
|
||||
transmittance_lut, sunZenithCosTheta, normHeight);
|
||||
L += transmittanceFromGround * throughput
|
||||
* clamp(sunZenithCosTheta, 0.0, 1.0) * ground_albedo / PI;
|
||||
}
|
||||
|
||||
Ltotal += L * INV_SAMPLES;
|
||||
LMStotal += LMS * INV_SAMPLES;
|
||||
}
|
||||
}
|
||||
|
||||
fragColor = Ltotal / (1.0 - LMStotal);
|
||||
}
|
|
@ -1,114 +1,54 @@
|
|||
// An implementation of Sébastien Hillaire's "A Scalable and Production Ready
|
||||
// Sky and Atmosphere Rendering Technique".
|
||||
//
|
||||
// This shader generates the sky-view texture. Since the sky generally has low
|
||||
// frequency detail, it's possible to pre-compute it on a small texture and
|
||||
// sample it later when rendering the skydome. This effectively bypasses the
|
||||
// need for raymarching on screen-sized textures, which is specially costly on
|
||||
// larger resolutions like 4K.
|
||||
|
||||
#version 330 core
|
||||
|
||||
out vec3 fragColor;
|
||||
out vec4 fragColor;
|
||||
|
||||
in vec2 texCoord;
|
||||
|
||||
uniform sampler2D transmittance_lut;
|
||||
uniform sampler2D multiscattering_lut;
|
||||
|
||||
uniform float fg_SunZenithCosTheta;
|
||||
uniform float fg_CameraDistanceToEarthCenter;
|
||||
uniform float fg_EarthRadius;
|
||||
|
||||
const float PI = 3.141592653;
|
||||
const float PI = 3.14159265358979323846;
|
||||
const int SKY_STEPS = 32;
|
||||
|
||||
const float ATMOSPHERE_RADIUS = 6471e3;
|
||||
const int SCATTERING_SAMPLES = 32;
|
||||
|
||||
float raySphereIntersection(vec3 ro, vec3 rd, float radius);
|
||||
vec3 sampleMedium(in float height,
|
||||
out float mieScattering, out float mieAbsorption,
|
||||
out vec3 rayleighScattering, out vec3 ozoneAbsorption);
|
||||
float miePhaseFunction(float cosTheta);
|
||||
float rayleighPhaseFunction(float cosTheta);
|
||||
vec3 getValueFromLUT(sampler2D lut, float sunCosTheta, float normalizedHeight);
|
||||
// atmos-include.frag
|
||||
vec4 compute_inscattering(in vec3 ray_origin,
|
||||
in vec3 ray_dir,
|
||||
in float t_max,
|
||||
in vec3 sun_dir,
|
||||
in int steps,
|
||||
in sampler2D transmittance_lut,
|
||||
out vec4 transmittance);
|
||||
|
||||
void main()
|
||||
{
|
||||
// Always leave the sun right in the middle of the texture as the skydome
|
||||
// model is already being rotated.
|
||||
vec3 sunDir = vec3(-sqrt(1.0 - fg_SunZenithCosTheta*fg_SunZenithCosTheta),
|
||||
0.0,
|
||||
fg_SunZenithCosTheta);
|
||||
// Always leave the Sun right in the middle of the sky texture.
|
||||
// The skydome model implemented in SimGear already takes care of rotating
|
||||
// the Sun for us.
|
||||
vec3 sun_dir = vec3(
|
||||
-sqrt(1.0 - fg_SunZenithCosTheta*fg_SunZenithCosTheta),
|
||||
0.0,
|
||||
fg_SunZenithCosTheta);
|
||||
|
||||
float azimuth = 2.0 * PI * texCoord.x; // [0, 2pi]
|
||||
// Apply a non-linear transformation to the elevation to dedicate more
|
||||
// texels to the horizon, which is where having more detail matters.
|
||||
// texels to the horizon, where having more detail matters.
|
||||
float l = texCoord.y * 2.0 - 1.0;
|
||||
float elev = l*l * sign(l) * PI * 0.5; // [-pi/2, pi/2]
|
||||
vec3 rayDir = vec3(cos(elev) * cos(azimuth), cos(elev) * sin(azimuth), sin(elev));
|
||||
|
||||
vec3 rayOrigin = vec3(0.0, 0.0, fg_CameraDistanceToEarthCenter);
|
||||
vec3 ray_dir = vec3(cos(elev) * cos(azimuth),
|
||||
cos(elev) * sin(azimuth),
|
||||
sin(elev));
|
||||
|
||||
// Handle the camera being underground
|
||||
float earthRadius = min(fg_EarthRadius, fg_CameraDistanceToEarthCenter);
|
||||
|
||||
float atmosDist = raySphereIntersection(rayOrigin, rayDir, ATMOSPHERE_RADIUS);
|
||||
float groundDist = raySphereIntersection(rayOrigin, rayDir, earthRadius);
|
||||
|
||||
float tmax;
|
||||
if (fg_CameraDistanceToEarthCenter < ATMOSPHERE_RADIUS) {
|
||||
// We are inside the atmosphere
|
||||
if (groundDist < 0.0) {
|
||||
// No ground collision, use the distance to the outer atmosphere
|
||||
tmax = atmosDist;
|
||||
} else {
|
||||
// Use the distance to the ground
|
||||
tmax = groundDist;
|
||||
}
|
||||
} else {
|
||||
// We are in outer space, skip
|
||||
fragColor = vec3(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
float cosTheta = dot(rayDir, sunDir);
|
||||
float miePhase = miePhaseFunction(cosTheta);
|
||||
float rayleighPhase = rayleighPhaseFunction(-cosTheta);
|
||||
|
||||
vec3 L = vec3(0.0);
|
||||
vec3 throughput = vec3(1.0);
|
||||
float t = 0.0;
|
||||
|
||||
for (int i = 0; i < SCATTERING_SAMPLES; ++i) {
|
||||
float newT = ((float(i) + 0.3) / SCATTERING_SAMPLES) * tmax;
|
||||
float dt = newT - t;
|
||||
t = newT;
|
||||
|
||||
vec3 samplePos = rayOrigin + rayDir * t;
|
||||
float height = length(samplePos) - fg_EarthRadius;
|
||||
float normalizedHeight = height / (ATMOSPHERE_RADIUS - fg_EarthRadius);
|
||||
|
||||
float mieScattering, mieAbsorption;
|
||||
vec3 rayleighScattering, ozoneAbsorption;
|
||||
vec3 extinction = sampleMedium(height, mieScattering, mieAbsorption,
|
||||
rayleighScattering, ozoneAbsorption);
|
||||
|
||||
vec3 sampleTransmittance = exp(-dt*extinction);
|
||||
|
||||
vec3 sunTransmittance = getValueFromLUT(
|
||||
transmittance_lut, fg_SunZenithCosTheta, normalizedHeight);
|
||||
vec3 multiscattering = getValueFromLUT(
|
||||
multiscattering_lut, fg_SunZenithCosTheta, normalizedHeight);
|
||||
|
||||
vec3 S =
|
||||
rayleighScattering * (rayleighPhase * sunTransmittance + multiscattering) +
|
||||
mieScattering * (miePhase * sunTransmittance + multiscattering);
|
||||
|
||||
vec3 Sint = (S - S * sampleTransmittance) / extinction;
|
||||
L += throughput * Sint;
|
||||
throughput *= sampleTransmittance;
|
||||
}
|
||||
vec3 ray_origin = vec3(0.0, 0.0, fg_CameraDistanceToEarthCenter);
|
||||
|
||||
vec4 transmittance;
|
||||
vec4 L = compute_inscattering(ray_origin,
|
||||
ray_dir,
|
||||
1e7,
|
||||
sun_dir,
|
||||
SKY_STEPS,
|
||||
transmittance_lut,
|
||||
transmittance);
|
||||
fragColor = L;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
// An implementation of Sébastien Hillaire's "A Scalable and Production Ready
|
||||
// Sky and Atmosphere Rendering Technique".
|
||||
//
|
||||
// This shader generates the transmittance LUT. It stores the transmittance to
|
||||
// the Sun through the atmosphere for a given Sun zenith angle and a height
|
||||
// inside the atmosphere (0 being the ground).
|
||||
|
||||
#version 330 core
|
||||
|
||||
out vec3 fragColor;
|
||||
out vec4 fragColor;
|
||||
|
||||
in vec2 texCoord;
|
||||
|
||||
|
@ -16,38 +9,46 @@ uniform float fg_EarthRadius;
|
|||
const float ATMOSPHERE_RADIUS = 6471e3;
|
||||
const int TRANSMITTANCE_STEPS = 40;
|
||||
|
||||
float raySphereIntersection(vec3 ro, vec3 rd, float radius);
|
||||
vec3 sampleMedium(in float height,
|
||||
out float mieScattering, out float mieAbsorption,
|
||||
out vec3 rayleighScattering, out vec3 ozoneAbsorption);
|
||||
// atmos-include.frag
|
||||
float ray_sphere_intersection(vec3 ro, vec3 rd, float radius);
|
||||
void get_atmosphere_collision_coefficients(in float h,
|
||||
out vec4 aerosol_absorption,
|
||||
out vec4 aerosol_scattering,
|
||||
out vec4 molecular_absorption,
|
||||
out vec4 molecular_scattering,
|
||||
out vec4 extinction);
|
||||
|
||||
void main()
|
||||
{
|
||||
float sunCosTheta = texCoord.x * 2.0 - 1.0;
|
||||
vec3 sunDir = vec3(-sqrt(1.0 - sunCosTheta*sunCosTheta), 0.0, sunCosTheta);
|
||||
float sun_cos_theta = texCoord.x * 2.0 - 1.0;
|
||||
vec3 sun_dir = vec3(-sqrt(1.0 - sun_cos_theta*sun_cos_theta), 0.0, sun_cos_theta);
|
||||
|
||||
float altitude = mix(fg_EarthRadius, ATMOSPHERE_RADIUS, texCoord.y);
|
||||
vec3 rayOrigin = vec3(0.0, 0.0, altitude);
|
||||
float distance_to_earth_center = mix(fg_EarthRadius, ATMOSPHERE_RADIUS, texCoord.y);
|
||||
vec3 ray_origin = vec3(0.0, 0.0, distance_to_earth_center);
|
||||
|
||||
float dist = raySphereIntersection(rayOrigin, sunDir, ATMOSPHERE_RADIUS);
|
||||
float t = 0.0;
|
||||
vec3 transmittance = vec3(1.0);
|
||||
float t_d = ray_sphere_intersection(ray_origin, sun_dir, ATMOSPHERE_RADIUS);
|
||||
float dt = t_d / float(TRANSMITTANCE_STEPS);
|
||||
|
||||
vec4 result = vec4(0.0);
|
||||
|
||||
for (int i = 0; i < TRANSMITTANCE_STEPS; ++i) {
|
||||
float newT = ((float(i) + 0.3) / TRANSMITTANCE_STEPS) * dist;
|
||||
float dt = newT - t;
|
||||
t = newT;
|
||||
float t = (float(i) + 0.5) * dt;
|
||||
vec3 x_t = ray_origin + sun_dir * t;
|
||||
|
||||
vec3 samplePos = rayOrigin + sunDir * t;
|
||||
float height = length(samplePos) - fg_EarthRadius;
|
||||
float altitude = length(x_t) - fg_EarthRadius;
|
||||
|
||||
float mieScattering, mieAbsorption;
|
||||
vec3 rayleighScattering, ozoneAbsorption;
|
||||
vec3 extinction = sampleMedium(height, mieScattering, mieAbsorption,
|
||||
rayleighScattering, ozoneAbsorption);
|
||||
vec4 aerosol_absorption, aerosol_scattering;
|
||||
vec4 molecular_absorption, molecular_scattering;
|
||||
vec4 extinction;
|
||||
get_atmosphere_collision_coefficients(
|
||||
altitude,
|
||||
aerosol_absorption, aerosol_scattering,
|
||||
molecular_absorption, molecular_scattering,
|
||||
extinction);
|
||||
|
||||
transmittance *= exp(-dt * extinction);
|
||||
result += extinction * dt;
|
||||
}
|
||||
|
||||
vec4 transmittance = exp(-result);
|
||||
fragColor = transmittance;
|
||||
}
|
||||
|
|
74
Shaders/HDR/cloud-static.vert
Normal file
74
Shaders/HDR/cloud-static.vert
Normal file
|
@ -0,0 +1,74 @@
|
|||
#version 330 core
|
||||
|
||||
layout(location = 0) in vec4 pos;
|
||||
layout(location = 2) in vec4 vertexColor;
|
||||
layout(location = 3) in vec4 multiTexCoord0;
|
||||
|
||||
out vec2 texCoord;
|
||||
out vec4 cloudColor;
|
||||
|
||||
uniform mat4 osg_ModelViewMatrix;
|
||||
uniform mat4 osg_ModelViewProjectionMatrix;
|
||||
uniform mat4 osg_ViewMatrixInverse;
|
||||
uniform vec3 fg_SunDirectionWorld;
|
||||
|
||||
const float shade = 0.8;
|
||||
const float cloud_height = 1000.0;
|
||||
|
||||
// aerial-perspective-include.frag
|
||||
vec3 add_aerial_perspective(vec3 color, vec2 coord, float depth);
|
||||
vec3 get_sun_radiance(vec3 p);
|
||||
|
||||
void main()
|
||||
{
|
||||
texCoord = multiTexCoord0.st;
|
||||
|
||||
// XXX: Should be sent as an uniform
|
||||
mat4 inverseModelViewMatrix = inverse(osg_ModelViewMatrix);
|
||||
|
||||
vec4 ep = inverseModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0);
|
||||
vec4 l = inverseModelViewMatrix * vec4(0.0, 0.0, 1.0, 1.0);
|
||||
vec3 u = normalize(ep.xyz - l.xyz);
|
||||
|
||||
vec4 final_pos = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
final_pos.x = pos.x;
|
||||
final_pos.y = pos.y;
|
||||
final_pos.z = pos.z;
|
||||
final_pos.xyz += vertexColor.xyz;
|
||||
|
||||
gl_Position = osg_ModelViewProjectionMatrix * final_pos;
|
||||
|
||||
// Determine a lighting normal based on the vertex position from the
|
||||
// center of the cloud, so that sprite on the opposite side of the cloud
|
||||
// to the sun are darker.
|
||||
vec3 n = normalize(vec3(osg_ViewMatrixInverse *
|
||||
osg_ModelViewMatrix * vec4(-final_pos.xyz, 0.0)));
|
||||
float NdotL = dot(-fg_SunDirectionWorld, n);
|
||||
|
||||
vec4 final_view_pos = osg_ModelViewMatrix * final_pos;
|
||||
vec4 final_world_pos = osg_ViewMatrixInverse * final_view_pos;
|
||||
|
||||
float fogCoord = abs(final_view_pos.z);
|
||||
float fract = smoothstep(0.0, cloud_height, final_pos.z + cloud_height);
|
||||
|
||||
vec3 sun_radiance = get_sun_radiance(final_world_pos.xyz);
|
||||
|
||||
// Determine the shading of the sprite based on its vertical position and
|
||||
// position relative to the sun.
|
||||
NdotL = min(smoothstep(-0.5, 0.0, NdotL), fract);
|
||||
// Determine the shading based on a mixture from the backlight to the front
|
||||
vec3 backlight = shade * sun_radiance;
|
||||
|
||||
cloudColor.rgb = mix(backlight, sun_radiance, NdotL);
|
||||
|
||||
// Perspective division and scale to [0, 1] to get the screen position
|
||||
// of the vertex.
|
||||
vec2 coord = (gl_Position.xy / gl_Position.w) * 0.5 + 0.5;
|
||||
cloudColor.rgb = add_aerial_perspective(
|
||||
cloudColor.rgb, coord, length(final_view_pos));
|
||||
|
||||
// As we get within 100m of the sprite, it is faded out. Equally at large
|
||||
// distances it also fades out.
|
||||
cloudColor.a = min(smoothstep(100.0, 250.0, fogCoord),
|
||||
1.0 - smoothstep(70000.0, 75000.0, fogCoord));
|
||||
}
|
190
Shaders/HDR/clustered-include.frag
Normal file
190
Shaders/HDR/clustered-include.frag
Normal file
|
@ -0,0 +1,190 @@
|
|||
#version 330 core
|
||||
|
||||
uniform sampler3D fg_Clusters;
|
||||
uniform sampler2D fg_ClusteredIndices;
|
||||
uniform sampler2D fg_ClusteredPointLights;
|
||||
uniform sampler2D fg_ClusteredSpotLights;
|
||||
|
||||
uniform int fg_ClusteredMaxPointLights;
|
||||
uniform int fg_ClusteredMaxSpotLights;
|
||||
uniform int fg_ClusteredMaxLightIndices;
|
||||
uniform int fg_ClusteredTileSize;
|
||||
uniform int fg_ClusteredDepthSlices;
|
||||
uniform float fg_ClusteredSliceScale;
|
||||
uniform float fg_ClusteredSliceBias;
|
||||
uniform int fg_ClusteredHorizontalTiles;
|
||||
uniform int fg_ClusteredVerticalTiles;
|
||||
|
||||
// lighting-include.frag
|
||||
vec3 evaluateLight(
|
||||
vec3 baseColor,
|
||||
float metallic,
|
||||
float roughness,
|
||||
vec3 f0,
|
||||
vec3 intensity,
|
||||
float visibility,
|
||||
vec3 n,
|
||||
vec3 l,
|
||||
vec3 v,
|
||||
float NdotL,
|
||||
float NdotV);
|
||||
|
||||
struct PointLight {
|
||||
vec3 position;
|
||||
vec3 color;
|
||||
float intensity;
|
||||
float range;
|
||||
};
|
||||
|
||||
struct SpotLight {
|
||||
vec3 position;
|
||||
vec3 direction;
|
||||
vec3 color;
|
||||
float intensity;
|
||||
float range;
|
||||
float cos_cutoff;
|
||||
float exponent;
|
||||
};
|
||||
|
||||
PointLight unpackPointLight(int index)
|
||||
{
|
||||
float v = (float(index) + 0.5) / float(fg_ClusteredMaxPointLights);
|
||||
PointLight light;
|
||||
vec4 block;
|
||||
block = texture(fg_ClusteredPointLights, vec2(0.25, v));
|
||||
light.position = block.xyz;
|
||||
light.range = block.w;
|
||||
block = texture(fg_ClusteredPointLights, vec2(0.75, v));
|
||||
light.color = block.xyz;
|
||||
light.intensity = block.w;
|
||||
return light;
|
||||
}
|
||||
|
||||
SpotLight unpackSpotLight(int index)
|
||||
{
|
||||
float v = (float(index) + 0.5) / float(fg_ClusteredMaxSpotLights);
|
||||
SpotLight light;
|
||||
vec4 block;
|
||||
block = texture(fg_ClusteredSpotLights, vec2(0.125, v));
|
||||
light.position = block.xyz;
|
||||
light.range = block.w;
|
||||
block = texture(fg_ClusteredSpotLights, vec2(0.375, v));
|
||||
light.direction = block.xyz;
|
||||
light.cos_cutoff = block.w;
|
||||
block = texture(fg_ClusteredSpotLights, vec2(0.625, v));
|
||||
light.color = block.xyz;
|
||||
light.intensity = block.w;
|
||||
block = texture(fg_ClusteredSpotLights, vec2(0.875, v));
|
||||
light.exponent = block.x;
|
||||
return light;
|
||||
}
|
||||
|
||||
int getIndex(int counter)
|
||||
{
|
||||
vec2 coords = vec2(mod(float(counter), float(fg_ClusteredMaxLightIndices)) + 0.5,
|
||||
float(counter / fg_ClusteredMaxLightIndices) + 0.5);
|
||||
// Normalize
|
||||
coords /= vec2(fg_ClusteredMaxLightIndices);
|
||||
return int(texture(fg_ClusteredIndices, coords).r);
|
||||
}
|
||||
|
||||
float get_square_falloff_attenuation(vec3 to_light, float inv_range)
|
||||
{
|
||||
float dd = dot(to_light, to_light);
|
||||
float factor = dd * inv_range * inv_range;
|
||||
float smooth_factor = max(1.0 - factor * factor, 0.0);
|
||||
return (smooth_factor * smooth_factor) / max(dd, 0.0001);
|
||||
}
|
||||
|
||||
float get_spot_angle_attenuation(vec3 l, vec3 light_dir,
|
||||
float cos_cutoff, float exponent)
|
||||
{
|
||||
float cd = dot(-l, light_dir);
|
||||
if (cd < cos_cutoff)
|
||||
return 0.0;
|
||||
return pow(cd, exponent);
|
||||
}
|
||||
|
||||
vec3 get_contribution_from_scene_lights(
|
||||
vec3 p,
|
||||
vec3 base_color,
|
||||
float metallic,
|
||||
float roughness,
|
||||
vec3 f0,
|
||||
vec3 n,
|
||||
vec3 v)
|
||||
{
|
||||
int slice = int(max(log2(-p.z) * fg_ClusteredSliceScale
|
||||
+ fg_ClusteredSliceBias, 0.0));
|
||||
vec3 clusterCoords = vec3(floor(gl_FragCoord.xy / fg_ClusteredTileSize),
|
||||
slice) + vec3(0.5); // Pixel center
|
||||
// Normalize
|
||||
clusterCoords /= vec3(fg_ClusteredHorizontalTiles,
|
||||
fg_ClusteredVerticalTiles,
|
||||
fg_ClusteredDepthSlices);
|
||||
|
||||
vec3 cluster = texture(fg_Clusters, clusterCoords).rgb;
|
||||
int lightIndex = int(cluster.r);
|
||||
int pointCount = int(cluster.g);
|
||||
int spotCount = int(cluster.b);
|
||||
|
||||
vec3 color = vec3(0.0);
|
||||
|
||||
for (int i = 0; i < pointCount; ++i) {
|
||||
int index = getIndex(lightIndex++);
|
||||
PointLight light = unpackPointLight(index);
|
||||
|
||||
vec3 to_light = light.position - p;
|
||||
vec3 l = normalize(to_light);
|
||||
|
||||
float attenuation = get_square_falloff_attenuation(
|
||||
to_light, 1.0 / light.range);
|
||||
if (attenuation <= 0.0)
|
||||
continue;
|
||||
|
||||
vec3 intensity = light.color * light.intensity * attenuation;
|
||||
|
||||
float NdotL = max(dot(n, l), 0.0);
|
||||
float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
|
||||
|
||||
color += evaluateLight(base_color,
|
||||
metallic,
|
||||
roughness,
|
||||
f0,
|
||||
intensity,
|
||||
1.0,
|
||||
n, l, v,
|
||||
NdotL, NdotV);
|
||||
}
|
||||
|
||||
for (int i = 0; i < spotCount; ++i) {
|
||||
int index = getIndex(lightIndex++);
|
||||
SpotLight light = unpackSpotLight(index);
|
||||
|
||||
vec3 to_light = light.position - p;
|
||||
vec3 l = normalize(to_light);
|
||||
|
||||
float attenuation = get_square_falloff_attenuation(
|
||||
to_light, 1.0 / light.range);
|
||||
attenuation *= get_spot_angle_attenuation(
|
||||
l, light.direction, light.cos_cutoff, light.exponent);
|
||||
if (attenuation <= 0.0)
|
||||
continue;
|
||||
|
||||
vec3 intensity = light.color * light.intensity * attenuation;
|
||||
|
||||
float NdotL = max(dot(n, l), 0.0);
|
||||
float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
|
||||
|
||||
color += evaluateLight(base_color,
|
||||
metallic,
|
||||
roughness,
|
||||
f0,
|
||||
intensity,
|
||||
1.0,
|
||||
n, l, v,
|
||||
NdotL, NdotV);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
out float prevLum;
|
||||
|
||||
uniform sampler2D lum_tex;
|
||||
uniform sampler2D tex;
|
||||
|
||||
void main()
|
||||
{
|
||||
prevLum = texelFetch(lum_tex, ivec2(0), 0).r;
|
||||
prevLum = texelFetch(tex, ivec2(0), 0).r;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ float log10(float x)
|
|||
// http://resources.mpi-inf.mpg.de/hdr/peffects/krawczyk05sccg.pdf
|
||||
float keyValue(float L)
|
||||
{
|
||||
return 1.03 - 2.0 / (log10(L + 1.0) + 2.0);
|
||||
return 1.0 - 2.0 / (log10(L + 1.0) + 2.0);
|
||||
}
|
||||
|
||||
vec3 applyExposure(vec3 color, float avgLuminance, float threshold)
|
||||
|
|
30
Shaders/HDR/geometry-lfeat.frag
Normal file
30
Shaders/HDR/geometry-lfeat.frag
Normal file
|
@ -0,0 +1,30 @@
|
|||
#version 330 core
|
||||
|
||||
layout(location = 0) out vec4 outGBuffer0;
|
||||
layout(location = 1) out vec4 outGBuffer1;
|
||||
layout(location = 2) out vec4 outGBuffer2;
|
||||
|
||||
in vec3 normalVS;
|
||||
in vec2 texCoord;
|
||||
|
||||
uniform sampler2D color_tex;
|
||||
|
||||
vec2 encodeNormal(vec3 n);
|
||||
vec3 decodeSRGB(vec3 screenRGB);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 texel = texture(color_tex, texCoord);
|
||||
if (texel.a < 0.5)
|
||||
discard;
|
||||
|
||||
vec3 color = decodeSRGB(texel.rgb);
|
||||
|
||||
outGBuffer0.rg = encodeNormal(normalVS);
|
||||
outGBuffer0.b = 0.9;
|
||||
outGBuffer0.a = 1.0;
|
||||
outGBuffer1.rgb = color;
|
||||
outGBuffer1.a = 0.0;
|
||||
outGBuffer2.rgb = vec3(0.0);
|
||||
outGBuffer2.a = 1.0;
|
||||
}
|
21
Shaders/HDR/geometry-lfeat.vert
Normal file
21
Shaders/HDR/geometry-lfeat.vert
Normal file
|
@ -0,0 +1,21 @@
|
|||
#version 330 core
|
||||
|
||||
layout(location = 0) in vec4 pos;
|
||||
layout(location = 1) in vec3 normal;
|
||||
layout(location = 2) in vec4 vertexColor;
|
||||
layout(location = 3) in vec4 multiTexCoord0;
|
||||
|
||||
out vec3 normalVS;
|
||||
out vec2 texCoord;
|
||||
|
||||
uniform mat4 osg_ModelViewProjectionMatrix;
|
||||
uniform mat3 osg_NormalMatrix;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 raised_pos = pos;
|
||||
raised_pos.z += 0.05;
|
||||
gl_Position = osg_ModelViewProjectionMatrix * raised_pos;
|
||||
normalVS = normalize(osg_NormalMatrix * normal);
|
||||
texCoord = multiTexCoord0.st;
|
||||
}
|
|
@ -45,8 +45,8 @@ vec3 evaluateIBL(
|
|||
vec3 nWorldSpace,
|
||||
float NdotV,
|
||||
vec3 reflected);
|
||||
vec3 addAerialPerspective(vec3 color, vec2 coord, float depth);
|
||||
vec3 getSunIntensity();
|
||||
vec3 add_aerial_perspective(vec3 color, vec2 coord, float depth);
|
||||
vec3 get_sun_radiance(vec3 p);
|
||||
|
||||
void main()
|
||||
{
|
||||
|
@ -74,14 +74,16 @@ void main()
|
|||
|
||||
vec3 f0 = getF0Reflectance(baseColor.rgb, metallic);
|
||||
|
||||
vec3 sunIlluminance = getSunIntensity() * clamp(NdotL, 0.0, 1.0);
|
||||
vec3 pos_world = (osg_ViewMatrixInverse * vec4(ecPos, 1.0)).xyz;
|
||||
vec3 sun_radiance = get_sun_radiance(pos_world);
|
||||
|
||||
float shadowFactor = getShadowing(ecPos, n, l, osg_ProjectionMatrix);
|
||||
|
||||
vec3 color = evaluateLight(baseColor.rgb,
|
||||
metallic,
|
||||
roughness,
|
||||
f0,
|
||||
sunIlluminance,
|
||||
sun_radiance,
|
||||
shadowFactor,
|
||||
n, l, v,
|
||||
NdotL, NdotV);
|
||||
|
@ -99,7 +101,7 @@ void main()
|
|||
worldReflected);
|
||||
|
||||
vec2 coord = (gl_FragCoord.xy - fg_Viewport.xy) / fg_Viewport.zw;
|
||||
color = addAerialPerspective(color, coord, length(ecPos));
|
||||
color = add_aerial_perspective(color, coord, length(ecPos));
|
||||
|
||||
fragColor = vec4(color, baseColor.a);
|
||||
}
|
||||
|
|
45
Shaders/HDR/geometry-runway.frag
Normal file
45
Shaders/HDR/geometry-runway.frag
Normal file
|
@ -0,0 +1,45 @@
|
|||
#version 330 core
|
||||
|
||||
layout(location = 0) out vec4 outGBuffer0;
|
||||
layout(location = 1) out vec4 outGBuffer1;
|
||||
layout(location = 2) out vec4 outGBuffer2;
|
||||
|
||||
in vec3 rawpos;
|
||||
in vec2 texCoord;
|
||||
in mat3 TBN;
|
||||
|
||||
uniform sampler2D color_tex;
|
||||
uniform sampler2D normal_tex;
|
||||
uniform sampler3D noise_tex;
|
||||
|
||||
const float NORMAL_MAP_SCALE = 8.0;
|
||||
|
||||
vec2 encodeNormal(vec3 n);
|
||||
vec3 decodeSRGB(vec3 screenRGB);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 texel = texture(color_tex, texCoord);
|
||||
vec3 color = decodeSRGB(texel.rgb);
|
||||
|
||||
vec3 normal_texel = texture(normal_tex, texCoord * NORMAL_MAP_SCALE).rgb;
|
||||
vec3 normal = normalize(TBN * (normal_texel * 2.0 - 1.0));
|
||||
|
||||
vec3 noise_large = texture(noise_tex, rawpos * 0.0045).rgb;
|
||||
vec3 noise_small = texture(noise_tex, rawpos).rgb;
|
||||
|
||||
float mix_factor = noise_large.r * noise_large.g * noise_large.b * 350.0;
|
||||
mix_factor = smoothstep(0.0, 1.0, mix_factor);
|
||||
|
||||
color = mix(color, noise_small, 0.15);
|
||||
|
||||
float roughness = mix(0.94, 0.98, mix_factor);
|
||||
|
||||
outGBuffer0.rg = encodeNormal(normal);
|
||||
outGBuffer0.b = roughness;
|
||||
outGBuffer0.a = 1.0;
|
||||
outGBuffer1.rgb = vec3(color);
|
||||
outGBuffer1.a = 0.0;
|
||||
outGBuffer2.rgb = vec3(0.0);
|
||||
outGBuffer2.a = 1.0;
|
||||
}
|
27
Shaders/HDR/geometry-runway.vert
Normal file
27
Shaders/HDR/geometry-runway.vert
Normal file
|
@ -0,0 +1,27 @@
|
|||
#version 330 core
|
||||
|
||||
layout(location = 0) in vec4 pos;
|
||||
layout(location = 1) in vec3 normal;
|
||||
layout(location = 3) in vec4 multiTexCoord0;
|
||||
|
||||
out vec3 rawpos;
|
||||
out vec2 texCoord;
|
||||
out mat3 TBN;
|
||||
|
||||
uniform mat4 osg_ModelViewProjectionMatrix;
|
||||
uniform mat3 osg_NormalMatrix;
|
||||
|
||||
void main()
|
||||
{
|
||||
rawpos = pos.xyz / pos.w;
|
||||
gl_Position = osg_ModelViewProjectionMatrix * pos;
|
||||
texCoord = multiTexCoord0.st;
|
||||
|
||||
vec3 tangent = cross(normal, vec3(1.0, 0.0, 0.0));
|
||||
vec3 binormal = cross(normal, tangent);
|
||||
|
||||
vec3 T = normalize(osg_NormalMatrix * tangent);
|
||||
vec3 B = normalize(osg_NormalMatrix * binormal);
|
||||
vec3 N = normalize(osg_NormalMatrix * normal);
|
||||
TBN = mat3(T, B, N);
|
||||
}
|
38
Shaders/HDR/geometry-terrain.frag
Normal file
38
Shaders/HDR/geometry-terrain.frag
Normal file
|
@ -0,0 +1,38 @@
|
|||
#version 330 core
|
||||
|
||||
layout(location = 0) out vec4 outGBuffer0;
|
||||
layout(location = 1) out vec4 outGBuffer1;
|
||||
layout(location = 2) out vec4 outGBuffer2;
|
||||
|
||||
in vec3 normalVS;
|
||||
in vec2 texCoord;
|
||||
in vec2 orthophoto_texCoord;
|
||||
|
||||
uniform sampler2D color_tex;
|
||||
uniform sampler2D orthophoto_tex;
|
||||
|
||||
uniform bool orthophotoAvailable;
|
||||
|
||||
vec2 encodeNormal(vec3 n);
|
||||
vec3 decodeSRGB(vec3 screenRGB);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 texel = texture(color_tex, texCoord).rgb;
|
||||
if (orthophotoAvailable) {
|
||||
vec4 sat_texel = texture(orthophoto_tex, orthophoto_texCoord);
|
||||
if (sat_texel.a > 0.0) {
|
||||
texel.rgb = sat_texel.rgb;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 color = decodeSRGB(texel);
|
||||
|
||||
outGBuffer0.rg = encodeNormal(normalVS);
|
||||
outGBuffer0.b = 0.95;
|
||||
outGBuffer0.a = 1.0;
|
||||
outGBuffer1.rgb = color;
|
||||
outGBuffer1.a = 0.0;
|
||||
outGBuffer2.rgb = vec3(0.0);
|
||||
outGBuffer2.a = 1.0;
|
||||
}
|
21
Shaders/HDR/geometry-terrain.vert
Normal file
21
Shaders/HDR/geometry-terrain.vert
Normal file
|
@ -0,0 +1,21 @@
|
|||
#version 330 core
|
||||
|
||||
layout(location = 0) in vec4 pos;
|
||||
layout(location = 1) in vec3 normal;
|
||||
layout(location = 3) in vec4 multiTexCoord0;
|
||||
layout(location = 5) in vec4 multiTexCoord2;
|
||||
|
||||
out vec3 normalVS;
|
||||
out vec2 texCoord;
|
||||
out vec2 orthophoto_texCoord;
|
||||
|
||||
uniform mat4 osg_ModelViewProjectionMatrix;
|
||||
uniform mat3 osg_NormalMatrix;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = osg_ModelViewProjectionMatrix * pos;
|
||||
normalVS = normalize(osg_NormalMatrix * normal);
|
||||
texCoord = multiTexCoord0.st;
|
||||
orthophoto_texCoord = multiTexCoord2.st;
|
||||
}
|
|
@ -41,8 +41,8 @@ vec3 evaluateIBL(
|
|||
vec3 nWorldSpace,
|
||||
float NdotV,
|
||||
vec3 reflected);
|
||||
vec3 addAerialPerspective(vec3 color, vec2 coord, float depth);
|
||||
vec3 getSunIntensity();
|
||||
vec3 add_aerial_perspective(vec3 color, vec2 coord, float depth);
|
||||
vec3 get_sun_radiance(vec3 p);
|
||||
|
||||
void main()
|
||||
{
|
||||
|
@ -59,14 +59,16 @@ void main()
|
|||
|
||||
vec3 f0 = getF0Reflectance(baseColor.rgb, 0.0);
|
||||
|
||||
vec3 sunIlluminance = getSunIntensity() * clamp(NdotL, 0.0, 1.0);
|
||||
vec3 pos_world = (osg_ViewMatrixInverse * vec4(ecPos, 1.0)).xyz;
|
||||
vec3 sun_radiance = get_sun_radiance(pos_world);
|
||||
|
||||
float shadowFactor = getShadowing(ecPos, n, l, osg_ProjectionMatrix);
|
||||
|
||||
vec3 color = evaluateLight(baseColor,
|
||||
DEFAULT_TRANSPARENT_METALNESS,
|
||||
DEFAULT_TRANSPARENT_ROUGHNESS,
|
||||
f0,
|
||||
sunIlluminance,
|
||||
sun_radiance,
|
||||
shadowFactor,
|
||||
n, l, v,
|
||||
NdotL, NdotV);
|
||||
|
@ -84,7 +86,7 @@ void main()
|
|||
worldReflected);
|
||||
|
||||
vec2 coord = (gl_FragCoord.xy - fg_Viewport.xy) / fg_Viewport.zw;
|
||||
color = addAerialPerspective(color, coord, length(ecPos));
|
||||
color = add_aerial_perspective(color, coord, length(ecPos));
|
||||
|
||||
fragColor = vec4(color, alpha);
|
||||
}
|
||||
|
|
20
Shaders/HDR/histogram-aggregate.frag
Normal file
20
Shaders/HDR/histogram-aggregate.frag
Normal file
|
@ -0,0 +1,20 @@
|
|||
#version 330 core
|
||||
|
||||
out uint fragHits;
|
||||
|
||||
uniform usampler2D partial_histogram_tex;
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 partial_histogram_size = textureSize(partial_histogram_tex, 0); // screen x 256
|
||||
uint bin = uint(gl_FragCoord.x); // [0, 255]
|
||||
|
||||
uint hits = 0u;
|
||||
|
||||
for (int column = 0; column < partial_histogram_size.x; ++column) {
|
||||
uint partial_hits = texelFetch(partial_histogram_tex, ivec2(column, bin), 0).r;
|
||||
hits += partial_hits;
|
||||
}
|
||||
|
||||
fragHits = hits;
|
||||
}
|
35
Shaders/HDR/histogram-column.frag
Normal file
35
Shaders/HDR/histogram-column.frag
Normal file
|
@ -0,0 +1,35 @@
|
|||
#version 330 core
|
||||
|
||||
out uint fragHits;
|
||||
|
||||
uniform sampler2D hdr_tex;
|
||||
|
||||
uint luminance_to_bin_index(float luminance);
|
||||
|
||||
float srgb_to_luminance(vec3 color)
|
||||
{
|
||||
return dot(color, vec3(0.2125, 0.7154, 0.0721));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 hdr_tex_size = textureSize(hdr_tex, 0);
|
||||
int column = int(gl_FragCoord.x);
|
||||
uint target_bin = uint(gl_FragCoord.y); // [0, 255]
|
||||
|
||||
uint hits = 0u;
|
||||
|
||||
for (int row = 0; row < hdr_tex_size.y; ++row) {
|
||||
vec3 hdr_color = texelFetch(hdr_tex, ivec2(column, row), 0).rgb;
|
||||
// sRGB to relative luminance
|
||||
float lum = srgb_to_luminance(hdr_color);
|
||||
// Get the bin index corresponding to the given pixel luminance
|
||||
uint pixel_bin = luminance_to_bin_index(lum);
|
||||
// Check if this pixel should go in the bin
|
||||
if (pixel_bin == target_bin) {
|
||||
hits += 1u;
|
||||
}
|
||||
}
|
||||
|
||||
fragHits = hits;
|
||||
}
|
24
Shaders/HDR/histogram-include.frag
Normal file
24
Shaders/HDR/histogram-include.frag
Normal file
|
@ -0,0 +1,24 @@
|
|||
#version 330 core
|
||||
|
||||
const float NUM_BINS = 254.0;
|
||||
const float INV_NUM_BINS = 1.0 / NUM_BINS;
|
||||
|
||||
const float MIN_LOG_LUM = -10.0;
|
||||
const float LOG_LUM_RANGE = 16.0;
|
||||
const float INV_LOG_LUM_RANGE = 1.0 / LOG_LUM_RANGE;
|
||||
|
||||
uint luminance_to_bin_index(float luminance)
|
||||
{
|
||||
// Avoid taking the log of zero
|
||||
if (luminance < 0.005)
|
||||
return 0u;
|
||||
float log_lum = (log2(luminance) - MIN_LOG_LUM) * INV_LOG_LUM_RANGE;
|
||||
log_lum = clamp(log_lum, 0.0, 1.0);
|
||||
// From [0, 1] to [1, 255]. The 0th bin is handled by the near-zero check
|
||||
return uint(log_lum * NUM_BINS + 1.0);
|
||||
}
|
||||
|
||||
float bin_index_to_luminance(float bin)
|
||||
{
|
||||
return exp2(((bin * INV_NUM_BINS) * LOG_LUM_RANGE) + MIN_LOG_LUM);
|
||||
}
|
42
Shaders/HDR/histogram-luminance.frag
Normal file
42
Shaders/HDR/histogram-luminance.frag
Normal file
|
@ -0,0 +1,42 @@
|
|||
#version 330 core
|
||||
|
||||
out float fragLuminance;
|
||||
|
||||
uniform usampler2D histogram_tex;
|
||||
uniform sampler2D prev_lum_tex;
|
||||
|
||||
uniform float osg_DeltaFrameTime;
|
||||
|
||||
// Higher values give faster eye adaptation times
|
||||
const float TAU = 1.1;
|
||||
|
||||
float bin_index_to_luminance(float bin);
|
||||
|
||||
void main()
|
||||
{
|
||||
int num_bins = textureSize(histogram_tex, 0).x; // [0, 255]
|
||||
|
||||
uint sum = 0u;
|
||||
uint total_pixels = 0u;
|
||||
|
||||
// Calculate the mean of the luminance histogram.
|
||||
// We start indexing at 1 to ignore the first bin, which contains the
|
||||
// luminance values that are lower than our threshold.
|
||||
for (int i = 1; i < num_bins; ++i) {
|
||||
uint hits = texelFetch(histogram_tex, ivec2(i, 0), 0).r;
|
||||
sum += uint(i) * hits;
|
||||
total_pixels += hits;
|
||||
}
|
||||
|
||||
float mean = float(sum) / max(float(total_pixels), 1.0) - 1.0;
|
||||
|
||||
// Transform the bin index [1, 255] to an actual luminance value
|
||||
float average_lum = bin_index_to_luminance(mean);
|
||||
|
||||
// Simulate smooth eye adaptation over time
|
||||
float prev_lum = texelFetch(prev_lum_tex, ivec2(0), 0).r;
|
||||
float adapted_lum = prev_lum + (average_lum - prev_lum) *
|
||||
(1.0 - exp(-osg_DeltaFrameTime * TAU));
|
||||
|
||||
fragLuminance = adapted_lum;
|
||||
}
|
|
@ -180,6 +180,6 @@ vec3 evaluateLight(
|
|||
|
||||
vec3 material = f_diffuse + f_specular;
|
||||
|
||||
vec3 color = material * intensity * visibility;
|
||||
vec3 color = material * intensity * visibility * NdotL;
|
||||
return color;
|
||||
}
|
||||
|
|
|
@ -43,8 +43,17 @@ vec3 evaluateIBL(
|
|||
vec3 nWorldSpace,
|
||||
float NdotV,
|
||||
vec3 reflected);
|
||||
vec3 addAerialPerspective(vec3 color, vec2 coord, float depth);
|
||||
vec3 getSunIntensity();
|
||||
vec3 add_aerial_perspective(vec3 color, vec2 coord, float depth);
|
||||
vec3 get_sun_radiance(vec3 p);
|
||||
|
||||
vec3 get_contribution_from_scene_lights(
|
||||
vec3 p,
|
||||
vec3 base_color,
|
||||
float metallic,
|
||||
float roughness,
|
||||
vec3 f0,
|
||||
vec3 n,
|
||||
vec3 v);
|
||||
|
||||
float GTAOMultiBounce(float x, vec3 albedo)
|
||||
{
|
||||
|
@ -81,18 +90,26 @@ void main()
|
|||
|
||||
vec3 f0 = getF0Reflectance(baseColor, metallic);
|
||||
|
||||
vec3 sunIlluminance = getSunIntensity() * clamp(NdotL, 0.0, 1.0);
|
||||
vec3 pos_world = (fg_ViewMatrixInverse * vec4(pos, 1.0)).xyz;
|
||||
vec3 sun_radiance = get_sun_radiance(pos_world);
|
||||
|
||||
float shadowFactor = getShadowing(pos, n, l, fg_ProjectionMatrix);
|
||||
|
||||
vec3 color = evaluateLight(baseColor,
|
||||
metallic,
|
||||
roughness,
|
||||
f0,
|
||||
sunIlluminance,
|
||||
sun_radiance,
|
||||
shadowFactor,
|
||||
n, l, v,
|
||||
NdotL, NdotV);
|
||||
|
||||
color += get_contribution_from_scene_lights(pos,
|
||||
baseColor,
|
||||
metallic,
|
||||
roughness,
|
||||
f0, n, v);
|
||||
|
||||
float ao = occlusion;
|
||||
if (ambient_occlusion_enabled) {
|
||||
ao *= GTAOMultiBounce(texture(ao_tex, texCoord).r, baseColor);
|
||||
|
@ -110,7 +127,7 @@ void main()
|
|||
NdotV,
|
||||
worldNormal);
|
||||
|
||||
color = addAerialPerspective(color, texCoord, length(pos));
|
||||
color = add_aerial_perspective(color, texCoord, length(pos));
|
||||
|
||||
if (debug_shadow_cascades)
|
||||
color *= debugShadowColor(pos, n, l);
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
#version 330 core
|
||||
|
||||
out float luminance;
|
||||
|
||||
in vec2 texCoord;
|
||||
|
||||
uniform sampler2D hdr_tex;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 hdrColor = texture(hdr_tex, texCoord).rgb;
|
||||
luminance = log(max(dot(hdrColor, vec3(0.299, 0.587, 0.114)), 0.0001));
|
||||
}
|
|
@ -74,6 +74,11 @@ vec3 encodeSRGB(vec3 linearRGB)
|
|||
return mix(a, b, c);
|
||||
}
|
||||
|
||||
float rand2D(vec2 co)
|
||||
{
|
||||
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 hdrColor = texture(hdr_tex, texCoord).rgb;
|
||||
|
@ -95,5 +100,8 @@ void main()
|
|||
vec3 bloom = texture(bloom_tex, texCoord).rgb;
|
||||
color += bloom.rgb * bloom_magnitude;
|
||||
|
||||
// Dithering
|
||||
color += mix(-0.5/255.0, 0.5/255.0, rand2D(texCoord));
|
||||
|
||||
fragColor = vec4(color, 1.0);
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
out vec4 fragColor;
|
||||
|
||||
in vec3 vRayDir;
|
||||
in vec3 vRayDirView;
|
||||
in vec3 v_ray_dir;
|
||||
in vec3 v_ray_dir_view;
|
||||
|
||||
uniform bool sun_disk;
|
||||
uniform sampler2D sky_view_lut;
|
||||
|
@ -14,51 +14,73 @@ uniform float fg_CameraDistanceToEarthCenter;
|
|||
uniform float fg_EarthRadius;
|
||||
uniform vec3 fg_CameraViewUp;
|
||||
|
||||
const float PI = 3.141592653;
|
||||
const vec3 EXTRATERRESTRIAL_SOLAR_ILLUMINANCE = vec3(128.0);
|
||||
const float PI = 3.14159265358979323846;
|
||||
const float ATMOSPHERE_RADIUS = 6471e3;
|
||||
|
||||
const float sun_solid_angle = 0.545*PI/180.0; // ~half a degree
|
||||
const float sun_solid_angle = radians(0.545); // ~half a degree
|
||||
const float sun_cos_solid_angle = cos(sun_solid_angle);
|
||||
// Limb darkening constants, sampled for
|
||||
// 630, 560, 490, 430 nanometers
|
||||
const vec4 u = vec4(1.0);
|
||||
const vec4 alpha = vec4(0.429, 0.502, 0.575, 0.643);
|
||||
|
||||
//-- BEGIN spectral include
|
||||
// Extraterrestial Solar Irradiance Spectra, units W * m^-2 * nm^-1
|
||||
// https://www.nrel.gov/grid/solar-resource/spectra.html
|
||||
const vec4 sun_spectral_irradiance = vec4(1.679, 1.828, 1.986, 1.307);
|
||||
|
||||
const mat4x3 M = mat4x3(
|
||||
137.672389239975, -8.632904716299537, -1.7181567391931372,
|
||||
32.549094028629234, 91.29801417199785, -12.005406444382531,
|
||||
-38.91428392614275, 34.31665471469816, 29.89044807197628,
|
||||
8.572844237945445, -11.103384660054624, 117.47585277566478);
|
||||
|
||||
vec3 linear_srgb_from_spectral_samples(vec4 L)
|
||||
{
|
||||
return M * L;
|
||||
}
|
||||
//-- END spectral include
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 rayDir = normalize(vRayDir);
|
||||
float azimuth = atan(rayDir.y, rayDir.x) / PI * 0.5 + 0.5;
|
||||
vec3 ray_dir = normalize(v_ray_dir);
|
||||
float azimuth = atan(ray_dir.y, ray_dir.x) / PI * 0.5 + 0.5;
|
||||
// Undo the non-linear transformation from the sky-view LUT
|
||||
float l = asin(rayDir.z);
|
||||
float l = asin(ray_dir.z);
|
||||
float elev = sqrt(abs(l) / (PI * 0.5)) * sign(l) * 0.5 + 0.5;
|
||||
|
||||
vec3 color = texture(sky_view_lut, vec2(azimuth, elev)).rgb;
|
||||
color *= EXTRATERRESTRIAL_SOLAR_ILLUMINANCE;
|
||||
vec4 sky_radiance = texture(sky_view_lut, vec2(azimuth, elev));
|
||||
// When computing the sky texture we assumed an unitary light source.
|
||||
// Now multiply by the sun irradiance.
|
||||
sky_radiance *= sun_spectral_irradiance;
|
||||
|
||||
if (sun_disk) {
|
||||
// Render the Sun disk
|
||||
vec3 rayDirView = normalize(vRayDirView);
|
||||
float cosTheta = dot(rayDirView, fg_SunDirection);
|
||||
vec3 ray_dir_view = normalize(v_ray_dir_view);
|
||||
float cos_theta = dot(ray_dir_view, fg_SunDirection);
|
||||
|
||||
if (cosTheta >= sun_cos_solid_angle) {
|
||||
float normalizedHeight = (fg_CameraDistanceToEarthCenter - fg_EarthRadius)
|
||||
if (cos_theta >= sun_cos_solid_angle) {
|
||||
float normalized_altitude =
|
||||
(fg_CameraDistanceToEarthCenter - fg_EarthRadius)
|
||||
/ (ATMOSPHERE_RADIUS - fg_EarthRadius);
|
||||
|
||||
float sunZenithCosTheta = dot(-rayDirView, fg_CameraViewUp);
|
||||
float sun_zenith_cos_theta = dot(-ray_dir_view, fg_CameraViewUp);
|
||||
|
||||
vec2 coords = vec2(sunZenithCosTheta * 0.5 + 0.5,
|
||||
clamp(normalizedHeight, 0.0, 1.0));
|
||||
vec3 transmittance = texture(transmittance_lut, coords).rgb;
|
||||
vec2 uv = vec2(sun_zenith_cos_theta * 0.5 + 0.5,
|
||||
clamp(normalized_altitude, 0.0, 1.0));
|
||||
vec4 transmittance = texture(transmittance_lut, uv);
|
||||
|
||||
// Limb darkening
|
||||
// http://www.physics.hmc.edu/faculty/esin/a101/limbdarkening.pdf
|
||||
vec3 u = vec3(1.0);
|
||||
vec3 a = vec3(0.397, 0.503, 0.652);
|
||||
float centerToEdge = 1.0 - (cosTheta - sun_cos_solid_angle)
|
||||
float center_to_edge = 1.0 - (cos_theta - sun_cos_solid_angle)
|
||||
/ (1.0 - sun_cos_solid_angle);
|
||||
float mu = sqrt(max(1.0 - centerToEdge * centerToEdge, 0.0));
|
||||
vec3 factor = vec3(1.0) - u * (vec3(1.0) - pow(vec3(mu), a));
|
||||
float mu = sqrt(max(1.0 - center_to_edge*center_to_edge, 0.0));
|
||||
vec4 factor = vec4(1.0) - u * (vec4(1.0) - pow(vec4(mu), alpha));
|
||||
|
||||
color += EXTRATERRESTRIAL_SOLAR_ILLUMINANCE * transmittance * factor;
|
||||
vec4 sun_radiance = sun_spectral_irradiance * transmittance * factor;
|
||||
sky_radiance += sun_radiance;
|
||||
}
|
||||
}
|
||||
|
||||
fragColor = vec4(color, 1.0);
|
||||
vec3 sky_color = linear_srgb_from_spectral_samples(sky_radiance);
|
||||
fragColor = vec4(sky_color, 1.0);
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
layout(location = 0) in vec4 pos;
|
||||
|
||||
out vec3 vRayDir;
|
||||
out vec3 vRayDirView;
|
||||
out vec3 v_ray_dir;
|
||||
out vec3 v_ray_dir_view;
|
||||
|
||||
uniform mat4 osg_ModelViewMatrix;
|
||||
uniform mat4 osg_ModelViewProjectionMatrix;
|
||||
|
@ -15,6 +15,6 @@ void main()
|
|||
vec4 groundPoint = osg_ModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0);
|
||||
float altitude = length(groundPoint);
|
||||
// Compensate for the skydome being fixed on the ground
|
||||
vRayDir = normalize(pos.xyz - vec3(0.0, 0.0, altitude));
|
||||
vRayDirView = (osg_ModelViewMatrix * vec4(vRayDir, 0.0)).xyz;
|
||||
v_ray_dir = normalize(pos.xyz - vec3(0.0, 0.0, altitude));
|
||||
v_ray_dir_view = (osg_ModelViewMatrix * vec4(v_ray_dir, 0.0)).xyz;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ const vec3 EXTRATERRESTRIAL_SOLAR_ILLUMINANCE = vec3(128.0);
|
|||
|
||||
vec3 decodeNormal(vec2 f);
|
||||
vec3 positionFromDepth(vec2 pos, float depth);
|
||||
vec3 addAerialPerspective(vec3 color, vec2 coord, float depth);
|
||||
vec3 add_aerial_perspective(vec3 color, vec2 coord, float depth);
|
||||
|
||||
float F_Schlick(float VdotH, float F0)
|
||||
{
|
||||
|
@ -79,7 +79,7 @@ void main()
|
|||
// Add reflected Sun light
|
||||
color += RECIPROCAL_PI * fresnel * D_GGX(NdotH, 0.001) * sunIntensity * NdotL;
|
||||
|
||||
color = addAerialPerspective(color, texCoord, length(pos));
|
||||
color = add_aerial_perspective(color, texCoord, length(pos));
|
||||
|
||||
fragColor = color;
|
||||
}
|
||||
|
|
|
@ -531,6 +531,7 @@ Started September 2000 by David Megginson, david@megginson.com
|
|||
<available type="bool" userarchive="n">false</available>
|
||||
<enabled type="bool" userarchive="y">true</enabled>
|
||||
</pilot-model>
|
||||
|
||||
<hdr>
|
||||
<antialiasing-technique type="int" userarchive="y">2</antialiasing-technique>
|
||||
<exposure-compensation type="float">0.0</exposure-compensation>
|
||||
|
@ -546,6 +547,7 @@ Started September 2000 by David Megginson, david@megginson.com
|
|||
<show-shadow-cascades type="bool">false</show-shadow-cascades>
|
||||
</debug>
|
||||
</hdr>
|
||||
|
||||
<composite-viewer-enabled type="bool">true</composite-viewer-enabled>
|
||||
</rendering>
|
||||
<vr>
|
||||
|
@ -1185,7 +1187,9 @@ Started September 2000 by David Megginson, david@megginson.com
|
|||
<max-rate-hz type="int">50</max-rate-hz>
|
||||
<rate-hz type="int">30</rate-hz>
|
||||
</emexec>
|
||||
|
||||
<debug>
|
||||
<show-light-volumes type="bool">false</show-light-volumes>
|
||||
</debug>
|
||||
</sim>
|
||||
<!-- accelerations -->
|
||||
<accelerations>
|
||||
|
|
Loading…
Add table
Reference in a new issue