mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added rain occlusion
This commit is contained in:
parent
b3200ed89f
commit
79cac935c8
@ -28,19 +28,19 @@
|
||||
// This *MUST* come after `cloud.glsl`: it contains a function that depends on `cloud.glsl` when clouds are enabled
|
||||
#include <point_glow.glsl>
|
||||
|
||||
layout(set = 1, binding = 0)
|
||||
layout(set = 2, binding = 0)
|
||||
uniform texture2D t_src_color;
|
||||
layout(set = 1, binding = 1)
|
||||
layout(set = 2, binding = 1)
|
||||
uniform sampler s_src_color;
|
||||
|
||||
layout(set = 1, binding = 2)
|
||||
layout(set = 2, binding = 2)
|
||||
uniform texture2D t_src_depth;
|
||||
layout(set = 1, binding = 3)
|
||||
layout(set = 2, binding = 3)
|
||||
uniform sampler s_src_depth;
|
||||
|
||||
layout(location = 0) in vec2 uv;
|
||||
|
||||
layout (std140, set = 1, binding = 4)
|
||||
layout (std140, set = 2, binding = 4)
|
||||
uniform u_locals {
|
||||
mat4 proj_mat_inv;
|
||||
mat4 view_mat_inv;
|
||||
@ -112,40 +112,37 @@ void main() {
|
||||
vec2 view_pos = vec2(atan2(dir_2d.x, dir_2d.y), z);
|
||||
|
||||
vec3 cam_wpos = cam_pos.xyz + focus_off.xyz;
|
||||
float rain_density = rain_density_at(cam_wpos.xy) * 10.0;
|
||||
if (rain_density > 0) {
|
||||
float rain_dist = 150.0;
|
||||
for (int i = 0; i < 7; i ++) {
|
||||
rain_dist *= 0.3;
|
||||
float rain_dist = 150.0;
|
||||
for (int i = 0; i < 7; i ++) {
|
||||
rain_dist *= 0.3;
|
||||
|
||||
vec3 rpos = vec3(vec2(dir_2d), view_pos.y) * rain_dist;
|
||||
float dist_to_rain = length(rpos);
|
||||
|
||||
if (dist < dist_to_rain || cam_wpos.z + rpos.z > CLOUD_AVG_ALT) {
|
||||
vec3 rpos = vec3(vec2(dir_2d), view_pos.y) * rain_dist;
|
||||
float dist_to_rain = length(rpos);
|
||||
if (dist < dist_to_rain || cam_wpos.z + rpos.z > CLOUD_AVG_ALT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dot(rpos * vec3(1, 1, 0.5), rpos) < 1.0) {
|
||||
break;
|
||||
}
|
||||
|
||||
vec2 drop_density = vec2(30, 1);
|
||||
vec2 drop_size = vec2(0.0008, 0.05);
|
||||
|
||||
vec2 rain_pos = (view_pos * rain_dist);
|
||||
rain_pos += vec2(0, tick.x * fall_rate + cam_wpos.z);
|
||||
|
||||
vec2 cell = floor(rain_pos * drop_density) / drop_density;
|
||||
if (fract(hash(fract(vec4(cell, rain_dist, 0) * 0.01))) > rain_density) {
|
||||
continue;
|
||||
}
|
||||
vec2 near_drop = cell + (vec2(0.5) + (vec2(hash(vec4(cell, 0, 0)), 0.5) - 0.5) * vec2(2, 0)) / drop_density;
|
||||
|
||||
float avg_alpha = (drop_size.x * drop_size.y) * 10 / 1;
|
||||
float alpha = sign(max(1 - length((rain_pos - near_drop) / drop_size * 0.1), 0));
|
||||
float light = sqrt(dot(old_color, vec3(1))) + (get_sun_brightness() + get_moon_brightness()) * 0.01;
|
||||
color.rgb = mix(color.rgb, vec3(0.3, 0.4, 0.5) * light, mix(avg_alpha, alpha, min(1000 / dist_to_rain, 1)) * 0.25);
|
||||
if (dot(rpos * vec3(1, 1, 0.5), rpos) < 1.0) {
|
||||
break;
|
||||
}
|
||||
float rain_density = rain_density_at(cam_wpos.xy + rpos.xy) * rain_occlusion_at(cam_pos.xyz + rpos.xyz) * 10.0;
|
||||
|
||||
vec2 drop_density = vec2(30, 1);
|
||||
vec2 drop_size = vec2(0.0008, 0.05);
|
||||
|
||||
vec2 rain_pos = (view_pos * rain_dist);
|
||||
rain_pos += vec2(0, tick.x * fall_rate + cam_wpos.z);
|
||||
|
||||
vec2 cell = floor(rain_pos * drop_density) / drop_density;
|
||||
if (fract(hash(fract(vec4(cell, rain_dist, 0) * 0.01))) > rain_density) {
|
||||
continue;
|
||||
}
|
||||
vec2 near_drop = cell + (vec2(0.5) + (vec2(hash(vec4(cell, 0, 0)), 0.5) - 0.5) * vec2(2, 0)) / drop_density;
|
||||
|
||||
float avg_alpha = (drop_size.x * drop_size.y) * 10 / 1;
|
||||
float alpha = sign(max(1 - length((rain_pos - near_drop) / drop_size * 0.1), 0));
|
||||
float light = sqrt(dot(old_color, vec3(1))) + (get_sun_brightness() + get_moon_brightness()) * 0.01;
|
||||
color.rgb = mix(color.rgb, vec3(0.3, 0.4, 0.5) * light, mix(avg_alpha, alpha, min(1000 / dist_to_rain, 1)) * 0.25);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -150,7 +150,7 @@ void main() {
|
||||
);
|
||||
|
||||
#ifdef EXPERIMENTAL_RAIN
|
||||
float rain_density = rain_density_at(cam_pos.xy + focus_off.xy) * 50.0;
|
||||
float rain_density = rain_density_at(f_pos.xy + focus_off.xy) * rain_occlusion_at(f_pos.xyz) * 50.0;
|
||||
if (rain_density > 0 && surf_norm.z > 0.5) {
|
||||
vec3 drop_density = vec3(2, 2, 2);
|
||||
vec3 drop_pos = wave_pos + vec3(0, 0, -time_of_day.x * 0.025);
|
||||
|
36
assets/voxygen/shaders/include/rain_occlusion.glsl
Normal file
36
assets/voxygen/shaders/include/rain_occlusion.glsl
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
#ifndef RAIN_OCCLUSION_GLSL
|
||||
#define RAIN_OCCLUSION_GLSL
|
||||
|
||||
// Use with sampler2DShadow
|
||||
layout(set = 1, binding = 4)
|
||||
uniform texture2D t_directed_occlusion_maps;
|
||||
layout(set = 1, binding = 5)
|
||||
uniform samplerShadow s_directed_occlusion_maps;
|
||||
|
||||
layout (std140, set = 0, binding = 14)
|
||||
uniform u_rain_occlusion {
|
||||
mat4 occlusionMatrices;
|
||||
mat4 occlusion_texture_mat;
|
||||
};
|
||||
|
||||
float rain_occlusion_at(in vec3 fragPos)
|
||||
{
|
||||
float bias = 0.000;
|
||||
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);
|
||||
|
||||
float visibility = textureProj(sampler2DShadow(t_directed_occlusion_maps, s_directed_occlusion_maps), rain_pos);
|
||||
|
||||
return visibility;
|
||||
}
|
||||
#endif
|
@ -5,6 +5,7 @@
|
||||
#include <srgb.glsl>
|
||||
#include <shadows.glsl>
|
||||
#include <globals.glsl>
|
||||
#include <rain_occlusion.glsl>
|
||||
|
||||
// Information about an approximately directional light, like the sun or moon.
|
||||
struct DirectionalLight {
|
||||
@ -121,8 +122,9 @@ float cloud_tendency_at(vec2 pos) {
|
||||
}
|
||||
|
||||
const float RAIN_CLOUD = 0.05;
|
||||
|
||||
float rain_density_at(vec2 pos) {
|
||||
return sample_weather(pos).g;
|
||||
return 1.0; //sample_weather(pos).g;
|
||||
//return clamp((cloud_tendency_at(pos) - RAIN_CLOUD) * 10, 0, 1);
|
||||
}
|
||||
|
||||
|
61
assets/voxygen/shaders/rain-occlusion-directed-vert.glsl
Normal file
61
assets/voxygen/shaders/rain-occlusion-directed-vert.glsl
Normal file
@ -0,0 +1,61 @@
|
||||
#version 420 core
|
||||
// #extension ARB_texture_storage : enable
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#define HAS_SHADOW_MAPS
|
||||
|
||||
// Currently, we only need globals for focus_off.
|
||||
#include <globals.glsl>
|
||||
// For shadow locals.
|
||||
// #include <shadows.glsl>
|
||||
|
||||
layout (std140, set = 0, binding = 14)
|
||||
uniform u_rain_occlusion {
|
||||
mat4 rainOcclusionMatrices;
|
||||
mat4 texture_mat;
|
||||
};
|
||||
|
||||
/* Accurate packed shadow maps for many lights at once!
|
||||
*
|
||||
* Ideally, we would just write to a bitmask...
|
||||
*
|
||||
* */
|
||||
|
||||
layout(location = 0) in uint v_pos_norm;
|
||||
// in uint v_col_light;
|
||||
// in vec4 v_pos;
|
||||
// layout(location = 1) in uint v_atlas_pos;
|
||||
|
||||
// Light projection matrices.
|
||||
layout (std140, set = 1, binding = 0)
|
||||
uniform u_locals {
|
||||
vec3 model_offs;
|
||||
float load_time;
|
||||
ivec4 atlas_offs;
|
||||
};
|
||||
|
||||
// out vec4 shadowMapCoord;
|
||||
|
||||
const float EXTRA_NEG_Z = 32768.0;
|
||||
|
||||
void main() {
|
||||
vec3 f_chunk_pos = vec3(v_pos_norm & 0x3Fu, (v_pos_norm >> 6) & 0x3Fu, float((v_pos_norm >> 12) & 0xFFFFu) - EXTRA_NEG_Z);
|
||||
vec3 f_pos = f_chunk_pos + (model_offs - focus_off.xyz);
|
||||
|
||||
gl_Position = rainOcclusionMatrices * vec4(f_pos, 1.0);
|
||||
}
|
82
assets/voxygen/shaders/rain-occlusion-figure-vert.glsl
Normal file
82
assets/voxygen/shaders/rain-occlusion-figure-vert.glsl
Normal file
@ -0,0 +1,82 @@
|
||||
#version 420 core
|
||||
// #extension ARB_texture_storage : enable
|
||||
|
||||
#define FIGURE_SHADER
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION
|
||||
|
||||
#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY
|
||||
|
||||
#if (FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE
|
||||
#elif (FLUID_MODE == FLUID_MODE_SHINY)
|
||||
#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_RADIANCE
|
||||
#endif
|
||||
|
||||
#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
#define HAS_SHADOW_MAPS
|
||||
|
||||
// Currently, we only need globals for focus_off.
|
||||
#include <globals.glsl>
|
||||
// For shadow locals.
|
||||
// #include <shadows.glsl>
|
||||
|
||||
layout (std140, set = 0, binding = 14)
|
||||
uniform u_rain_occlusion {
|
||||
mat4 rainOcclusionMatrices;
|
||||
mat4 texture_mat;
|
||||
};
|
||||
|
||||
/* Accurate packed shadow maps for many lights at once!
|
||||
*
|
||||
* Ideally, we would just write to a bitmask...
|
||||
*
|
||||
* */
|
||||
|
||||
layout(location = 0) in uint v_pos_norm;
|
||||
layout(location = 1) in uint v_atlas_pos;
|
||||
// in uint v_col_light;
|
||||
// in vec4 v_pos;
|
||||
|
||||
layout (std140, set = 1, binding = 0)
|
||||
uniform u_locals {
|
||||
mat4 model_mat;
|
||||
vec4 highlight_col;
|
||||
vec4 model_light;
|
||||
vec4 model_glow;
|
||||
ivec4 atlas_offs;
|
||||
vec3 model_pos;
|
||||
// bit 0 - is player
|
||||
// bit 1-31 - unused
|
||||
int flags;
|
||||
};
|
||||
|
||||
struct BoneData {
|
||||
mat4 bone_mat;
|
||||
mat4 normals_mat;
|
||||
};
|
||||
|
||||
layout (std140, set = 1, binding = 1)
|
||||
uniform u_bones {
|
||||
// Warning: might not actually be 16 elements long. Don't index out of bounds!
|
||||
BoneData bones[16];
|
||||
};
|
||||
|
||||
// out vec4 shadowMapCoord;
|
||||
|
||||
void main() {
|
||||
uint bone_idx = (v_pos_norm >> 27) & 0xFu;
|
||||
vec3 pos = (vec3((uvec3(v_pos_norm) >> uvec3(0, 9, 18)) & uvec3(0x1FFu)) - 256.0) / 2.0;
|
||||
|
||||
vec3 f_pos = (
|
||||
bones[bone_idx].bone_mat *
|
||||
vec4(pos, 1.0)
|
||||
).xyz + (model_pos - focus_off.xyz/* + vec3(0.0, 0.0, 0.0001)*/);
|
||||
|
||||
gl_Position = rainOcclusionMatrices * vec4(f_pos, 1.0);
|
||||
}
|
@ -30,7 +30,7 @@ layout(location = 7) in float inst_glow;
|
||||
layout(location = 8) in float model_wind_sway; // NOTE: this only varies per model
|
||||
layout(location = 9) in float model_z_scale; // NOTE: this only varies per model
|
||||
|
||||
layout(set = 0, binding = 14) restrict readonly buffer sprite_verts {
|
||||
layout(set = 0, binding = 15) restrict readonly buffer sprite_verts {
|
||||
uvec2 verts[];
|
||||
};
|
||||
|
||||
|
@ -232,9 +232,11 @@ void main() {
|
||||
vec3 k_s = vec3(R_s);
|
||||
|
||||
#ifdef EXPERIMENTAL_RAIN
|
||||
float rain_density = rain_density_at(cam_pos.xy + focus_off.xy) * 50.0;
|
||||
vec3 pos = f_pos + focus_off.xyz;
|
||||
float rain_density = rain_density_at(pos.xy) * rain_occlusion_at(f_pos.xyz) * 50.0;
|
||||
// tgt_color = vec4(rain_occlusion_at(f_pos.xyz), 0.0, 0.0, 1.0);
|
||||
// return;
|
||||
if (rain_density > 0 && !faces_fluid && f_norm.z > 0.5) {
|
||||
vec3 pos = f_pos + focus_off.xyz;
|
||||
vec3 drop_density = vec3(2, 2, 2);
|
||||
vec3 drop_pos = pos + vec3(pos.zz, 0) + vec3(0, 0, -tick.x * 1.0);
|
||||
drop_pos.z += noise_2d(floor(drop_pos.xy * drop_density.xy) * 13.1) * 10;
|
||||
|
@ -166,11 +166,13 @@ impl WeatherLerp {
|
||||
fn update(&mut self) {
|
||||
let old = &self.old.0;
|
||||
let new = &self.new.0;
|
||||
if old.size() != new.size() {
|
||||
if self.current.size() != new.size() {
|
||||
self.current = new.clone();
|
||||
}
|
||||
} else {
|
||||
if new.size() == Vec2::zero() {
|
||||
return;
|
||||
}
|
||||
if self.current.size() != new.size() {
|
||||
self.current = new.clone();
|
||||
}
|
||||
if old.size() == new.size() {
|
||||
// Assume updates are regular
|
||||
let t = (self.new.1.elapsed().as_secs_f32()
|
||||
/ self.new.1.duration_since(self.old.1).as_secs_f32())
|
||||
|
@ -186,7 +186,9 @@ pub fn handle_mine_block(
|
||||
) {
|
||||
let skill_group = SkillGroupKind::Weapon(tool);
|
||||
let outcome_bus = state.ecs().read_resource::<EventBus<Outcome>>();
|
||||
if let Some(level_outcome) = skillset.add_experience(skill_group, exp_reward) {
|
||||
if let Some(level_outcome) =
|
||||
skillset.add_experience(skill_group, exp_reward)
|
||||
{
|
||||
outcome_bus.emit_now(Outcome::SkillPointGain {
|
||||
uid,
|
||||
skill_tree: skill_group,
|
||||
|
@ -13,8 +13,8 @@ use common::{
|
||||
};
|
||||
use common_state::State;
|
||||
use serde::Deserialize;
|
||||
use strum::IntoEnumIterator;
|
||||
use std::time::Instant;
|
||||
use strum::IntoEnumIterator;
|
||||
use tracing::warn;
|
||||
use vek::*;
|
||||
|
||||
@ -66,14 +66,17 @@ impl AmbientMgr {
|
||||
if index >= audio.ambient_channels.len() {
|
||||
println!("Creating audio channel with this tag: {:?}", tag);
|
||||
audio.new_ambient_channel(tag);
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
// even if the conditions don't warrant the creation of a channel
|
||||
// with that tag, but a channel with that tag remains
|
||||
// nonetheless, run the code
|
||||
// even if the conditions don't warrant the creation of a
|
||||
// channel with that tag, but a channel with
|
||||
// that tag remains nonetheless, run the code
|
||||
} else if audio.get_ambient_channel(tag).is_some() {
|
||||
println!("Channel for {:?} is actually present, performing volume code", tag);
|
||||
println!(
|
||||
"Channel for {:?} is actually present, performing volume code",
|
||||
tag
|
||||
);
|
||||
for index in 0..AmbientChannelTag::iter().len() {
|
||||
// update with sfx volume
|
||||
audio.ambient_channels[index].set_volume(sfx_volume);
|
||||
@ -121,7 +124,11 @@ impl AmbientMgr {
|
||||
|
||||
// remove channel if not playing
|
||||
if audio.ambient_channels[index].get_multiplier() == 0.0 {
|
||||
println!("Removing channel {:?} with tag {:?}", index, audio.ambient_channels[index].get_tag());
|
||||
println!(
|
||||
"Removing channel {:?} with tag {:?}",
|
||||
index,
|
||||
audio.ambient_channels[index].get_tag()
|
||||
);
|
||||
audio.ambient_channels[index].stop();
|
||||
audio.ambient_channels.remove(index);
|
||||
};
|
||||
@ -182,8 +189,8 @@ impl AmbientMgr {
|
||||
// Tree density factors into wind volume. The more trees,
|
||||
// the lower wind volume. The trees make more of an impact
|
||||
// the closer the camera is to the ground.
|
||||
let tree_multiplier =
|
||||
1.0 - (((1.0 - tree_density) + ((cam_pos.z - terrain_alt).abs() / 150.0).powi(2)).min(1.0));
|
||||
let tree_multiplier = 1.0
|
||||
- (((1.0 - tree_density) + ((cam_pos.z - terrain_alt).abs() / 150.0).powi(2)).min(1.0));
|
||||
|
||||
return tree_multiplier > 0.05;
|
||||
}
|
||||
@ -264,10 +271,13 @@ impl AmbientChannel {
|
||||
let tree_multiplier =
|
||||
((1.0 - tree_density) + ((cam_pos.z - terrain_alt).abs() / 150.0).powi(2)).min(1.0);
|
||||
|
||||
// Lastly, we of course have to take into account actual wind speed from weathersim
|
||||
// Lastly, we of course have to take into account actual wind speed from
|
||||
// weathersim
|
||||
let wind_speed_multiplier = (client_wind_speed_sq / 30.0_f32.powi(2)).min(1.0);
|
||||
|
||||
return alt_multiplier * tree_multiplier * (wind_speed_multiplier + ((cam_pos.z - terrain_alt).abs() / 150.0).powi(2)).min(1.0);
|
||||
return alt_multiplier
|
||||
* tree_multiplier
|
||||
* (wind_speed_multiplier + ((cam_pos.z - terrain_alt).abs() / 150.0).powi(2)).min(1.0);
|
||||
}
|
||||
|
||||
fn get_rain_volume(&mut self, client: &Client) -> f32 {
|
||||
@ -301,8 +311,8 @@ impl AmbientChannel {
|
||||
// Tree density factors into wind volume. The more trees,
|
||||
// the lower wind volume. The trees make more of an impact
|
||||
// the closer the camera is to the ground.
|
||||
let tree_multiplier =
|
||||
1.0 - (((1.0 - tree_density) + ((cam_pos.z - terrain_alt).abs() / 150.0).powi(2)).min(1.0));
|
||||
let tree_multiplier = 1.0
|
||||
- (((1.0 - tree_density) + ((cam_pos.z - terrain_alt).abs() / 150.0).powi(2)).min(1.0));
|
||||
|
||||
if tree_multiplier > 0.05 {
|
||||
tree_multiplier
|
||||
|
@ -22,8 +22,8 @@ use crate::audio::{
|
||||
};
|
||||
use rodio::{OutputStreamHandle, Sample, Sink, Source, SpatialSink};
|
||||
use serde::Deserialize;
|
||||
use strum::EnumIter;
|
||||
use std::time::Instant;
|
||||
use strum::EnumIter;
|
||||
use tracing::warn;
|
||||
use vek::*;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::render::{
|
||||
GlobalModel, Globals, GlobalsBindGroup, Light, LodData, PointLightMatrix, Renderer, Shadow,
|
||||
ShadowLocals,
|
||||
GlobalModel, Globals, GlobalsBindGroup, Light, LodData, PointLightMatrix, RainOcclusionLocals,
|
||||
Renderer, Shadow, ShadowLocals,
|
||||
};
|
||||
|
||||
pub struct Scene {
|
||||
@ -14,6 +14,8 @@ impl Scene {
|
||||
lights: renderer.create_consts(&[Light::default(); 32]),
|
||||
shadows: renderer.create_consts(&[Shadow::default(); 32]),
|
||||
shadow_mats: renderer.create_shadow_bound_locals(&[ShadowLocals::default()]),
|
||||
rain_occlusion_mats: renderer
|
||||
.create_rain_occlusion_bound_locals(&[RainOcclusionLocals::default()]),
|
||||
point_light_matrices: Box::new([PointLightMatrix::default(); 126]),
|
||||
};
|
||||
|
||||
|
@ -30,6 +30,7 @@ pub use self::{
|
||||
lod_terrain::{LodData, Vertex as LodTerrainVertex},
|
||||
particle::{Instance as ParticleInstance, Vertex as ParticleVertex},
|
||||
postprocess::Locals as PostProcessLocals,
|
||||
rain_occlusion::Locals as RainOcclusionLocals,
|
||||
shadow::{Locals as ShadowLocals, PointLightMatrix},
|
||||
skybox::{create_mesh as create_skybox_mesh, Vertex as SkyboxVertex},
|
||||
sprite::{
|
||||
@ -122,6 +123,10 @@ pub enum CloudMode {
|
||||
High,
|
||||
}
|
||||
|
||||
impl CloudMode {
|
||||
pub fn is_enabled(&self) -> bool { *self != CloudMode::None }
|
||||
}
|
||||
|
||||
impl Default for CloudMode {
|
||||
fn default() -> Self { CloudMode::High }
|
||||
}
|
||||
@ -398,7 +403,7 @@ impl RenderMode {
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
pub struct PipelineModes {
|
||||
aa: AaMode,
|
||||
cloud: CloudMode,
|
||||
pub cloud: CloudMode,
|
||||
fluid: FluidMode,
|
||||
lighting: LightingMode,
|
||||
pub shadow: ShadowMode,
|
||||
|
@ -153,7 +153,11 @@ impl CloudsPipeline {
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("Clouds pipeline layout"),
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[&global_layout.globals, &layout.layout],
|
||||
bind_group_layouts: &[
|
||||
&global_layout.globals,
|
||||
&global_layout.shadow_textures,
|
||||
&layout.layout,
|
||||
],
|
||||
});
|
||||
|
||||
let samples = match aa_mode {
|
||||
|
@ -8,6 +8,7 @@ pub mod lod_object;
|
||||
pub mod lod_terrain;
|
||||
pub mod particle;
|
||||
pub mod postprocess;
|
||||
pub mod rain_occlusion;
|
||||
pub mod shadow;
|
||||
pub mod skybox;
|
||||
pub mod sprite;
|
||||
@ -254,6 +255,7 @@ pub struct GlobalModel {
|
||||
pub lights: Consts<Light>,
|
||||
pub shadows: Consts<Shadow>,
|
||||
pub shadow_mats: shadow::BoundLocals,
|
||||
pub rain_occlusion_mats: rain_occlusion::BoundLocals,
|
||||
pub point_light_matrices: Box<[shadow::PointLightMatrix; 126]>,
|
||||
}
|
||||
|
||||
@ -425,6 +427,18 @@ impl GlobalsLayouts {
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
// rain occlusion
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 14,
|
||||
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||
// TODO: is this relevant?
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@ -503,6 +517,26 @@ impl GlobalsLayouts {
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
// Rain occlusion maps
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 4,
|
||||
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
sample_type: wgpu::TextureSampleType::Depth,
|
||||
view_dimension: wgpu::TextureViewDimension::D2,
|
||||
multisampled: false,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 5,
|
||||
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler {
|
||||
filtering: true,
|
||||
comparison: true,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@ -584,6 +618,11 @@ impl GlobalsLayouts {
|
||||
binding: 13,
|
||||
resource: wgpu::BindingResource::Sampler(&lod_data.weather.sampler),
|
||||
},
|
||||
// rain occlusion
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 14,
|
||||
resource: global_model.rain_occlusion_mats.buf().as_entire_binding(),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@ -608,6 +647,7 @@ impl GlobalsLayouts {
|
||||
device: &wgpu::Device,
|
||||
point_shadow_map: &Texture,
|
||||
directed_shadow_map: &Texture,
|
||||
rain_occlusion_map: &Texture,
|
||||
) -> ShadowTexturesBindGroup {
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
@ -629,6 +669,14 @@ impl GlobalsLayouts {
|
||||
binding: 3,
|
||||
resource: wgpu::BindingResource::Sampler(&directed_shadow_map.sampler),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 4,
|
||||
resource: wgpu::BindingResource::TextureView(&rain_occlusion_map.view),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 5,
|
||||
resource: wgpu::BindingResource::Sampler(&rain_occlusion_map.sampler),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
|
213
voxygen/src/render/pipelines/rain_occlusion.rs
Normal file
213
voxygen/src/render/pipelines/rain_occlusion.rs
Normal file
@ -0,0 +1,213 @@
|
||||
use super::super::{
|
||||
AaMode, Bound, Consts, FigureLayout, GlobalsLayouts, TerrainLayout, TerrainVertex,
|
||||
};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use vek::*;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||
pub struct Locals {
|
||||
shadow_matrices: [[f32; 4]; 4],
|
||||
texture_mats: [[f32; 4]; 4],
|
||||
}
|
||||
|
||||
impl Locals {
|
||||
pub fn new(shadow_mat: Mat4<f32>, texture_mat: Mat4<f32>) -> Self {
|
||||
Self {
|
||||
shadow_matrices: shadow_mat.into_col_arrays(),
|
||||
texture_mats: texture_mat.into_col_arrays(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default() -> Self { Self::new(Mat4::identity(), Mat4::identity()) }
|
||||
}
|
||||
|
||||
pub type BoundLocals = Bound<Consts<Locals>>;
|
||||
|
||||
pub struct RainOcclusionLayout {
|
||||
pub locals: wgpu::BindGroupLayout,
|
||||
}
|
||||
|
||||
impl RainOcclusionLayout {
|
||||
pub fn new(device: &wgpu::Device) -> Self {
|
||||
Self {
|
||||
locals: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
label: None,
|
||||
entries: &[wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
}],
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bind_locals(&self, device: &wgpu::Device, locals: Consts<Locals>) -> BoundLocals {
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &self.locals,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: locals.buf().as_entire_binding(),
|
||||
}],
|
||||
});
|
||||
|
||||
BoundLocals {
|
||||
bind_group,
|
||||
with: locals,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RainOcclusionFigurePipeline {
|
||||
pub pipeline: wgpu::RenderPipeline,
|
||||
}
|
||||
|
||||
impl RainOcclusionFigurePipeline {
|
||||
pub fn new(
|
||||
device: &wgpu::Device,
|
||||
vs_module: &wgpu::ShaderModule,
|
||||
global_layout: &GlobalsLayouts,
|
||||
figure_layout: &FigureLayout,
|
||||
aa_mode: AaMode,
|
||||
) -> Self {
|
||||
common_base::span!(_guard, "new");
|
||||
|
||||
let render_pipeline_layout =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("Directed figure shadow pipeline layout"),
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[&global_layout.globals, &figure_layout.locals],
|
||||
});
|
||||
|
||||
let samples = match aa_mode {
|
||||
AaMode::None | AaMode::Fxaa => 1,
|
||||
AaMode::MsaaX4 => 4,
|
||||
AaMode::MsaaX8 => 8,
|
||||
AaMode::MsaaX16 => 16,
|
||||
};
|
||||
|
||||
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Directed shadow figure pipeline"),
|
||||
layout: Some(&render_pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: vs_module,
|
||||
entry_point: "main",
|
||||
buffers: &[TerrainVertex::desc()],
|
||||
},
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
strip_index_format: None,
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: None,
|
||||
clamp_depth: true,
|
||||
polygon_mode: wgpu::PolygonMode::Fill,
|
||||
conservative: false,
|
||||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24Plus,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::Less,
|
||||
stencil: wgpu::StencilState {
|
||||
front: wgpu::StencilFaceState::IGNORE,
|
||||
back: wgpu::StencilFaceState::IGNORE,
|
||||
read_mask: !0,
|
||||
write_mask: !0,
|
||||
},
|
||||
bias: wgpu::DepthBiasState {
|
||||
constant: 0,
|
||||
slope_scale: 0.0,
|
||||
clamp: 0.0,
|
||||
},
|
||||
}),
|
||||
multisample: wgpu::MultisampleState {
|
||||
count: samples,
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
fragment: None,
|
||||
});
|
||||
|
||||
Self {
|
||||
pipeline: render_pipeline,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RainOcclusionPipeline {
|
||||
pub pipeline: wgpu::RenderPipeline,
|
||||
}
|
||||
|
||||
impl RainOcclusionPipeline {
|
||||
pub fn new(
|
||||
device: &wgpu::Device,
|
||||
vs_module: &wgpu::ShaderModule,
|
||||
global_layout: &GlobalsLayouts,
|
||||
terrain_layout: &TerrainLayout,
|
||||
aa_mode: AaMode,
|
||||
) -> Self {
|
||||
let render_pipeline_layout =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("Rain occlusion pipeline layout"),
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[&global_layout.globals, &terrain_layout.locals],
|
||||
});
|
||||
|
||||
let samples = match aa_mode {
|
||||
AaMode::None | AaMode::Fxaa => 1,
|
||||
AaMode::MsaaX4 => 4,
|
||||
AaMode::MsaaX8 => 8,
|
||||
AaMode::MsaaX16 => 16,
|
||||
};
|
||||
|
||||
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Rain occlusion pipeline"),
|
||||
layout: Some(&render_pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: vs_module,
|
||||
entry_point: "main",
|
||||
buffers: &[TerrainVertex::desc()],
|
||||
},
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
strip_index_format: None,
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: Some(wgpu::Face::Front),
|
||||
clamp_depth: true,
|
||||
polygon_mode: wgpu::PolygonMode::Fill,
|
||||
conservative: false,
|
||||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24Plus,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::Less,
|
||||
stencil: wgpu::StencilState {
|
||||
front: wgpu::StencilFaceState::IGNORE,
|
||||
back: wgpu::StencilFaceState::IGNORE,
|
||||
read_mask: !0,
|
||||
write_mask: !0,
|
||||
},
|
||||
bias: wgpu::DepthBiasState {
|
||||
constant: 0,
|
||||
slope_scale: 0.0,
|
||||
clamp: 0.0,
|
||||
},
|
||||
}),
|
||||
multisample: wgpu::MultisampleState {
|
||||
count: samples,
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
fragment: None,
|
||||
});
|
||||
|
||||
Self {
|
||||
pipeline: render_pipeline,
|
||||
}
|
||||
}
|
||||
}
|
@ -176,11 +176,11 @@ pub struct SpriteLayout {
|
||||
impl SpriteLayout {
|
||||
pub fn new(device: &wgpu::Device) -> Self {
|
||||
let mut entries = GlobalsLayouts::base_globals_layout();
|
||||
debug_assert_eq!(14, entries.len()); // To remember to adjust the bindings below
|
||||
debug_assert_eq!(15, entries.len()); // To remember to adjust the bindings below
|
||||
entries.extend_from_slice(&[
|
||||
// sprite_verts
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 14,
|
||||
binding: 15,
|
||||
visibility: wgpu::ShaderStage::VERTEX,
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Storage { read_only: true },
|
||||
@ -214,7 +214,7 @@ impl SpriteLayout {
|
||||
entries.extend_from_slice(&[
|
||||
// sprite_verts
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 14,
|
||||
binding: 15,
|
||||
resource: sprite_verts.0.buf.as_entire_binding(),
|
||||
},
|
||||
]);
|
||||
|
@ -3,6 +3,7 @@ pub(super) mod drawer;
|
||||
// Consts and bind groups for post-process and clouds
|
||||
mod locals;
|
||||
mod pipeline_creation;
|
||||
mod rain_occlusion_map;
|
||||
mod screenshot;
|
||||
mod shaders;
|
||||
mod shadow_map;
|
||||
@ -14,6 +15,8 @@ use pipeline_creation::{
|
||||
use shaders::Shaders;
|
||||
use shadow_map::{ShadowMap, ShadowMapRenderer};
|
||||
|
||||
use self::{pipeline_creation::RainOcclusionPipelines, rain_occlusion_map::RainOcclusionMap};
|
||||
|
||||
use super::{
|
||||
buffer::Buffer,
|
||||
consts::Consts,
|
||||
@ -21,8 +24,8 @@ use super::{
|
||||
mesh::Mesh,
|
||||
model::{DynamicModel, Model},
|
||||
pipelines::{
|
||||
blit, bloom, clouds, debug, figure, postprocess, shadow, sprite, terrain, ui,
|
||||
GlobalsBindGroup, GlobalsLayouts, ShadowTexturesBindGroup,
|
||||
blit, bloom, clouds, debug, figure, postprocess, rain_occlusion, shadow, sprite, terrain,
|
||||
ui, GlobalsBindGroup, GlobalsLayouts, ShadowTexturesBindGroup,
|
||||
},
|
||||
texture::Texture,
|
||||
AaMode, AddressMode, FilterMode, OtherModes, PipelineModes, RenderError, RenderMode,
|
||||
@ -54,6 +57,7 @@ struct ImmutableLayouts {
|
||||
debug: debug::DebugLayout,
|
||||
figure: figure::FigureLayout,
|
||||
shadow: shadow::ShadowLayout,
|
||||
rain_occlusion: rain_occlusion::RainOcclusionLayout,
|
||||
sprite: sprite::SpriteLayout,
|
||||
terrain: terrain::TerrainLayout,
|
||||
clouds: clouds::CloudsLayout,
|
||||
@ -90,6 +94,7 @@ struct Views {
|
||||
|
||||
/// Shadow rendering textures, layouts, pipelines, and bind groups
|
||||
struct Shadow {
|
||||
rain_map: RainOcclusionMap,
|
||||
map: ShadowMap,
|
||||
bind: ShadowTexturesBindGroup,
|
||||
}
|
||||
@ -104,6 +109,7 @@ enum State {
|
||||
Interface {
|
||||
pipelines: InterfacePipelines,
|
||||
shadow_views: Option<(Texture, Texture)>,
|
||||
rain_occlusion_view: Option<Texture>,
|
||||
// In progress creation of the remaining pipelines in the background
|
||||
creating: PipelineCreation<IngameAndShadowPipelines>,
|
||||
},
|
||||
@ -117,6 +123,7 @@ enum State {
|
||||
(
|
||||
Pipelines,
|
||||
ShadowPipelines,
|
||||
RainOcclusionPipelines,
|
||||
Arc<postprocess::PostProcessLayout>,
|
||||
),
|
||||
RenderError,
|
||||
@ -359,6 +366,16 @@ impl Renderer {
|
||||
})
|
||||
.ok();
|
||||
|
||||
let rain_occlusion_view = RainOcclusionMap::create_view(
|
||||
&device,
|
||||
(dims.width, dims.height),
|
||||
&ShadowMapMode::try_from(pipeline_modes.shadow).unwrap_or_default(),
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("Could not create rain occlusion map views: {:?}", err);
|
||||
})
|
||||
.ok();
|
||||
|
||||
let shaders = Shaders::load_expect("");
|
||||
let shaders_watcher = shaders.reload_watcher();
|
||||
|
||||
@ -368,6 +385,7 @@ impl Renderer {
|
||||
let debug = debug::DebugLayout::new(&device);
|
||||
let figure = figure::FigureLayout::new(&device);
|
||||
let shadow = shadow::ShadowLayout::new(&device);
|
||||
let rain_occlusion = rain_occlusion::RainOcclusionLayout::new(&device);
|
||||
let sprite = sprite::SpriteLayout::new(&device);
|
||||
let terrain = terrain::TerrainLayout::new(&device);
|
||||
let clouds = clouds::CloudsLayout::new(&device);
|
||||
@ -385,6 +403,7 @@ impl Renderer {
|
||||
debug,
|
||||
figure,
|
||||
shadow,
|
||||
rain_occlusion,
|
||||
sprite,
|
||||
terrain,
|
||||
clouds,
|
||||
@ -417,6 +436,7 @@ impl Renderer {
|
||||
let state = State::Interface {
|
||||
pipelines: interface_pipelines,
|
||||
shadow_views,
|
||||
rain_occlusion_view,
|
||||
creating,
|
||||
};
|
||||
|
||||
@ -680,34 +700,49 @@ impl Renderer {
|
||||
|
||||
// Get mutable reference to shadow views out of the current state
|
||||
let shadow_views = match &mut self.state {
|
||||
State::Interface { shadow_views, .. } => {
|
||||
shadow_views.as_mut().map(|s| (&mut s.0, &mut s.1))
|
||||
},
|
||||
State::Interface {
|
||||
shadow_views,
|
||||
rain_occlusion_view,
|
||||
..
|
||||
} => shadow_views
|
||||
.as_mut()
|
||||
.map(|s| (&mut s.0, &mut s.1))
|
||||
.zip(rain_occlusion_view.as_mut()),
|
||||
State::Complete {
|
||||
shadow:
|
||||
Shadow {
|
||||
map: ShadowMap::Enabled(shadow_map),
|
||||
rain_map: RainOcclusionMap::Enabled(rain_occlusion_map),
|
||||
..
|
||||
},
|
||||
..
|
||||
} => Some((&mut shadow_map.point_depth, &mut shadow_map.directed_depth)),
|
||||
} => Some((
|
||||
(&mut shadow_map.point_depth, &mut shadow_map.directed_depth),
|
||||
&mut rain_occlusion_map.depth,
|
||||
)),
|
||||
State::Complete { .. } => None,
|
||||
State::Nothing => None, // Should never hit this
|
||||
};
|
||||
|
||||
if let (Some((point_depth, directed_depth)), ShadowMode::Map(mode)) =
|
||||
if let (Some(((point_depth, directed_depth), rain_depth)), ShadowMode::Map(mode)) =
|
||||
(shadow_views, self.pipeline_modes.shadow)
|
||||
{
|
||||
match ShadowMap::create_shadow_views(&self.device, (dims.x, dims.y), &mode) {
|
||||
Ok((new_point_depth, new_directed_depth)) => {
|
||||
match (
|
||||
ShadowMap::create_shadow_views(&self.device, (dims.x, dims.y), &mode),
|
||||
RainOcclusionMap::create_view(&self.device, (dims.x, dims.y), &mode),
|
||||
) {
|
||||
(Ok((new_point_depth, new_directed_depth)), Ok(new_rain_depth)) => {
|
||||
*point_depth = new_point_depth;
|
||||
*directed_depth = new_directed_depth;
|
||||
*rain_depth = new_rain_depth;
|
||||
|
||||
// Recreate the shadow bind group if needed
|
||||
if let State::Complete {
|
||||
shadow:
|
||||
Shadow {
|
||||
bind,
|
||||
map: ShadowMap::Enabled(shadow_map),
|
||||
rain_map: RainOcclusionMap::Enabled(rain_occlusion_map),
|
||||
..
|
||||
},
|
||||
..
|
||||
@ -717,11 +752,17 @@ impl Renderer {
|
||||
&self.device,
|
||||
&shadow_map.point_depth,
|
||||
&shadow_map.directed_depth,
|
||||
&rain_occlusion_map.depth,
|
||||
);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
warn!("Could not create shadow map views: {:?}", err);
|
||||
(shadow, rain) => {
|
||||
if let Err(err) = shadow {
|
||||
warn!("Could not create shadow map views: {:?}", err);
|
||||
}
|
||||
if let Err(err) = rain {
|
||||
warn!("Could not create rain occlusion map view: {:?}", err);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -951,12 +992,17 @@ impl Renderer {
|
||||
self.state = if let State::Interface {
|
||||
pipelines: interface,
|
||||
shadow_views,
|
||||
rain_occlusion_view,
|
||||
creating,
|
||||
} = state
|
||||
{
|
||||
match creating.try_complete() {
|
||||
Ok(pipelines) => {
|
||||
let IngameAndShadowPipelines { ingame, shadow } = pipelines;
|
||||
let IngameAndShadowPipelines {
|
||||
ingame,
|
||||
shadow,
|
||||
rain_occlusion,
|
||||
} = pipelines;
|
||||
|
||||
let pipelines = Pipelines::consolidate(interface, ingame);
|
||||
|
||||
@ -969,14 +1015,26 @@ impl Renderer {
|
||||
shadow_views,
|
||||
);
|
||||
|
||||
let rain_occlusion_map = RainOcclusionMap::new(
|
||||
&self.device,
|
||||
&self.queue,
|
||||
rain_occlusion.terrain,
|
||||
rain_occlusion.figure,
|
||||
rain_occlusion_view,
|
||||
);
|
||||
|
||||
let shadow_bind = {
|
||||
let (point, directed) = shadow_map.textures();
|
||||
self.layouts
|
||||
.global
|
||||
.bind_shadow_textures(&self.device, point, directed)
|
||||
self.layouts.global.bind_shadow_textures(
|
||||
&self.device,
|
||||
point,
|
||||
directed,
|
||||
rain_occlusion_map.texture(),
|
||||
)
|
||||
};
|
||||
|
||||
let shadow = Shadow {
|
||||
rain_map: rain_occlusion_map,
|
||||
map: shadow_map,
|
||||
bind: shadow_bind,
|
||||
};
|
||||
@ -991,6 +1049,7 @@ impl Renderer {
|
||||
Err(creating) => State::Interface {
|
||||
pipelines: interface,
|
||||
shadow_views,
|
||||
rain_occlusion_view,
|
||||
creating,
|
||||
},
|
||||
}
|
||||
@ -1002,7 +1061,12 @@ impl Renderer {
|
||||
} = state
|
||||
{
|
||||
match pipeline_creation.try_complete() {
|
||||
Ok(Ok((pipelines, shadow_pipelines, postprocess_layout))) => {
|
||||
Ok(Ok((
|
||||
pipelines,
|
||||
shadow_pipelines,
|
||||
rain_occlusion_pipelines,
|
||||
postprocess_layout,
|
||||
))) => {
|
||||
if let (
|
||||
Some(point_pipeline),
|
||||
Some(terrain_directed_pipeline),
|
||||
@ -1019,6 +1083,19 @@ impl Renderer {
|
||||
shadow_map.figure_directed_pipeline = figure_directed_pipeline;
|
||||
}
|
||||
|
||||
if let (
|
||||
Some(terrain_directed_pipeline),
|
||||
Some(figure_directed_pipeline),
|
||||
RainOcclusionMap::Enabled(rain_occlusion_map),
|
||||
) = (
|
||||
rain_occlusion_pipelines.terrain,
|
||||
rain_occlusion_pipelines.figure,
|
||||
&mut shadow.rain_map,
|
||||
) {
|
||||
rain_occlusion_map.terrain_pipeline = terrain_directed_pipeline;
|
||||
rain_occlusion_map.figure_pipeline = figure_directed_pipeline;
|
||||
}
|
||||
|
||||
self.pipeline_modes = new_pipeline_modes;
|
||||
self.layouts.postprocess = postprocess_layout;
|
||||
// TODO: we have the potential to skip recreating bindings / render targets on
|
||||
|
@ -1,3 +1,5 @@
|
||||
use crate::render::pipelines::rain_occlusion;
|
||||
|
||||
use super::{
|
||||
super::{
|
||||
pipelines::{
|
||||
@ -74,6 +76,16 @@ impl Renderer {
|
||||
self.layouts.shadow.bind_locals(&self.device, locals)
|
||||
}
|
||||
|
||||
pub fn create_rain_occlusion_bound_locals(
|
||||
&mut self,
|
||||
locals: &[rain_occlusion::Locals],
|
||||
) -> rain_occlusion::BoundLocals {
|
||||
let locals = self.create_consts(locals);
|
||||
self.layouts
|
||||
.rain_occlusion
|
||||
.bind_locals(&self.device, locals)
|
||||
}
|
||||
|
||||
pub fn figure_bind_col_light(&self, col_light: Texture) -> ColLights<figure::Locals> {
|
||||
self.layouts.global.bind_col_light(&self.device, col_light)
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ use super::{
|
||||
ShadowTexturesBindGroup,
|
||||
},
|
||||
},
|
||||
rain_occlusion_map::{RainOcclusionMap, RainOcclusionMapRenderer},
|
||||
Renderer, ShadowMap, ShadowMapRenderer,
|
||||
};
|
||||
use core::{num::NonZeroU32, ops::Range};
|
||||
@ -135,6 +136,46 @@ impl<'frame> Drawer<'frame> {
|
||||
/// Get the pipeline modes.
|
||||
pub fn pipeline_modes(&self) -> &super::super::PipelineModes { self.borrow.pipeline_modes }
|
||||
|
||||
/// Returns None if the shadow renderer is not enabled at some level or the
|
||||
/// pipelines are not available yet
|
||||
pub fn rain_occlusion_pass(&mut self) -> Option<RainOcclusionPassDrawer> {
|
||||
if !self.borrow.pipeline_modes.cloud.is_enabled() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let RainOcclusionMap::Enabled(ref rain_occlusion_renderer) = self.borrow.shadow?.rain_map
|
||||
{
|
||||
let encoder = self.encoder.as_mut().unwrap();
|
||||
let device = self.borrow.device;
|
||||
let mut render_pass = encoder.scoped_render_pass(
|
||||
"rain_occlusion_pass",
|
||||
device,
|
||||
&wgpu::RenderPassDescriptor {
|
||||
label: Some("rain occlusion pass"),
|
||||
color_attachments: &[],
|
||||
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
|
||||
view: &rain_occlusion_renderer.depth.view,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(1.0),
|
||||
store: true,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
|
||||
|
||||
Some(RainOcclusionPassDrawer {
|
||||
render_pass,
|
||||
borrow: &self.borrow,
|
||||
rain_occlusion_renderer,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns None if the shadow renderer is not enabled at some level or the
|
||||
/// pipelines are not available yet
|
||||
pub fn shadow_pass(&mut self) -> Option<ShadowPassDrawer> {
|
||||
@ -216,6 +257,8 @@ impl<'frame> Drawer<'frame> {
|
||||
/// Returns None if the clouds pipeline is not available
|
||||
pub fn second_pass(&mut self) -> Option<SecondPassDrawer> {
|
||||
let pipelines = &self.borrow.pipelines.all()?;
|
||||
let shadow = self.borrow.shadow?;
|
||||
|
||||
let encoder = self.encoder.as_mut().unwrap();
|
||||
let device = self.borrow.device;
|
||||
let mut render_pass =
|
||||
@ -237,6 +280,7 @@ impl<'frame> Drawer<'frame> {
|
||||
});
|
||||
|
||||
render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
|
||||
render_pass.set_bind_group(1, &shadow.bind.bind_group, &[]);
|
||||
|
||||
Some(SecondPassDrawer {
|
||||
render_pass,
|
||||
@ -639,6 +683,37 @@ impl<'pass> ShadowPassDrawer<'pass> {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub struct RainOcclusionPassDrawer<'pass> {
|
||||
render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
|
||||
borrow: &'pass RendererBorrow<'pass>,
|
||||
rain_occlusion_renderer: &'pass RainOcclusionMapRenderer,
|
||||
}
|
||||
|
||||
impl<'pass> RainOcclusionPassDrawer<'pass> {
|
||||
pub fn draw_figure_shadows(&mut self) -> FigureShadowDrawer<'_, 'pass> {
|
||||
let mut render_pass = self
|
||||
.render_pass
|
||||
.scope("direcred_figure_rain_occlusion", self.borrow.device);
|
||||
|
||||
render_pass.set_pipeline(&self.rain_occlusion_renderer.figure_pipeline.pipeline);
|
||||
set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
|
||||
|
||||
FigureShadowDrawer { render_pass }
|
||||
}
|
||||
|
||||
pub fn draw_terrain_shadows(&mut self) -> TerrainShadowDrawer<'_, 'pass> {
|
||||
let mut render_pass = self
|
||||
.render_pass
|
||||
.scope("direcred_terrain_rain_occlusion", self.borrow.device);
|
||||
|
||||
render_pass.set_pipeline(&self.rain_occlusion_renderer.terrain_pipeline.pipeline);
|
||||
set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
|
||||
|
||||
TerrainShadowDrawer { render_pass }
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub struct FigureShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
|
||||
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
|
||||
@ -970,7 +1045,7 @@ impl<'pass> SecondPassDrawer<'pass> {
|
||||
self.render_pass
|
||||
.set_pipeline(&self.clouds_pipeline.pipeline);
|
||||
self.render_pass
|
||||
.set_bind_group(1, &self.borrow.locals.clouds_bind.bind_group, &[]);
|
||||
.set_bind_group(2, &self.borrow.locals.clouds_bind.bind_group, &[]);
|
||||
self.render_pass.draw(0..3, 0..1);
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
use crate::render::pipelines::rain_occlusion;
|
||||
|
||||
use super::{
|
||||
super::{
|
||||
pipelines::{
|
||||
@ -60,9 +62,16 @@ pub struct ShadowPipelines {
|
||||
pub figure: Option<shadow::ShadowFigurePipeline>,
|
||||
}
|
||||
|
||||
pub struct RainOcclusionPipelines {
|
||||
pub terrain: Option<rain_occlusion::RainOcclusionPipeline>,
|
||||
pub figure: Option<rain_occlusion::RainOcclusionFigurePipeline>,
|
||||
}
|
||||
|
||||
// TODO: Find a better name for this?
|
||||
pub struct IngameAndShadowPipelines {
|
||||
pub ingame: IngamePipelines,
|
||||
pub shadow: ShadowPipelines,
|
||||
pub rain_occlusion: RainOcclusionPipelines,
|
||||
}
|
||||
|
||||
/// Pipelines neccesary to display the UI and take screenshots
|
||||
@ -131,6 +140,8 @@ struct ShaderModules {
|
||||
point_light_shadows_vert: wgpu::ShaderModule,
|
||||
light_shadows_directed_vert: wgpu::ShaderModule,
|
||||
light_shadows_figure_vert: wgpu::ShaderModule,
|
||||
rain_occlusion_directed_vert: wgpu::ShaderModule,
|
||||
rain_occlusion_figure_vert: wgpu::ShaderModule,
|
||||
}
|
||||
|
||||
impl ShaderModules {
|
||||
@ -151,6 +162,7 @@ impl ShaderModules {
|
||||
let random = shaders.get("include.random").unwrap();
|
||||
let lod = shaders.get("include.lod").unwrap();
|
||||
let shadows = shaders.get("include.shadows").unwrap();
|
||||
let rain_occlusion = shaders.get("include.rain_occlusion").unwrap();
|
||||
let point_glow = shaders.get("include.point_glow").unwrap();
|
||||
|
||||
// We dynamically add extra configuration settings to the constants file.
|
||||
@ -252,6 +264,7 @@ impl ShaderModules {
|
||||
"constants.glsl" => constants.clone(),
|
||||
"globals.glsl" => globals.0.to_owned(),
|
||||
"shadows.glsl" => shadows.0.to_owned(),
|
||||
"rain_occlusion.glsl" => rain_occlusion.0.to_owned(),
|
||||
"sky.glsl" => sky.0.to_owned(),
|
||||
"light.glsl" => light.0.to_owned(),
|
||||
"srgb.glsl" => srgb.0.to_owned(),
|
||||
@ -332,6 +345,14 @@ impl ShaderModules {
|
||||
"light-shadows-figure-vert",
|
||||
ShaderKind::Vertex,
|
||||
)?,
|
||||
rain_occlusion_directed_vert: create_shader(
|
||||
"rain-occlusion-directed-vert",
|
||||
ShaderKind::Vertex,
|
||||
)?,
|
||||
rain_occlusion_figure_vert: create_shader(
|
||||
"rain-occlusion-figure-vert",
|
||||
ShaderKind::Vertex,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -422,7 +443,7 @@ fn create_ingame_and_shadow_pipelines(
|
||||
needs: PipelineNeeds,
|
||||
pool: &rayon::ThreadPool,
|
||||
// TODO: Reduce the boilerplate in this file
|
||||
tasks: [Task; 16],
|
||||
tasks: [Task; 18],
|
||||
) -> IngameAndShadowPipelines {
|
||||
prof_span!(_guard, "create_ingame_and_shadow_pipelines");
|
||||
|
||||
@ -454,6 +475,8 @@ fn create_ingame_and_shadow_pipelines(
|
||||
point_shadow_task,
|
||||
terrain_directed_shadow_task,
|
||||
figure_directed_shadow_task,
|
||||
terrain_directed_rain_occlusion_task,
|
||||
figure_directed_rain_occlusion_task,
|
||||
] = tasks;
|
||||
|
||||
// TODO: pass in format of target color buffer
|
||||
@ -739,6 +762,36 @@ fn create_ingame_and_shadow_pipelines(
|
||||
"figure directed shadow pipeline creation",
|
||||
)
|
||||
};
|
||||
// Pipeline for rendering directional light terrain rain occlusion maps.
|
||||
let create_terrain_directed_rain_occlusion = || {
|
||||
terrain_directed_rain_occlusion_task.run(
|
||||
|| {
|
||||
rain_occlusion::RainOcclusionPipeline::new(
|
||||
device,
|
||||
&shaders.rain_occlusion_directed_vert,
|
||||
&layouts.global,
|
||||
&layouts.terrain,
|
||||
pipeline_modes.aa,
|
||||
)
|
||||
},
|
||||
"terrain directed rain occlusion pipeline creation",
|
||||
)
|
||||
};
|
||||
// Pipeline for rendering directional light figure rain occlusion maps.
|
||||
let create_figure_directed_rain_occlusion = || {
|
||||
figure_directed_rain_occlusion_task.run(
|
||||
|| {
|
||||
rain_occlusion::RainOcclusionFigurePipeline::new(
|
||||
device,
|
||||
&shaders.rain_occlusion_figure_vert,
|
||||
&layouts.global,
|
||||
&layouts.figure,
|
||||
pipeline_modes.aa,
|
||||
)
|
||||
},
|
||||
"figure directed rain occlusion pipeline creation",
|
||||
)
|
||||
};
|
||||
|
||||
let j1 = || pool.join(create_debug, || pool.join(create_skybox, create_figure));
|
||||
let j2 = || pool.join(create_terrain, || pool.join(create_fluid, create_bloom));
|
||||
@ -755,7 +808,14 @@ fn create_ingame_and_shadow_pipelines(
|
||||
create_figure_directed_shadow,
|
||||
)
|
||||
};
|
||||
let j7 = create_lod_object;
|
||||
let j7 = || {
|
||||
pool.join(create_lod_object, || {
|
||||
pool.join(
|
||||
create_terrain_directed_rain_occlusion,
|
||||
create_figure_directed_rain_occlusion,
|
||||
)
|
||||
})
|
||||
};
|
||||
|
||||
// Ignore this
|
||||
let (
|
||||
@ -765,7 +825,7 @@ fn create_ingame_and_shadow_pipelines(
|
||||
),
|
||||
(
|
||||
((postprocess, point_shadow), (terrain_directed_shadow, figure_directed_shadow)),
|
||||
lod_object,
|
||||
(lod_object, (terrain_directed_rain_occlusion, figure_directed_rain_occlusion)),
|
||||
),
|
||||
) = pool.join(
|
||||
|| pool.join(|| pool.join(j1, j2), || pool.join(j3, j4)),
|
||||
@ -795,6 +855,10 @@ fn create_ingame_and_shadow_pipelines(
|
||||
directed: Some(terrain_directed_shadow),
|
||||
figure: Some(figure_directed_shadow),
|
||||
},
|
||||
rain_occlusion: RainOcclusionPipelines {
|
||||
terrain: Some(terrain_directed_rain_occlusion),
|
||||
figure: Some(figure_directed_rain_occlusion),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -887,6 +951,7 @@ pub(super) fn recreate_pipelines(
|
||||
(
|
||||
Pipelines,
|
||||
ShadowPipelines,
|
||||
RainOcclusionPipelines,
|
||||
Arc<postprocess::PostProcessLayout>,
|
||||
),
|
||||
RenderError,
|
||||
@ -952,14 +1017,18 @@ pub(super) fn recreate_pipelines(
|
||||
let interface = create_interface_pipelines(needs, pool, interface_tasks);
|
||||
|
||||
// Create the rest of the pipelines
|
||||
let IngameAndShadowPipelines { ingame, shadow } =
|
||||
create_ingame_and_shadow_pipelines(needs, pool, ingame_and_shadow_tasks);
|
||||
let IngameAndShadowPipelines {
|
||||
ingame,
|
||||
shadow,
|
||||
rain_occlusion,
|
||||
} = create_ingame_and_shadow_pipelines(needs, pool, ingame_and_shadow_tasks);
|
||||
|
||||
// Send them
|
||||
result_send
|
||||
.send(Ok((
|
||||
Pipelines::consolidate(interface, ingame),
|
||||
shadow,
|
||||
rain_occlusion,
|
||||
layouts.postprocess,
|
||||
)))
|
||||
.expect("Channel disconnected");
|
||||
|
226
voxygen/src/render/renderer/rain_occlusion_map.rs
Normal file
226
voxygen/src/render/renderer/rain_occlusion_map.rs
Normal file
@ -0,0 +1,226 @@
|
||||
use crate::render::pipelines::rain_occlusion;
|
||||
|
||||
use super::{
|
||||
super::{texture::Texture, RenderError, ShadowMapMode},
|
||||
Renderer,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
/// A type that holds shadow map data. Since shadow mapping may not be
|
||||
/// supported on all platforms, we try to keep it separate.
|
||||
pub struct RainOcclusionMapRenderer {
|
||||
pub depth: Texture,
|
||||
|
||||
pub terrain_pipeline: rain_occlusion::RainOcclusionPipeline,
|
||||
pub figure_pipeline: rain_occlusion::RainOcclusionFigurePipeline,
|
||||
pub layout: rain_occlusion::RainOcclusionLayout,
|
||||
}
|
||||
|
||||
pub enum RainOcclusionMap {
|
||||
Enabled(RainOcclusionMapRenderer),
|
||||
/// Dummy texture
|
||||
Disabled(Texture),
|
||||
}
|
||||
|
||||
impl RainOcclusionMap {
|
||||
pub fn new(
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
directed: Option<rain_occlusion::RainOcclusionPipeline>,
|
||||
figure: Option<rain_occlusion::RainOcclusionFigurePipeline>,
|
||||
view: Option<Texture>,
|
||||
) -> Self {
|
||||
if let (Some(terrain_pipeline), Some(figure_pipeline), Some(depth)) =
|
||||
(directed, figure, view)
|
||||
{
|
||||
let layout = rain_occlusion::RainOcclusionLayout::new(device);
|
||||
|
||||
Self::Enabled(RainOcclusionMapRenderer {
|
||||
depth,
|
||||
terrain_pipeline,
|
||||
figure_pipeline,
|
||||
layout,
|
||||
})
|
||||
} else {
|
||||
Self::Disabled(Self::create_dummy_tex(device, queue))
|
||||
}
|
||||
}
|
||||
|
||||
fn create_dummy_tex(device: &wgpu::Device, queue: &wgpu::Queue) -> Texture {
|
||||
let tex = {
|
||||
let tex = wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size: wgpu::Extent3d {
|
||||
width: 4,
|
||||
height: 4,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Depth24Plus,
|
||||
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::RENDER_ATTACHMENT,
|
||||
};
|
||||
|
||||
let view = wgpu::TextureViewDescriptor {
|
||||
label: None,
|
||||
format: Some(wgpu::TextureFormat::Depth24Plus),
|
||||
dimension: Some(wgpu::TextureViewDimension::D2),
|
||||
aspect: wgpu::TextureAspect::DepthOnly,
|
||||
base_mip_level: 0,
|
||||
mip_level_count: None,
|
||||
base_array_layer: 0,
|
||||
array_layer_count: None,
|
||||
};
|
||||
|
||||
let sampler_info = wgpu::SamplerDescriptor {
|
||||
label: None,
|
||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
||||
mag_filter: wgpu::FilterMode::Linear,
|
||||
min_filter: wgpu::FilterMode::Linear,
|
||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||
compare: Some(wgpu::CompareFunction::LessEqual),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Texture::new_raw(device, &tex, &view, &sampler_info)
|
||||
};
|
||||
|
||||
// Clear to 1.0
|
||||
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||
label: Some("Dummy rain occlusion tex clearing encoder"),
|
||||
});
|
||||
|
||||
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("Clear dummy rain occlusion texture"),
|
||||
color_attachments: &[],
|
||||
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
|
||||
view: &tex.view,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(1.0),
|
||||
store: true,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
}),
|
||||
});
|
||||
|
||||
queue.submit(std::iter::once(encoder.finish()));
|
||||
|
||||
tex
|
||||
}
|
||||
|
||||
/// Create texture and view for rain ocllusion maps.
|
||||
/// Returns (point, directed)
|
||||
pub(super) fn create_view(
|
||||
device: &wgpu::Device,
|
||||
size: (u32, u32),
|
||||
mode: &ShadowMapMode,
|
||||
) -> Result<Texture, RenderError> {
|
||||
// (Attempt to) apply resolution factor to rain occlusion map resolution.
|
||||
let resolution_factor = mode.resolution.clamped(0.25, 4.0);
|
||||
|
||||
let max_texture_size = Renderer::max_texture_size_raw(device);
|
||||
// Limit to max texture size, rather than erroring.
|
||||
let size = Vec2::new(size.0, size.1).map(|e| {
|
||||
let size = e as f32 * resolution_factor;
|
||||
// NOTE: We know 0 <= e since we clamped the resolution factor to be between
|
||||
// 0.25 and 4.0.
|
||||
if size <= max_texture_size as f32 {
|
||||
size as u32
|
||||
} else {
|
||||
max_texture_size
|
||||
}
|
||||
});
|
||||
|
||||
let levels = 1;
|
||||
// Limit to max texture size rather than erroring.
|
||||
let two_size = size.map(|e| {
|
||||
u32::checked_next_power_of_two(e)
|
||||
.filter(|&e| e <= max_texture_size)
|
||||
.unwrap_or(max_texture_size)
|
||||
});
|
||||
let min_size = size.reduce_min();
|
||||
let max_size = size.reduce_max();
|
||||
let _min_two_size = two_size.reduce_min();
|
||||
let _max_two_size = two_size.reduce_max();
|
||||
// For rotated shadow maps, the maximum size of a pixel along any axis is the
|
||||
// size of a diagonal along that axis.
|
||||
let diag_size = size.map(f64::from).magnitude();
|
||||
let diag_cross_size = f64::from(min_size) / f64::from(max_size) * diag_size;
|
||||
let (diag_size, _diag_cross_size) =
|
||||
if 0.0 < diag_size && diag_size <= f64::from(max_texture_size) {
|
||||
// NOTE: diag_cross_size must be non-negative, since it is the ratio of a
|
||||
// non-negative and a positive number (if max_size were zero,
|
||||
// diag_size would be 0 too). And it must be <= diag_size,
|
||||
// since min_size <= max_size. Therefore, if diag_size fits in a
|
||||
// u16, so does diag_cross_size.
|
||||
(diag_size as u32, diag_cross_size as u32)
|
||||
} else {
|
||||
// Limit to max texture resolution rather than error.
|
||||
(max_texture_size as u32, max_texture_size as u32)
|
||||
};
|
||||
let diag_two_size = u32::checked_next_power_of_two(diag_size)
|
||||
.filter(|&e| e <= max_texture_size)
|
||||
// Limit to max texture resolution rather than error.
|
||||
.unwrap_or(max_texture_size)
|
||||
// Make sure we don't try to create a zero sized texture (divided by 4 below)
|
||||
.max(4);
|
||||
|
||||
let rain_occlusion_tex = wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size: wgpu::Extent3d {
|
||||
width: diag_two_size,
|
||||
height: diag_two_size,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: levels,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Depth24Plus,
|
||||
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::RENDER_ATTACHMENT,
|
||||
};
|
||||
|
||||
let rain_occlusion_view = wgpu::TextureViewDescriptor {
|
||||
label: None,
|
||||
format: Some(wgpu::TextureFormat::Depth24Plus),
|
||||
dimension: Some(wgpu::TextureViewDimension::D2),
|
||||
aspect: wgpu::TextureAspect::DepthOnly,
|
||||
base_mip_level: 0,
|
||||
mip_level_count: None,
|
||||
base_array_layer: 0,
|
||||
array_layer_count: None,
|
||||
};
|
||||
|
||||
let sampler_info = wgpu::SamplerDescriptor {
|
||||
label: None,
|
||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
||||
mag_filter: wgpu::FilterMode::Linear,
|
||||
min_filter: wgpu::FilterMode::Linear,
|
||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||
compare: Some(wgpu::CompareFunction::LessEqual),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let rain_occlusion_tex = Texture::new_raw(
|
||||
device,
|
||||
&rain_occlusion_tex,
|
||||
&rain_occlusion_view,
|
||||
&sampler_info,
|
||||
);
|
||||
|
||||
Ok(rain_occlusion_tex)
|
||||
}
|
||||
|
||||
pub fn texture(&self) -> &Texture {
|
||||
match self {
|
||||
Self::Enabled(renderer) => &renderer.depth,
|
||||
Self::Disabled(dummy) => dummy,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_enabled(&self) -> bool { matches!(self, Self::Enabled(_)) }
|
||||
}
|
@ -34,6 +34,7 @@ impl assets::Compound for Shaders {
|
||||
"include.random",
|
||||
"include.lod",
|
||||
"include.shadows",
|
||||
"include.rain_occlusion",
|
||||
"include.point_glow",
|
||||
"antialias.none",
|
||||
"antialias.fxaa",
|
||||
@ -45,6 +46,8 @@ impl assets::Compound for Shaders {
|
||||
"figure-vert",
|
||||
"light-shadows-figure-vert",
|
||||
"light-shadows-directed-vert",
|
||||
"rain-occlusion-figure-vert",
|
||||
"rain-occlusion-directed-vert",
|
||||
"point-light-shadows-vert",
|
||||
"skybox-vert",
|
||||
"skybox-frag",
|
||||
|
@ -22,8 +22,8 @@ use crate::{
|
||||
audio::{ambient, ambient::AmbientMgr, music::MusicMgr, sfx::SfxMgr, AudioFrontend},
|
||||
render::{
|
||||
create_skybox_mesh, CloudsLocals, Consts, Drawer, GlobalModel, Globals, GlobalsBindGroup,
|
||||
Light, Model, PointLightMatrix, PostProcessLocals, Renderer, Shadow, ShadowLocals,
|
||||
SkyboxVertex,
|
||||
Light, Model, PointLightMatrix, PostProcessLocals, RainOcclusionLocals, Renderer, Shadow,
|
||||
ShadowLocals, SkyboxVertex,
|
||||
},
|
||||
settings::Settings,
|
||||
window::{AnalogGameInput, Event},
|
||||
@ -282,6 +282,8 @@ impl Scene {
|
||||
lights: renderer.create_consts(&[Light::default(); MAX_LIGHT_COUNT]),
|
||||
shadows: renderer.create_consts(&[Shadow::default(); MAX_SHADOW_COUNT]),
|
||||
shadow_mats: renderer.create_shadow_bound_locals(&[ShadowLocals::default()]),
|
||||
rain_occlusion_mats: renderer
|
||||
.create_rain_occlusion_bound_locals(&[RainOcclusionLocals::default()]),
|
||||
point_light_matrices: Box::new([PointLightMatrix::default(); MAX_LIGHT_COUNT * 6 + 6]),
|
||||
};
|
||||
|
||||
@ -1010,6 +1012,13 @@ impl Scene {
|
||||
);
|
||||
|
||||
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.
|
||||
@ -1139,6 +1148,21 @@ impl Scene {
|
||||
self.terrain.chunks_for_point_shadows(focus_pos),
|
||||
)
|
||||
}
|
||||
// Render rain occlusion texture
|
||||
{
|
||||
prof_span!("rain occlusion");
|
||||
if let Some(mut occlusion_pass) = drawer.rain_occlusion_pass() {
|
||||
self.terrain
|
||||
.render_shadows(&mut occlusion_pass.draw_terrain_shadows(), focus_pos);
|
||||
|
||||
self.figure_mgr.render_shadows(
|
||||
&mut occlusion_pass.draw_figure_shadows(),
|
||||
state,
|
||||
tick,
|
||||
camera_data,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prof_span!(guard, "main pass");
|
||||
|
@ -2,8 +2,8 @@ use crate::{
|
||||
mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_terrain},
|
||||
render::{
|
||||
create_skybox_mesh, BoneMeshes, Consts, FigureModel, FirstPassDrawer, GlobalModel, Globals,
|
||||
GlobalsBindGroup, Light, LodData, Mesh, Model, PointLightMatrix, Renderer, Shadow,
|
||||
ShadowLocals, SkyboxVertex, TerrainVertex,
|
||||
GlobalsBindGroup, Light, LodData, Mesh, Model, PointLightMatrix, RainOcclusionLocals,
|
||||
Renderer, Shadow, ShadowLocals, SkyboxVertex, TerrainVertex,
|
||||
},
|
||||
scene::{
|
||||
camera::{self, Camera, CameraMode},
|
||||
@ -113,6 +113,8 @@ impl Scene {
|
||||
lights: renderer.create_consts(&[Light::default(); 20]),
|
||||
shadows: renderer.create_consts(&[Shadow::default(); 24]),
|
||||
shadow_mats: renderer.create_shadow_bound_locals(&[ShadowLocals::default()]),
|
||||
rain_occlusion_mats: renderer
|
||||
.create_rain_occlusion_bound_locals(&[RainOcclusionLocals::default()]),
|
||||
point_light_matrices: Box::new([PointLightMatrix::default(); 126]),
|
||||
};
|
||||
let lod = LodData::dummy(renderer);
|
||||
|
Loading…
Reference in New Issue
Block a user