1
0
Fork 0

Impostors simulating distant clouds for Advanced Weather / ALS

This commit is contained in:
Thorsten Renk 2014-02-17 10:21:26 +02:00
parent a505e29309
commit 22e3852cad
8 changed files with 492 additions and 1 deletions

168
Effects/cloud-impostor.eff Normal file
View file

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="utf-8"?>
<PropertyList>
<name>Effects/cloud-impostor</name>
<parameters>
<texture n ="0">
</texture>
<range><use>/sim/rendering/clouds3d-vis-range</use></range>
<terminator><use>/environment/terminator-relative-position-m</use></terminator>
<altitude><use>/sim/rendering/eye-altitude-m</use></altitude>
<cloud_self_shading><use>/environment/cloud-self-shading</use></cloud_self_shading>
<moonlight><use>/environment/moonlight</use></moonlight>
<air_pollution><use>/environment/air-pollution-norm</use></air_pollution>
</parameters>
<technique n="9">
<predicate>
<and>
<property>/sim/rendering/shaders/skydome</property>
<property>/sim/rendering/clouds3d-enable</property>
<less-equal>
<value type="float">1.0</value>
<shader-language/>
</less-equal>
</and>
</predicate>
<pass n="0">
<!-- This is apparently not used, so maybe we'll blow it way soon. -->
<lighting>true</lighting>
<material>
<ambient type="vec4d">0.5 0.5 0.5 1.0</ambient>
<diffuse type="vec4d">0.5 0.5 0.5 1.0</diffuse>
<color-mode>off</color-mode>
</material>
<alpha-test>
<comparison>greater</comparison>
<reference type="float">0.01</reference>
</alpha-test>
<shade-model>smooth</shade-model>
<blend>
<source>src-alpha</source>
<destination>one-minus-src-alpha</destination>
</blend>
<depth>
<write-mask>false</write-mask>
</depth>
<render-bin>
<bin-number>9</bin-number>
<bin-name>DepthSortedBin</bin-name>
</render-bin>
<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>
<!--<wrap-s>clamp</wrap-s>
<wrap-t>clamp</wrap-t>-->
</texture-unit>
<program>
<vertex-shader>Shaders/cloud-impostor-lightfield.vert</vertex-shader>
<fragment-shader>Shaders/cloud-static-lightfield.frag</fragment-shader>
</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>terminator</name>
<type>float</type>
<value><use>terminator</use></value>
</uniform>
<uniform>
<name>altitude</name>
<type>float</type>
<value><use>altitude</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>
<vertex-program-two-side>true</vertex-program-two-side>
</pass>
</technique>
<technique n="10">
<predicate>
<and>
<property>/sim/rendering/clouds3d-enable</property>
<less-equal>
<value type="float">1.0</value>
<shader-language/>
</less-equal>
</and>
</predicate>
<pass n="0">
<!-- This is apparently not used, so maybe we'll blow it way soon. -->
<lighting>true</lighting>
<material>
<ambient type="vec4d">0.5 0.5 0.5 1.0</ambient>
<diffuse type="vec4d">0.5 0.5 0.5 1.0</diffuse>
<color-mode>off</color-mode>
</material>
<alpha-test>
<comparison>greater</comparison>
<reference type="float">0.01</reference>
</alpha-test>
<shade-model>smooth</shade-model>
<blend>
<source>src-alpha</source>
<destination>one-minus-src-alpha</destination>
</blend>
<depth>
<write-mask>false</write-mask>
</depth>
<render-bin>
<bin-number>9</bin-number>
<bin-name>DepthSortedBin</bin-name>
</render-bin>
<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>
<!--<wrap-s>clamp</wrap-s>
<wrap-t>clamp</wrap-t>-->
</texture-unit>
<program>
<vertex-shader>Shaders/cloud-static.vert</vertex-shader>
<fragment-shader>Shaders/cloud-static.frag</fragment-shader>
</program>
<uniform>
<name>baseTexture</name>
<type>sampler-2d</type>
<value type="int">0</value>
</uniform>
<uniform>
<name>terminator</name>
<type>float</type>
<value><use>terminator</use></value>
</uniform>
<uniform>
<name>altitude</name>
<type>float</type>
<value><use>altitude</use></value>
</uniform>
<vertex-program-two-side>true</vertex-program-two-side>
</pass>
</technique>
</PropertyList>

