Experimental underwater lighting.

This commit is contained in:
Joshua Yanovski 2020-04-28 20:49:03 +02:00
parent 2c5ad9d076
commit ef67bd58ba
19 changed files with 425 additions and 134 deletions

View File

@ -40,6 +40,7 @@ void main() {
vec3 view_dir = -cam_to_frag;
// vec3 surf_color = /*srgb_to_linear*/(vec3(0.4, 0.7, 2.0));
/*const */vec3 water_color = srgb_to_linear(vec3(0.2, 0.5, 1.0));
// /*const */vec3 water_color = srgb_to_linear(vec3(0.0, 0.25, 0.5));
vec3 sun_dir = get_sun_dir(time_of_day.x);
vec3 moon_dir = get_moon_dir(time_of_day.x);
@ -112,7 +113,7 @@ void main() {
float passthrough = /*pow(*/dot(faceforward(f_norm, f_norm, cam_to_frag/*view_dir*/), -cam_to_frag/*view_dir*/)/*, 0.5)*/;
vec3 surf_color = illuminate(max_light, water_color * emitted_light, /*surf_color * */fog_color * reflected_light);
vec3 surf_color = illuminate(max_light, water_color * fog_color * emitted_light, /*surf_color * */water_color * reflected_light);
vec4 color = mix(vec4(surf_color, 1.0), vec4(surf_color, 1.0 / (1.0 + /*diffuse_light*//*(f_light * point_shadow + point_light)*/reflected_light_point/* * 0.25*/)), passthrough);
tgt_color = mix(mix(color, vec4(fog_color, 0.0), fog_level), vec4(clouds.rgb, 0.0), clouds.a);

View File

@ -102,19 +102,39 @@ void main() {
vec3 norm = vec3(0, 0, 1) * nmap.z + b_norm * nmap.x + c_norm * nmap.y;
float f_alt = alt_at_real(f_pos.xy);
float fluid_alt = max(ceil(f_pos.z), floor(f_alt));// f_alt;//max(f_alt - f_pos.z, 0.0);
const float alpha = 0.255/*/ / 4.0*//* / 4.0 / sqrt(2.0)*/;
const float n2 = 1.3325;
const float R_s2s0 = pow((1.0 - n2) / (1.0 + n2), 2);
const float R_s1s0 = pow((1.3325 - n2) / (1.3325 + n2), 2);
const float R_s2s1 = pow((1.0 - 1.3325) / (1.0 + 1.3325), 2);
const float R_s1s2 = pow((1.3325 - 1.0) / (1.3325 + 1.0), 2);
float R_s = (f_pos.z < fluid_alt) ? mix(R_s2s1 * R_s1s0, R_s1s0, medium.x) : mix(R_s2s0, R_s1s2 * R_s2s0, medium.x);
// Water is transparent so both normals are valid.
vec3 cam_norm = faceforward(norm, norm, cam_to_frag);
vec4 _clouds;
vec3 reflect_ray_dir = reflect(cam_to_frag/*-view_dir*/, norm);
vec3 refract_ray_dir = refract(cam_to_frag/*-view_dir*/, norm, 1.0 / n2);
vec3 sun_view_dir = cam_pos.z <= fluid_alt ? -view_dir : view_dir;
vec3 beam_view_dir = reflect_ray_dir;//cam_pos.z <= fluid_alt ? -refract_ray_dir : reflect_ray_dir;
/* vec4 reflect_ray_dir4 = view_mat * vec4(reflect_ray_dir, 1.0);
reflect_ray_dir = normalize(vec3(reflect_ray_dir4) / reflect_ray_dir4.w); */
// vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
// Squared to account for prior saturation.
float f_light = pow(f_light, 1.5);
vec3 reflect_color = get_sky_color(reflect_ray_dir, time_of_day.x, f_pos, vec3(-100000), 0.25, false, _clouds) * f_light;
/*const */vec3 water_color = srgb_to_linear(vec3(0.2, 0.5, 1.0));
vec3 reflect_color = get_sky_color(/*reflect_ray_dir*/beam_view_dir, time_of_day.x, f_pos, vec3(-100000), 0.25, false, _clouds) * f_light;
// /*const */vec3 water_color = srgb_to_linear(vec3(0.2, 0.5, 1.0));
// /*const */vec3 water_color = srgb_to_linear(vec3(0.8, 0.9, 1.0));
// NOTE: Linear RGB, attenuation coefficients for water at roughly R, G, B wavelengths.
// See https://en.wikipedia.org/wiki/Electromagnetic_absorption_by_water
/*const */vec3 water_attenuation = vec3(0.8, 0.05, 0.01);
// /*const */vec3 water_color = vec3(0.2, 0.95, 0.99);
vec3 sun_dir = get_sun_dir(time_of_day.x);
vec3 moon_dir = get_moon_dir(time_of_day.x);
float f_alt = alt_at(f_pos.xy);
vec4 f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy));
float sun_shade_frac = horizon_at2(f_shadow, f_alt, f_pos, sun_dir);
float moon_shade_frac = horizon_at2(f_shadow, f_alt, f_pos, moon_dir);
@ -122,16 +142,46 @@ void main() {
// float moon_shade_frac = horizon_at(/*f_shadow, f_pos.z, */f_pos, moon_dir);
float shade_frac = /*1.0;*/sun_shade_frac + moon_shade_frac;
const float alpha = 0.255/*/ / 4.0*//* / 4.0 / sqrt(2.0)*/;
const float n2 = 1.3325;
const float R_s2s0 = pow((1.0 - n2) / (1.0 + n2), 2);
const float R_s1s0 = pow((1.3325 - n2) / (1.3325 + n2), 2);
const float R_s2s1 = pow((1.0 - 1.3325) / (1.0 + 1.3325), 2);
const float R_s1s2 = pow((1.3325 - 1.0) / (1.3325 + 1.0), 2);
float R_s = (f_pos.z < f_alt) ? mix(R_s2s1 * R_s1s0, R_s1s0, medium.x) : mix(R_s2s0, R_s1s2 * R_s2s0, medium.x);
// Hack to determine water depth: color goes down with distance through water, so
// we assume water color absorption from this point a to some other point b is the distance
// along the the ray from a to b where it intersects with the surface plane; if it doesn't,
// then the whole segment from a to b is considered underwater.
// TODO: Consider doing for point lights.
// vec3 cam_surface_dir = faceforward(vec3(0.0, 0.0, 1.0), cam_to_frag, vec3(0.0, 0.0, 1.0));
// vec3 water_intersection_surface_camera = vec3(cam_pos);
// bool _water_intersects_surface_camera = IntersectRayPlane(f_pos, view_dir, vec3(0.0, 0.0, /*f_alt*/f_pos.z + f_light), cam_surface_dir, water_intersection_surface_camera);
// // Should work because we set it up so that if IntersectRayPlane returns false for camera, its default intersection point is cam_pos.
// float water_depth_to_camera = length(water_intersection_surface_camera - f_pos);
// vec3 water_intersection_surface_light = f_pos;
// bool _light_intersects_surface_water = IntersectRayPlane(f_pos, sun_dir.z <= 0.0 ? sun_dir : moon_dir, vec3(0.0, 0.0, /*f_alt*/f_pos.z + f_light), vec3(0.0, 0.0, 1.0), water_intersection_surface_light);
// // Should work because we set it up so that if IntersectRayPlane returns false for light, its default intersection point is f_pos--
// // i.e. if a light ray can't hit the water, it shouldn't contribute to coloring at all.
// float water_depth_to_light = length(water_intersection_surface_light - f_pos);
// // For ambient color, we just take the distance to the surface out of laziness.
// float water_depth_to_vertical = max(/*f_alt - f_pos.z*/f_light, 0.0);
// // Color goes down with distance...
// // See https://en.wikipedia.org/wiki/Beer%E2%80%93Lambert_law.
vec3 water_color_direct = vec3(1.0);//exp(-MU_WATER);//vec3(1.0);
// vec3 water_color_direct = exp(-water_attenuation * (water_depth_to_light + water_depth_to_camera));
// vec3 water_color_ambient = exp(-water_attenuation * (water_depth_to_vertical + water_depth_to_camera));
vec3 mu = MU_WATER;
// NOTE: Default intersection point is camera position, meaning if we fail to intersect we assume the whole camera is in water.
vec3 cam_attenuation = compute_attenuation_point(f_pos, -view_dir, mu, fluid_alt, cam_pos.xyz);
// float water_depth_to_vertical = max(/*f_alt - f_pos.z*/f_light, 0.0);
// For ambient color, we just take the distance to the surface out of laziness.
// See https://en.wikipedia.org/wiki/Beer%E2%80%93Lambert_law.
float water_depth_to_vertical = max(fluid_alt - cam_pos.z/*f_light*/, 0.0);
vec3 ambient_attenuation = exp(-mu * water_depth_to_vertical);
// For ambient reflection, we just take the water
vec3 k_a = vec3(1.0);
vec3 k_d = vec3(1.0);
// Oxygen is light blue.
vec3 k_d = vec3(/*vec3(0.2, 0.9, 0.99)*/1.0);
vec3 k_s = vec3(R_s);//2.0 * reflect_color;
vec3 emitted_light, reflected_light;
@ -142,21 +192,26 @@ void main() {
float passthrough = /*pow(*/dot(faceforward(f_norm, f_norm, cam_to_frag/*view_dir*/), -cam_to_frag/*view_dir*/)/*, 0.5)*/;
float max_light = 0.0;
max_light += get_sun_diffuse2(norm, /*time_of_day.x*/sun_dir, moon_dir, view_dir, k_a/* * (shade_frac * 0.5 + light_frac * 0.5)*/, vec3(0.0), /*vec3(f_light * point_shadow)*//*reflect_color*/k_s, alpha, emitted_light, reflected_light);
reflected_light *= reflect_color * f_light * point_shadow * shade_frac;
emitted_light *= f_light * point_shadow * max(shade_frac, MIN_SHADOW);
max_light += get_sun_diffuse2(norm, /*time_of_day.x*/sun_dir, moon_dir, sun_view_dir, f_pos, mu, cam_attenuation, fluid_alt, k_a/* * (shade_frac * 0.5 + light_frac * 0.5)*/, vec3(k_d), /*vec3(f_light * point_shadow)*//*reflect_color*/k_s, alpha, emitted_light, reflected_light);
reflected_light *= /*water_color_direct * */reflect_color * f_light * point_shadow * shade_frac;
emitted_light *= /*water_color_direct*//*ambient_attenuation * */f_light * point_shadow * max(shade_frac, MIN_SHADOW);
max_light *= f_light * point_shadow * shade_frac;
vec3 diffuse_light_point = vec3(0.0);
max_light += lights_at(f_pos, norm, view_dir, k_a, vec3(1.0), /*vec3(0.0)*/k_s, alpha, emitted_light, diffuse_light_point);
// vec3 diffuse_light_point = vec3(0.0);
// max_light += lights_at(f_pos, cam_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, vec3(1.0), /*vec3(0.0)*/k_s, alpha, emitted_light, diffuse_light_point);
vec3 dump_light = vec3(0.0);
vec3 specular_light_point = vec3(0.0);
lights_at(f_pos, norm, view_dir, vec3(0.0), vec3(0.0), /*vec3(1.0)*/k_s, alpha, dump_light, specular_light_point);
diffuse_light_point -= specular_light_point;
// vec3 dump_light = vec3(0.0);
// vec3 specular_light_point = vec3(0.0);
// lights_at(f_pos, cam_norm, view_dir, mu, cam_attenuation, fluid_alt, vec3(0.0), vec3(0.0), /*vec3(1.0)*/k_s, alpha, dump_light, specular_light_point);
// diffuse_light_point -= specular_light_point;
// max_light += lights_at(f_pos, cam_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, /*k_d*/vec3(0.0), /*vec3(0.0)*/k_s, alpha, emitted_light, /*diffuse_light*/reflected_light);
max_light += lights_at(f_pos, cam_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, /*k_d*//*vec3(0.0)*/k_d, /*vec3(0.0)*/k_s, alpha, emitted_light, /*diffuse_light*/reflected_light);
float reflected_light_point = length(reflected_light);///*length*/(diffuse_light_point.r) + f_light * point_shadow;
// TODO: See if we can be smarter about this using point light distances.
// reflected_light += k_d * (diffuse_light_point/* + f_light * point_shadow * shade_frac*/) + /*water_color_ambient*/specular_light_point;
float reflected_light_point = /*length*/(diffuse_light_point.r) + f_light * point_shadow;
reflected_light += reflect_color * k_d * (diffuse_light_point + f_light * point_shadow * shade_frac) + reflect_color * specular_light_point;
/* vec3 point_light = light_at(f_pos, norm);
emitted_light += point_light;
reflected_light += point_light; */
@ -169,12 +224,19 @@ void main() {
// diffuse_light += point_light;
// reflected_light += point_light;
// vec3 surf_color = srgb_to_linear(vec3(0.2, 0.5, 1.0)) * light * diffuse_light * ambient_light;
vec3 surf_color = illuminate(max_light, water_color * emitted_light, reflected_light);
vec3 surf_color = illuminate(max_light, emitted_light/* * log(1.0 - MU_WATER)*/, /*water_color * */reflected_light/* * log(1.0 - MU_WATER)*/);
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
vec4 clouds;
vec3 fog_color = get_sky_color(cam_to_frag/*-view_dir*/, time_of_day.x, cam_pos.xyz, f_pos, 0.25, true, clouds);
// passthrough = pow(passthrough, 1.0 / (1.0 + water_depth_to_camera));
/* surf_color = cam_attenuation.g < 0.5 ?
vec3(1.0, 0.0, 0.0) :
vec3(0.0, 1.0, 1.0)
; */
// passthrough = passthrough * length(cam_attenuation);
// vec3 reflect_ray_dir = reflect(cam_to_frag, norm);
// Hack to prevent the reflection ray dipping below the horizon and creating weird blue spots in the water
// reflect_ray_dir.z = max(reflect_ray_dir.z, 0.01);
@ -189,7 +251,11 @@ void main() {
// vec4 color = mix(vec4(surf_color, 1.0), vec4(surf_color, 0.0), passthrough);
//vec4 color = vec4(surf_color, 1.0);
// vec4 color = mix(vec4(reflect_color, 1.0), vec4(surf_color, 1.0 / (1.0 + /*diffuse_light*/(/*f_light * point_shadow*/reflected_light_point/* + point_light*//*reflected_light*/))), passthrough);
vec4 color = vec4(surf_color, mix(1.0, 1.0 / (1.0 + /*0.25 * *//*diffuse_light*/(/*f_light * point_shadow*/reflected_light_point)), passthrough));
vec4 color = vec4(surf_color, 1.0 - passthrough * /*log(1.0 + cam_attenuation)*/cam_attenuation);
// vec4 color = vec4(surf_color, mix(1.0, 1.0 / (1.0 + /*0.25 * *//*diffuse_light*/(/*f_light * point_shadow*/reflected_light_point)), passthrough));
// vec4 color = vec4(surf_color, mix(1.0, length(cam_attenuation), passthrough));
/* reflect_color = reflect_color * 0.5 * (diffuse_light + ambient_light);
// 0 = 100% reflection, 1 = translucent water
float passthrough = dot(faceforward(f_norm, f_norm, cam_to_frag), -cam_to_frag);

View File

@ -25,6 +25,41 @@ float attenuation_strength(vec3 rpos) {
return max(2.0 / pow(d2 + 10, 0.35) - pow(d2 / 50000.0, 0.8), 0.0);
}
// Linear RGB, attenuation coefficients for water at roughly R, G, B wavelengths.
// See https://en.wikipedia.org/wiki/Electromagnetic_absorption_by_water
const vec3 MU_WATER = vec3(0.6, 0.04, 0.01);
// // Compute attenuation due to light passing through a substance that fills an area below a horizontal plane
// // (e.g. in most cases, water below the water surface depth).
// //
// // wpos is the position of the point being hit.
// // ray_dir is the reversed direction of the ray (going "out" of the point being hit).
// // surface_alt is the estimated altitude of the horizontal surface separating the substance from air.
// // defaultpos is the position to use in computing the distance along material at this point if there was a failure.
// //
// // Ideally, defaultpos is set so we can avoid branching on error.
// float compute_attenuation_beam(vec3 wpos, vec3 ray_dir, float surface_alt, vec3 defaultpos, float attenuation_depth) {
// vec3 water_intersection_surface_camera = vec3(cam_pos);
// bool _water_intersects_surface_camera = IntersectRayPlane(f_pos, view_dir, vec3(0.0, 0.0, /*f_alt*/f_pos.z + f_light), cam_surface_dir, water_intersection_surface_camera);
// // Should work because we set it up so that if IntersectRayPlane returns false for camera, its default intersection point is cam_pos.
// float water_depth_to_camera = length(water_intersection_surface_camera - f_pos);
//
// vec3 water_intersection_surface_light = f_pos;
// bool _light_intersects_surface_water = IntersectRayPlane(f_pos, sun_dir.z <= 0.0 ? sun_dir : moon_dir, vec3(0.0, 0.0, /*f_alt*/f_pos.z + f_light), vec3(0.0, 0.0, 1.0), water_intersection_surface_light);
// // Should work because we set it up so that if IntersectRayPlane returns false for light, its default intersection point is f_pos--
// // i.e. if a light ray can't hit the water, it shouldn't contribute to coloring at all.
// float water_depth_to_light = length(water_intersection_surface_light - f_pos);
//
// // For ambient color, we just take the distance to the surface out of laziness.
// float water_depth_to_vertical = max(/*f_alt - f_pos.z*/f_light, 0.0);
//
// // Color goes down with distance...
// // See https://en.wikipedia.org/wiki/Beer%E2%80%93Lambert_law.
// vec3 water_color_direct = exp(-water_attenuation * (water_depth_to_light + water_depth_to_camera));
// vec3 water_color_ambient = exp(-water_attenuation * (water_depth_to_vertical + water_depth_to_camera));
//
// }
vec3 light_at(vec3 wpos, vec3 wnorm) {
const float LIGHT_AMBIENCE = 0.025;
@ -75,7 +110,11 @@ float shadow_at(vec3 wpos, vec3 wnorm) {
}
// Returns computed maximum intensity.
float lights_at(vec3 wpos, vec3 wnorm, vec3 cam_to_frag, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, inout vec3 emitted_light, inout vec3 reflected_light/*, out float shadow*/) {
//
// mu is the attenuation coefficient for any substance on a horizontal plane.
// cam_attenuation is the total light attenuation due to the substance for beams between the point and the camera.
// surface_alt is the altitude of the attenuating surface.
float lights_at(vec3 wpos, vec3 wnorm, vec3 cam_to_frag, vec3 mu, vec3 cam_attenuation, float surface_alt, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, inout vec3 emitted_light, inout vec3 reflected_light/*, out float shadow*/) {
// shadow = 0.0;
vec3 ambient_light = vec3(0.0);
vec3 directed_light = vec3(0.0);
@ -125,7 +164,13 @@ float lights_at(vec3 wpos, vec3 wnorm, vec3 cam_to_frag, vec3 k_a, vec3 k_d, vec
// light_dir = faceforward(light_dir, wnorm, light_dir);
bool is_direct = dot(-light_dir, wnorm) > 0.0;
// reflected_light += color * (distance_2 == 0.0 ? vec3(1.0) : light_reflection_factor(wnorm, cam_to_frag, light_dir, k_d, k_s, alpha));
vec3 direct_light = PI * color * strength * square_factor * light_reflection_factor(wnorm, cam_to_frag, is_direct ? light_dir : -light_dir, k_d, k_s, alpha);
vec3 direct_light_dir = is_direct ? light_dir : -light_dir;
// Compute attenuation due to fluid.
// Default is light_pos, so we take the whole segment length for this beam if it never intersects the surface, unlesss the beam itself
// is above the surface, in which case we take zero (wpos).
color *= cam_attenuation * compute_attenuation_point(wpos, -direct_light_dir, mu, surface_alt, light_pos.z < surface_alt ? light_pos : wpos);
vec3 direct_light = PI * color * strength * square_factor * light_reflection_factor(wnorm, cam_to_frag, direct_light_dir, k_d, k_s, alpha);
directed_light += is_direct ? direct_light * square_factor : vec3(0.0);
ambient_light += is_direct ? vec3(0.0) : direct_light * LIGHT_AMBIENCE;
@ -164,3 +209,8 @@ float lights_at(vec3 wpos, vec3 wnorm, vec3 cam_to_frag, vec3 k_a, vec3 k_d, vec
emitted_light += k_a * ambient_light/* * shadow*/;// min(shadow, 1.0);
return /*rel_luminance(ambient_light + directed_light)*/rel_luminance(max_light);//ambient_light;
}
// Same as lights_at, but with no assumed attenuation due to fluid.
float lights_at(vec3 wpos, vec3 wnorm, vec3 cam_to_frag, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, inout vec3 emitted_light, inout vec3 reflected_light) {
return lights_at(wpos, wnorm, cam_to_frag, vec3(0.0), vec3(1.0), 0.0, k_a, k_d, k_s, alpha, emitted_light, reflected_light);
}

View File

@ -1,13 +1,14 @@
#include <random.glsl>
#include <srgb.glsl>
#include <cloud.glsl>
#include <srgb.glsl>
const float PI = 3.141592;
const vec3 SKY_DAY_TOP = vec3(0.1, 0.5, 0.9);
const vec3 SKY_DAY_MID = vec3(0.02, 0.28, 0.8);
const vec3 SKY_DAY_BOT = vec3(0.1, 0.2, 0.3);
const vec3 DAY_LIGHT = vec3(1.2, 1.0, 1.0);
const vec3 DAY_LIGHT = vec3(1.0, 1.0, 1.0);
const vec3 SUN_HALO_DAY = vec3(0.35, 0.35, 0.0);
const vec3 SKY_DUSK_TOP = vec3(0.06, 0.1, 0.20);
@ -19,9 +20,14 @@ const vec3 SUN_HALO_DUSK = vec3(1.2, 0.15, 0.0);
const vec3 SKY_NIGHT_TOP = vec3(0.001, 0.001, 0.0025);
const vec3 SKY_NIGHT_MID = vec3(0.001, 0.005, 0.02);
const vec3 SKY_NIGHT_BOT = vec3(0.002, 0.004, 0.004);
const vec3 NIGHT_LIGHT = vec3(0.002, 0.01, 0.03);
const vec3 NIGHT_LIGHT = vec3(0.002, 0.02, 0.02);
// const vec3 NIGHT_LIGHT = vec3(0.0, 0.0, 0.0);
// Linear RGB, scattering coefficients for atmosphere at roughly R, G, B wavelengths.
//
// See https://en.wikipedia.org/wiki/Diffuse_sky_radiation
const vec3 MU_SCATTER = vec3(0.05, 0.10, 0.23);
const float SUN_COLOR_FACTOR = 6.0;//1.8;
const float UNDERWATER_MIST_DIST = 100.0;
@ -48,7 +54,7 @@ vec3 get_moon_dir(float time_of_day) {
return normalize(-vec3(sin(moon_angle_rad), 0.0, cos(moon_angle_rad) - 0.5));
}
const float PERSISTENT_AMBIANCE = 0.00125; // 0.1;// 0.025; // 0.1;
const float PERSISTENT_AMBIANCE = 1.0 / 512;// 1.0 / 512; // 0.00125 // 0.1;// 0.025; // 0.1;
float get_sun_brightness(vec3 sun_dir) {
return max(-sun_dir.z + 0.6, 0.0) * 0.9;
@ -124,9 +130,14 @@ vec3 get_moon_color(vec3 moon_dir) {
// }
// Returns computed maximum intensity.
float get_sun_diffuse2(vec3 norm, vec3 sun_dir, vec3 moon_dir, vec3 dir, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, out vec3 emitted_light, out vec3 reflected_light) {
const float SUN_AMBIANCE = 0.23;/* / 1.8*/;// 0.1 / 3.0;
const float MOON_AMBIANCE = 0.23;//0.1;
//
// wpos is the position of this fragment.
// mu is the attenuation coefficient for any substance on a horizontal plane.
// cam_attenuation is the total light attenuation due to the substance for beams between the point and the camera.
// surface_alt is the altitude of the attenuating surface.
float get_sun_diffuse2(vec3 norm, vec3 sun_dir, vec3 moon_dir, vec3 dir, vec3 wpos, vec3 mu, vec3 cam_attenuation, float surface_alt, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, out vec3 emitted_light, out vec3 reflected_light) {
const vec3 SUN_AMBIANCE = MU_SCATTER;//0.23;/* / 1.8*/;// 0.1 / 3.0;
const vec3 MOON_AMBIANCE = MU_SCATTER;//0.23;//0.1;
float sun_light = get_sun_brightness(sun_dir);
float moon_light = get_moon_brightness(moon_dir);
@ -134,8 +145,12 @@ float get_sun_diffuse2(vec3 norm, vec3 sun_dir, vec3 moon_dir, vec3 dir, vec3 k_
vec3 sun_color = get_sun_color(sun_dir) * SUN_COLOR_FACTOR;
vec3 moon_color = get_moon_color(moon_dir);
vec3 sun_chroma = sun_color * sun_light;
vec3 moon_chroma = moon_color * moon_light;
// If the sun is facing the wrong way, we currently just want zero light, hence default point is wpos.
vec3 sun_attenuation = compute_attenuation(wpos, -sun_dir, mu, surface_alt, wpos);
vec3 moon_attenuation = compute_attenuation(wpos, -moon_dir, mu, surface_alt, wpos);
vec3 sun_chroma = sun_color * sun_light * cam_attenuation * sun_attenuation;
vec3 moon_chroma = moon_color * moon_light * cam_attenuation * moon_attenuation;
// https://en.m.wikipedia.org/wiki/Diffuse_sky_radiation
//
@ -256,9 +271,12 @@ float get_sun_diffuse2(vec3 norm, vec3 sun_dir, vec3 moon_dir, vec3 dir, vec3 k_
moon_chroma * mix(1.0, pow(dot(-norm, moon_dir) * 2.0, 2.0), diffusion) +
PERSISTENT_AMBIANCE;
ambient_light = vec3(SUN_AMBIANCE * sun_light + moon_light); */
return 0.0;//rel_luminance(emitted_light + reflected_light);//sun_chroma + moon_chroma + PERSISTENT_AMBIANCE;
return rel_luminance(emitted_light + reflected_light);//rel_luminance(emitted_light + reflected_light);//sun_chroma + moon_chroma + PERSISTENT_AMBIANCE;
}
float get_sun_diffuse2(vec3 norm, vec3 sun_dir, vec3 moon_dir, vec3 dir, vec3 k_a, vec3 k_d, vec3 k_s, float alpha, out vec3 emitted_light, out vec3 reflected_light) {
return get_sun_diffuse2(norm, sun_dir, moon_dir, dir, vec3(0.0), vec3(0.0), vec3(1.0), 0.0, k_a, k_d, k_s, alpha, emitted_light, reflected_light);
}
// This has been extracted into a function to allow quick exit when detecting a star.
float is_star_at(vec3 dir) {
@ -399,8 +417,8 @@ vec3 illuminate(float max_light, /*vec3 max_light, */vec3 emitted, vec3 reflecte
const float DUSK_EXPOSURE = 2.0;//0.8;
const float DAY_EXPOSURE = 1.0;//0.7;
const float DAY_SATURATION = 1.0;
const float DUSK_SATURATION = 0.5;
const float DAY_SATURATION = 1.1;
const float DUSK_SATURATION = 0.6;
const float NIGHT_SATURATION = 0.1;
const float gamma = /*0.5*//*1.*0*/1.0;//1.0;

View File

@ -207,3 +207,68 @@ float rel_luminance(vec3 rgb)
const vec3 W = vec3(0.2126, 0.7152, 0.0722);
return dot(rgb, W);
}
// From https://discourse.vvvv.org/t/infinite-ray-intersects-with-infinite-plane/10537
// out of laziness.
bool IntersectRayPlane(vec3 rayOrigin, vec3 rayDirection, vec3 posOnPlane, vec3 planeNormal, inout vec3 intersectionPoint)
{
float rDotn = dot(rayDirection, planeNormal);
//parallel to plane or pointing away from plane?
if (rDotn < 0.0000001 )
return false;
float s = dot(planeNormal, (posOnPlane - rayOrigin)) / rDotn;
intersectionPoint = rayOrigin + s * rayDirection;
return true;
}
// Compute uniform attenuation due to beam passing through a substance that fills an area below a horizontal plane
// (e.g. in most cases, water below the water surface depth) using the simplest form of the Beer-Lambert law
// (https://en.wikipedia.org/wiki/Beer%E2%80%93Lambert_law):
//
// I(z) = I₀ e^(-μz)
//
// We compute this value, except for the initial intensity which may be multiplied out later.
//
// wpos is the position of the point being hit.
// ray_dir is the reversed direction of the ray (going "out" of the point being hit).
// mu is the attenuation coefficient for R, G, and B wavelenghts.
// surface_alt is the estimated altitude of the horizontal surface separating the substance from air.
// defaultpos is the position to use in computing the distance along material at this point if there was a failure.
//
// Ideally, defaultpos is set so we can avoid branching on error.
vec3 compute_attenuation(vec3 wpos, vec3 ray_dir, vec3 mu, float surface_alt, vec3 defaultpos) {
// return vec3(1.0);
/*if (dot(mu, mu) == 0.0) {
return vec3(1.0);
}*//* else {
return vec3(0.0);
}*/
// return vec3(0.0);
vec3 surface_dir = surface_alt < wpos.z ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0);
// vec3 surface_dir = faceforward(vec3(0.0, 0.0, 1.0), ray_dir, vec3(0.0, 0.0, 1.0));
bool _intersects_surface = IntersectRayPlane(wpos, ray_dir, vec3(0.0, 0.0, surface_alt), surface_dir, defaultpos);
float depth = length(defaultpos - wpos);
return exp(-mu * depth);
}
// Same as compute_attenuation but since both point are known, set a maximum to make sure we don't exceed the length
// from the default point.
vec3 compute_attenuation_point(vec3 wpos, vec3 ray_dir, vec3 mu, float surface_alt, vec3 defaultpos) {
// return vec3(1.0);
/*if (dot(mu, mu) == 0.0) {
return vec3(1.0);
}*//* else {
return vec3(0.0);
}*/
// return vec3(0.0);
vec3 surface_dir = surface_alt < wpos.z ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0);
// vec3 surface_dir = faceforward(vec3(0.0, 0.0, 1.0), ray_dir, vec3(0.0, 0.0, 1.0));
float max_length = dot(defaultpos - wpos, defaultpos - wpos);
bool _intersects_surface = IntersectRayPlane(wpos, ray_dir, vec3(0.0, 0.0, surface_alt), surface_dir, defaultpos);
float depth2 = min(max_length, dot(defaultpos - wpos, defaultpos - wpos));
return exp(-mu * sqrt(depth2));
}

View File

@ -46,9 +46,9 @@ void main() {
vec4 final_color = pow(aa_color, gamma);
if (medium.x == 1u) {
/* if (medium.x == 1u) {
final_color *= vec4(0.2, 0.2, 0.8, 1.0);
}
} */
tgt_color = vec4(final_color.rgb, 1);
}

View File

@ -21,9 +21,9 @@ void main() {
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
float dist = 100000.0;
if (medium.x == 1u) {
/* if (medium.x == 1u) {
dist = UNDERWATER_MIST_DIST;
}
} */
vec3 wpos = cam_pos.xyz + /*normalize(f_pos)*/cam_dir * dist;
tgt_color = vec4(get_sky_color(normalize(f_pos), time_of_day.x, cam_pos.xyz, wpos, 1.0, true, _clouds), 1.0);

View File

@ -28,6 +28,8 @@ void main() {
uint norm_dir = ((f_pos_norm >> 29) & 0x1u) * 3u;
// Use an array to avoid conditional branching
vec3 f_norm = normals[(f_pos_norm >> 29) & 0x7u];
// Whether this face is facing fluid or not.
bool faces_fluid = bool((f_pos_norm >> 28) & 0x1u);
vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz);
// vec4 vert_pos4 = view_mat * vec4(f_pos, 1.0);
@ -61,23 +63,31 @@ void main() {
const float R_s1s0 = pow((1.3325 - n2) / (1.3325 + n2), 2);
const float R_s2s1 = pow((1.0 - 1.3325) / (1.0 + 1.3325), 2);
const float R_s1s2 = pow((1.3325 - 1.0) / (1.3325 + 1.0), 2);
float R_s = (f_pos.z < f_alt) ? mix(R_s2s1 * R_s1s0, R_s1s0, medium.x) : mix(R_s2s0, R_s1s2 * R_s2s0, medium.x);
// float faces_fluid = faces_fluid && f_pos.z <= floor(f_alt);
float fluid_alt = max(ceil(f_pos.z), floor(f_alt));
float R_s = /*(f_pos.z < f_alt)*/faces_fluid /*&& f_pos.z <= fluid_alt*/ ? mix(R_s2s1 * R_s1s0, R_s1s0, medium.x) : mix(R_s2s0, R_s1s2 * R_s2s0, medium.x);
vec3 k_a = vec3(1.0);
vec3 k_d = vec3(1.0);
vec3 k_s = vec3(R_s);
float max_light = 0.0;
// Compute attenuation due to water from the camera.
vec3 mu = faces_fluid/* && f_pos.z <= fluid_alt*/ ? MU_WATER : vec3(0.0);
// NOTE: Default intersection point is camera position, meaning if we fail to intersect we assume the whole camera is in water.
vec3 cam_attenuation = compute_attenuation_point(f_pos, view_dir, mu, fluid_alt, /*cam_pos.z <= fluid_alt ? cam_pos.xyz : f_pos*/cam_pos.xyz);
// Computing light attenuation from water.
vec3 emitted_light, reflected_light;
// To account for prior saturation
float f_light = pow(f_light, 1.5);
float point_shadow = shadow_at(f_pos, f_norm);
max_light += get_sun_diffuse2(f_norm, /*time_of_day.x, */sun_dir, moon_dir, view_dir, k_a/* * (shade_frac * 0.5 + light_frac * 0.5)*/, k_d, k_s, alpha, emitted_light, reflected_light);
max_light += get_sun_diffuse2(f_norm, /*time_of_day.x, */sun_dir, moon_dir, view_dir, f_pos, mu, cam_attenuation, fluid_alt, k_a/* * (shade_frac * 0.5 + light_frac * 0.5)*/, k_d, k_s, alpha, emitted_light, reflected_light);
emitted_light *= f_light * point_shadow * max(shade_frac, MIN_SHADOW);
reflected_light *= f_light * point_shadow * shade_frac;
max_light *= f_light * point_shadow * shade_frac;
max_light += lights_at(f_pos, f_norm, view_dir, k_a, k_d, k_s, alpha, emitted_light, reflected_light);
max_light += lights_at(f_pos, f_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, emitted_light, reflected_light);
float ao = /*pow(f_ao, 0.5)*/f_ao * 0.9 + 0.1;
emitted_light *= ao;

View File

@ -22,10 +22,10 @@ out vec3 f_col;
out float f_light;
out float f_ao;
const int EXTRA_NEG_Z = 65536;
const int EXTRA_NEG_Z = 32768;
void main() {
f_chunk_pos = vec3(ivec3((uvec3(v_pos_norm) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0x1FFFFu)) - ivec3(0, 0, EXTRA_NEG_Z));
f_chunk_pos = vec3(ivec3((uvec3(v_pos_norm) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0xFFFFu)) - ivec3(0, 0, EXTRA_NEG_Z));
f_pos = f_chunk_pos + model_offs;
f_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0));
@ -39,7 +39,7 @@ void main() {
f_pos_norm = v_pos_norm;
// Also precalculate shadow texture and estimated terrain altitude.
f_alt = alt_at(f_pos.xy);
f_alt = alt_at_real(f_pos.xy);
f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy));
gl_Position =

View File

@ -25,8 +25,6 @@ impl CharSelectionState {
pub fn new(global_state: &mut GlobalState, client: Rc<RefCell<Client>>) -> Self {
let scene = Scene::new(
global_state.window.renderer_mut(),
&client.borrow(),
&global_state.settings,
Some("fixture.selection_bg"),
);
Self {

View File

@ -46,7 +46,7 @@ where
faces_to_make(self, pos, true, |vox| vox.is_empty()),
offs + pos.map(|e| e as f32),
&[[[Rgba::from_opaque(col); 3]; 3]; 3],
|origin, norm, col, light, ao| {
|origin, norm, col, light, ao, _meta| {
FigureVertex::new(
origin * scale,
norm,
@ -112,7 +112,7 @@ where
faces_to_make(self, pos, true, |vox| vox.is_empty()),
offs + pos.map(|e| e as f32),
&[[[Rgba::from_opaque(col); 3]; 3]; 3],
|origin, norm, col, light, ao| {
|origin, norm, col, light, ao, _meta| {
SpriteVertex::new(
origin * scale,
norm,
@ -150,12 +150,14 @@ fn faces_to_make<V: ReadVol>(
pos: Vec3<i32>,
error_makes_face: bool,
should_add: impl Fn(&V::Vox) -> bool,
) -> [bool; 6] {
) -> [Option<()>; 6] {
let (x, y, z) = (Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z());
let make_face = |offset| {
seg.get(pos + offset)
let res = seg
.get(pos + offset)
.map(|v| should_add(v))
.unwrap_or(error_makes_face)
.unwrap_or(error_makes_face);
if res { Some(()) } else { None }
};
[
make_face(-x),

View File

@ -395,10 +395,16 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug>
if block.map_or(false, |vox| vox.is_opaque()) {
vol::push_vox_verts(
&mut opaque_mesh, //selected_opaque_mesh,
faces_to_make(&blocks, false, |vox| !vox.is_opaque()),
faces_to_make(&blocks, None, |vox| {
if vox.is_opaque() {
None
} else {
Some(vox.is_fluid())
}
}),
offs,
&colors,
|pos, norm, col, light, ao| {
|pos, norm, col, light, ao, &meta| {
//let light = (light.min(ao) * 255.0) as u32;
let light = (light * 255.0) as u32;
let ao = (ao * 255.0) as u32;
@ -409,17 +415,33 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug>
} else {
if norm.z < 0.0 { 4 } else { 5 }
};
TerrainVertex::new(norm, light, ao, pos, col)
TerrainVertex::new(norm, light, ao, pos, col, meta)
},
&lights,
);
} else if block.map_or(false, |vox| vox.is_fluid()) {
vol::push_vox_verts(
&mut fluid_mesh,
faces_to_make(&blocks, true, |vox| vox.is_air()),
// NOTE: want to skip blocks that aren't either next to air, or next to
// opaque blocks like ground. Addnig the blocks next to ground lets us
// make sure we compute lighting effects both at the water surface, and
// just before hitting the ground.
faces_to_make(&blocks, Some(()), |vox| {
if vox.is_air() { Some(()) } else { None }
}),
offs,
&colors,
|pos, norm, col, light, _ao| {
|pos, norm, col, light, _ao, _meta| {
/* let rel_pos = pos - offs;
let rel_vox_pos = if rel_pos == offs {
rel_pos + norm + 1.0
} else {
rel_pos + 1.0
}.map(|e| e as usize);
let vox_neighbor = blocks[rel_vox_pos.z][rel_vox_pos.y][rel_vox_pos.x];
if vox_neighbor.is_opaque() {
} else {
} */
FluidVertex::new(pos, norm, col, light, 0.3)
},
&lights,
@ -450,13 +472,17 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug>
/// Unlike the one in segments.rs this uses a provided array of blocks instead
/// of retrieving from a volume
/// blocks[z][y][x]
fn faces_to_make(
fn faces_to_make<M: Clone>(
blocks: &[[[Option<Block>; 3]; 3]; 3],
error_makes_face: bool,
should_add: impl Fn(Block) -> bool,
) -> [bool; 6] {
error_makes_face: Option<M>,
should_add: impl Fn(Block) -> Option<M>,
) -> [Option<M>; 6] {
// Faces to draw
let make_face = |opt_v: Option<Block>| opt_v.map(|v| should_add(v)).unwrap_or(error_makes_face);
let make_face = |opt_v: Option<Block>| {
opt_v
.map(|v| should_add(v))
.unwrap_or(error_makes_face.clone())
};
[
make_face(blocks[1][1][0]),
make_face(blocks[1][1][2]),

View File

@ -96,13 +96,14 @@ fn get_col_quad(dirs: &[Vec3<i32>], cols: &[[[Rgba<u8>; 3]; 3]; 3]) -> Vec4<Rgb<
}
// Utility function
fn create_quad<P: Pipeline, F: Fn(Vec3<f32>, Vec3<f32>, Rgb<f32>, f32, f32) -> P::Vertex>(
fn create_quad<P: Pipeline, M, F: Fn(Vec3<f32>, Vec3<f32>, Rgb<f32>, f32, f32, &M) -> P::Vertex>(
origin: Vec3<f32>,
unit_x: Vec3<f32>,
unit_y: Vec3<f32>,
norm: Vec3<f32>,
cols: Vec4<Rgb<f32>>,
darkness_ao: Vec4<(f32, f32)>,
meta: &M,
vcons: &F,
) -> Quad<P> {
let darkness = darkness_ao.map(|e| e.0);
@ -112,45 +113,47 @@ fn create_quad<P: Pipeline, F: Fn(Vec3<f32>, Vec3<f32>, Rgb<f32>, f32, f32) -> P
if ao[0].min(ao[2]) < ao[1].min(ao[3]) {
Quad::new(
vcons(origin + unit_y, norm, cols[3], darkness[3], ao_map[3]),
vcons(origin, norm, cols[0], darkness[0], ao_map[0]),
vcons(origin + unit_x, norm, cols[1], darkness[1], ao_map[1]),
vcons(origin + unit_y, norm, cols[3], darkness[3], ao_map[3], meta),
vcons(origin, norm, cols[0], darkness[0], ao_map[0], meta),
vcons(origin + unit_x, norm, cols[1], darkness[1], ao_map[1], meta),
vcons(
origin + unit_x + unit_y,
norm,
cols[2],
darkness[2],
ao_map[2],
meta,
),
)
} else {
Quad::new(
vcons(origin, norm, cols[0], darkness[0], ao_map[0]),
vcons(origin + unit_x, norm, cols[1], darkness[1], ao_map[1]),
vcons(origin, norm, cols[0], darkness[0], ao_map[0], meta),
vcons(origin + unit_x, norm, cols[1], darkness[1], ao_map[1], meta),
vcons(
origin + unit_x + unit_y,
norm,
cols[2],
darkness[2],
ao_map[2],
meta,
),
vcons(origin + unit_y, norm, cols[3], darkness[3], ao_map[3]),
vcons(origin + unit_y, norm, cols[3], darkness[3], ao_map[3], meta),
)
}
}
pub fn push_vox_verts<P: Pipeline>(
pub fn push_vox_verts<P: Pipeline, M>(
mesh: &mut Mesh<P>,
faces: [bool; 6],
faces: [Option<M>; 6],
offs: Vec3<f32>,
cols: &[[[Rgba<u8>; 3]; 3]; 3],
vcons: impl Fn(Vec3<f32>, Vec3<f32>, Rgb<f32>, f32, f32) -> P::Vertex,
vcons: impl Fn(Vec3<f32>, Vec3<f32>, Rgb<f32>, f32, f32, &M) -> P::Vertex,
darknesses: &[[[Option<f32>; 3]; 3]; 3],
) {
let (x, y, z) = (Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z());
// -x
if faces[0] {
if let Some(meta) = &faces[0] {
mesh.push_quad(create_quad(
offs,
Vec3::unit_z(),
@ -158,11 +161,12 @@ pub fn push_vox_verts<P: Pipeline>(
-Vec3::unit_x(),
get_col_quad(&[-z, -y, z, y, -z], cols),
get_ao_quad(-Vec3::unit_x(), &[-z, -y, z, y, -z], darknesses),
meta,
&vcons,
));
}
// +x
if faces[1] {
if let Some(meta) = &faces[1] {
mesh.push_quad(create_quad(
offs + Vec3::unit_x(),
Vec3::unit_y(),
@ -170,11 +174,12 @@ pub fn push_vox_verts<P: Pipeline>(
Vec3::unit_x(),
get_col_quad(&[-y, -z, y, z, -y], cols),
get_ao_quad(Vec3::unit_x(), &[-y, -z, y, z, -y], darknesses),
meta,
&vcons,
));
}
// -y
if faces[2] {
if let Some(meta) = &faces[2] {
mesh.push_quad(create_quad(
offs,
Vec3::unit_x(),
@ -182,11 +187,12 @@ pub fn push_vox_verts<P: Pipeline>(
-Vec3::unit_y(),
get_col_quad(&[-x, -z, x, z, -x], cols),
get_ao_quad(-Vec3::unit_y(), &[-x, -z, x, z, -x], darknesses),
meta,
&vcons,
));
}
// +y
if faces[3] {
if let Some(meta) = &faces[3] {
mesh.push_quad(create_quad(
offs + Vec3::unit_y(),
Vec3::unit_z(),
@ -194,11 +200,12 @@ pub fn push_vox_verts<P: Pipeline>(
Vec3::unit_y(),
get_col_quad(&[-z, -x, z, x, -z], cols),
get_ao_quad(Vec3::unit_y(), &[-z, -x, z, x, -z], darknesses),
meta,
&vcons,
));
}
// -z
if faces[4] {
if let Some(meta) = &faces[4] {
mesh.push_quad(create_quad(
offs,
Vec3::unit_y(),
@ -206,11 +213,12 @@ pub fn push_vox_verts<P: Pipeline>(
-Vec3::unit_z(),
get_col_quad(&[-y, -x, y, x, -y], cols),
get_ao_quad(-Vec3::unit_z(), &[-y, -x, y, x, -y], darknesses),
meta,
&vcons,
));
}
// +z
if faces[5] {
if let Some(meta) = &faces[5] {
mesh.push_quad(create_quad(
offs + Vec3::unit_z(),
Vec3::unit_x(),
@ -218,6 +226,7 @@ pub fn push_vox_verts<P: Pipeline>(
Vec3::unit_z(),
get_col_quad(&[-x, -y, x, y, -x], cols),
get_ao_quad(Vec3::unit_z(), &[-x, -y, x, y, -x], darknesses),
meta,
&vcons,
));
}

View File

@ -40,14 +40,22 @@ gfx_defines! {
}
impl Vertex {
pub fn new(norm_bits: u32, light: u32, ao: u32, pos: Vec3<f32>, col: Rgb<f32>) -> Self {
const EXTRA_NEG_Z: f32 = 65536.0;
pub fn new(
norm_bits: u32,
light: u32,
ao: u32,
pos: Vec3<f32>,
col: Rgb<f32>,
meta: bool,
) -> Self {
const EXTRA_NEG_Z: f32 = 32768.0;
Self {
pos_norm: 0
| ((pos.x as u32) & 0x003F) << 0
| ((pos.y as u32) & 0x003F) << 6
| (((pos + EXTRA_NEG_Z).z.max(0.0).min((1 << 17) as f32) as u32) & 0xFFFFF) << 12
| (((pos + EXTRA_NEG_Z).z.max(0.0).min((1 << 16) as f32) as u32) & 0xFFFF) << 12
| if meta { 1 } else { 0 } << 28
| (norm_bits & 0x7) << 29,
col_light: 0
| ((col.r.mul(255.0) as u32) & 0xFF) << 8

View File

@ -16,7 +16,7 @@ use crate::{
render::{Consts, FigureBoneData, FigureLocals, Globals, Light, Renderer, Shadow},
scene::{
camera::{Camera, CameraMode},
Lod, SceneData,
LodData, SceneData,
},
};
use common::{
@ -1499,7 +1499,7 @@ impl FigureMgr {
globals: &Consts<Globals>,
lights: &Consts<Light>,
shadows: &Consts<Shadow>,
lod: &Lod,
lod: &LodData,
camera: &Camera,
figure_lod_render_distance: f32,
) {
@ -1553,7 +1553,7 @@ impl FigureMgr {
globals: &Consts<Globals>,
lights: &Consts<Light>,
shadows: &Consts<Shadow>,
lod: &Lod,
lod: &LodData,
camera: &Camera,
figure_lod_render_distance: f32,
) {
@ -1602,7 +1602,7 @@ impl FigureMgr {
globals: &Consts<Globals>,
lights: &Consts<Light>,
shadows: &Consts<Shadow>,
lod: &Lod,
lod: &LodData,
camera: &Camera,
character_state: Option<&CharacterState>,
entity: EcsEntity,

View File

@ -10,53 +10,79 @@ use client::Client;
use common::{spiral::Spiral2d, util::srgba_to_linear};
use vek::*;
pub struct Lod {
model: Option<(u32, Model<LodTerrainPipeline>)>,
locals: Consts<Locals>,
pub struct LodData {
pub map: Texture<LodColorFmt>,
pub horizon: Texture<LodTextureFmt>,
pub tgt_detail: u32,
}
pub struct Lod {
model: Option<(u32, Model<LodTerrainPipeline>)>,
locals: Consts<Locals>,
data: LodData,
}
impl LodData {
pub fn new(
renderer: &mut Renderer,
lod_base: &image::DynamicImage,
lod_horizon: &image::DynamicImage,
tgt_detail: u32,
border_color: gfx::texture::PackedColor,
) -> Self {
Self {
map: renderer
.create_texture(
lod_base,
Some(FilterMethod::Bilinear),
Some(WrapMode::Border),
Some(border_color),
)
.expect("Failed to generate map texture"),
horizon: renderer
.create_texture(
lod_horizon,
Some(FilterMethod::Trilinear),
Some(WrapMode::Border),
Some([0.0, 1.0, 0.0, 1.0].into()),
)
.expect("Failed to generate map texture"),
tgt_detail,
}
}
}
impl Lod {
pub fn new(renderer: &mut Renderer, client: &Client, settings: &Settings) -> Self {
let water_color = /*Rgba::new(0.2, 0.5, 1.0, 0.0)*/srgba_to_linear(Rgba::new(0.0, 0.25, 0.5, 0.0)/* * 0.5*/);
Self {
model: None,
locals: renderer.create_consts(&[Locals::default()]).unwrap(),
map: renderer
.create_texture(
&client.lod_base,
Some(FilterMethod::Bilinear),
Some(WrapMode::Border),
Some([water_color.r, water_color.g, water_color.b, water_color.a].into()),
)
.expect("Failed to generate map texture"),
horizon: renderer
.create_texture(
&client.lod_horizon,
Some(FilterMethod::Trilinear),
Some(WrapMode::Border),
Some([0.0, 1.0, 0.0, 1.0].into()),
)
.expect("Failed to generate map texture"),
tgt_detail: settings.graphics.lod_detail.max(100).min(2500),
data: LodData::new(
renderer,
&client.lod_base,
&client.lod_horizon,
settings.graphics.lod_detail.max(100).min(2500),
[water_color.r, water_color.g, water_color.b, water_color.a].into(),
),
}
}
pub fn set_detail(&mut self, detail: u32) { self.tgt_detail = detail.max(100).min(2500); }
pub fn get_data(&self) -> &LodData { &self.data }
pub fn set_detail(&mut self, detail: u32) { self.data.tgt_detail = detail.max(100).min(2500); }
pub fn maintain(&mut self, renderer: &mut Renderer, _time_of_day: f64) {
if self
.model
.as_ref()
.map(|(detail, _)| *detail != self.tgt_detail)
.map(|(detail, _)| *detail != self.data.tgt_detail)
.unwrap_or(true)
{
self.model = Some((
self.tgt_detail,
self.data.tgt_detail,
renderer
.create_model(&create_lod_terrain_mesh(self.tgt_detail))
.create_model(&create_lod_terrain_mesh(self.data.tgt_detail))
.unwrap(),
));
}
@ -64,7 +90,13 @@ impl Lod {
pub fn render(&self, renderer: &mut Renderer, globals: &Consts<Globals>) {
if let Some((_, model)) = self.model.as_ref() {
renderer.render_lod_terrain(&model, globals, &self.locals, &self.map, &self.horizon);
renderer.render_lod_terrain(
&model,
globals,
&self.locals,
&self.data.map,
&self.data.horizon,
);
}
}
}

View File

@ -7,7 +7,7 @@ pub mod terrain;
use self::{
camera::{Camera, CameraMode},
figure::FigureMgr,
lod::Lod,
lod::{Lod, LodData},
terrain::Terrain,
};
use crate::{
@ -352,7 +352,7 @@ impl Scene {
cam_pos,
self.camera.get_focus_pos(),
self.loaded_distance,
self.lod.tgt_detail as f32,
self.lod.get_data().tgt_detail as f32,
self.map_bounds,
scene_data.state.get_time_of_day(),
scene_data.state.get_time(),
@ -413,7 +413,7 @@ impl Scene {
&self.globals,
&self.lights,
&self.shadows,
&self.lod,
self.lod.get_data(),
self.camera.get_focus_pos(),
);
self.figure_mgr.render(
@ -424,7 +424,7 @@ impl Scene {
&self.globals,
&self.lights,
&self.shadows,
&self.lod,
self.lod.get_data(),
&self.camera,
scene_data.figure_lod_render_distance,
);
@ -441,7 +441,7 @@ impl Scene {
&self.globals,
&self.lights,
&self.shadows,
&self.lod,
self.lod.get_data(),
&self.camera,
scene_data.figure_lod_render_distance,
);
@ -451,7 +451,7 @@ impl Scene {
&self.globals,
&self.lights,
&self.shadows,
&self.lod,
self.lod.get_data(),
self.camera.get_focus_pos(),
scene_data.sprite_render_distance,
);

View File

@ -12,12 +12,10 @@ use crate::{
scene::{
camera::{self, Camera, CameraMode},
figure::{load_mesh, FigureModelCache, FigureState},
Lod,
LodData,
},
settings::Settings,
window::{Event, PressState},
};
use client::Client;
use common::{
comp::{humanoid, Body, Loadout},
figure::Segment,
@ -67,7 +65,7 @@ pub struct Scene {
skybox: Skybox,
postprocess: PostProcess,
lod: Lod,
lod: LodData,
map_bounds: Vec2<f32>,
backdrop: Option<(Model<FigurePipeline>, FigureState<FixtureSkeleton>)>,
@ -89,15 +87,23 @@ pub struct SceneData {
}
impl Scene {
pub fn new(
renderer: &mut Renderer,
client: &Client,
settings: &Settings,
backdrop: Option<&str>,
) -> Self {
pub fn new(renderer: &mut Renderer, backdrop: Option<&str>) -> Self {
let start_angle = 90.0f32.to_radians();
let resolution = renderer.get_resolution().map(|e| e as f32);
let map_bounds = Vec2::new(-65536.0, 131071.0);
let map_border = [0.0, 0.0, 0.0, 0.0];
let map_image = image::DynamicImage::ImageRgba8(image::RgbaImage::from_pixel(
1,
1,
image::Rgba([0, 0, 0, 0]),
));
let horizon_image = image::DynamicImage::ImageRgba8(image::RgbaImage::from_pixel(
1,
1,
image::Rgba([0, 1, 0, 1]),
));
let mut camera = Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson);
camera.set_focus_pos(Vec3::unit_z() * 1.5);
camera.set_distance(3.0); // 4.2
@ -118,8 +124,8 @@ impl Scene {
.create_consts(&[PostProcessLocals::default()])
.unwrap(),
},
lod: Lod::new(renderer, client, settings),
map_bounds: client.world_map.2,
lod: LodData::new(renderer, &map_image, &horizon_image, 1, map_border.into()),// Lod::new(renderer, client, settings),
map_bounds,//: client.world_map.2,
figure_model_cache: FigureModelCache::new(),
figure_state: FigureState::new(renderer, CharacterSkeleton::new()),

View File

@ -6,7 +6,7 @@ use crate::{
},
};
use super::{Lod, SceneData};
use super::{LodData, SceneData};
use common::{
assets,
figure::Segment,
@ -2191,7 +2191,7 @@ impl<V: RectRasterableVol> Terrain<V> {
globals: &Consts<Globals>,
lights: &Consts<Light>,
shadows: &Consts<Shadow>,
lod: &Lod,
lod: &LodData,
focus_pos: Vec3<f32>,
) {
let focus_chunk = Vec2::from(focus_pos).map2(TerrainChunk::RECT_SIZE, |e: f32, sz| {
@ -2227,7 +2227,7 @@ impl<V: RectRasterableVol> Terrain<V> {
globals: &Consts<Globals>,
lights: &Consts<Light>,
shadows: &Consts<Shadow>,
lod: &Lod,
lod: &LodData,
focus_pos: Vec3<f32>,
sprite_render_distance: f32,
) {