Rain occlusion projection matrix

This commit is contained in:
IsseW 2022-03-17 10:28:14 +01:00
parent 295b89d446
commit 234ed5afb2
6 changed files with 297 additions and 293 deletions

View File

@ -102,8 +102,8 @@ void main() {
#ifdef EXPERIMENTAL_RAIN
vec3 old_color = color.rgb;
// If this value is changed also change it in voxygen/src/scene/mod.rs
float fall_rate = 70.0;
dir.xy += wind_vel * dir.z / fall_rate;
dir = normalize(dir);

View File

@ -17,15 +17,6 @@ uniform u_rain_occlusion {
float rain_occlusion_at(in vec3 fragPos)
{
float bias = -0.2;
float diskRadius = 0.01;
const vec3 sampleOffsetDirections[20] = vec3[]
(
vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1),
vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
vec3( 1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0),
vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1),
vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1)
);
vec4 rain_pos = occlusion_texture_mat * vec4(fragPos, 1.0) - vec4(0, 0, bias, 0);

View File

@ -124,7 +124,7 @@ float cloud_tendency_at(vec2 pos) {
const float RAIN_CLOUD = 0.05;
float rain_density_at(vec2 pos) {
return 1.0; //sample_weather(pos).g;
return sample_weather(pos).g;
//return clamp((cloud_tendency_at(pos) - RAIN_CLOUD) * 10, 0, 1);
}

View File

@ -494,7 +494,6 @@ pub struct DebugInfo {
pub num_figures_visible: u32,
pub num_particles: u32,
pub num_particles_visible: u32,
pub weather: Weather,
}
pub struct HudInfo {

View File

@ -722,13 +722,300 @@ impl Scene {
Some(&self.terrain),
);
let fov = self.camera.get_effective_fov();
let aspect_ratio = self.camera.get_aspect_ratio();
let view_dir = ((focus_pos.map(f32::fract)) - cam_pos).normalized();
// We need to compute these offset matrices to transform world space coordinates
// to the translated ones we use when multiplying by the light space
// matrix; this helps avoid precision loss during the
// multiplication.
let look_at = math::Vec3::from(cam_pos);
let new_dir = math::Vec3::from(view_dir);
let new_dir = new_dir.normalized();
let up: math::Vec3<f32> = math::Vec3::unit_y();
// Optimal warping for directed lights:
//
// n_opt = 1 / sin y (z_n + √(z_n + (f - n) sin y))
//
// where n is near plane, f is far plane, y is the tilt angle between view and
// light direction, and n_opt is the optimal near plane.
// We also want a way to transform and scale this matrix (* 0.5 + 0.5) in order
// to transform it correctly into texture coordinates, as well as
// OpenGL coordinates. Note that the matrix for directional light
// is *already* linear in the depth buffer.
//
// Also, observe that we flip the texture sampling matrix in order to account
// for the fact that DirectX renders top-down.
let texture_mat = Mat4::<f32>::scaling_3d::<Vec3<f32>>(Vec3::new(0.5, -0.5, 1.0))
* Mat4::translation_3d(Vec3::new(1.0, -1.0, 0.0));
let directed_mats = |d_view_mat: math::Mat4<f32>,
d_dir: math::Vec3<f32>|
-> (Mat4<f32>, Mat4<f32>) {
// NOTE: Light view space, right-handed.
let v_p_orig = math::Vec3::from(d_view_mat * math::Vec4::from_direction(new_dir));
let mut v_p = v_p_orig.normalized();
let cos_gamma = new_dir.map(f64::from).dot(d_dir.map(f64::from));
let sin_gamma = (1.0 - cos_gamma * cos_gamma).sqrt();
let gamma = sin_gamma.asin();
let view_mat = math::Mat4::from_col_array(view_mat.into_col_array());
// coordinates are transformed from world space (right-handed) to view space
// (right-handed).
let bounds1 = math::fit_psr(
view_mat.map_cols(math::Vec4::from),
visible_light_volume.iter().copied(),
math::Vec4::homogenized,
);
let n_e = f64::from(-bounds1.max.z);
let factor = compute_warping_parameter_perspective(
gamma,
n_e,
f64::from(fov),
f64::from(aspect_ratio),
);
v_p.z = 0.0;
v_p.normalize();
let l_r: math::Mat4<f32> = if factor > EPSILON_UPSILON {
// NOTE: Our coordinates are now in left-handed space, but v_p isn't; however,
// v_p has no z component, so we don't have to adjust it for left-handed
// spaces.
math::Mat4::look_at_lh(math::Vec3::zero(), math::Vec3::unit_z(), v_p)
} else {
math::Mat4::identity()
};
// Convert from right-handed to left-handed coordinates.
let directed_proj_mat = math::Mat4::new(
1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
);
let light_all_mat = l_r * directed_proj_mat * d_view_mat;
// coordinates are transformed from world space (right-handed) to rotated light
// space (left-handed).
let bounds0 = math::fit_psr(
light_all_mat,
visible_light_volume.iter().copied(),
math::Vec4::homogenized,
);
// Vague idea: project z_n from the camera view to the light view (where it's
// tilted by γ).
//
// NOTE: To transform a normal by M, we multiply by the transpose of the inverse
// of M. For the cases below, we are transforming by an
// already-inverted matrix, so the transpose of its inverse is
// just the transpose of the original matrix.
let (z_0, z_1) = {
let f_e = f64::from(-bounds1.min.z).max(n_e);
// view space, right-handed coordinates.
let p_z = bounds1.max.z;
// rotated light space, left-handed coordinates.
let p_y = bounds0.min.y;
let p_x = bounds0.center().x;
// moves from view-space (right-handed) to world space (right-handed)
let view_inv = view_mat.inverted();
// moves from rotated light space (left-handed) to world space (right-handed).
let light_all_inv = light_all_mat.inverted();
// moves from view-space (right-handed) to world-space (right-handed).
let view_point = view_inv
* math::Vec4::from_point(
-math::Vec3::unit_z() * p_z, /* + math::Vec4::unit_w() */
);
let view_plane = view_mat.transposed() * -math::Vec4::unit_z();
// moves from rotated light space (left-handed) to world space (right-handed).
let light_point = light_all_inv
* math::Vec4::from_point(
math::Vec3::unit_y() * p_y, /* + math::Vec4::unit_w() */
);
let light_plane = light_all_mat.transposed() * math::Vec4::unit_y();
// moves from rotated light space (left-handed) to world space (right-handed).
let shadow_point = light_all_inv
* math::Vec4::from_point(
math::Vec3::unit_x() * p_x, /* + math::Vec4::unit_w() */
);
let shadow_plane = light_all_mat.transposed() * math::Vec4::unit_x();
// Find the point at the intersection of the three planes; note that since the
// equations are already in right-handed world space, we don't need to negate
// the z coordinates.
let solve_p0 = math::Mat4::new(
view_plane.x,
view_plane.y,
view_plane.z,
0.0,
light_plane.x,
light_plane.y,
light_plane.z,
0.0,
shadow_plane.x,
shadow_plane.y,
shadow_plane.z,
0.0,
0.0,
0.0,
0.0,
1.0,
);
// in world-space (right-handed).
let plane_dist = math::Vec4::new(
view_plane.dot(view_point),
light_plane.dot(light_point),
shadow_plane.dot(shadow_point),
1.0,
);
let p0_world = solve_p0.inverted() * plane_dist;
// in rotated light-space (left-handed).
let p0 = light_all_mat * p0_world;
let mut p1 = p0;
// in rotated light-space (left-handed).
p1.y = bounds0.max.y;
// transforms from rotated light-space (left-handed) to view space
// (right-handed).
let view_from_light_mat = view_mat * light_all_inv;
// z0 and z1 are in view space (right-handed).
let z0 = view_from_light_mat * p0;
let z1 = view_from_light_mat * p1;
// Extract the homogenized forward component (right-handed).
//
// NOTE: I don't think the w component should be anything but 1 here, but
// better safe than sorry.
(
f64::from(z0.homogenized().dot(-math::Vec4::unit_z())).clamp(n_e, f_e),
f64::from(z1.homogenized().dot(-math::Vec4::unit_z())).clamp(n_e, f_e),
)
};
// all of this is in rotated light-space (left-handed).
let mut light_focus_pos: math::Vec3<f32> = math::Vec3::zero();
light_focus_pos.x = bounds0.center().x;
light_focus_pos.y = bounds0.min.y;
light_focus_pos.z = bounds0.center().z;
let d = f64::from(bounds0.max.y - bounds0.min.y).abs();
let w_l_y = d;
// NOTE: See section 5.1.2.2 of Lloyd's thesis.
// NOTE: Since z_1 and z_0 are in the same coordinate space, we don't have to
// worry about the handedness of their ratio.
let alpha = z_1 / z_0;
let alpha_sqrt = alpha.sqrt();
let directed_near_normal = if factor < 0.0 {
// Standard shadow map to LiSPSM
(1.0 + alpha_sqrt - factor * (alpha - 1.0)) / ((alpha - 1.0) * (factor + 1.0))
} else {
// LiSPSM to PSM
((alpha_sqrt - 1.0) * (factor * alpha_sqrt + 1.0)).recip()
};
// Equation 5.14 - 5.16
let y_ = |v: f64| w_l_y * (v + directed_near_normal).abs();
let directed_near = y_(0.0) as f32;
let directed_far = y_(1.0) as f32;
light_focus_pos.y = if factor > EPSILON_UPSILON {
light_focus_pos.y - directed_near
} else {
light_focus_pos.y
};
// Left-handed translation.
let w_v: math::Mat4<f32> = math::Mat4::translation_3d(-math::Vec3::new(
light_focus_pos.x,
light_focus_pos.y,
light_focus_pos.z,
));
let shadow_view_mat: math::Mat4<f32> = w_v * light_all_mat;
let w_p: math::Mat4<f32> = {
if factor > EPSILON_UPSILON {
// Projection for y
let near = directed_near;
let far = directed_far;
let left = -1.0;
let right = 1.0;
let bottom = -1.0;
let top = 1.0;
let s_x = 2.0 * near / (right - left);
let o_x = (right + left) / (right - left);
let s_z = 2.0 * near / (top - bottom);
let o_z = (top + bottom) / (top - bottom);
let s_y = (far + near) / (far - near);
let o_y = -2.0 * far * near / (far - near);
math::Mat4::new(
s_x, o_x, 0.0, 0.0, 0.0, s_y, 0.0, o_y, 0.0, o_z, s_z, 0.0, 0.0, 1.0, 0.0,
0.0,
)
} else {
math::Mat4::identity()
}
};
let shadow_all_mat: math::Mat4<f32> = w_p * shadow_view_mat;
// coordinates are transformed from world space (right-handed)
// to post-warp light space (left-handed), then homogenized.
let math::Aabb::<f32> {
min:
math::Vec3 {
x: xmin,
y: ymin,
z: zmin,
},
max:
math::Vec3 {
x: xmax,
y: ymax,
z: zmax,
},
} = math::fit_psr(
shadow_all_mat,
visible_light_volume.iter().copied(),
math::Vec4::homogenized,
);
let s_x = 2.0 / (xmax - xmin);
let s_y = 2.0 / (ymax - ymin);
let s_z = 1.0 / (zmax - zmin);
let o_x = -(xmax + xmin) / (xmax - xmin);
let o_y = -(ymax + ymin) / (ymax - ymin);
let o_z = -zmin / (zmax - zmin);
let directed_proj_mat = Mat4::new(
s_x, 0.0, 0.0, o_x, 0.0, s_y, 0.0, o_y, 0.0, 0.0, s_z, o_z, 0.0, 0.0, 0.0, 1.0,
);
let shadow_all_mat: Mat4<f32> = Mat4::from_col_arrays(shadow_all_mat.into_col_arrays());
let directed_texture_proj_mat = texture_mat * directed_proj_mat;
(
directed_proj_mat * shadow_all_mat,
directed_texture_proj_mat * shadow_all_mat,
)
};
let weather = client.current_weather_wpos(focus_off.xy() + cam_pos.xy());
if true || weather.rain > 0.001
// TODO: check if rain map mode is on
{
// If this value is changed also change it in cloud-frag.glsl
const FALL_RATE: f32 = 70.0;
let rain_dir =
math::Vec3::from(-Vec3::unit_z() + weather.wind / FALL_RATE).normalized();
let rain_view_mat = math::Mat4::look_at_rh(look_at, look_at + rain_dir, up);
let (shadow_mat, texture_mat) = directed_mats(rain_view_mat, rain_dir);
let rain_occlusion_locals = RainOcclusionLocals::new(shadow_mat, texture_mat);
renderer.update_consts(&mut self.data.rain_occlusion_mats, &[rain_occlusion_locals]);
}
let sun_dir = scene_data.get_sun_dir();
let is_daylight = sun_dir.z < 0.0;
if renderer.pipeline_modes().shadow.is_map() && (is_daylight || !lights.is_empty()) {
let fov = self.camera.get_effective_fov();
let aspect_ratio = self.camera.get_aspect_ratio();
let view_dir = ((focus_pos.map(f32::fract)) - cam_pos).normalized();
let (point_shadow_res, _directed_shadow_res) = renderer.get_shadow_resolution();
// NOTE: The aspect ratio is currently always 1 for our cube maps, since they
// are equal on all sides.
@ -737,289 +1024,17 @@ impl Scene {
// and moon.
let directed_light_dir = math::Vec3::from(sun_dir);
// Optimal warping for directed lights:
//
// n_opt = 1 / sin y (z_n + √(z_n + (f - n) sin y))
//
// where n is near plane, f is far plane, y is the tilt angle between view and
// light direction, and n_opt is the optimal near plane.
// We also want a way to transform and scale this matrix (* 0.5 + 0.5) in order
// to transform it correctly into texture coordinates, as well as
// OpenGL coordinates. Note that the matrix for directional light
// is *already* linear in the depth buffer.
//
// Also, observe that we flip the texture sampling matrix in order to account
// for the fact that DirectX renders top-down.
let texture_mat = Mat4::<f32>::scaling_3d::<Vec3<f32>>(Vec3::new(0.5, -0.5, 1.0))
* Mat4::translation_3d(Vec3::new(1.0, -1.0, 0.0));
// We need to compute these offset matrices to transform world space coordinates
// to the translated ones we use when multiplying by the light space
// matrix; this helps avoid precision loss during the
// multiplication.
let look_at = math::Vec3::from(cam_pos);
// We upload view matrices as well, to assist in linearizing vertex positions.
// (only for directional lights, so far).
let mut directed_shadow_mats = Vec::with_capacity(6);
let new_dir = math::Vec3::from(view_dir);
let new_dir = new_dir.normalized();
let up: math::Vec3<f32> = math::Vec3::unit_y();
let light_view_mat = math::Mat4::look_at_rh(look_at, look_at + directed_light_dir, up);
{
// NOTE: Light view space, right-handed.
let v_p_orig =
math::Vec3::from(light_view_mat * math::Vec4::from_direction(new_dir));
let mut v_p = v_p_orig.normalized();
let cos_gamma = new_dir
.map(f64::from)
.dot(directed_light_dir.map(f64::from));
let sin_gamma = (1.0 - cos_gamma * cos_gamma).sqrt();
let gamma = sin_gamma.asin();
let view_mat = math::Mat4::from_col_array(view_mat.into_col_array());
// coordinates are transformed from world space (right-handed) to view space
// (right-handed).
let bounds1 = math::fit_psr(
view_mat.map_cols(math::Vec4::from),
visible_light_volume.iter().copied(),
math::Vec4::homogenized,
);
let n_e = f64::from(-bounds1.max.z);
let factor = compute_warping_parameter_perspective(
gamma,
n_e,
f64::from(fov),
f64::from(aspect_ratio),
);
let (shadow_mat, texture_mat) = directed_mats(light_view_mat, directed_light_dir);
v_p.z = 0.0;
v_p.normalize();
let l_r: math::Mat4<f32> = if factor > EPSILON_UPSILON {
// NOTE: Our coordinates are now in left-handed space, but v_p isn't; however,
// v_p has no z component, so we don't have to adjust it for left-handed
// spaces.
math::Mat4::look_at_lh(math::Vec3::zero(), math::Vec3::unit_z(), v_p)
} else {
math::Mat4::identity()
};
// Convert from right-handed to left-handed coordinates.
let directed_proj_mat = math::Mat4::new(
1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
);
let shadow_locals = ShadowLocals::new(shadow_mat, texture_mat);
let light_all_mat = l_r * directed_proj_mat * light_view_mat;
// coordinates are transformed from world space (right-handed) to rotated light
// space (left-handed).
let bounds0 = math::fit_psr(
light_all_mat,
visible_light_volume.iter().copied(),
math::Vec4::homogenized,
);
// Vague idea: project z_n from the camera view to the light view (where it's
// tilted by γ).
//
// NOTE: To transform a normal by M, we multiply by the transpose of the inverse
// of M. For the cases below, we are transforming by an
// already-inverted matrix, so the transpose of its inverse is
// just the transpose of the original matrix.
let (z_0, z_1) = {
let f_e = f64::from(-bounds1.min.z).max(n_e);
// view space, right-handed coordinates.
let p_z = bounds1.max.z;
// rotated light space, left-handed coordinates.
let p_y = bounds0.min.y;
let p_x = bounds0.center().x;
// moves from view-space (right-handed) to world space (right-handed)
let view_inv = view_mat.inverted();
// moves from rotated light space (left-handed) to world space (right-handed).
let light_all_inv = light_all_mat.inverted();
renderer.update_consts(&mut self.data.shadow_mats, &[shadow_locals]);
// moves from view-space (right-handed) to world-space (right-handed).
let view_point = view_inv
* math::Vec4::from_point(
-math::Vec3::unit_z() * p_z, /* + math::Vec4::unit_w() */
);
let view_plane = view_mat.transposed() * -math::Vec4::unit_z();
// moves from rotated light space (left-handed) to world space (right-handed).
let light_point = light_all_inv
* math::Vec4::from_point(
math::Vec3::unit_y() * p_y, /* + math::Vec4::unit_w() */
);
let light_plane = light_all_mat.transposed() * math::Vec4::unit_y();
// moves from rotated light space (left-handed) to world space (right-handed).
let shadow_point = light_all_inv
* math::Vec4::from_point(
math::Vec3::unit_x() * p_x, /* + math::Vec4::unit_w() */
);
let shadow_plane = light_all_mat.transposed() * math::Vec4::unit_x();
// Find the point at the intersection of the three planes; note that since the
// equations are already in right-handed world space, we don't need to negate
// the z coordinates.
let solve_p0 = math::Mat4::new(
view_plane.x,
view_plane.y,
view_plane.z,
0.0,
light_plane.x,
light_plane.y,
light_plane.z,
0.0,
shadow_plane.x,
shadow_plane.y,
shadow_plane.z,
0.0,
0.0,
0.0,
0.0,
1.0,
);
// in world-space (right-handed).
let plane_dist = math::Vec4::new(
view_plane.dot(view_point),
light_plane.dot(light_point),
shadow_plane.dot(shadow_point),
1.0,
);
let p0_world = solve_p0.inverted() * plane_dist;
// in rotated light-space (left-handed).
let p0 = light_all_mat * p0_world;
let mut p1 = p0;
// in rotated light-space (left-handed).
p1.y = bounds0.max.y;
// transforms from rotated light-space (left-handed) to view space
// (right-handed).
let view_from_light_mat = view_mat * light_all_inv;
// z0 and z1 are in view space (right-handed).
let z0 = view_from_light_mat * p0;
let z1 = view_from_light_mat * p1;
// Extract the homogenized forward component (right-handed).
//
// NOTE: I don't think the w component should be anything but 1 here, but
// better safe than sorry.
(
f64::from(z0.homogenized().dot(-math::Vec4::unit_z())).clamp(n_e, f_e),
f64::from(z1.homogenized().dot(-math::Vec4::unit_z())).clamp(n_e, f_e),
)
};
// all of this is in rotated light-space (left-handed).
let mut light_focus_pos: math::Vec3<f32> = math::Vec3::zero();
light_focus_pos.x = bounds0.center().x;
light_focus_pos.y = bounds0.min.y;
light_focus_pos.z = bounds0.center().z;
let d = f64::from(bounds0.max.y - bounds0.min.y).abs();
let w_l_y = d;
// NOTE: See section 5.1.2.2 of Lloyd's thesis.
// NOTE: Since z_1 and z_0 are in the same coordinate space, we don't have to
// worry about the handedness of their ratio.
let alpha = z_1 / z_0;
let alpha_sqrt = alpha.sqrt();
let directed_near_normal = if factor < 0.0 {
// Standard shadow map to LiSPSM
(1.0 + alpha_sqrt - factor * (alpha - 1.0)) / ((alpha - 1.0) * (factor + 1.0))
} else {
// LiSPSM to PSM
((alpha_sqrt - 1.0) * (factor * alpha_sqrt + 1.0)).recip()
};
// Equation 5.14 - 5.16
let y_ = |v: f64| w_l_y * (v + directed_near_normal).abs();
let directed_near = y_(0.0) as f32;
let directed_far = y_(1.0) as f32;
light_focus_pos.y = if factor > EPSILON_UPSILON {
light_focus_pos.y - directed_near
} else {
light_focus_pos.y
};
// Left-handed translation.
let w_v: math::Mat4<f32> = math::Mat4::translation_3d(-math::Vec3::new(
light_focus_pos.x,
light_focus_pos.y,
light_focus_pos.z,
));
let shadow_view_mat: math::Mat4<f32> = w_v * light_all_mat;
let w_p: math::Mat4<f32> = {
if factor > EPSILON_UPSILON {
// Projection for y
let near = directed_near;
let far = directed_far;
let left = -1.0;
let right = 1.0;
let bottom = -1.0;
let top = 1.0;
let s_x = 2.0 * near / (right - left);
let o_x = (right + left) / (right - left);
let s_z = 2.0 * near / (top - bottom);
let o_z = (top + bottom) / (top - bottom);
let s_y = (far + near) / (far - near);
let o_y = -2.0 * far * near / (far - near);
math::Mat4::new(
s_x, o_x, 0.0, 0.0, 0.0, s_y, 0.0, o_y, 0.0, o_z, s_z, 0.0, 0.0, 1.0,
0.0, 0.0,
)
} else {
math::Mat4::identity()
}
};
let shadow_all_mat: math::Mat4<f32> = w_p * shadow_view_mat;
// coordinates are transformed from world space (right-handed)
// to post-warp light space (left-handed), then homogenized.
let math::Aabb::<f32> {
min:
math::Vec3 {
x: xmin,
y: ymin,
z: zmin,
},
max:
math::Vec3 {
x: xmax,
y: ymax,
z: zmax,
},
} = math::fit_psr(
shadow_all_mat,
visible_light_volume.iter().copied(),
math::Vec4::homogenized,
);
let s_x = 2.0 / (xmax - xmin);
let s_y = 2.0 / (ymax - ymin);
let s_z = 1.0 / (zmax - zmin);
let o_x = -(xmax + xmin) / (xmax - xmin);
let o_y = -(ymax + ymin) / (ymax - ymin);
let o_z = -zmin / (zmax - zmin);
let directed_proj_mat = Mat4::new(
s_x, 0.0, 0.0, o_x, 0.0, s_y, 0.0, o_y, 0.0, 0.0, s_z, o_z, 0.0, 0.0, 0.0, 1.0,
);
let shadow_all_mat: Mat4<f32> =
Mat4::from_col_arrays(shadow_all_mat.into_col_arrays());
let directed_texture_proj_mat = texture_mat * directed_proj_mat;
let shadow_locals = ShadowLocals::new(
directed_proj_mat * shadow_all_mat,
directed_texture_proj_mat * shadow_all_mat,
);
renderer.update_consts(&mut self.data.shadow_mats, &[shadow_locals]);
let rain_occlusion_locals = RainOcclusionLocals::new(
directed_proj_mat * shadow_all_mat,
directed_texture_proj_mat * shadow_all_mat,
);
renderer
.update_consts(&mut self.data.rain_occlusion_mats, &[rain_occlusion_locals]);
}
directed_shadow_mats.push(light_view_mat);
// This leaves us with five dummy slots, which we push as defaults.
directed_shadow_mats

View File

@ -1104,7 +1104,6 @@ impl PlayState for SessionState {
num_particles: self.scene.particle_mgr().particle_count() as u32,
num_particles_visible: self.scene.particle_mgr().particle_count_visible()
as u32,
weather: client.current_weather(),
}
});