View file

@ -536,6 +536,27 @@ else if (type=="Noctilucent") {
else if (rn > 0.25) {path = "Models/Weather/noctilucent9.xml";}
else {path = "Models/Weather/noctilucent10.xml";}
}
else if (type=="Impostor sheet") {
if (subtype=="Nimbus") {
if (rn>0.0) {path = "Models/Weather/impostor_nimbus.xml";}
}
else if (subtype=="broken") {
if (rn>0.5) {path = "Models/Weather/impostor_broken1.xml";}
else if (rn>0.0) {path = "Models/Weather/impostor_broken2.xml";}
}
else if (subtype=="scattered") {
if (rn>0.6) {path = "Models/Weather/impostor_scattered1.xml";}
else if (rn>0.4) {path = "Models/Weather/impostor_scattered2.xml";}
else if (rn > 0.2) {path = "Models/Weather/impostor_few1.xml";}
else {path = "Models/Weather/impostor_few2.xml";}
}
else if (subtype=="few") {
if (rn>0.7) {path = "Models/Weather/impostor_few1.xml";}
else if (rn>0.4) {path = "Models/Weather/impostor_few2.xml";}
else if (rn>0.3) {path = "Models/Weather/impostor_scattered2.xml";}
else {path = "void";}
}
}
else if (type == "Cirrocumulus (cloudlet)") {
cloudAssembly = local_weather.cloud.new(type, subtype);

View file

@ -20,6 +20,7 @@
# setWindSmoothly to set the wind gradually across a second
# smooth_wind_loop (helper function for setWindSmoothly)
# create_cloud to place a single cloud into the scenery
# create_impostor to place an impostor sheet mimicking far clouds into the scene
# create_cloud_array to place clouds from storage arrays into the scenery
# get_elevation to get the terrain elevation at given coordinates
# get_elevation_vector to get terrain elevation at given coordinate vector
@ -542,7 +543,36 @@ if (local_weather.dynamics_flag == 1)
}
###########################################################
# place an impostor sheet
###########################################################
var create_impostor = func(path, lat, long, alt, heading) {
var n = props.globals.getNode("local-weather/clouds", 1);
var model_number = n.getNode("model-placement-index").getValue();
var m = props.globals.getNode("models", 1);
for (var i = model_number; 1; i += 1)
if (m.getChild("model", i, 0) == nil)
break;
var model = m.getChild("model", i, 1);
n.getNode("model-placement-index").setValue(i);
model.getNode("path", 1).setValue(path);
model.getNode("latitude-deg", 1).setValue(lat);
model.getNode("longitude-deg", 1).setValue(long);
model.getNode("elevation-ft", 1).setValue(alt);
model.getNode("heading-deg", 1).setValue(local_weather.wind.cloudlayer[0]+180.0);
model.getNode("speed-kt",1).setValue(local_weather.wind.cloudlayer[1]);
model.getNode("load", 1).remove();
var imp = weather_tile_management.cloudImpostor.new(model);
append(weather_tile_management.cloudImpostorArray,imp);
}
###########################################################

View file

