WS30: landclass and texture lookups in fragment shader
commit e131ffaca7b2c934474f0e447b5852cb4c7c8d4a Author: vs <vs2009@mail.com> Date: Fri Oct 15 22:19:42 2021 +1000 WS30: landclass and texture lookups in fragment shader: Changelog: - Testing: Procedural random landclass function, get_random_landclass(). 1). Avoids a texture lookup for profiling. 2). Creates squares of configurable size with controllable random landclass ranges - to test landclass transition algorithms and quickly profile lots of landclasses in view. It's also possible to put pressure on GPU memory even with 1 lookup of ground textures per fragment, by reducing size to <20m and viewing from altitude. - Add ALS ultra technique as no 5, move existing ALS technique to no. 6. Add WS30-ALS-ultra frag & vert in preparation for eventual ALS ultra port. Change comments/variables to match using a texture array instead of atlas. Sampler name: atlas -> textureArray. - Testing/optimisation of de-tiling: WS30-ALS.frag: reorder perlin detiling to make noise source easier to switch. WS30-ALS-ultra.frag: Create alternative to perlin noise used for reducing tiling that avoids a texture lookup - to profile and optimise. This is commented out. The performance difference in the final version depends on memory pressure versus arithmetic load of the full shader. It varies by GPU and what's in view. In future, once a full ALS port is done, maybe it'll be more efficient to run a higher quality de-tiling algorithm all the time to avoid branching overhead due to effects like agriculture which need more de-tiling. De-tiling code in shaders should /eventually/ match CPU-side de-tiling of texture masks used for object and vegetation placement. De-tiling code in GPUs might be subject to precision and numerical artifacts, and if so maybe the texture lookup version would work better. The same applies to noise used for rendering WS3 water waves and collision queries. One option is to use exactly the same glsl code, with a C++ header to convert glsl syntax e.g. https://github.com/g-truc/glm .
This commit is contained in:
parent
38dc00faf1
commit
0bce3c966f
4 changed files with 946 additions and 24 deletions
291
Effects/ws30.eff
291
Effects/ws30.eff
|
@ -188,7 +188,289 @@
|
|||
</parameters>
|
||||
<!-- put techniques at a "high" index to allow derived effects to
|
||||
insert their own techniques first. -->
|
||||
|
||||
|
||||
<!-- ALS ultra shaders -->
|
||||
<technique n="5">
|
||||
<predicate>
|
||||
<and>
|
||||
<property>/sim/rendering/shaders/skydome</property>
|
||||
<and>
|
||||
<less-equal>
|
||||
<value type="float">6.0</value>
|
||||
<float-property>/sim/rendering/shaders/landmass</float-property>
|
||||
</less-equal>
|
||||
<less-equal>
|
||||
<value type="float">6.0</value>
|
||||
<float-property>/sim/rendering/shaders/transition</float-property>
|
||||
</less-equal>
|
||||
</and>
|
||||
<or>
|
||||
<less-equal>
|
||||
<value type="float">2.0</value>
|
||||
<glversion/>
|
||||
</less-equal>
|
||||
<and>
|
||||
<extension-supported>GL_ARB_shader_objects</extension-supported>
|
||||
<extension-supported>GL_ARB_shading_language_100</extension-supported>
|
||||
<extension-supported>GL_ARB_vertex_shader</extension-supported>
|
||||
<extension-supported>GL_ARB_fragment_shader</extension-supported>
|
||||
</and>
|
||||
</or>
|
||||
</and>
|
||||
</predicate>
|
||||
|
||||
<pass>
|
||||
<lighting>true</lighting>
|
||||
<material>
|
||||
<ambient><use>material/ambient</use></ambient>
|
||||
<diffuse><use>material/diffuse</use></diffuse>
|
||||
<specular><use>material/specular</use></specular>
|
||||
<emissive><use>material/emissive</use></emissive>
|
||||
<shininess><use>material/shininess</use></shininess>
|
||||
<color-mode>ambient-and-diffuse</color-mode>
|
||||
</material>
|
||||
<blend><use>transparent</use></blend>
|
||||
<alpha-test><use>transparent</use></alpha-test>
|
||||
<shade-model>smooth</shade-model>
|
||||
<cull-face>back</cull-face>
|
||||
<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 0 direct from VPBBuilder.cxx -->
|
||||
|
||||
<texture-unit>
|
||||
<unit>1</unit>
|
||||
<image><use>texture[1]/image</use></image>
|
||||
<filter>nearest-mipmap-nearest</filter>
|
||||
<mag-filter>nearest-mipmap-nearest</mag-filter>
|
||||
<wrap-s><use>texture[0]/wrap-s</use></wrap-s>
|
||||
<wrap-t><use>texture[0]/wrap-t</use></wrap-t>
|
||||
<internal-format><use>texture[0]/internal-format</use></internal-format>
|
||||
</texture-unit>
|
||||
|
||||
<texture-unit>
|
||||
<unit>2</unit>
|
||||
<image><use>texture[2]/image</use></image>
|
||||
<filter><use>texture[2]/filter</use></filter>
|
||||
<wrap-s><use>texture[2]/wrap-s</use></wrap-s>
|
||||
<wrap-t><use>texture[2]/wrap-t</use></wrap-t>
|
||||
<internal-format><use>texture[2]/internal-format</use></internal-format>
|
||||
</texture-unit>
|
||||
|
||||
<texture-unit>
|
||||
<unit>3</unit>
|
||||
<image><use>texture[3]/image</use></image>
|
||||
<filter><use>texture[3]/filter</use></filter>
|
||||
<wrap-s><use>texture[3]/wrap-s</use></wrap-s>
|
||||
<wrap-t><use>texture[3]/wrap-t</use></wrap-t>
|
||||
<internal-format><use>texture[3]/internal-format</use></internal-format>
|
||||
</texture-unit>
|
||||
|
||||
<texture-unit>
|
||||
<unit>4</unit>
|
||||
<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>
|
||||
<internal-format><use>texture[4]/internal-format</use></internal-format>
|
||||
</texture-unit>
|
||||
|
||||
<texture-unit>
|
||||
<unit>6</unit>
|
||||
<image><use>texture[6]/image</use></image>
|
||||
<filter><use>texture[6]/filter</use></filter>
|
||||
<wrap-s><use>texture[6]/wrap-s</use></wrap-s>
|
||||
<wrap-t><use>texture[6]/wrap-t</use></wrap-t>
|
||||
<internal-format><use>texture[6]/internal-format</use></internal-format>
|
||||
</texture-unit>
|
||||
|
||||
<program>
|
||||
<vertex-shader>Shaders/ws30-ALS-ultra.vert</vertex-shader>
|
||||
<vertex-shader>Shaders/filters-ALS.vert</vertex-shader>
|
||||
<vertex-shader>Shaders/shadows-include.vert</vertex-shader>
|
||||
<fragment-shader>Shaders/ws30-ALS-ultra.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/noise.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/cloud-shadowfunc.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/hazes.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/secondary_lights.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/filters-ALS.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/shadows-include.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/clustered-include.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>visibility</name>
|
||||
<type>float</type>
|
||||
<value><use>visibility</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>avisibility</name>
|
||||
<type>float</type>
|
||||
<value><use>avisibility</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>hazeLayerAltitude</name>
|
||||
<type>float</type>
|
||||
<value><use>lthickness</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>scattering</name>
|
||||
<type>float</type>
|
||||
<value><use>scattering</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>ground_scattering</name>
|
||||
<type>float</type>
|
||||
<value><use>ground_scattering</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>terminator</name>
|
||||
<type>float</type>
|
||||
<value><use>terminator</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>terrain_alt</name>
|
||||
<type>float</type>
|
||||
<value><use>terrain_alt</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>overcast</name>
|
||||
<type>float</type>
|
||||
<value><use>overcast</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>eye_alt</name>
|
||||
<type>float</type>
|
||||
<value><use>eye_alt</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>cloud_self_shading</name>
|
||||
<type>float</type>
|
||||
<value><use>cloud_self_shading</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>moonlight</name>
|
||||
<type>float</type>
|
||||
<value><use>moonlight</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>air_pollution</name>
|
||||
<type>float</type>
|
||||
<value><use>air_pollution</use></value>
|
||||
</uniform>
|
||||
<!-- filtering -->
|
||||
<uniform>
|
||||
<name>gamma</name>
|
||||
<type>float</type>
|
||||
<value><use>gamma</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>brightness</name>
|
||||
<type>float</type>
|
||||
<value><use>brightness</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>use_night_vision</name>
|
||||
<type>bool</type>
|
||||
<value><use>use_night_vision</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>use_IR_vision</name>
|
||||
<type>bool</type>
|
||||
<value><use>use_IR_vision</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>use_filtering</name>
|
||||
<type>bool</type>
|
||||
<value><use>use_filtering</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>delta_T</name>
|
||||
<type>float</type>
|
||||
<value><use>delta_T</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>fact_grey</name>
|
||||
<type>float</type>
|
||||
<value><use>fact_grey</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>fact_black</name>
|
||||
<type>float</type>
|
||||
<value><use>fact_black</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>display_xsize</name>
|
||||
<type>int</type>
|
||||
<value><use>display_xsize</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>display_ysize</name>
|
||||
<type>int</type>
|
||||
<value><use>display_ysize</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>landclass</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>textureArray</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">1</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>dimensionsArray</name>
|
||||
<type>sampler-1d</type>
|
||||
<value type="int">2</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>diffuseArray</name>
|
||||
<type>sampler-1d</type>
|
||||
<value type="int">3</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>specularArray</name>
|
||||
<type>sampler-1d</type>
|
||||
<value type="int">4</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>perlin</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">6</value>
|
||||
</uniform>
|
||||
|
||||
<uniform>
|
||||
<name>colorMode</name>
|
||||
<type>int</type>
|
||||
<value>2</value>
|
||||
<!-- AMBIENT_AND_DIFFUSE -->
|
||||
</uniform>
|
||||
<!-- BEGIN shadows include -->
|
||||
<uniform>
|
||||
<name>shadow_tex</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">10</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>shadows_enabled</name>
|
||||
<type>bool</type>
|
||||
<value><use>shadows_enabled</use></value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>sun_atlas_size</name>
|
||||
<type>int</type>
|
||||
<value><use>sun_atlas_size</use></value>
|
||||
</uniform>
|
||||
<!-- END shadows include -->
|
||||
</pass>
|
||||
</technique>
|
||||
|
||||
|
||||
|
||||
<technique n="6">
|
||||
<predicate>
|
||||
<and>
|
||||
<property>/sim/rendering/shaders/skydome</property>
|
||||
|
@ -401,7 +683,7 @@
|
|||
<value type="int">0</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>atlas</name>
|
||||
<name>textureArray</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">1</value>
|
||||
</uniform>
|
||||
|
@ -452,6 +734,13 @@
|
|||
</pass>
|
||||
</technique>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Non-ALS technique with texture rotation -->
|
||||
<technique n="11">
|
||||
<predicate>
|
||||
|
|
346
Shaders/ws30-ALS-ultra.frag
Normal file
346
Shaders/ws30-ALS-ultra.frag
Normal file
|
@ -0,0 +1,346 @@
|
|||
// WS30 FRAGMENT SHADER
|
||||
|
||||
// -*-C++-*-
|
||||
#version 130
|
||||
#extension GL_EXT_texture_array : enable
|
||||
|
||||
// written by Thorsten Renk, Oct 2011, based on default.frag
|
||||
// Ambient term comes in gl_Color.rgb.
|
||||
varying vec4 diffuse_term;
|
||||
varying vec3 normal;
|
||||
varying vec3 relPos;
|
||||
|
||||
uniform sampler2D landclass;
|
||||
uniform sampler2DArray textureArray;
|
||||
uniform sampler1D dimensionsArray;
|
||||
uniform sampler1D diffuseArray;
|
||||
uniform sampler1D specularArray;
|
||||
uniform sampler2D perlin;
|
||||
|
||||
varying float yprime_alt;
|
||||
varying float mie_angle;
|
||||
varying vec4 ecPosition;
|
||||
|
||||
uniform float visibility;
|
||||
uniform float avisibility;
|
||||
uniform float scattering;
|
||||
uniform float terminator;
|
||||
uniform float terrain_alt;
|
||||
uniform float hazeLayerAltitude;
|
||||
uniform float overcast;
|
||||
uniform float eye_alt;
|
||||
uniform float cloud_self_shading;
|
||||
|
||||
// Passed from VPBTechnique, not the Effect
|
||||
uniform int tile_level;
|
||||
uniform float tile_width;
|
||||
uniform float tile_height;
|
||||
|
||||
const float EarthRadius = 5800000.0;
|
||||
const float terminator_width = 200000.0;
|
||||
|
||||
float alt;
|
||||
float eShade;
|
||||
|
||||
float fog_func (in float targ, in float alt);
|
||||
vec3 get_hazeColor(in float light_arg);
|
||||
vec3 filter_combined (in vec3 color) ;
|
||||
|
||||
float shadow_func (in float x, in float y, in float noise, in float dist);
|
||||
float DotNoise2D(in vec2 coord, in float wavelength, in float fractionalMaxDotSize, in float dot_density);
|
||||
float Noise2D(in vec2 coord, in float wavelength);
|
||||
float Noise3D(in vec3 coord, in float wavelength);
|
||||
float SlopeLines2D(in vec2 coord, in vec2 gradDir, in float wavelength, in float steepness);
|
||||
float Strata3D(in vec3 coord, in float wavelength, in float variation);
|
||||
float fog_func (in float targ, in float alt);
|
||||
float rayleigh_in_func(in float dist, in float air_pollution, in float avisibility, in float eye_alt, in float vertex_alt);
|
||||
float alt_factor(in float eye_alt, in float vertex_alt);
|
||||
float light_distance_fading(in float dist);
|
||||
float fog_backscatter(in float avisibility);
|
||||
|
||||
vec3 rayleigh_out_shift(in vec3 color, in float outscatter);
|
||||
vec3 get_hazeColor(in float light_arg);
|
||||
vec3 searchlight();
|
||||
vec3 landing_light(in float offset, in float offsetv);
|
||||
vec3 filter_combined (in vec3 color) ;
|
||||
|
||||
float getShadowing();
|
||||
vec3 getClusteredLightsContribution(vec3 p, vec3 n, vec3 texel);
|
||||
|
||||
// Not used
|
||||
float luminance(vec3 color)
|
||||
{
|
||||
return dot(vec3(0.212671, 0.715160, 0.072169), color);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////
|
||||
// Test-phase code:
|
||||
|
||||
float rand2D(in vec2 co);
|
||||
|
||||
// Create random landclasses without a texture lookup to stress test
|
||||
// Each square of square_size in m is assigned a random landclass value
|
||||
int get_random_landclass(in vec2 co)
|
||||
{
|
||||
float square_size = 200.0;
|
||||
//float r = rand2D( floor(vec2(co.s*tile_width, co.t*tile_height)/square_size) );
|
||||
float r = rand2D( floor(vec2(co.s*tile_height, co.t*tile_width)/square_size) );
|
||||
int lc = int(r*48.0); // only 48 landclasses mapped so far
|
||||
return lc;
|
||||
}
|
||||
|
||||
// End Test-phase code
|
||||
////////////////////////
|
||||
|
||||
void main()
|
||||
{
|
||||
|
||||
|
||||
vec3 shadedFogColor = vec3(0.55, 0.67, 0.88);
|
||||
// this is taken from default.frag
|
||||
vec3 n;
|
||||
float NdotL, NdotHV, fogFactor;
|
||||
vec3 lightDir = gl_LightSource[0].position.xyz;
|
||||
vec3 halfVector = gl_LightSource[0].halfVector.xyz;
|
||||
vec4 texel;
|
||||
vec4 fragColor;
|
||||
vec4 specular = vec4(0.0);
|
||||
float intensity;
|
||||
|
||||
|
||||
|
||||
// Oct 2021:
|
||||
// Geometry is in the form of roughly rectangular 'tiles'
|
||||
// with a mesh forming a grid with regular spacing.
|
||||
// Each vertex in the mesh is given an elevation
|
||||
|
||||
// Tile dimensions in m
|
||||
vec2 tile_size = vec2(tile_width , tile_height);
|
||||
// Temp: sizes are the wrong way around currently
|
||||
tile_size.xy =tile_size.yx;
|
||||
|
||||
// Tile texture coordinates range [0..1] over the tile 'rectangle'
|
||||
vec2 tile_coord = gl_TexCoord[0].st;
|
||||
|
||||
// Look up the landclass id [0 .. 255] for this particular fragment
|
||||
// Each tile has 1 texture containing landclass ids stetched over it
|
||||
|
||||
// Testing. Landclass sources: texture or random
|
||||
int tlc = int(texture2D(landclass, tile_coord.st).g * 255.0 + 0.5);
|
||||
//int rlc = get_random_landclass(tile_coord.st);
|
||||
int lc = tlc;
|
||||
|
||||
// The landclass id is used to index into arrays containing
|
||||
// material parameters and textures for the landclass as
|
||||
// defined in the regional definitions
|
||||
float index = float(lc)/512.0;
|
||||
|
||||
float mat_shininess = texture(dimensionsArray, index).z;
|
||||
vec4 mat_diffuse = texture(diffuseArray, index);
|
||||
vec4 mat_specular = texture(specularArray, index);
|
||||
|
||||
vec4 color = mat_diffuse * NdotL * gl_LightSource[0].diffuse;
|
||||
|
||||
// Testing code:
|
||||
// Use rlc even when looking up textures to recreate the extra performance hit
|
||||
// so any performance difference between the two is due to the texture lookup
|
||||
// color = color+0.00001*float(rlc);
|
||||
|
||||
float effective_scattering = min(scattering, cloud_self_shading);
|
||||
|
||||
vec4 light_specular = gl_LightSource[0].specular;
|
||||
|
||||
// If gl_Color.a == 0, this is a back-facing polygon and the
|
||||
// normal should be reversed.
|
||||
//n = (2.0 * gl_Color.a - 1.0) * normal;
|
||||
n = normalize(normal);
|
||||
|
||||
|
||||
NdotL = dot(n, lightDir);
|
||||
if (NdotL > 0.0) {
|
||||
float shadowmap = getShadowing();
|
||||
color += diffuse_term * NdotL * shadowmap;
|
||||
NdotHV = max(dot(n, halfVector), 0.0);
|
||||
if (mat_shininess > 0.0)
|
||||
specular.rgb = (mat_specular.rgb
|
||||
* light_specular.rgb
|
||||
* pow(NdotHV, gl_FrontMaterial.shininess)
|
||||
* shadowmap);
|
||||
}
|
||||
color.a = diffuse_term.a;
|
||||
// This shouldn't be necessary, but our lighting becomes very
|
||||
// saturated. Clamping the color before modulating by the texture
|
||||
// is closer to what the OpenGL fixed function pipeline does.
|
||||
color = clamp(color, 0.0, 1.0);
|
||||
|
||||
|
||||
// Look up ground textures by indexing into the texture array.
|
||||
// Different textures are stretched along the ground to different
|
||||
// lengths along each axes as set by <xsize> and <ysize>
|
||||
// regional definitions parameters
|
||||
|
||||
// Look up stretching dimensions of textures in m - scaled to fit in [0..1], so rescale
|
||||
vec2 g_texture_stretch_dim = 10000.0 * texture(dimensionsArray, index).st;
|
||||
|
||||
vec2 g_texture_scale = tile_size.xy / g_texture_stretch_dim.xy;
|
||||
// Ground texture coords
|
||||
vec2 st = g_texture_scale * tile_coord.st;
|
||||
|
||||
// Rotate texture using the perlin texture as a mask to reduce tiling
|
||||
float pnoise1 = texture(perlin, st / 8.0).r;
|
||||
float pnoise2 = texture(perlin, - st / 16.0).r;
|
||||
|
||||
//Testing: Non texture alternative
|
||||
//float pnoise1 = Noise2D(st, 8.0);
|
||||
//float pnoise2 = Noise2D(-st, 16.0);
|
||||
|
||||
if (pnoise1 >= 0.5) st = g_texture_scale.st * tile_coord.ts;
|
||||
if (pnoise2 >= 0.5) st = -st;
|
||||
|
||||
texel = texture(textureArray, vec3(st, lc));
|
||||
|
||||
fragColor = color * texel + specular;
|
||||
fragColor.rgb += getClusteredLightsContribution(ecPosition.xyz, n, texel.rgb);
|
||||
|
||||
// here comes the terrain haze model
|
||||
float delta_z = hazeLayerAltitude - eye_alt;
|
||||
float dist = length(relPos);
|
||||
|
||||
float mvisibility = min(visibility,avisibility);
|
||||
|
||||
if (dist > 0.04 * mvisibility)
|
||||
{
|
||||
|
||||
alt = eye_alt;
|
||||
|
||||
float transmission;
|
||||
float vAltitude;
|
||||
float delta_zv;
|
||||
float H;
|
||||
float distance_in_layer;
|
||||
float transmission_arg;
|
||||
|
||||
// angle with horizon
|
||||
float ct = dot(vec3(0.0, 0.0, 1.0), relPos)/dist;
|
||||
|
||||
|
||||
// we solve the geometry what part of the light path is attenuated normally and what is through the haze layer
|
||||
if (delta_z > 0.0) // we're inside the layer
|
||||
{
|
||||
if (ct < 0.0) // we look down
|
||||
{
|
||||
distance_in_layer = dist;
|
||||
vAltitude = min(distance_in_layer,mvisibility) * ct;
|
||||
delta_zv = delta_z - vAltitude;
|
||||
}
|
||||
else // we may look through upper layer edge
|
||||
{
|
||||
H = dist * ct;
|
||||
if (H > delta_z) {distance_in_layer = dist/H * delta_z;}
|
||||
else {distance_in_layer = dist;}
|
||||
vAltitude = min(distance_in_layer,visibility) * ct;
|
||||
delta_zv = delta_z - vAltitude;
|
||||
}
|
||||
}
|
||||
else // we see the layer from above, delta_z < 0.0
|
||||
{
|
||||
H = dist * -ct;
|
||||
if (H < (-delta_z)) // we don't see into the layer at all, aloft visibility is the only fading
|
||||
{
|
||||
distance_in_layer = 0.0;
|
||||
delta_zv = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
vAltitude = H + delta_z;
|
||||
distance_in_layer = vAltitude/H * dist;
|
||||
vAltitude = min(distance_in_layer,visibility) * (-ct);
|
||||
delta_zv = vAltitude;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ground haze cannot be thinner than aloft visibility in the model,
|
||||
// so we need to use aloft visibility otherwise
|
||||
transmission_arg = (dist-distance_in_layer)/avisibility;
|
||||
|
||||
float eqColorFactor;
|
||||
|
||||
|
||||
|
||||
if (visibility < avisibility)
|
||||
{
|
||||
transmission_arg = transmission_arg + (distance_in_layer/visibility);
|
||||
// this combines the Weber-Fechner intensity
|
||||
eqColorFactor = 1.0 - 0.1 * delta_zv/visibility - (1.0 -effective_scattering);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
transmission_arg = transmission_arg + (distance_in_layer/avisibility);
|
||||
// this combines the Weber-Fechner intensity
|
||||
eqColorFactor = 1.0 - 0.1 * delta_zv/avisibility - (1.0 -effective_scattering);
|
||||
}
|
||||
|
||||
transmission = fog_func(transmission_arg, alt);
|
||||
|
||||
// there's always residual intensity, we should never be driven to zero
|
||||
if (eqColorFactor < 0.2) {eqColorFactor = 0.2;}
|
||||
|
||||
float lightArg = (terminator-yprime_alt)/100000.0;
|
||||
vec3 hazeColor = get_hazeColor(lightArg);
|
||||
|
||||
// now dim the light for haze
|
||||
eShade = 1.0 - 0.9 * smoothstep(-terminator_width+ terminator, terminator_width + terminator, yprime_alt);
|
||||
|
||||
// Mie-like factor
|
||||
if (lightArg < 10.0)
|
||||
{intensity = length(hazeColor);
|
||||
float mie_magnitude = 0.5 * smoothstep(350000.0, 150000.0, terminator-sqrt(2.0 * EarthRadius * terrain_alt));
|
||||
hazeColor = intensity * ((1.0 - mie_magnitude) + mie_magnitude * mie_angle) * normalize(mix(hazeColor, vec3 (0.5, 0.58, 0.65), mie_magnitude * (0.5 - 0.5 * mie_angle)) );
|
||||
}
|
||||
|
||||
// high altitude desaturation of the haze color
|
||||
|
||||
intensity = length(hazeColor);
|
||||
hazeColor = intensity * normalize (mix(hazeColor, intensity * vec3 (1.0,1.0,1.0), 0.7* smoothstep(5000.0, 50000.0, alt)));
|
||||
|
||||
// blue hue of haze
|
||||
|
||||
hazeColor.x = hazeColor.x * 0.83;
|
||||
hazeColor.y = hazeColor.y * 0.9;
|
||||
|
||||
|
||||
// additional blue in indirect light
|
||||
float fade_out = max(0.65 - 0.3 *overcast, 0.45);
|
||||
intensity = length(hazeColor);
|
||||
hazeColor = intensity * normalize(mix(hazeColor, 1.5* shadedFogColor, 1.0 -smoothstep(0.25, fade_out,eShade) ));
|
||||
|
||||
// change haze color to blue hue for strong fogging
|
||||
//intensity = length(hazeColor);
|
||||
hazeColor = intensity * normalize(mix(hazeColor, shadedFogColor, (1.0-smoothstep(0.5,0.9,eqColorFactor))));
|
||||
|
||||
|
||||
// reduce haze intensity when looking at shaded surfaces, only in terminator region
|
||||
|
||||
float shadow = mix( min(1.0 + dot(normal,lightDir),1.0), 1.0, 1.0-smoothstep(0.1, 0.4, transmission));
|
||||
hazeColor = mix(shadow * hazeColor, hazeColor, 0.3 + 0.7* smoothstep(250000.0, 400000.0, terminator));
|
||||
|
||||
// don't let the light fade out too rapidly
|
||||
lightArg = (terminator + 200000.0)/100000.0;
|
||||
float minLightIntensity = min(0.2,0.16 * lightArg + 0.5);
|
||||
vec3 minLight = minLightIntensity * vec3 (0.2, 0.3, 0.4);
|
||||
hazeColor *= eqColorFactor * eShade;
|
||||
hazeColor.rgb = max(hazeColor.rgb, minLight.rgb);
|
||||
|
||||
// determine the right mix of transmission and haze
|
||||
|
||||
fragColor.rgb = mix(hazeColor, fragColor.rgb,transmission);
|
||||
}
|
||||
|
||||
fragColor.rgb = filter_combined(fragColor.rgb);
|
||||
|
||||
gl_FragColor = fragColor;
|
||||
|
||||
}
|
234
Shaders/ws30-ALS-ultra.vert
Normal file
234
Shaders/ws30-ALS-ultra.vert
Normal file
|
@ -0,0 +1,234 @@
|
|||
// WS30 VERTEX SHADER
|
||||
// -*-C++-*-
|
||||
#version 120
|
||||
|
||||
// Shader that uses OpenGL state values to do per-pixel lighting
|
||||
//
|
||||
// The only light used is gl_LightSource[0], which is assumed to be
|
||||
// directional.
|
||||
//
|
||||
// Colors are not assigned in this shader, as they will come from
|
||||
// the landclass lookup in the fragment shader.
|
||||
// Haze part added by Thorsten Renk, Oct. 2011
|
||||
|
||||
|
||||
#define MODE_OFF 0
|
||||
#define MODE_DIFFUSE 1
|
||||
#define MODE_AMBIENT_AND_DIFFUSE 2
|
||||
|
||||
attribute vec2 orthophotoTexCoord;
|
||||
|
||||
// The constant term of the lighting equation that doesn't depend on
|
||||
// the surface normal is passed in gl_{Front,Back}Color. The alpha
|
||||
// component is set to 1 for front, 0 for back in order to work around
|
||||
// bugs with gl_FrontFacing in the fragment shader.
|
||||
varying vec4 diffuse_term;
|
||||
varying vec3 normal;
|
||||
varying vec3 relPos;
|
||||
varying vec2 orthoTexCoord;
|
||||
varying vec4 ecPosition;
|
||||
|
||||
varying float yprime_alt;
|
||||
varying float mie_angle;
|
||||
|
||||
uniform int colorMode;
|
||||
uniform float hazeLayerAltitude;
|
||||
uniform float terminator;
|
||||
uniform float terrain_alt;
|
||||
uniform float avisibility;
|
||||
uniform float visibility;
|
||||
uniform float overcast;
|
||||
uniform float ground_scattering;
|
||||
uniform float moonlight;
|
||||
|
||||
void setupShadows(vec4 eyeSpacePos);
|
||||
|
||||
// This is the value used in the skydome scattering shader - use the same here for consistency?
|
||||
const float EarthRadius = 5800000.0;
|
||||
const float terminator_width = 200000.0;
|
||||
|
||||
|
||||
float earthShade;
|
||||
|
||||
float light_func (in float x, in float a, in float b, in float c, in float d, in float e)
|
||||
{
|
||||
//x = x - 0.5;
|
||||
|
||||
// use the asymptotics to shorten computations
|
||||
if (x < -15.0) {return 0.0;}
|
||||
|
||||
return e / pow((1.0 + a * exp(-b * (x-c)) ),(1.0/d));
|
||||
}
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
|
||||
vec4 light_diffuse;
|
||||
vec4 light_ambient;
|
||||
vec3 shadedFogColor = vec3(0.55, 0.67, 0.88);
|
||||
vec3 moonLightColor = vec3 (0.095, 0.095, 0.15) * moonlight;
|
||||
|
||||
|
||||
//float yprime_alt;
|
||||
float yprime;
|
||||
float lightArg;
|
||||
float intensity;
|
||||
float vertex_alt;
|
||||
float scattering;
|
||||
|
||||
// this code is copied from default.vert
|
||||
|
||||
vec4 ecPosition = gl_ModelViewMatrix * gl_Vertex;
|
||||
gl_Position = ftransform();
|
||||
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
|
||||
orthoTexCoord = orthophotoTexCoord;
|
||||
normal = gl_NormalMatrix * gl_Normal;
|
||||
|
||||
// here start computations for the haze layer
|
||||
// we need several geometrical quantities
|
||||
|
||||
// first current altitude of eye position in model space
|
||||
vec4 ep = gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0);
|
||||
|
||||
// and relative position to vector
|
||||
relPos = gl_Vertex.xyz - ep.xyz;
|
||||
|
||||
// unfortunately, we need the distance in the vertex shader, although the more accurate version
|
||||
// is later computed in the fragment shader again
|
||||
float dist = length(relPos);
|
||||
|
||||
// altitude of the vertex in question, somehow zero leads to artefacts, so ensure it is at least 100m
|
||||
vertex_alt = max(gl_Vertex.z,100.0);
|
||||
scattering = ground_scattering + (1.0 - ground_scattering) * smoothstep(hazeLayerAltitude -100.0, hazeLayerAltitude + 100.0, vertex_alt);
|
||||
|
||||
|
||||
// branch dependent on daytime
|
||||
|
||||
if (terminator < 1000000.0) // the full, sunrise and sunset computation
|
||||
{
|
||||
|
||||
|
||||
// establish coordinates relative to sun position
|
||||
|
||||
vec3 lightFull = (gl_ModelViewMatrixInverse * gl_LightSource[0].position).xyz;
|
||||
vec3 lightHorizon = normalize(vec3(lightFull.x,lightFull.y, 0.0));
|
||||
|
||||
|
||||
|
||||
// yprime is the distance of the vertex into sun direction
|
||||
yprime = -dot(relPos, lightHorizon);
|
||||
|
||||
// this gets an altitude correction, higher terrain gets to see the sun earlier
|
||||
yprime_alt = yprime - sqrt(2.0 * EarthRadius * vertex_alt);
|
||||
|
||||
// two times terminator width governs how quickly light fades into shadow
|
||||
// now the light-dimming factor
|
||||
earthShade = 0.6 * (1.0 - smoothstep(-terminator_width+ terminator, terminator_width + terminator, yprime_alt)) + 0.4;
|
||||
|
||||
// parametrized version of the Flightgear ground lighting function
|
||||
lightArg = (terminator-yprime_alt)/100000.0;
|
||||
|
||||
// directional scattering for low sun
|
||||
if (lightArg < 10.0)
|
||||
{mie_angle = (0.5 * dot(normalize(relPos), normalize(lightFull)) ) + 0.5;}
|
||||
else
|
||||
{mie_angle = 1.0;}
|
||||
|
||||
|
||||
|
||||
|
||||
light_diffuse.b = light_func(lightArg, 1.330e-05, 0.264, 3.827, 1.08e-05, 1.0);
|
||||
light_diffuse.g = light_func(lightArg, 3.931e-06, 0.264, 3.827, 7.93e-06, 1.0);
|
||||
light_diffuse.r = light_func(lightArg, 8.305e-06, 0.161, 3.827, 3.04e-05, 1.0);
|
||||
light_diffuse.a = 1.0;
|
||||
light_diffuse = light_diffuse * scattering;
|
||||
|
||||
|
||||
light_ambient.r = light_func(lightArg, 0.236, 0.253, 1.073, 0.572, 0.33);
|
||||
light_ambient.g = light_ambient.r * 0.4/0.33;
|
||||
light_ambient.b = light_ambient.r * 0.5/0.33;
|
||||
light_ambient.a = 1.0;
|
||||
|
||||
|
||||
|
||||
|
||||
// correct ambient light intensity and hue before sunrise
|
||||
if (earthShade < 0.5)
|
||||
{
|
||||
//light_ambient = light_ambient * (0.7 + 0.3 * smoothstep(0.2, 0.5, earthShade));
|
||||
intensity = length(light_ambient.xyz);
|
||||
|
||||
light_ambient.rgb = intensity * normalize(mix(light_ambient.rgb, shadedFogColor, 1.0 -smoothstep(0.4, 0.8,earthShade) ));
|
||||
light_ambient.rgb = light_ambient.rgb + moonLightColor * (1.0 - smoothstep(0.4, 0.5, earthShade));
|
||||
|
||||
intensity = length(light_diffuse.xyz);
|
||||
light_diffuse.rgb = intensity * normalize(mix(light_diffuse.rgb, shadedFogColor, 1.0 -smoothstep(0.4, 0.7,earthShade) ));
|
||||
}
|
||||
|
||||
|
||||
// the haze gets the light at the altitude of the haze top if the vertex in view is below
|
||||
// but the light at the vertex if the vertex is above
|
||||
|
||||
vertex_alt = max(vertex_alt,hazeLayerAltitude);
|
||||
|
||||
if (vertex_alt > hazeLayerAltitude)
|
||||
{
|
||||
if (dist > 0.8 * avisibility)
|
||||
{
|
||||
vertex_alt = mix(vertex_alt, hazeLayerAltitude, smoothstep(0.8*avisibility, avisibility, dist));
|
||||
yprime_alt = yprime -sqrt(2.0 * EarthRadius * vertex_alt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vertex_alt = hazeLayerAltitude;
|
||||
yprime_alt = yprime -sqrt(2.0 * EarthRadius * vertex_alt);
|
||||
}
|
||||
|
||||
}
|
||||
else // the faster, full-day version without lightfields
|
||||
{
|
||||
//vertex_alt = max(gl_Vertex.z,100.0);
|
||||
|
||||
earthShade = 1.0;
|
||||
mie_angle = 1.0;
|
||||
|
||||
if (terminator > 3000000.0)
|
||||
{light_diffuse = vec4 (1.0, 1.0, 1.0, 0.0);
|
||||
light_ambient = vec4 (0.33, 0.4, 0.5, 0.0); }
|
||||
else
|
||||
{
|
||||
|
||||
lightArg = (terminator/100000.0 - 10.0)/20.0;
|
||||
light_diffuse.b = 0.78 + lightArg * 0.21;
|
||||
light_diffuse.g = 0.907 + lightArg * 0.091;
|
||||
light_diffuse.r = 0.904 + lightArg * 0.092;
|
||||
light_diffuse.a = 1.0;
|
||||
|
||||
light_ambient.r = 0.316 + lightArg * 0.016;
|
||||
light_ambient.g = light_ambient.r * 0.4/0.33;
|
||||
light_ambient.b = light_ambient.r * 0.5/0.33;
|
||||
light_ambient.a = 1.0;
|
||||
}
|
||||
|
||||
light_diffuse = light_diffuse * scattering;
|
||||
yprime_alt = -sqrt(2.0 * EarthRadius * hazeLayerAltitude);
|
||||
}
|
||||
|
||||
|
||||
// default lighting based on texture and material using the light we have just computed
|
||||
|
||||
diffuse_term = light_diffuse;
|
||||
vec4 constant_term = (gl_LightModel.ambient + light_ambient);
|
||||
// Another hack for supporting two-sided lighting without using
|
||||
// gl_FrontFacing in the fragment shader.
|
||||
gl_FrontColor.rgb = constant_term.rgb; gl_FrontColor.a = 1.0;
|
||||
gl_BackColor.rgb = constant_term.rgb; gl_BackColor.a = 0.0;
|
||||
|
||||
setupShadows(gl_ModelViewMatrix * gl_Vertex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ varying vec3 normal;
|
|||
varying vec3 relPos;
|
||||
|
||||
uniform sampler2D landclass;
|
||||
uniform sampler2DArray atlas;
|
||||
uniform sampler2DArray textureArray;
|
||||
uniform sampler1D dimensionsArray;
|
||||
uniform sampler1D diffuseArray;
|
||||
uniform sampler1D specularArray;
|
||||
|
@ -55,11 +55,29 @@ float luminance(vec3 color)
|
|||
}
|
||||
|
||||
|
||||
// Test-phase code:
|
||||
|
||||
float rand2D(in vec2 co);
|
||||
|
||||
// Create random landclasses without a texture lookup to stress test
|
||||
// Each square of square_size in m is assigned a random landclass value
|
||||
int get_random_landclass(in vec2 co)
|
||||
{
|
||||
float square_size = 200.0;
|
||||
//float r = rand2D( floor(vec2(co.s*tile_width, co.t*tile_height)/square_size) );
|
||||
float r = rand2D( floor(vec2(co.s*tile_height, co.t*tile_width)/square_size) );
|
||||
int lc = int(r*48.0); // only 48 landclasses mapped so far
|
||||
return lc;
|
||||
}
|
||||
|
||||
float Noise2D(in vec2 coord, in float wavelength);
|
||||
// End Test-phase code
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 shadedFogColor = vec3(0.55, 0.67, 0.88);
|
||||
// this is taken from default.frag
|
||||
// this is taken from default.frag
|
||||
vec3 n;
|
||||
float NdotL, NdotHV, fogFactor;
|
||||
vec3 lightDir = gl_LightSource[0].position.xyz;
|
||||
|
@ -69,16 +87,46 @@ void main()
|
|||
vec4 specular = vec4(0.0);
|
||||
float intensity;
|
||||
|
||||
int lc = int(texture2D(landclass, gl_TexCoord[0].st).g * 255.0 + 0.5);
|
||||
float mat_index = float(lc)/512.0;
|
||||
float mat_shininess = texture(dimensionsArray, mat_index).z;
|
||||
vec4 mat_diffuse = texture(diffuseArray, mat_index);
|
||||
vec4 mat_specular = texture(specularArray, mat_index);
|
||||
|
||||
|
||||
// Oct 2021:
|
||||
// Geometry is in the form of roughly rectangular 'tiles'
|
||||
// with a mesh forming a grid with regular spacing.
|
||||
// Each vertex in the mesh is given an elevation
|
||||
|
||||
// Tile dimensions in m
|
||||
vec2 tile_size = vec2(tile_width , tile_height);
|
||||
// Temp: sizes are the wrong way around currently
|
||||
tile_size.xy =tile_size.yx;
|
||||
|
||||
// Tile texture coordinates range [0..1] over the tile 'rectangle'
|
||||
vec2 tile_coord = gl_TexCoord[0].st;
|
||||
|
||||
// Look up the landclass id [0 .. 255] for this particular fragment
|
||||
// Each tile has 1 texture containing landclass ids stetched over it
|
||||
|
||||
// Testing. Landclass sources: texture or random
|
||||
int tlc = int(texture2D(landclass, tile_coord.st).g * 255.0 + 0.5);
|
||||
//int rlc = get_random_landclass(tile_coord.st);
|
||||
int lc = tlc;
|
||||
|
||||
// The landclass id is used to index into arrays containing
|
||||
// material parameters and textures for the landclass as
|
||||
// defined in the regional definitions
|
||||
float index = float(lc)/512.0;
|
||||
|
||||
float mat_shininess = texture(dimensionsArray, index).z;
|
||||
vec4 mat_diffuse = texture(diffuseArray, index);
|
||||
vec4 mat_specular = texture(specularArray, index);
|
||||
|
||||
vec4 color = mat_diffuse * NdotL * gl_LightSource[0].diffuse;
|
||||
|
||||
float effective_scattering = min(scattering, cloud_self_shading);
|
||||
// Testing code:
|
||||
// Use rlc even when looking up textures to recreate the extra performance hit
|
||||
// so any performance difference between the two is due to the texture lookup
|
||||
// color = color+0.00001*float(rlc);
|
||||
|
||||
float effective_scattering = min(scattering, cloud_self_shading);
|
||||
|
||||
vec4 light_specular = gl_LightSource[0].specular;
|
||||
|
||||
|
@ -106,25 +154,30 @@ void main()
|
|||
color = clamp(color, 0.0, 1.0);
|
||||
|
||||
|
||||
// Different textures have different have different dimensions.
|
||||
// Dimensions array is scaled to fit in [0...1.0] in the texture1D, so has to be scaled back up here.
|
||||
// Look up ground textures by indexing into the texture array.
|
||||
// Different textures are stretched along the ground to different
|
||||
// lengths along each axes as set by <xsize> and <ysize>
|
||||
// regional definitions parameters
|
||||
|
||||
// The Landclass for this particular fragment. This can be used to
|
||||
// index into the atlas textures.
|
||||
vec2 atlas_dimensions = 10000.0 * texture(dimensionsArray, float(lc)/512.0).st;
|
||||
vec2 atlas_scale = vec2(tile_width / atlas_dimensions.s, tile_height / atlas_dimensions.t );
|
||||
vec2 st = atlas_scale * gl_TexCoord[0].st;
|
||||
// Look up stretching dimensions of textures in m - scaled to fit in [0..1], so rescale
|
||||
vec2 g_texture_stretch_dim = 10000.0 * texture(dimensionsArray, index).st;
|
||||
|
||||
// Rotate texture using the perlin texture as a mask to reduce tiling
|
||||
if (step(0.5, texture(perlin, atlas_scale * gl_TexCoord[0].st / 8.0).r) == 1.0) {
|
||||
st = vec2(atlas_scale.s * gl_TexCoord[0].t, atlas_scale.t * gl_TexCoord[0].s);
|
||||
}
|
||||
vec2 g_texture_scale = tile_size.xy / g_texture_stretch_dim.xy;
|
||||
// Ground texture coords
|
||||
vec2 st = g_texture_scale * tile_coord.st;
|
||||
|
||||
if (step(0.5, texture(perlin, - atlas_scale * gl_TexCoord[0].st / 16.0).r) == 1.0) {
|
||||
st = -st;
|
||||
}
|
||||
// Rotate texture using the perlin texture as a mask to reduce tiling
|
||||
float pnoise1 = texture(perlin, st / 8.0).r;
|
||||
float pnoise2 = texture(perlin, - st / 16.0).r;
|
||||
|
||||
texel = texture(atlas, vec3(st, lc));
|
||||
//Testing: Non texture alternative
|
||||
//float pnoise1 = Noise2D(st, 8.0);
|
||||
//float pnoise2 = Noise2D(-st, 16.0);
|
||||
|
||||
if (pnoise1 >= 0.5) st = g_texture_scale.st * tile_coord.ts;
|
||||
if (pnoise2 >= 0.5) st = -st;
|
||||
|
||||
texel = texture(textureArray, vec3(st, lc));
|
||||
|
||||
fragColor = color * texel + specular;
|
||||
fragColor.rgb += getClusteredLightsContribution(ecPosition.xyz, n, texel.rgb);
|
||||
|
|
Loading…
Reference in a new issue