mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Tweaks to shadows.
Added shadow map resolution configuration, added seamless cubemaps, documented all existing rendering options, and fixed a few Clippy errors.
This commit is contained in:
parent
23b4058906
commit
be438657c3
@ -298,7 +298,7 @@ magischen Gegenstände ergattern?"#,
|
|||||||
"hud.settings.cloud_rendering_mode.regular": "Realistisch",
|
"hud.settings.cloud_rendering_mode.regular": "Realistisch",
|
||||||
"hud.settings.fullscreen": "Vollbild",
|
"hud.settings.fullscreen": "Vollbild",
|
||||||
"hud.settings.lighting_rendering_mode": "Beleuchtung",
|
"hud.settings.lighting_rendering_mode": "Beleuchtung",
|
||||||
"hud.settings.lighting_rendering_mode.ashikmin": "Typ A",
|
"hud.settings.lighting_rendering_mode.ashikhmin": "Typ A",
|
||||||
"hud.settings.lighting_rendering_mode.blinnphong": "Typ B",
|
"hud.settings.lighting_rendering_mode.blinnphong": "Typ B",
|
||||||
"hud.settings.lighting_rendering_mode.lambertian": "Typ L",
|
"hud.settings.lighting_rendering_mode.lambertian": "Typ L",
|
||||||
"hud.settings.shadow_rendering_mode": "Schatten",
|
"hud.settings.shadow_rendering_mode": "Schatten",
|
||||||
|
@ -298,13 +298,14 @@ magically infused items?"#,
|
|||||||
"hud.settings.fullscreen": "Fullscreen",
|
"hud.settings.fullscreen": "Fullscreen",
|
||||||
"hud.settings.save_window_size": "Save window size",
|
"hud.settings.save_window_size": "Save window size",
|
||||||
"hud.settings.lighting_rendering_mode": "Lighting Rendering Mode",
|
"hud.settings.lighting_rendering_mode": "Lighting Rendering Mode",
|
||||||
"hud.settings.lighting_rendering_mode.ashikmin": "Type A",
|
"hud.settings.lighting_rendering_mode.ashikhmin": "Type A",
|
||||||
"hud.settings.lighting_rendering_mode.blinnphong": "Type B",
|
"hud.settings.lighting_rendering_mode.blinnphong": "Type B",
|
||||||
"hud.settings.lighting_rendering_mode.lambertian": "Type L",
|
"hud.settings.lighting_rendering_mode.lambertian": "Type L",
|
||||||
"hud.settings.shadow_rendering_mode": "Shadow Rendering Mode",
|
"hud.settings.shadow_rendering_mode": "Shadow Rendering Mode",
|
||||||
"hud.settings.shadow_rendering_mode.none": "None",
|
"hud.settings.shadow_rendering_mode.none": "None",
|
||||||
"hud.settings.shadow_rendering_mode.cheap": "Cheap",
|
"hud.settings.shadow_rendering_mode.cheap": "Cheap",
|
||||||
"hud.settings.shadow_rendering_mode.map": "Map",
|
"hud.settings.shadow_rendering_mode.map": "Map",
|
||||||
|
"hud.settings.shadow_rendering_mode.map.resolution": "Resolution",
|
||||||
"hud.settings.lod_detail": "LoD Detail",
|
"hud.settings.lod_detail": "LoD Detail",
|
||||||
"hud.settings.save_window_size": "Save window size",
|
"hud.settings.save_window_size": "Save window size",
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ uniform u_locals {
|
|||||||
out vec4 tgt_color;
|
out vec4 tgt_color;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// tgt_color = vec4(MU_SCATTER, 1.0);
|
tgt_color = vec4(MU_SCATTER, 1.0);
|
||||||
// return;
|
return;
|
||||||
vec4 _clouds;
|
vec4 _clouds;
|
||||||
|
|
||||||
vec3 cam_dir = normalize(f_pos - cam_pos.xyz);
|
vec3 cam_dir = normalize(f_pos - cam_pos.xyz);
|
||||||
|
@ -134,8 +134,8 @@ impl Client {
|
|||||||
// We reduce the thread count by 1 to keep rendering smooth
|
// We reduce the thread count by 1 to keep rendering smooth
|
||||||
thread_pool.set_num_threads((num_cpus::get() - 1).max(1));
|
thread_pool.set_num_threads((num_cpus::get() - 1).max(1));
|
||||||
|
|
||||||
let (network, f) = Network::new(Pid::new(), None);
|
let (network, scheduler) = Network::new(Pid::new(), None);
|
||||||
thread_pool.execute(f);
|
thread_pool.execute(scheduler);
|
||||||
|
|
||||||
let participant = block_on(network.connect(Address::Tcp(addr.into())))?;
|
let participant = block_on(network.connect(Address::Tcp(addr.into())))?;
|
||||||
let mut stream = block_on(participant.open(10, PROMISES_ORDERED | PROMISES_CONSISTENCY))?;
|
let mut stream = block_on(participant.open(10, PROMISES_ORDERED | PROMISES_CONSISTENCY))?;
|
||||||
|
@ -4,7 +4,7 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
i18n::{list_localizations, LanguageMetadata, VoxygenLocalization},
|
i18n::{list_localizations, LanguageMetadata, VoxygenLocalization},
|
||||||
render::{AaMode, CloudMode, FluidMode, LightingMode, RenderMode, ShadowMode},
|
render::{AaMode, CloudMode, FluidMode, LightingMode, RenderMode, ShadowMapMode, ShadowMode},
|
||||||
ui::{fonts::ConrodVoxygenFonts, ImageSlider, ScaleMode, ToggleButton},
|
ui::{fonts::ConrodVoxygenFonts, ImageSlider, ScaleMode, ToggleButton},
|
||||||
window::GameInput,
|
window::GameInput,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
@ -16,6 +16,7 @@ use conrod_core::{
|
|||||||
widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget,
|
widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget,
|
||||||
WidgetCommon,
|
WidgetCommon,
|
||||||
};
|
};
|
||||||
|
use core::convert::TryFrom;
|
||||||
|
|
||||||
const FPS_CHOICES: [u32; 11] = [15, 30, 40, 50, 60, 90, 120, 144, 240, 300, 500];
|
const FPS_CHOICES: [u32; 11] = [15, 30, 40, 50, 60, 90, 120, 144, 240, 300, 500];
|
||||||
|
|
||||||
@ -119,6 +120,9 @@ widget_ids! {
|
|||||||
lighting_mode_list,
|
lighting_mode_list,
|
||||||
shadow_mode_text,
|
shadow_mode_text,
|
||||||
shadow_mode_list,
|
shadow_mode_list,
|
||||||
|
shadow_mode_map_resolution_text,
|
||||||
|
shadow_mode_map_resolution_slider,
|
||||||
|
shadow_mode_map_resolution_value,
|
||||||
save_window_size_button,
|
save_window_size_button,
|
||||||
audio_volume_slider,
|
audio_volume_slider,
|
||||||
audio_volume_text,
|
audio_volume_text,
|
||||||
@ -1884,6 +1888,8 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
.set(state.ids.figure_dist_value, ui);
|
.set(state.ids.figure_dist_value, ui);
|
||||||
|
|
||||||
|
let render_mode = self.global_state.settings.graphics.render_mode;
|
||||||
|
|
||||||
// AaMode
|
// AaMode
|
||||||
Text::new(&self.localized_strings.get("hud.settings.antialiasing_mode"))
|
Text::new(&self.localized_strings.get("hud.settings.antialiasing_mode"))
|
||||||
.down_from(state.ids.gamma_slider, 8.0)
|
.down_from(state.ids.gamma_slider, 8.0)
|
||||||
@ -1910,9 +1916,7 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Get which AA mode is currently active
|
// Get which AA mode is currently active
|
||||||
let selected = mode_list
|
let selected = mode_list.iter().position(|x| *x == render_mode.aa);
|
||||||
.iter()
|
|
||||||
.position(|x| *x == self.global_state.settings.graphics.render_mode.aa);
|
|
||||||
|
|
||||||
if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
|
if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
|
||||||
.w_h(400.0, 22.0)
|
.w_h(400.0, 22.0)
|
||||||
@ -1924,7 +1928,7 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
{
|
{
|
||||||
events.push(Event::ChangeRenderMode(RenderMode {
|
events.push(Event::ChangeRenderMode(RenderMode {
|
||||||
aa: mode_list[clicked],
|
aa: mode_list[clicked],
|
||||||
..self.global_state.settings.graphics.render_mode
|
..render_mode
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1949,9 +1953,7 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Get which cloud rendering mode is currently active
|
// Get which cloud rendering mode is currently active
|
||||||
let selected = mode_list
|
let selected = mode_list.iter().position(|x| *x == render_mode.cloud);
|
||||||
.iter()
|
|
||||||
.position(|x| *x == self.global_state.settings.graphics.render_mode.cloud);
|
|
||||||
|
|
||||||
if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
|
if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
|
||||||
.w_h(400.0, 22.0)
|
.w_h(400.0, 22.0)
|
||||||
@ -1963,7 +1965,7 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
{
|
{
|
||||||
events.push(Event::ChangeRenderMode(RenderMode {
|
events.push(Event::ChangeRenderMode(RenderMode {
|
||||||
cloud: mode_list[clicked],
|
cloud: mode_list[clicked],
|
||||||
..self.global_state.settings.graphics.render_mode
|
..render_mode
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1990,9 +1992,7 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Get which fluid rendering mode is currently active
|
// Get which fluid rendering mode is currently active
|
||||||
let selected = mode_list
|
let selected = mode_list.iter().position(|x| *x == render_mode.fluid);
|
||||||
.iter()
|
|
||||||
.position(|x| *x == self.global_state.settings.graphics.render_mode.fluid);
|
|
||||||
|
|
||||||
if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
|
if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
|
||||||
.w_h(400.0, 22.0)
|
.w_h(400.0, 22.0)
|
||||||
@ -2004,7 +2004,7 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
{
|
{
|
||||||
events.push(Event::ChangeRenderMode(RenderMode {
|
events.push(Event::ChangeRenderMode(RenderMode {
|
||||||
fluid: mode_list[clicked],
|
fluid: mode_list[clicked],
|
||||||
..self.global_state.settings.graphics.render_mode
|
..render_mode
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2021,14 +2021,14 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
.set(state.ids.lighting_mode_text, ui);
|
.set(state.ids.lighting_mode_text, ui);
|
||||||
|
|
||||||
let mode_list = [
|
let mode_list = [
|
||||||
LightingMode::Ashikmin,
|
LightingMode::Ashikhmin,
|
||||||
LightingMode::BlinnPhong,
|
LightingMode::BlinnPhong,
|
||||||
LightingMode::Lambertian,
|
LightingMode::Lambertian,
|
||||||
];
|
];
|
||||||
let mode_label_list = [
|
let mode_label_list = [
|
||||||
&self
|
&self
|
||||||
.localized_strings
|
.localized_strings
|
||||||
.get("hud.settings.lighting_rendering_mode.ashikmin"),
|
.get("hud.settings.lighting_rendering_mode.ashikhmin"),
|
||||||
&self
|
&self
|
||||||
.localized_strings
|
.localized_strings
|
||||||
.get("hud.settings.lighting_rendering_mode.blinnphong"),
|
.get("hud.settings.lighting_rendering_mode.blinnphong"),
|
||||||
@ -2038,9 +2038,7 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Get which lighting rendering mode is currently active
|
// Get which lighting rendering mode is currently active
|
||||||
let selected = mode_list
|
let selected = mode_list.iter().position(|x| *x == render_mode.lighting);
|
||||||
.iter()
|
|
||||||
.position(|x| *x == self.global_state.settings.graphics.render_mode.lighting);
|
|
||||||
|
|
||||||
if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
|
if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
|
||||||
.w_h(400.0, 22.0)
|
.w_h(400.0, 22.0)
|
||||||
@ -2052,7 +2050,7 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
{
|
{
|
||||||
events.push(Event::ChangeRenderMode(RenderMode {
|
events.push(Event::ChangeRenderMode(RenderMode {
|
||||||
lighting: mode_list[clicked],
|
lighting: mode_list[clicked],
|
||||||
..self.global_state.settings.graphics.render_mode
|
..render_mode
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2068,7 +2066,12 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
.set(state.ids.shadow_mode_text, ui);
|
.set(state.ids.shadow_mode_text, ui);
|
||||||
|
|
||||||
let mode_list = [ShadowMode::None, ShadowMode::Cheap, ShadowMode::Map];
|
let shadow_map_mode = ShadowMapMode::try_from(render_mode.shadow).ok();
|
||||||
|
let mode_list = [
|
||||||
|
ShadowMode::None,
|
||||||
|
ShadowMode::Cheap,
|
||||||
|
ShadowMode::Map(shadow_map_mode.unwrap_or_default()),
|
||||||
|
];
|
||||||
let mode_label_list = [
|
let mode_label_list = [
|
||||||
&self
|
&self
|
||||||
.localized_strings
|
.localized_strings
|
||||||
@ -2082,9 +2085,7 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Get which shadow rendering mode is currently active
|
// Get which shadow rendering mode is currently active
|
||||||
let selected = mode_list
|
let selected = mode_list.iter().position(|x| *x == render_mode.shadow);
|
||||||
.iter()
|
|
||||||
.position(|x| *x == self.global_state.settings.graphics.render_mode.shadow);
|
|
||||||
|
|
||||||
if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
|
if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
|
||||||
.w_h(400.0, 22.0)
|
.w_h(400.0, 22.0)
|
||||||
@ -2096,10 +2097,56 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
{
|
{
|
||||||
events.push(Event::ChangeRenderMode(RenderMode {
|
events.push(Event::ChangeRenderMode(RenderMode {
|
||||||
shadow: mode_list[clicked],
|
shadow: mode_list[clicked],
|
||||||
..self.global_state.settings.graphics.render_mode
|
..render_mode
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(shadow_map_mode) = shadow_map_mode {
|
||||||
|
// Display the shadow map mode if selected.
|
||||||
|
Text::new(
|
||||||
|
&self
|
||||||
|
.localized_strings
|
||||||
|
.get("hud.settings.shadow_rendering_mode.map.resolution"),
|
||||||
|
)
|
||||||
|
.right_from(state.ids.shadow_mode_list, 10.0)
|
||||||
|
.font_size(self.fonts.cyri.scale(14))
|
||||||
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
|
.color(TEXT_COLOR)
|
||||||
|
.set(state.ids.shadow_mode_map_resolution_text, ui);
|
||||||
|
|
||||||
|
if let Some(new_val) = ImageSlider::discrete(
|
||||||
|
(shadow_map_mode.resolution.log2() * 4.0).round() as i8,
|
||||||
|
-8,
|
||||||
|
8,
|
||||||
|
self.imgs.slider_indicator,
|
||||||
|
self.imgs.slider,
|
||||||
|
)
|
||||||
|
.w_h(104.0, 22.0)
|
||||||
|
.right_from(state.ids.shadow_mode_map_resolution_text, 8.0)
|
||||||
|
.track_breadth(12.0)
|
||||||
|
.slider_length(10.0)
|
||||||
|
.pad_track((5.0, 5.0))
|
||||||
|
.set(state.ids.shadow_mode_map_resolution_slider, ui)
|
||||||
|
{
|
||||||
|
events.push(Event::ChangeRenderMode(RenderMode {
|
||||||
|
shadow: ShadowMode::Map(ShadowMapMode {
|
||||||
|
resolution: 2.0f32.powf(f32::from(new_val) / 4.0),
|
||||||
|
..shadow_map_mode
|
||||||
|
}),
|
||||||
|
..render_mode
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Consider fixing to avoid allocation (it's probably not a bottleneck but
|
||||||
|
// there's no reason to allocate for numbers).
|
||||||
|
Text::new(&format!("{}", shadow_map_mode.resolution))
|
||||||
|
.right_from(state.ids.shadow_mode_map_resolution_slider, 8.0)
|
||||||
|
.font_size(self.fonts.cyri.scale(14))
|
||||||
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
|
.color(TEXT_COLOR)
|
||||||
|
.set(state.ids.shadow_mode_map_resolution_value, ui);
|
||||||
|
}
|
||||||
|
|
||||||
// Fullscreen
|
// Fullscreen
|
||||||
Text::new(&self.localized_strings.get("hud.settings.fullscreen"))
|
Text::new(&self.localized_strings.get("hud.settings.fullscreen"))
|
||||||
.font_size(self.fonts.cyri.scale(14))
|
.font_size(self.fonts.cyri.scale(14))
|
||||||
|
@ -10,6 +10,7 @@ pub enum RenderError {
|
|||||||
IncludeError(glsl_include::Error),
|
IncludeError(glsl_include::Error),
|
||||||
MappingError(gfx::mapping::Error),
|
MappingError(gfx::mapping::Error),
|
||||||
CopyError(gfx::CopyError<[u16; 3], usize>),
|
CopyError(gfx::CopyError<[u16; 3], usize>),
|
||||||
|
CustomError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<gfx::PipelineStateError<String>> for RenderError {
|
impl From<gfx::PipelineStateError<String>> for RenderError {
|
||||||
|
@ -63,13 +63,38 @@ pub trait Pipeline {
|
|||||||
|
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
/// Anti-aliasing modes
|
/// Anti-aliasing modes
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
|
#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
pub enum AaMode {
|
pub enum AaMode {
|
||||||
None,
|
None,
|
||||||
|
/// Fast approximate antialiasing.
|
||||||
|
///
|
||||||
|
/// This is a screen-space technique, and therefore
|
||||||
Fxaa,
|
Fxaa,
|
||||||
|
/// Multisampling AA, up to 4 samples per pixel.
|
||||||
|
///
|
||||||
|
/// NOTE: MSAA modes don't (currently) work with greedy meshing, and will
|
||||||
|
/// also struggle in the futrue with deferred shading, so they may be
|
||||||
|
/// removed in the future.
|
||||||
MsaaX4,
|
MsaaX4,
|
||||||
|
/// Multisampling AA, up to 8 samples per pixel.
|
||||||
|
///
|
||||||
|
/// NOTE: MSAA modes don't (currently) work with greedy meshing, and will
|
||||||
|
/// also struggle in the futrue with deferred shading, so they may be
|
||||||
|
/// removed in the future.
|
||||||
MsaaX8,
|
MsaaX8,
|
||||||
|
/// Multisampling AA, up to 16 samples per pixel.
|
||||||
|
///
|
||||||
|
/// NOTE: MSAA modes don't (currently) work with greedy meshing, and will
|
||||||
|
/// also struggle in the futrue with deferred shading, so they may be
|
||||||
|
/// removed in the future.
|
||||||
MsaaX16,
|
MsaaX16,
|
||||||
|
/// Super-sampling antialiasing, 4 samples per pixel.
|
||||||
|
///
|
||||||
|
/// Unlike MSAA, SSAA *always* performs 4 samples per pixel, rather than
|
||||||
|
/// trying to choose importance samples at boundary regions, so it works
|
||||||
|
/// much better with techniques like deferred rendering and greedy
|
||||||
|
/// meshing that (without significantly more work) invalidate the
|
||||||
|
/// GPU's assumptions about importance sampling.
|
||||||
SsaaX4,
|
SsaaX4,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,9 +103,38 @@ impl Default for AaMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Cloud modes
|
/// Cloud modes
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
|
#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
pub enum CloudMode {
|
pub enum CloudMode {
|
||||||
|
/// No clouds. On computers that can't handle loops well, have performance
|
||||||
|
/// issues in fragment shaders in general, or just have large
|
||||||
|
/// resolutions, this can be a *very* impactful performance difference.
|
||||||
|
/// Part of that is because of inefficiencies in how we implement
|
||||||
|
/// regular clouds. It is still not all that cheap on low-end machines, due
|
||||||
|
/// to many calculations being performed that use relatively expensive
|
||||||
|
/// functions, and at some point I'd like to both optimize the regular
|
||||||
|
/// sky shader further and create an even cheaper option.
|
||||||
None,
|
None,
|
||||||
|
/// Volumetric clouds. This option can be *very* expensive on low-end
|
||||||
|
/// machines, to the point of making the game unusable, for several
|
||||||
|
/// reasons:
|
||||||
|
///
|
||||||
|
/// - The volumetric clouds use raymarching, which will cause catastrophic
|
||||||
|
/// performance degradation on GPUs without good support for loops. There
|
||||||
|
/// is an attempt to minimize the impact of this using a z-range check,
|
||||||
|
/// but on some low-end GPUs (such as some integraetd graphics cards) this
|
||||||
|
/// test doesn't appear to be able to be predicted well at shader
|
||||||
|
/// invocation time.
|
||||||
|
/// - The cloud computations themselves are fairly involved, further
|
||||||
|
/// degrading performance.
|
||||||
|
/// - Although the sky shader is always drawn at the outer edges of the
|
||||||
|
/// skybox, the clouds themselves are supposed to be positioned much
|
||||||
|
/// lower, which means the depth check for the skybox incorrectly cuts off
|
||||||
|
/// clouds in some places. To compensate for these cases (e.g. where
|
||||||
|
/// terrain is occluded by clouds from above, and the camera is above the
|
||||||
|
/// clouds), we currently branch to see if we need to render the clouds in
|
||||||
|
/// *every* fragment shader. For machines that can't optimize the check,
|
||||||
|
/// this is absurdly expensive, so we should look at alternatives in the
|
||||||
|
/// future that player better iwth the GPU.
|
||||||
Regular,
|
Regular,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,9 +143,28 @@ impl Default for CloudMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Fluid modes
|
/// Fluid modes
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
|
#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
pub enum FluidMode {
|
pub enum FluidMode {
|
||||||
|
/// "Cheap" water. This water implements no waves, no reflections, no
|
||||||
|
/// diffraction, and no light attenuation through water. As a result,
|
||||||
|
/// it can be much cheaper than shiny reflection.
|
||||||
Cheap,
|
Cheap,
|
||||||
|
/// "Shiny" water. This water implements waves on the surfaces, some
|
||||||
|
/// attempt at reflections, and tries to compute accurate light
|
||||||
|
/// attenuation through water (this is what results in the
|
||||||
|
/// colors changing as you descend into deep water).
|
||||||
|
///
|
||||||
|
/// Unfortunately, the way the engine is currently set up, calculating
|
||||||
|
/// accurate attenuation is a bit difficult; we use estimates from
|
||||||
|
/// horizon maps for the current water altitude, which can both be off
|
||||||
|
/// by up to (max_altitude / 255) meters, only has per-chunk horizontal
|
||||||
|
/// resolution, and cannot handle edge cases like horizontal water (e.g.
|
||||||
|
/// waterfalls) well. We are okay with the latter, and will try to fix
|
||||||
|
/// the former soon.
|
||||||
|
///
|
||||||
|
/// Another issue is that we don't always know whether light is *blocked*,
|
||||||
|
/// which causes attenuation to be computed incorrectly; this can be
|
||||||
|
/// addressed by using shadow maps (at least for terrain).
|
||||||
Shiny,
|
Shiny,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,10 +173,22 @@ impl Default for FluidMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Lighting modes
|
/// Lighting modes
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
|
#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
pub enum LightingMode {
|
pub enum LightingMode {
|
||||||
Ashikmin,
|
/// Ashikhmin-Shirley BRDF lighting model. Attempts to generate a
|
||||||
|
/// physically plausible (to some extent) lighting distribution.
|
||||||
|
///
|
||||||
|
/// This mdoel may not work as well with purely directional lighting, and is
|
||||||
|
/// more expensive than the otehr models.
|
||||||
|
Ashikhmin,
|
||||||
|
/// Standard Blinn-Phong shading, combing Lambertian diffuse reflections and
|
||||||
|
/// specular highlights.
|
||||||
BlinnPhong,
|
BlinnPhong,
|
||||||
|
/// Standard Lambertian lighting model, with only diffuse reflections. The
|
||||||
|
/// cheapest lighting model by a decent margin, but the performance
|
||||||
|
/// dfifference between it and Blinn-Phong will probably only be
|
||||||
|
/// significant on low-end machines that are bottlenecked on fragment
|
||||||
|
/// shading.
|
||||||
Lambertian,
|
Lambertian,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,25 +196,67 @@ impl Default for LightingMode {
|
|||||||
fn default() -> Self { LightingMode::BlinnPhong }
|
fn default() -> Self { LightingMode::BlinnPhong }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shadow map settings.
|
||||||
|
#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct ShadowMapMode {
|
||||||
|
/// Multiple of default resolution (default is currenttly the closest higher
|
||||||
|
/// power of two above the length of the longest diagonal of the screen
|
||||||
|
/// resolution, but this may change).
|
||||||
|
pub resolution: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ShadowMapMode {
|
||||||
|
fn default() -> Self { Self { resolution: 1.0 } }
|
||||||
|
}
|
||||||
|
|
||||||
/// Shadow modes
|
/// Shadow modes
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
|
#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
pub enum ShadowMode {
|
pub enum ShadowMode {
|
||||||
|
/// No shadows at all. By far the cheapest option.
|
||||||
None,
|
None,
|
||||||
|
/// Point shadows (draw circles under figures, up to a configured maximum;
|
||||||
|
/// also render LOD shadows using horizon maps). Can be expensive on
|
||||||
|
/// some machines, probably mostly due to horizon mapping; the point
|
||||||
|
/// shadows are not rendered too efficiently, but that can probably
|
||||||
|
/// be addressed later.
|
||||||
Cheap,
|
Cheap,
|
||||||
/// Multiple of resolution.
|
/// Shadow map (render the scene from each light source, and also renders
|
||||||
Map, /* (f32) */
|
/// LOD shadows using horizon maps).
|
||||||
|
Map(ShadowMapMode),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ShadowMode {
|
impl Default for ShadowMode {
|
||||||
fn default() -> Self { ShadowMode::Cheap }
|
fn default() -> Self { ShadowMode::Cheap }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl core::convert::TryFrom<ShadowMode> for ShadowMapMode {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
/// Get the shadow map details if they exist.
|
||||||
|
fn try_from(value: ShadowMode) -> Result<Self, Self::Error> {
|
||||||
|
if let ShadowMode::Map(map) = value {
|
||||||
|
Ok(map)
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShadowMode {
|
||||||
|
pub fn is_map(&self) -> bool { if let Self::Map(_) = self { true } else { false } }
|
||||||
|
}
|
||||||
|
|
||||||
/// Render modes
|
/// Render modes
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, Default, Serialize, Deserialize)]
|
#[derive(PartialEq, Clone, Copy, Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct RenderMode {
|
pub struct RenderMode {
|
||||||
|
#[serde(default)]
|
||||||
pub aa: AaMode,
|
pub aa: AaMode,
|
||||||
|
#[serde(default)]
|
||||||
pub cloud: CloudMode,
|
pub cloud: CloudMode,
|
||||||
|
#[serde(default)]
|
||||||
pub fluid: FluidMode,
|
pub fluid: FluidMode,
|
||||||
|
#[serde(default)]
|
||||||
pub lighting: LightingMode,
|
pub lighting: LightingMode,
|
||||||
|
#[serde(default)]
|
||||||
pub shadow: ShadowMode,
|
pub shadow: ShadowMode,
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ use super::{
|
|||||||
},
|
},
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
AaMode, CloudMode, FilterMethod, FluidMode, LightingMode, Pipeline, RenderError, RenderMode,
|
AaMode, CloudMode, FilterMethod, FluidMode, LightingMode, Pipeline, RenderError, RenderMode,
|
||||||
ShadowMode, WrapMode,
|
ShadowMapMode, ShadowMode, WrapMode,
|
||||||
};
|
};
|
||||||
use common::assets::{self, watch::ReloadIndicator};
|
use common::assets::{self, watch::ReloadIndicator};
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
@ -144,20 +144,29 @@ impl Renderer {
|
|||||||
/// Create a new `Renderer` from a variety of backend-specific components
|
/// Create a new `Renderer` from a variety of backend-specific components
|
||||||
/// and the window targets.
|
/// and the window targets.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: gfx_backend::Device,
|
mut device: gfx_backend::Device,
|
||||||
mut factory: gfx_backend::Factory,
|
mut factory: gfx_backend::Factory,
|
||||||
win_color_view: WinColorView,
|
win_color_view: WinColorView,
|
||||||
win_depth_view: WinDepthView,
|
win_depth_view: WinDepthView,
|
||||||
mode: RenderMode,
|
mode: RenderMode,
|
||||||
) -> Result<Self, RenderError> {
|
) -> Result<Self, RenderError> {
|
||||||
|
// Enable seamless cubemaps globally, where available--they are essentially a
|
||||||
|
// strict improvement on regular cube maps.
|
||||||
|
//
|
||||||
|
// Note that since we only have to enable this once globally, there is no point
|
||||||
|
// in doing this on rerender.
|
||||||
|
Self::enable_seamless_cube_maps(&mut device);
|
||||||
|
|
||||||
let dims = win_color_view.get_dimensions();
|
let dims = win_color_view.get_dimensions();
|
||||||
|
|
||||||
let mut shader_reload_indicator = ReloadIndicator::new();
|
let mut shader_reload_indicator = ReloadIndicator::new();
|
||||||
let shadow_views = Self::create_shadow_views(&mut factory, (dims.0, dims.1))
|
let shadow_views = ShadowMapMode::try_from(mode.shadow).ok().and_then(|mode| {
|
||||||
|
Self::create_shadow_views(&mut factory, (dims.0, dims.1), &mode)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
warn!("Could not create shadow map views: {:?}", err);
|
warn!("Could not create shadow map views: {:?}", err);
|
||||||
})
|
})
|
||||||
.ok();
|
.ok()
|
||||||
|
});
|
||||||
|
|
||||||
let (
|
let (
|
||||||
skybox_pipeline,
|
skybox_pipeline,
|
||||||
@ -320,8 +329,10 @@ impl Renderer {
|
|||||||
self.tgt_color_res = tgt_color_res;
|
self.tgt_color_res = tgt_color_res;
|
||||||
self.tgt_color_view = tgt_color_view;
|
self.tgt_color_view = tgt_color_view;
|
||||||
self.tgt_depth_stencil_view = tgt_depth_stencil_view;
|
self.tgt_depth_stencil_view = tgt_depth_stencil_view;
|
||||||
if let Some(shadow_map) = self.shadow_map.as_mut() {
|
if let (Some(shadow_map), ShadowMode::Map(mode)) =
|
||||||
match Self::create_shadow_views(&mut self.factory, (dims.0, dims.1)) {
|
(self.shadow_map.as_mut(), self.mode.shadow)
|
||||||
|
{
|
||||||
|
match Self::create_shadow_views(&mut self.factory, (dims.0, dims.1), &mode) {
|
||||||
Ok((
|
Ok((
|
||||||
point_depth_stencil_view,
|
point_depth_stencil_view,
|
||||||
point_res,
|
point_res,
|
||||||
@ -407,6 +418,7 @@ impl Renderer {
|
|||||||
fn create_shadow_views(
|
fn create_shadow_views(
|
||||||
factory: &mut gfx_device_gl::Factory,
|
factory: &mut gfx_device_gl::Factory,
|
||||||
size: (u16, u16),
|
size: (u16, u16),
|
||||||
|
mode: &ShadowMapMode,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
(
|
(
|
||||||
ShadowDepthStencilView,
|
ShadowDepthStencilView,
|
||||||
@ -418,17 +430,40 @@ impl Renderer {
|
|||||||
),
|
),
|
||||||
RenderError,
|
RenderError,
|
||||||
> {
|
> {
|
||||||
let size = Vec2::new(size.0, size.1);
|
// (Attempt to) apply resolution factor to shadow map resolution.
|
||||||
|
let resolution_factor = mode.resolution.clamped(0.25, 4.0);
|
||||||
|
fn vec2_result<T, E>(v: Vec2<Result<T, E>>) -> Result<Vec2<T>, E> {
|
||||||
|
Ok(Vec2::new(v.x?, v.y?))
|
||||||
|
};
|
||||||
|
|
||||||
let max_texture_size = Self::max_texture_size_raw(factory);
|
let max_texture_size = Self::max_texture_size_raw(factory);
|
||||||
|
let size = vec2_result(Vec2::new(size.0, size.1).map(|e| {
|
||||||
|
let size = f32::from(e) * resolution_factor;
|
||||||
|
// NOTE: We know 0 <= e since we clamped the resolution factor to be between
|
||||||
|
// 0.25 and 4.0.
|
||||||
|
if size <= f32::from(max_texture_size) {
|
||||||
|
Ok(size as u16)
|
||||||
|
} else {
|
||||||
|
Err(RenderError::CustomError(format!(
|
||||||
|
"Resolution factor {:?} multiplied by screen resolution axis {:?} does not \
|
||||||
|
fit in a texture on this machine.",
|
||||||
|
resolution_factor, e
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}))?;
|
||||||
|
|
||||||
let levels = 1; //10;
|
let levels = 1; //10;
|
||||||
let two_size = size.map(|e| {
|
let two_size = vec2_result(size.map(|e| {
|
||||||
u16::checked_next_power_of_two(e)
|
u16::checked_next_power_of_two(e)
|
||||||
.filter(|&e| e <= max_texture_size)
|
.filter(|&e| e <= max_texture_size)
|
||||||
.expect(
|
.ok_or_else(|| {
|
||||||
"Next power of two for max screen resolution axis does not fit in a texture \
|
RenderError::CustomError(format!(
|
||||||
on this machine.",
|
"Next power of two for shadow map resolution axis {:?} does not fit in a \
|
||||||
)
|
texture on this machine.",
|
||||||
});
|
e
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}))?;
|
||||||
let min_size = size.reduce_min();
|
let min_size = size.reduce_min();
|
||||||
let max_size = size.reduce_max();
|
let max_size = size.reduce_max();
|
||||||
let _min_two_size = two_size.reduce_min();
|
let _min_two_size = two_size.reduce_min();
|
||||||
@ -437,8 +472,9 @@ impl Renderer {
|
|||||||
// size of a diagonal along that axis.
|
// size of a diagonal along that axis.
|
||||||
let diag_size = size.map(f64::from).magnitude();
|
let diag_size = size.map(f64::from).magnitude();
|
||||||
let diag_cross_size = f64::from(min_size) / f64::from(max_size) * diag_size;
|
let diag_cross_size = f64::from(min_size) / f64::from(max_size) * diag_size;
|
||||||
let (diag_size, _diag_cross_size) =
|
let (diag_size, _diag_cross_size) = if 0.0 < diag_size
|
||||||
if 0.0 < diag_size && diag_size <= f64::from(max_texture_size) {
|
&& diag_size <= f64::from(max_texture_size)
|
||||||
|
{
|
||||||
// NOTE: diag_cross_size must be non-negative, since it is the ratio of a
|
// 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,
|
// non-negative and a positive number (if max_size were zero,
|
||||||
// diag_size would be 0 too). And it must be <= diag_size,
|
// diag_size would be 0 too). And it must be <= diag_size,
|
||||||
@ -446,14 +482,20 @@ impl Renderer {
|
|||||||
// u16, so does diag_cross_size.
|
// u16, so does diag_cross_size.
|
||||||
(diag_size as u16, diag_cross_size as u16)
|
(diag_size as u16, diag_cross_size as u16)
|
||||||
} else {
|
} else {
|
||||||
panic!("Resolution of screen diagonal does not fit in a texture on this machine.");
|
return Err(RenderError::CustomError(format!(
|
||||||
|
"Resolution of shadow map diagonal {:?} does not fit in a texture on this machine.",
|
||||||
|
diag_size
|
||||||
|
)));
|
||||||
};
|
};
|
||||||
let diag_two_size = u16::checked_next_power_of_two(diag_size)
|
let diag_two_size = u16::checked_next_power_of_two(diag_size)
|
||||||
.filter(|&e| e <= max_texture_size)
|
.filter(|&e| e <= max_texture_size)
|
||||||
.expect(
|
.ok_or_else(|| {
|
||||||
"Next power of two for resolution of screen diagonal does not fit in a texture on \
|
RenderError::CustomError(format!(
|
||||||
this machine.",
|
"Next power of two for resolution of shadow map diagonal {:?} does not fit in \
|
||||||
);
|
a texture on this machine.",
|
||||||
|
diag_size
|
||||||
|
))
|
||||||
|
})?;
|
||||||
/* let color_cty = <<TgtColorFmt as gfx::format::Formatted>::Channel as gfx::format::ChannelTyped
|
/* let color_cty = <<TgtColorFmt as gfx::format::Formatted>::Channel as gfx::format::ChannelTyped
|
||||||
>::get_channel_type();
|
>::get_channel_type();
|
||||||
let tgt_color_tex = factory.create_texture(
|
let tgt_color_tex = factory.create_texture(
|
||||||
@ -619,7 +661,7 @@ impl Renderer {
|
|||||||
/// Queue the clearing of the shadow targets ready for a new frame to be
|
/// Queue the clearing of the shadow targets ready for a new frame to be
|
||||||
/// rendered.
|
/// rendered.
|
||||||
pub fn clear_shadows(&mut self) {
|
pub fn clear_shadows(&mut self) {
|
||||||
if self.mode.shadow != ShadowMode::Map {
|
if !self.mode.shadow.is_map() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(shadow_map) = self.shadow_map.as_mut() {
|
if let Some(shadow_map) = self.shadow_map.as_mut() {
|
||||||
@ -633,18 +675,45 @@ impl Renderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// NOTE: Supported by Vulkan (by default), DirectX 10+ (it seems--it's hard
|
||||||
|
/// to find proof of this, but Direct3D 10 apparently does it by
|
||||||
|
/// default, and 11 definitely does, so I assume it's natively supported
|
||||||
|
/// by DirectX itself), OpenGL 3.2+, and Metal (done by default). While
|
||||||
|
/// there may be some GPUs that don't quite support it correctly, the
|
||||||
|
/// impact is relatively small, so there is no reaosn not to enable it where
|
||||||
|
/// available.
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
fn enable_seamless_cube_maps(device: &mut gfx_backend::Device) {
|
||||||
|
unsafe {
|
||||||
|
// NOTE: Currently just fail silently rather than complain if the computer is on
|
||||||
|
// a version lower than 3.2, where seamless cubemaps were introduced.
|
||||||
|
if !device.get_info().is_version_supported(3, 2) {
|
||||||
|
// println!("whoops");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Safe because GL_TEXTURE_CUBE_MAP_SEAMLESS is supported by OpenGL 3.2+
|
||||||
|
// (see https://www.khronos.org/opengl/wiki/Cubemap_Texture#Seamless_cubemap);
|
||||||
|
// enabling seamless cube maps should always be safe regardless of the state of
|
||||||
|
// the OpenGL context, so no further checks are needd.
|
||||||
|
device.with_gl(|gl| {
|
||||||
|
gl.Enable(gfx_gl::TEXTURE_CUBE_MAP_SEAMLESS);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// NOTE: Supported by all but a handful of mobile GPUs
|
/// NOTE: Supported by all but a handful of mobile GPUs
|
||||||
/// (see https://github.com/gpuweb/gpuweb/issues/480)
|
/// (see https://github.com/gpuweb/gpuweb/issues/480)
|
||||||
/// so wgpu should support it too.
|
/// so wgpu should support it too.
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn set_depth_clamp(&mut self, depth_clamp: bool) {
|
fn set_depth_clamp(device: &mut gfx_backend::Device, depth_clamp: bool) {
|
||||||
unsafe {
|
unsafe {
|
||||||
// NOTE: Currently just fail silently rather than complain if the computer is on
|
// NOTE: Currently just fail silently rather than complain if the computer is on
|
||||||
// a version lower than 3.3, though we probably will complain
|
// a version lower than 3.3, though we probably will complain
|
||||||
// elsewhere regardless, since shadow mapping is an optional feature
|
// elsewhere regardless, since shadow mapping is an optional feature
|
||||||
// and having depth clamping disabled won't cause undefined
|
// and having depth clamping disabled won't cause undefined
|
||||||
// behavior, just incorrect shadowing from objects behind the viewer.
|
// behavior, just incorrect shadowing from objects behind the viewer.
|
||||||
if !self.device.get_info().is_version_supported(3, 3) {
|
if !device.get_info().is_version_supported(3, 3) {
|
||||||
// println!("whoops");
|
// println!("whoops");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -654,7 +723,7 @@ impl Renderer {
|
|||||||
// may use different extensions. Also, enabling depth clamping should
|
// may use different extensions. Also, enabling depth clamping should
|
||||||
// essentially always be safe regardless of the state of the OpenGL
|
// essentially always be safe regardless of the state of the OpenGL
|
||||||
// context, so no further checks are needed.
|
// context, so no further checks are needed.
|
||||||
self.device.with_gl(|gl| {
|
device.with_gl(|gl| {
|
||||||
// println!("gl.Enable(gfx_gl::DEPTH_CLAMP) = {:?}",
|
// println!("gl.Enable(gfx_gl::DEPTH_CLAMP) = {:?}",
|
||||||
// gl.IsEnabled(gfx_gl::DEPTH_CLAMP));
|
// gl.IsEnabled(gfx_gl::DEPTH_CLAMP));
|
||||||
if depth_clamp {
|
if depth_clamp {
|
||||||
@ -676,18 +745,18 @@ impl Renderer {
|
|||||||
|
|
||||||
/// Set up shadow rendering.
|
/// Set up shadow rendering.
|
||||||
pub fn start_shadows(&mut self) {
|
pub fn start_shadows(&mut self) {
|
||||||
if self.mode.shadow != ShadowMode::Map {
|
if !self.mode.shadow.is_map() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(_shadow_map) = self.shadow_map.as_mut() {
|
if let Some(_shadow_map) = self.shadow_map.as_mut() {
|
||||||
self.encoder.flush(&mut self.device);
|
self.encoder.flush(&mut self.device);
|
||||||
self.set_depth_clamp(true);
|
Self::set_depth_clamp(&mut self.device, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform all queued draw calls for shadows.
|
/// Perform all queued draw calls for shadows.
|
||||||
pub fn flush_shadows(&mut self) {
|
pub fn flush_shadows(&mut self) {
|
||||||
if self.mode.shadow != ShadowMode::Map {
|
if !self.mode.shadow.is_map() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(_shadow_map) = self.shadow_map.as_mut() {
|
if let Some(_shadow_map) = self.shadow_map.as_mut() {
|
||||||
@ -697,7 +766,7 @@ impl Renderer {
|
|||||||
// let directed_encoder = &mut shadow_map.directed_encoder;
|
// let directed_encoder = &mut shadow_map.directed_encoder;
|
||||||
// directed_encoder.flush(&mut self.device);
|
// directed_encoder.flush(&mut self.device);
|
||||||
// Reset depth clamping.
|
// Reset depth clamping.
|
||||||
self.set_depth_clamp(false);
|
Self::set_depth_clamp(&mut self.device, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1322,7 +1391,7 @@ impl Renderer {
|
|||||||
* map: &Texture<LodColorFmt>,
|
* map: &Texture<LodColorFmt>,
|
||||||
* horizon: &Texture<LodTextureFmt>, */
|
* horizon: &Texture<LodTextureFmt>, */
|
||||||
) {
|
) {
|
||||||
if self.mode.shadow != ShadowMode::Map {
|
if !self.mode.shadow.is_map() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// NOTE: Don't render shadows if the shader is not supported.
|
// NOTE: Don't render shadows if the shader is not supported.
|
||||||
@ -1377,7 +1446,7 @@ impl Renderer {
|
|||||||
* map: &Texture<LodColorFmt>,
|
* map: &Texture<LodColorFmt>,
|
||||||
* horizon: &Texture<LodTextureFmt>, */
|
* horizon: &Texture<LodTextureFmt>, */
|
||||||
) {
|
) {
|
||||||
if self.mode.shadow != ShadowMode::Map {
|
if !self.mode.shadow.is_map() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// NOTE: Don't render shadows if the shader is not supported.
|
// NOTE: Don't render shadows if the shader is not supported.
|
||||||
@ -1433,7 +1502,7 @@ impl Renderer {
|
|||||||
* map: &Texture<LodColorFmt>,
|
* map: &Texture<LodColorFmt>,
|
||||||
* horizon: &Texture<LodTextureFmt>, */
|
* horizon: &Texture<LodTextureFmt>, */
|
||||||
) {
|
) {
|
||||||
if self.mode.shadow != ShadowMode::Map {
|
if !self.mode.shadow.is_map() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// NOTE: Don't render shadows if the shader is not supported.
|
// NOTE: Don't render shadows if the shader is not supported.
|
||||||
@ -1783,14 +1852,14 @@ fn create_pipelines(
|
|||||||
CloudMode::Regular => "CLOUD_MODE_REGULAR",
|
CloudMode::Regular => "CLOUD_MODE_REGULAR",
|
||||||
},
|
},
|
||||||
match mode.lighting {
|
match mode.lighting {
|
||||||
LightingMode::Ashikmin => "LIGHTING_ALGORITHM_ASHIKHMIN",
|
LightingMode::Ashikhmin => "LIGHTING_ALGORITHM_ASHIKHMIN",
|
||||||
LightingMode::BlinnPhong => "LIGHTING_ALGORITHM_BLINN_PHONG",
|
LightingMode::BlinnPhong => "LIGHTING_ALGORITHM_BLINN_PHONG",
|
||||||
LightingMode::Lambertian => "CLOUD_MODE_NONE",
|
LightingMode::Lambertian => "CLOUD_MODE_NONE",
|
||||||
},
|
},
|
||||||
match mode.shadow {
|
match mode.shadow {
|
||||||
ShadowMode::None => "SHADOW_MODE_NONE",
|
ShadowMode::None => "SHADOW_MODE_NONE",
|
||||||
ShadowMode::Map if has_shadow_views => "SHADOW_MODE_MAP",
|
ShadowMode::Map(_) if has_shadow_views => "SHADOW_MODE_MAP",
|
||||||
ShadowMode::Cheap | ShadowMode::Map => "SHADOW_MODE_CHEAP",
|
ShadowMode::Cheap | ShadowMode::Map(_) => "SHADOW_MODE_CHEAP",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ where
|
|||||||
) -> Result<Self, RenderError> {
|
) -> Result<Self, RenderError> {
|
||||||
let (tex, srv) = factory
|
let (tex, srv) = factory
|
||||||
.create_texture_immutable::<F>(kind, mipmap, data)
|
.create_texture_immutable::<F>(kind, mipmap, data)
|
||||||
.map_err(|err| RenderError::CombinedError(err))?;
|
.map_err(RenderError::CombinedError)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
tex,
|
tex,
|
||||||
|
@ -8,8 +8,8 @@ use crate::{
|
|||||||
ecs::comp::Interpolated,
|
ecs::comp::Interpolated,
|
||||||
mesh::greedy::GreedyMesh,
|
mesh::greedy::GreedyMesh,
|
||||||
render::{
|
render::{
|
||||||
self, BoneMeshes, ColLightFmt, Consts, FigureBoneData, FigureLocals, FigureModel, Globals,
|
BoneMeshes, ColLightFmt, Consts, FigureBoneData, FigureLocals, FigureModel, Globals, Light,
|
||||||
Light, RenderError, Renderer, Shadow, ShadowLocals, ShadowPipeline, Texture,
|
RenderError, Renderer, Shadow, ShadowLocals, ShadowPipeline, Texture,
|
||||||
},
|
},
|
||||||
scene::{
|
scene::{
|
||||||
camera::{Camera, CameraMode},
|
camera::{Camera, CameraMode},
|
||||||
@ -1805,7 +1805,7 @@ impl FigureMgr {
|
|||||||
) {
|
) {
|
||||||
let ecs = state.ecs();
|
let ecs = state.ecs();
|
||||||
|
|
||||||
if is_daylight && renderer.render_mode().shadow == render::ShadowMode::Map {
|
if is_daylight && renderer.render_mode().shadow.is_map() {
|
||||||
(
|
(
|
||||||
&ecs.entities(),
|
&ecs.entities(),
|
||||||
&ecs.read_storage::<Pos>(),
|
&ecs.read_storage::<Pos>(),
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
use core::{iter, mem};
|
use core::{iter, mem};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use num::traits::Float;
|
use num::traits::Float;
|
||||||
/* pub use vek::{
|
pub use vek::{geom::repr_simd::*, mat::repr_simd::column_major::Mat4, ops::*, vec::repr_simd::*};
|
||||||
geom::repr_simd::*, mat::repr_simd::column_major::Mat4, ops::*, vec::repr_simd::*,
|
// pub use vek::{geom::repr_c::*, mat::repr_c::column_major::Mat4, ops::*,
|
||||||
}; */
|
// vec::repr_c::*};
|
||||||
pub use vek::{geom::repr_c::*, mat::repr_c::column_major::Mat4, ops::*, vec::repr_c::*};
|
|
||||||
|
|
||||||
pub fn aabb_to_points<T: Float>(bounds: Aabb<T>) -> [Vec3<T>; 8] {
|
pub fn aabb_to_points<T: Float>(bounds: Aabb<T>) -> [Vec3<T>; 8] {
|
||||||
[
|
[
|
||||||
|
@ -14,7 +14,7 @@ use self::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
audio::{music::MusicMgr, sfx::SfxMgr, AudioFrontend},
|
audio::{music::MusicMgr, sfx::SfxMgr, AudioFrontend},
|
||||||
render::{
|
render::{
|
||||||
self, create_pp_mesh, create_skybox_mesh, Consts, Globals, Light, Model, PostProcessLocals,
|
create_pp_mesh, create_skybox_mesh, Consts, Globals, Light, Model, PostProcessLocals,
|
||||||
PostProcessPipeline, Renderer, Shadow, ShadowLocals, SkyboxLocals, SkyboxPipeline,
|
PostProcessPipeline, Renderer, Shadow, ShadowLocals, SkyboxLocals, SkyboxPipeline,
|
||||||
},
|
},
|
||||||
settings::Settings,
|
settings::Settings,
|
||||||
@ -553,9 +553,7 @@ impl Scene {
|
|||||||
|
|
||||||
let sun_dir = scene_data.get_sun_dir();
|
let sun_dir = scene_data.get_sun_dir();
|
||||||
let is_daylight = sun_dir.z < 0.0/*0.6*/;
|
let is_daylight = sun_dir.z < 0.0/*0.6*/;
|
||||||
if renderer.render_mode().shadow == render::ShadowMode::Map
|
if renderer.render_mode().shadow.is_map() && (is_daylight || !lights.is_empty()) {
|
||||||
&& (is_daylight || !lights.is_empty())
|
|
||||||
{
|
|
||||||
/* // We treat the actual scene bounds as being clipped by the horizontal terrain bounds, but
|
/* // We treat the actual scene bounds as being clipped by the horizontal terrain bounds, but
|
||||||
// expanded to contain the z values of all NPCs. This is potentially important to make
|
// expanded to contain the z values of all NPCs. This is potentially important to make
|
||||||
// sure we don't clip out figures in front of the camera.
|
// sure we don't clip out figures in front of the camera.
|
||||||
@ -1270,9 +1268,7 @@ impl Scene {
|
|||||||
let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc());
|
let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc());
|
||||||
|
|
||||||
// would instead have this as an extension.
|
// would instead have this as an extension.
|
||||||
if renderer.render_mode().shadow == render::ShadowMode::Map
|
if renderer.render_mode().shadow.is_map() && (is_daylight || self.light_data.len() > 0) {
|
||||||
&& (is_daylight || self.light_data.len() > 0)
|
|
||||||
{
|
|
||||||
// Set up shadow mapping.
|
// Set up shadow mapping.
|
||||||
renderer.start_shadows();
|
renderer.start_shadows();
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
mesh::{greedy::GreedyMesh, Meshable},
|
mesh::{greedy::GreedyMesh, Meshable},
|
||||||
render::{
|
render::{
|
||||||
self, ColLightFmt, ColLightInfo, Consts, FluidPipeline, Globals, Instances, Light, Mesh,
|
ColLightFmt, ColLightInfo, Consts, FluidPipeline, Globals, Instances, Light, Mesh, Model,
|
||||||
Model, RenderError, Renderer, Shadow, ShadowLocals, ShadowPipeline, SpriteInstance,
|
RenderError, Renderer, Shadow, ShadowLocals, ShadowPipeline, SpriteInstance, SpriteLocals,
|
||||||
SpriteLocals, SpritePipeline, TerrainLocals, TerrainPipeline, Texture,
|
SpritePipeline, TerrainLocals, TerrainPipeline, Texture,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2855,7 +2855,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
let collides_with_aabr = |a: math::Aabr<f32>, b: math::Aabr<f32>| {
|
let collides_with_aabr = |a: math::Aabr<f32>, b: math::Aabr<f32>| {
|
||||||
a.min.partial_cmple(&b.max).reduce_and() && a.max.partial_cmpge(&b.min).reduce_and()
|
a.min.partial_cmple(&b.max).reduce_and() && a.max.partial_cmpge(&b.min).reduce_and()
|
||||||
};
|
};
|
||||||
if ray_direction.z < 0.0 && renderer.render_mode().shadow == render::ShadowMode::Map {
|
if ray_direction.z < 0.0 && renderer.render_mode().shadow.is_map() {
|
||||||
let visible_bounding_box = Aabb {
|
let visible_bounding_box = Aabb {
|
||||||
min: visible_bounding_box.min - focus_off,
|
min: visible_bounding_box.min - focus_off,
|
||||||
max: visible_bounding_box.max - focus_off,
|
max: visible_bounding_box.max - focus_off,
|
||||||
@ -2962,7 +2962,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
min: -0.5,
|
min: -0.5,
|
||||||
max: 0.5,
|
max: 0.5,
|
||||||
}; */
|
}; */
|
||||||
/* if ray_direction.z < 0.0 && renderer.render_mode().shadow == render::ShadowMode::Map {
|
/* if ray_direction.z < 0.0 && renderer.render_mode().shadow.is_map() {
|
||||||
let ray = if ray_direction.x.abs() * scene_bounding_box.size().d > ray_direction.z.abs() * chunk_sz {
|
let ray = if ray_direction.x.abs() * scene_bounding_box.size().d > ray_direction.z.abs() * chunk_sz {
|
||||||
-ray_direction / ray_direction.x * chunk_sz
|
-ray_direction / ray_direction.x * chunk_sz
|
||||||
} else {
|
} else {
|
||||||
@ -3029,7 +3029,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
is_daylight: bool,
|
is_daylight: bool,
|
||||||
focus_pos: Vec3<f32>,
|
focus_pos: Vec3<f32>,
|
||||||
) {
|
) {
|
||||||
if !(renderer.render_mode().shadow == render::ShadowMode::Map) {
|
if !renderer.render_mode().shadow.is_map() {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -832,7 +832,6 @@ impl PlayState for SessionState {
|
|||||||
},
|
},
|
||||||
HudEvent::ChangeRenderMode(new_render_mode) => {
|
HudEvent::ChangeRenderMode(new_render_mode) => {
|
||||||
// Do this first so if it crashes the setting isn't saved :)
|
// Do this first so if it crashes the setting isn't saved :)
|
||||||
println!("Changing render mode: {:?}", new_render_mode);
|
|
||||||
global_state
|
global_state
|
||||||
.window
|
.window
|
||||||
.renderer_mut()
|
.renderer_mut()
|
||||||
|
@ -317,7 +317,7 @@ impl<'a> MapConfig<'a> {
|
|||||||
let water_color_factor = 2.0;
|
let water_color_factor = 2.0;
|
||||||
let g_water = 32.0 * water_color_factor;
|
let g_water = 32.0 * water_color_factor;
|
||||||
let b_water = 64.0 * water_color_factor;
|
let b_water = 64.0 * water_color_factor;
|
||||||
let column_rgb = column_rgb.unwrap_or(Rgb::new(
|
let default_rgb = Rgb::new(
|
||||||
if is_shaded || is_temperature {
|
if is_shaded || is_temperature {
|
||||||
1.0
|
1.0
|
||||||
} else {
|
} else {
|
||||||
@ -325,7 +325,8 @@ impl<'a> MapConfig<'a> {
|
|||||||
},
|
},
|
||||||
if is_shaded { 1.0 } else { alt },
|
if is_shaded { 1.0 } else { alt },
|
||||||
if is_shaded || is_humidity { 1.0 } else { 0.0 },
|
if is_shaded || is_humidity { 1.0 } else { 0.0 },
|
||||||
));
|
);
|
||||||
|
let column_rgb = column_rgb.unwrap_or(default_rgb);
|
||||||
let mut connections = [None; 8];
|
let mut connections = [None; 8];
|
||||||
let mut has_connections = false;
|
let mut has_connections = false;
|
||||||
// TODO: Support non-river connections.
|
// TODO: Support non-river connections.
|
||||||
|
@ -122,6 +122,11 @@ pub fn cdf_irwin_hall<const N: usize>(weights: &[f32; N], samples: [f32; N]) ->
|
|||||||
/// NOTE: Length should always be WORLD_SIZE.x * WORLD_SIZE.y.
|
/// NOTE: Length should always be WORLD_SIZE.x * WORLD_SIZE.y.
|
||||||
pub type InverseCdf<F = f32> = Box<[(f32, F)]>;
|
pub type InverseCdf<F = f32> = Box<[(f32, F)]>;
|
||||||
|
|
||||||
|
/// NOTE: First component is estimated horizon angles at each chunk; second
|
||||||
|
/// component is estimated heights of maximal occluder at each chunk (used
|
||||||
|
/// for making shadows volumetric).
|
||||||
|
pub type HorizonMap<A, H> = (Vec<A>, Vec<H>);
|
||||||
|
|
||||||
/// Computes the position Vec2 of a SimChunk from an index, where the index was
|
/// Computes the position Vec2 of a SimChunk from an index, where the index was
|
||||||
/// generated by uniform_noise.
|
/// generated by uniform_noise.
|
||||||
pub fn uniform_idx_as_vec2(idx: usize) -> Vec2<i32> {
|
pub fn uniform_idx_as_vec2(idx: usize) -> Vec2<i32> {
|
||||||
@ -395,7 +400,7 @@ pub fn get_horizon_map<F: Float + Sync, A: Send, H: Send>(
|
|||||||
h: impl Fn(usize) -> F + Sync,
|
h: impl Fn(usize) -> F + Sync,
|
||||||
to_angle: impl Fn(F) -> A + Sync,
|
to_angle: impl Fn(F) -> A + Sync,
|
||||||
to_height: impl Fn(F) -> H + Sync,
|
to_height: impl Fn(F) -> H + Sync,
|
||||||
) -> Result<[(Vec<A>, Vec<H>); 2], ()> {
|
) -> Result<[HorizonMap<A, H>; 2], ()> {
|
||||||
if maxh < minh {
|
if maxh < minh {
|
||||||
// maxh must be greater than minh
|
// maxh must be greater than minh
|
||||||
return Err(());
|
return Err(());
|
||||||
|
Loading…
Reference in New Issue
Block a user