@ -1687,6 +1687,9 @@ settimer ( func { setsize(weather_dynamics.cloudQuadtrees,0);},0.1); # to avoid
setsize(effectVolumeArray,0);
n_effectVolumeArray = 0;
# remove any impostors
weather_tile_management.remove_impostors();
# clear any wxradar echos
@ -3676,6 +3679,12 @@ if (compat_layer.features.can_disable_environment ==1)
local_weather.setDefaultCloudsOff();
# read max. visibility range and set far camera clipping
max_vis_range = math.exp(getprop(lw~"config/aux-max-vis-range-m"));
setprop(lw~"config/max-vis-range-m",max_vis_range);
if (max_vis_range>120000.0){setprop("/sim/rendering/camera-group/zfar",max_vis_range);}
# now see if we need to presample the terrain
if ((presampling_flag == 1) and (getprop(lw~"tmp/presampling-status") == "idle"))
@ -3972,6 +3981,8 @@ local_weather.init_sea_colors();
# start the mask loop
#local_weather.init_mask();
# create impostors - this should only happen when sufficiently high in air
weather_tile_management.create_impostors();
# weather_tile_management.watchdog_loop();

View file

@ -14,6 +14,8 @@
# create_neighbours to initialize the 8 neighbours of the initial tile
# buffer_loop to manage the buffering of faraway clouds in an array
# housekeeping_loop to shift clouds from the scenery into the buffer
# remove_impostors to delete a ring of impostors to mimick distant clouds
# create_impostors to create a ring of impostors to mimick distant clouds
# watchdog loop (debug helping structure)
# calc_geo to get local Cartesian geometry for latitude conversion
# get_lat to get latitude from Cartesian coordinates
@ -27,6 +29,7 @@
# cloud to provide the data hash for the new cloud rendering system
# cloudBuffer to store a cloud in a Nasal buffer, to provide methods to move it
# cloudScenery to store info for clouds in scenery, to provide methods to move and evolve them
# cloudImpostor to provide the hash data for an impostor cloud sheet
###################################
@ -876,6 +879,11 @@ if (system_rotation_angle > 0.0)
create_neighbour(lat, lon, 9, alpha);
rotate_tile_scheme(system_rotation_angle);
}
# ready the system for creating impostors
impostor_trigger = 1;
}
@ -1190,6 +1198,57 @@ if (getprop(lw~"housekeeping-loop-flag") ==1) {settimer( func {housekeeping_loop
}
###############################
# impostor handline routines
###############################
var impostor_trigger = 0;
var impostor_type_map = {"low_pressure_core" : "Nimbus", "low_pressure" : "broken", "low_pressure_border": "broken", "high_pressure_border" : "scattered", "high_pressure" : "few", "high_pressure_core": "few"};
var remove_impostors = func {
foreach (entry;cloudImpostorArray)
{
entry.removeNodes();
}
setsize(cloudImpostorArray,0);
}
var create_impostors = func {
var visibility = getprop("/environment/visibility-m");
var cloud_range = getprop("/sim/rendering/clouds3d-vis-range");
if ((visibility < 80000.0) or (cloud_range < 70000.0)) {return;}
if (visibility < cloud_range) {var range = visibility;}
else {var range = cloud_range;}
var n = int ((range - 60000.0)/40000.0);
var lat = getprop(lw~"tiles/tile[4]/latitude-deg");
var lon = getprop(lw~"tiles/tile[4]/longitude-deg");
var alpha = getprop(lw~"tiles/tile[4]/orientation-deg");
var code = getprop(lw~"tiles/tile[4]/code");
var index = getprop(lw~"tiles/tile[4]/tile-index");
var alt_offset = getprop(lw~"tmp/tile-alt-offset-ft");
var alt = weather_dynamics.tile_convective_altitude[index-1] + 1000.0 + alt_offset;
if (contains(impostor_type_map,code)) {var type = impostor_type_map[code];}
else {var type = "scattered";}
if (local_weather.debug_output_flag == 1)
{
printf("Creating impostor ring...");
print(lat, " ", lon, " ", alt, " ", alpha, " ", type, " ", n);
}
weather_tiles.create_impostor_ring(lat, lon, alt, alpha, type, n);
}
###############################
# watchdog loop for debugging
###############################
@ -1369,6 +1428,21 @@ var cloudBuffer = {
};
var cloudImpostorArray = [];
var cloudImpostor = {
new: func(modelNode) {
var c = { parents: [cloudImpostor] };
c.modelNode = modelNode;
return c;
},
removeNodes: func {
me.modelNode.remove();
},
};
var cloudSceneryArray = [];
var n_cloudSceneryArray = 0;

View file

@ -78,6 +78,15 @@ else # without worker threads, tile generation is complete at this point
{props.globals.getNode(lw~"tiles").getChild("tile",dir_index).getNode("generated-flag").setValue(2);}
# generate impostor ring if applicable
if (impostor_trigger == 1)
{
weather_tile_management.remove_impostors();
weather_tile_management.create_impostors();
impostor_trigger = 0;
}
}
@ -4418,6 +4427,38 @@ for (var i=0; i<2; i=i+1)
}
var create_impostor_ring = func (lat, lon, alt, alpha, type, n) {
var path = local_weather.select_cloud_model("Impostor sheet", type);
var phi = alpha * math.pi/180.0;
var limit = 4 + 2 * n;
for (var i = 0; i< limit+1; i=i+1)
{
for (var j = 0; j<limit+1; j=j+1)
{
x = -limit * 20.0 + i * 40.0;
y = -limit * 20.0 + j * 40.0;
var dsq = x*x + y*y;
if (dsq > 6000.0)
{
x=x*1000.0; y=y*1000.0;
path = local_weather.select_cloud_model("Impostor sheet", type);
if (path != "void")
{
var rnd = rand();
if (rnd > 0.75) {alpha = alpha + 90.0;}
compat_layer.create_impostor(path, lat + get_lat(x,y,phi), lon+get_lon(x,y,phi), alt ,alpha);
}
}
}
}
}
###################
# helper functions
###################

View file

@ -0,0 +1,146 @@
// -*-C++-*-
#version 120
varying float fogFactor;
varying vec3 hazeColor;
uniform float terminator;
uniform float altitude;
uniform float cloud_self_shading;
uniform float moonlight;
uniform float air_pollution;
uniform float range;
const float shade = 1.0;
const float cloud_height = 1000.0;
const float EarthRadius = 5800000.0;
// light_func is a generalized logistic function fit to the light intensity as a function
// of scaled terminator position obtained from Flightgear core
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 > 30.0) {return e;}
if (x < -15.0) {return 0.03;}
return e / pow((1.0 + a * exp(-b * (x-c)) ),(1.0/d));
}
void main(void)
{
vec3 shadedFogColor = vec3 (0.65, 0.67, 0.78);
vec3 moonLightColor = vec3 (0.095, 0.095, 0.15) * moonlight;
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
//gl_TexCoord[0] = gl_MultiTexCoord0 + vec4(textureIndexX, textureIndexY, 0.0, 0.0);
vec4 ep = gl_ModelViewMatrixInverse * vec4(0.0,0.0,0.0,1.0);
vec4 l = gl_ModelViewMatrixInverse * vec4(0.0,0.0,1.0,1.0);
vec3 u = normalize(ep.xyz - l.xyz);
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_Position.x = gl_Vertex.x;
gl_Position.y += gl_Vertex.y;
gl_Position.z += gl_Vertex.z;
gl_Position.xyz += gl_Color.xyz;
// 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.
float n = dot(normalize(-gl_LightSource[0].position.xyz),
normalize(mat3x3(gl_ModelViewMatrix) * (- gl_Position.xyz)));;
// Determine the position - used for fog and shading calculations
vec3 ecPosition = vec3(gl_ModelViewMatrix * gl_Position);
float fogCoord = abs(ecPosition.z);
float fract = smoothstep(0.0, cloud_height, gl_Position.z + cloud_height);
vec3 relVector = gl_Position.xyz - ep.xyz;
gl_Position = gl_ModelViewProjectionMatrix * gl_Position;
// Light at the final position
// first obtain normal 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, corrected for altitude
//float vertex_alt = max(altitude * 0.30480 + relVector.z,100.0);
float vertex_alt = altitude + relVector.z;
float yprime = -dot(relVector, lightHorizon);
float yprime_alt = yprime -sqrt(2.0 * EarthRadius * vertex_alt);
// compute the light at the position
vec4 light_diffuse;
float lightArg = (terminator-yprime_alt)/100000.0;
light_diffuse.b = light_func(lightArg -1.2 * air_pollution, 1.330e-05, 0.264, 2.227, 1.08e-05, 1.0);
light_diffuse.g = light_func(lightArg -0.6 * air_pollution, 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;
//float light_intensity = light_func(lightArg, 8.305e-06, 0.161, 3.827, 3.04e-05, 1.0);
//vec4 light_diffuse = vec4 (0.57, 0.57, 0.9, 1.0);
//light_diffuse.rgb = light_intensity * light_diffuse.rgb;
// two times terminator width governs how quickly light fades into shadow
float terminator_width = 200000.0;
float earthShade = 0.9 * smoothstep(terminator_width+ terminator, -terminator_width + terminator, yprime_alt) + 0.1;
//float intensity = length(light_diffuse.rgb);
float intensity = (1.0 - (0.5 * (1.0 - earthShade))) * length(light_diffuse.rgb);
//light_diffuse.rgb = intensity * normalize(mix(light_diffuse.rgb, shadedFogColor, (1.0 - smoothstep(0.5,0.9, cloud_self_shading ))));
light_diffuse.rgb = intensity * normalize(mix(light_diffuse.rgb, shadedFogColor, (1.0 - smoothstep(0.5,0.9, cloud_self_shading ))));
if (earthShade < 0.6)
{
intensity = length(light_diffuse.rgb);
light_diffuse.rgb = intensity * normalize(mix(light_diffuse.rgb, shadedFogColor, 1.0 -smoothstep(0.1, 0.6,earthShade ) ));
}
// Determine the shading of the sprite based on its vertical position and position relative to the sun.
// n = min(smoothstep(-0.5, 0.0, n), fract);
// Determine the shading based on a mixture from the backlight to the front
//vec4 backlight = light_diffuse * shade;
gl_FrontColor = light_diffuse;//mix(backlight, light_diffuse, n);
//gl_FrontColor += gl_FrontLightModelProduct.sceneColor;
// As we get within 100m of the sprite, it is faded out. Equally at large distances it also fades out.
gl_FrontColor.a = min(smoothstep(100.0, 250.0, fogCoord), 1.0 - smoothstep(0.9 * range, range, fogCoord));
// During the day, noctilucent clouds are invisible
//gl_FrontColor.a = gl_FrontColor.a * (1.0 - smoothstep(3.0,5.0,lightArg));
// Fog doesn't affect rain as much as other objects.
//fogFactor = exp( -gl_Fog.density * fogCoord * 0.4);
//fogFactor = clamp(fogFactor, 0.0, 1.0);
float fadeScale = 0.05 + 0.2 * log(fogCoord/1000.0);
if (fadeScale < 0.05) fadeScale = 0.05;
fogFactor = exp( -gl_Fog.density * 0.5* fogCoord * fadeScale);
hazeColor = light_diffuse.rgb;
hazeColor.r = hazeColor.r * 0.83;
hazeColor.g = hazeColor.g * 0.9;
// in sunset or sunrise conditions, do extra shading of clouds
//hazeColor = hazeColor * earthShade;
//gl_FrontColor.rgb = gl_FrontColor.rgb * earthShade;
gl_FrontColor.rgb = gl_FrontColor.rgb + moonLightColor * (1.0 - smoothstep(0.4, 0.5, earthShade));
hazeColor.rgb = hazeColor.rgb + moonLightColor * (1.0 - smoothstep(0.4, 0.5, earthShade));
gl_BackColor = gl_FrontColor;
}

View file

@ -616,7 +616,7 @@
<slider>
<name>cloud-vis-range</name>
<min>1000.0</min>
<max>45000.0</max>
<max>150000.0</max>
<property>/sim/rendering/clouds3d-vis-range</property>
<binding>
<command>dialog-apply</command>