From b3126ca68794c0c9afe93ea52f5fbddecf8afe82 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 00:53:19 +0100 Subject: [PATCH 01/31] Initial implementation of LoD trees --- Cargo.lock | 10 + assets/voxygen/lod/tree.mtl | 32 +++ assets/voxygen/lod/tree.obj | 244 ++++++++++++++++++ assets/voxygen/shaders/lod-object-vert.glsl | 43 +++ client/src/lib.rs | 43 ++- common/assets/Cargo.toml | 1 + common/assets/src/lib.rs | 16 ++ common/net/src/msg/client.rs | 4 + common/net/src/msg/server.rs | 6 + common/src/lib.rs | 1 + common/src/lod.rs | 35 +++ server/src/client.rs | 2 + server/src/lib.rs | 2 + server/src/lod.rs | 33 +++ server/src/sys/msg/in_game.rs | 1 + server/src/sys/msg/terrain.rs | 10 +- voxygen/src/render/mod.rs | 4 + voxygen/src/render/pipelines/lod_object.rs | 167 ++++++++++++ voxygen/src/render/pipelines/mod.rs | 1 + voxygen/src/render/renderer.rs | 2 +- voxygen/src/render/renderer/binding.rs | 2 +- voxygen/src/render/renderer/drawer.rs | 34 ++- .../src/render/renderer/pipeline_creation.rs | 31 ++- voxygen/src/render/renderer/shaders.rs | 1 + voxygen/src/scene/lod.rs | 110 +++++++- voxygen/src/scene/mod.rs | 4 +- world/src/layer/tree.rs | 30 ++- world/src/lib.rs | 30 +++ world/src/sim/mod.rs | 58 ++--- world/src/util/structure.rs | 28 +- 30 files changed, 906 insertions(+), 79 deletions(-) create mode 100644 assets/voxygen/lod/tree.mtl create mode 100644 assets/voxygen/lod/tree.obj create mode 100644 assets/voxygen/shaders/lod-object-vert.glsl create mode 100644 common/src/lod.rs create mode 100644 server/src/lod.rs create mode 100644 voxygen/src/render/pipelines/lod_object.rs diff --git a/Cargo.lock b/Cargo.lock index 76c15ad699..3de0c8fd88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6560,6 +6560,7 @@ dependencies = [ "serde", "tracing", "walkdir 2.3.2", + "wavefront", ] [[package]] @@ -7340,6 +7341,15 @@ dependencies = [ "wast", ] +[[package]] +name = "wavefront" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "249b7e6cd5bd1cc78a61d0475e5790c98bebabf2dc644a94a51ad58b39298652" +dependencies = [ + "hashbrown 0.9.1", +] + [[package]] name = "wayland-client" version = "0.28.6" diff --git a/assets/voxygen/lod/tree.mtl b/assets/voxygen/lod/tree.mtl new file mode 100644 index 0000000000..4f81bf8521 --- /dev/null +++ b/assets/voxygen/lod/tree.mtl @@ -0,0 +1,32 @@ +# Blender MTL File: 'None' +# Material Count: 3 + +newmtl Material +Ns 323.999994 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 + +newmtl Material.006 +Ns 225.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 + +newmtl Material.009 +Ns 225.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 diff --git a/assets/voxygen/lod/tree.obj b/assets/voxygen/lod/tree.obj new file mode 100644 index 0000000000..584b49c6bf --- /dev/null +++ b/assets/voxygen/lod/tree.obj @@ -0,0 +1,244 @@ +# Blender v3.0.0 OBJ File: '' +# www.blender.org +o Cube +v 1.000000 1.000000 1.000000 +v 1.000000 1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v 1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +v -1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +vt 0.875000 0.500000 +vt 0.625000 0.750000 +vt 0.625000 0.500000 +vt 0.375000 1.000000 +vt 0.375000 0.750000 +vt 0.625000 0.000000 +vt 0.375000 0.250000 +vt 0.375000 0.000000 +vt 0.375000 0.500000 +vt 0.125000 0.750000 +vt 0.125000 0.500000 +vt 0.625000 0.250000 +vt 0.875000 0.750000 +vt 0.625000 1.000000 +vn 0.0000 0.0000 1.0000 +vn 0.0000 -1.0000 0.0000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 1.0000 0.0000 +s off +f 5/1/1 3/2/1 1/3/1 +f 3/2/2 8/4/2 4/5/2 +f 7/6/3 6/7/3 8/8/3 +f 2/9/4 8/10/4 6/11/4 +f 1/3/5 4/5/5 2/9/5 +f 5/12/6 2/9/6 6/7/6 +f 5/1/1 7/13/1 3/2/1 +f 3/2/2 7/14/2 8/4/2 +f 7/6/3 5/12/3 6/7/3 +f 2/9/4 4/5/4 8/10/4 +f 1/3/5 3/2/5 4/5/5 +f 5/12/6 1/3/6 2/9/6 +o Cube.001 +v -1.814604 0.161418 -2.709981 +v -1.359475 0.002174 10.636601 +v 0.002174 1.363824 10.636601 +v 0.161417 2.137439 -2.709981 +v 1.363824 0.002174 10.636601 +v 2.137438 0.161418 -2.709981 +v 0.002174 -1.359475 10.636601 +v 0.161417 -1.814604 -2.709981 +v -0.028484 -9.424881 9.196677 +v -0.028485 -4.126693 23.008556 +v -4.223946 0.068768 23.008556 +v -9.522135 0.068768 9.196677 +v -0.028485 4.264229 23.008556 +v -0.028484 9.562418 9.196677 +v 4.166976 0.068767 23.008556 +v 9.465164 0.068769 9.196677 +v 6.263892 0.068768 10.372999 +v -0.028484 6.361145 10.372999 +v -0.028484 6.638610 21.179264 +v 6.541358 0.068768 21.179264 +v -0.028485 -6.501075 21.179264 +v -6.598328 0.068768 21.179264 +v -0.028485 -5.165573 30.045181 +v 5.205855 0.068768 30.045181 +v 2.329653 0.068768 37.773296 +v -0.028485 -2.289370 37.773296 +v -3.490429 0.068768 31.783909 +v -0.028485 -3.393177 31.783909 +v -5.262825 0.068767 30.045181 +v 3.433459 0.068768 31.783909 +v -0.028485 3.530712 31.783909 +v -0.028485 5.303108 30.045181 +v -0.217867 -0.120616 46.893818 +v -2.386622 0.068767 37.773296 +v -0.028485 2.426905 37.773296 +v -6.320862 0.068768 10.372999 +v -0.028484 -6.223608 10.372999 +vt 0.375000 0.250000 +vt 0.625000 0.500000 +vt 0.375000 0.500000 +vt 0.375000 0.750000 +vt 0.625000 0.750000 +vt 0.375000 1.000000 +vt 0.125000 0.750000 +vt 0.125000 0.500000 +vt 0.625000 0.000000 +vt 0.375000 0.000000 +vt 0.625000 0.250000 +vt 0.625000 1.000000 +vt 0.625000 0.000000 +vt 0.375000 0.250000 +vt 0.375000 0.000000 +vt 0.625000 0.250000 +vt 0.375000 0.500000 +vt 0.625000 0.500000 +vt 0.375000 0.750000 +vt 0.375000 0.750000 +vt 0.375000 0.500000 +vt 0.625000 0.750000 +vt 0.625000 0.500000 +vt 0.625000 0.750000 +vt 0.625000 1.000000 +vt 0.375000 1.000000 +vt 0.625000 0.250000 +vt 0.625000 1.000000 +vt 0.625000 1.000000 +vt 0.625000 0.750000 +vt 0.625000 1.000000 +vt 0.625000 0.000000 +vt 0.625000 0.250000 +vt 0.625000 0.250000 +vt 0.625000 0.750000 +vt 0.625000 1.000000 +vt 0.625000 0.500000 +vt 0.625000 0.500000 +vt 0.625000 1.000000 +vt 0.625000 0.500000 +vt 0.625000 0.750000 +vt 0.625000 0.000000 +vt 0.625000 0.250000 +vt 0.625000 0.500000 +vt 0.625000 0.750000 +vt 0.125000 0.750000 +vt 0.125000 0.500000 +vt 0.375000 0.250000 +vt 0.375000 0.000000 +vt 0.625000 0.250000 +vt 0.625000 0.000000 +vt 0.625000 0.000000 +vt 0.375000 1.000000 +vn -0.7067 0.7067 0.0325 +vn 0.7062 0.7062 0.0494 +vn 0.7067 -0.7067 0.0325 +vn 0.0000 0.0000 -1.0000 +vn -0.7070 -0.7070 0.0157 +vn -0.6824 -0.6824 0.2618 +vn -0.6824 0.6824 0.2618 +vn 0.6824 0.6824 0.2618 +vn -0.3261 -0.3261 -0.8873 +vn -0.5209 -0.5210 -0.6762 +vn 0.6824 -0.6824 0.2618 +vn 0.5209 0.5210 -0.6762 +vn 0.5210 0.5209 -0.6762 +vn -0.5210 0.5209 -0.6762 +vn -0.5210 0.5210 -0.6762 +vn -0.5209 0.5210 -0.6762 +vn 0.5210 -0.5210 -0.6762 +vn 0.5209 -0.5210 -0.6762 +vn 0.6838 -0.6838 0.2545 +vn 0.6894 -0.6894 0.2227 +vn 0.6895 -0.6895 0.2219 +vn 0.5736 0.5736 -0.5847 +vn -0.5736 0.5736 -0.5847 +vn 0.5736 -0.5736 -0.5847 +vn 0.6956 -0.6956 0.1798 +vn -0.6838 0.6838 0.2545 +vn -0.6894 0.6894 0.2227 +vn 0.6838 0.6838 0.2545 +vn 0.6874 0.6874 0.2342 +vn -0.6838 -0.6838 0.2545 +vn -0.6913 -0.6913 0.2102 +vn -0.6895 0.6895 0.2219 +vn -0.6956 0.6956 0.1798 +vn 0.6917 0.6917 0.2076 +vn -0.3261 0.3261 -0.8873 +vn 0.3261 -0.3261 -0.8873 +vn 0.3261 0.3261 -0.8873 +vn -0.5736 -0.5736 -0.5847 +vn -0.6989 -0.6989 0.1517 +vn 0.6924 0.6924 0.2029 +vn -0.6924 0.6924 0.2029 +vn 0.6924 -0.6924 0.2029 +vn -0.6924 -0.6924 0.2029 +vn 0.5210 -0.5209 -0.6762 +s 1 +f 9/15/7 11/16/7 12/17/7 +f 11/16/8 14/18/8 12/17/8 +f 13/19/9 16/20/9 14/18/9 +f 12/17/10 16/21/10 9/22/10 +f 15/23/11 9/15/11 16/24/11 +f 9/15/7 10/25/7 11/16/7 +f 11/16/8 13/19/8 14/18/8 +f 13/19/9 15/26/9 16/20/9 +f 12/17/10 14/18/10 16/21/10 +f 15/23/11 10/25/11 9/15/11 +f 18/27/12 20/28/12 17/29/12 +f 19/30/13 22/31/13 20/28/13 +f 21/32/14 24/33/14 22/31/14 +f 22/31/15 25/34/15 26/35/15 +f 23/36/16 27/37/16 28/38/16 +f 24/33/17 18/39/17 17/40/17 +f 18/27/18 30/41/19 19/30/19 +f 23/36/20 29/42/21 18/39/22 +f 19/30/23 27/37/24 21/32/24 +f 31/43/25 33/44/26 34/45/27 +f 36/46/28 37/47/28 35/48/28 +f 38/49/29 31/43/29 36/50/29 +f 35/48/30 40/51/30 39/52/30 +f 34/45/27 33/44/26 41/53/31 +f 37/47/32 43/54/33 40/51/32 +f 40/51/34 33/44/35 32/55/34 +f 37/47/36 34/56/37 42/57/37 +f 42/57/38 41/58/39 43/54/33 +f 43/54/35 41/59/40 33/44/35 +f 26/35/10 45/60/10 44/61/10 +f 17/40/41 25/34/41 24/33/41 +f 20/28/42 26/35/42 44/62/42 +f 20/28/43 45/63/43 17/29/43 +f 39/52/44 32/55/44 38/49/44 +f 34/56/37 41/64/45 42/57/37 +f 27/37/46 38/49/46 28/38/46 +f 30/41/47 39/52/47 27/37/47 +f 28/38/48 36/50/48 29/42/48 +f 29/65/49 35/48/49 30/41/49 +f 18/27/12 19/30/12 20/28/12 +f 19/30/13 21/32/13 22/31/13 +f 21/32/14 23/36/14 24/33/14 +f 22/31/15 24/33/15 25/34/15 +f 23/36/16 21/32/16 27/37/16 +f 24/33/17 23/36/17 18/39/17 +f 18/27/18 29/65/18 30/41/19 +f 23/36/20 28/38/20 29/42/21 +f 19/30/23 30/41/50 27/37/24 +f 31/43/25 32/55/25 33/44/26 +f 36/46/28 31/66/28 37/47/28 +f 38/49/29 32/55/29 31/43/29 +f 35/48/30 37/47/30 40/51/30 +f 37/47/32 42/57/38 43/54/33 +f 40/51/34 43/54/35 33/44/35 +f 37/47/36 31/66/36 34/56/37 +f 26/35/10 25/34/10 45/60/10 +f 17/40/41 45/67/41 25/34/41 +f 20/28/42 22/31/42 26/35/42 +f 20/28/43 44/62/43 45/63/43 +f 39/52/44 40/51/44 32/55/44 +f 27/37/46 39/52/46 38/49/46 +f 30/41/47 35/48/47 39/52/47 +f 28/38/48 38/49/48 36/50/48 +f 29/65/49 36/46/49 35/48/49 diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl new file mode 100644 index 0000000000..d585640c04 --- /dev/null +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -0,0 +1,43 @@ +#version 420 core + +#include + +#define LIGHTING_TYPE LIGHTING_TYPE_REFLECTION + +#define LIGHTING_REFLECTION_KIND LIGHTING_REFLECTION_KIND_GLOSSY + +#define LIGHTING_TRANSPORT_MODE LIGHTING_TRANSPORT_MODE_IMPORTANCE + +#define LIGHTING_DISTRIBUTION_SCHEME LIGHTING_DISTRIBUTION_SCHEME_MICROFACET + +#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN + +#include +#include +#include +#include + +layout(location = 0) in vec3 v_pos; +layout(location = 1) in vec3 v_norm; +layout(location = 2) in vec3 v_col; +layout(location = 3) in vec3 inst_pos; + +layout(location = 0) out vec3 f_pos; +layout(location = 1) out vec3 f_norm; +layout(location = 2) out vec4 f_col; +layout(location = 3) out float f_reflect; + +void main() { + f_pos = inst_pos + v_pos - focus_off.xyz; + + float pull_down = 1.0 / pow(distance(focus_pos.xy, f_pos.xy) / (view_distance.x * 0.95), 20.0); + f_pos.z -= pull_down; + + f_norm = v_norm; + f_col = vec4(vec3(0, 0.2, 0), 1.0);//vec4(v_col, 1.0); + f_reflect = 1.0; + + gl_Position = + all_mat * + vec4(f_pos, 1); +} diff --git a/client/src/lib.rs b/client/src/lib.rs index e4769b5381..1c5ebd26c2 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -46,6 +46,8 @@ use common::{ trade::{PendingTrade, SitePrices, TradeAction, TradeId, TradeResult}, uid::{Uid, UidAllocator}, vol::RectVolSize, + spiral::Spiral2d, + lod, }; use common_base::{prof_span, span}; use common_net::{ @@ -171,10 +173,12 @@ pub struct Client { pub chat_mode: ChatMode, recipe_book: RecipeBook, available_recipes: HashMap>, + lod_zones: HashMap, lod::Zone>, + lod_last_requested: Option, max_group_size: u32, // Client has received an invite (inviter uid, time out instant) - invite: Option<(Uid, std::time::Instant, std::time::Duration, InviteKind)>, + invite: Option<(Uid, Instant, Duration, InviteKind)>, group_leader: Option, // Note: potentially representable as a client only component group_members: HashMap, @@ -202,6 +206,7 @@ pub struct Client { state: State, view_distance: Option, + lod_distance: u32, // TODO: move into voxygen loaded_distance: f32, @@ -624,6 +629,9 @@ impl Client { available_recipes: HashMap::default(), chat_mode: ChatMode::default(), + lod_zones: HashMap::new(), + lod_last_requested: None, + max_group_size, invite: None, group_leader: None, @@ -650,6 +658,7 @@ impl Client { tick: 0, state, view_distance: None, + lod_distance: 2, // TODO: Make configurable loaded_distance: 0.0, pending_chunks: HashMap::new(), @@ -769,7 +778,8 @@ impl Client { &mut self.in_game_stream }, //Only in game, terrain - ClientGeneral::TerrainChunkRequest { .. } => { + ClientGeneral::TerrainChunkRequest { .. } + | ClientGeneral::LodZoneRequest { .. } => { #[cfg(feature = "tracy")] { terrain = 1.0; @@ -994,6 +1004,10 @@ impl Client { &self.available_recipes } + pub fn lod_zones(&self) -> &HashMap, lod::Zone> { + &self.lod_zones + } + /// Returns whether the specified recipe can be crafted and the sprite, if /// any, that is required to do so. pub fn can_craft_recipe(&self, recipe: &str) -> (bool, Option) { @@ -1709,6 +1723,27 @@ impl Client { let now = Instant::now(); self.pending_chunks .retain(|_, created| now.duration_since(*created) < Duration::from_secs(3)); + + // Manage LoD zones + let lod_zone = pos.0.xy().map(|e| lod::from_wpos(e as i32)); + + // Request LoD zones that are in range + if self.lod_last_requested.map_or(true, |i| i.elapsed() > Duration::from_secs(5)) { + + if let Some(unloaded) = Spiral2d::new() + .take((1 + self.lod_distance * 2).pow(2) as usize) + .map(|rpos| lod_zone + rpos) + .find(|p| !self.lod_zones.contains_key(p)) + { + self.send_msg_err(ClientGeneral::LodZoneRequest { + key: unloaded, + })?; + self.lod_last_requested = Some(Instant::now()); + } + } + + // Cull LoD zones out of range + self.lod_zones.retain(|p, _| (*p - lod_zone).map(i32::abs).reduce_max() < self.lod_distance as i32 + 1); } Ok(()) @@ -2084,6 +2119,10 @@ impl Client { } self.pending_chunks.remove(&key); }, + ServerGeneral::LodZoneUpdate { key, zone } => { + self.lod_zones.insert(key, zone); + self.lod_last_requested = None; + }, ServerGeneral::TerrainBlockUpdates(blocks) => { if let Some(mut blocks) = blocks.decompress() { blocks.drain().for_each(|(pos, block)| { diff --git a/common/assets/Cargo.toml b/common/assets/Cargo.toml index 3c11ceaae7..1b59285fed 100644 --- a/common/assets/Cargo.toml +++ b/common/assets/Cargo.toml @@ -10,6 +10,7 @@ lazy_static = "1.4.0" assets_manager = {version = "0.7", features = ["bincode", "ron", "json"]} ron = { version = "0.7", default-features = false } dot_vox = "4.0" +wavefront = "0.2" image = { version = "0.23.12", default-features = false, features = ["png"] } tracing = "0.1" diff --git a/common/assets/src/lib.rs b/common/assets/src/lib.rs index 594edc6864..4784de231e 100644 --- a/common/assets/src/lib.rs +++ b/common/assets/src/lib.rs @@ -191,6 +191,22 @@ impl Asset for DotVoxAsset { const EXTENSION: &'static str = "vox"; } +pub struct ObjAsset(pub wavefront::Obj); + +impl Asset for ObjAsset { + type Loader = ObjAssetLoader; + + const EXTENSION: &'static str = "obj"; +} + +pub struct ObjAssetLoader; +impl Loader for ObjAssetLoader { + fn load(content: std::borrow::Cow<[u8]>, _: &str) -> Result { + let data = wavefront::Obj::from_reader(&*content)?; + Ok(ObjAsset(data)) + } +} + /// Return path to repository root by searching 10 directories back pub fn find_root() -> Option { std::env::current_dir().map_or(None, |path| { diff --git a/common/net/src/msg/client.rs b/common/net/src/msg/client.rs index 9a7b9495b0..9f310dd962 100644 --- a/common/net/src/msg/client.rs +++ b/common/net/src/msg/client.rs @@ -83,6 +83,9 @@ pub enum ClientGeneral { TerrainChunkRequest { key: Vec2, }, + LodZoneRequest { + key: Vec2, + }, //Always possible ChatMsg(String), Command(String, Vec), @@ -128,6 +131,7 @@ impl ClientMsg { | ClientGeneral::ExitInGame | ClientGeneral::PlayerPhysics { .. } | ClientGeneral::TerrainChunkRequest { .. } + | ClientGeneral::LodZoneRequest { .. } | ClientGeneral::UnlockSkill(_) | ClientGeneral::RequestSiteInfo(_) | ClientGeneral::UnlockSkillGroup(_) diff --git a/common/net/src/msg/server.rs b/common/net/src/msg/server.rs index 04d413b633..d8174d2d7c 100644 --- a/common/net/src/msg/server.rs +++ b/common/net/src/msg/server.rs @@ -13,6 +13,7 @@ use common::{ terrain::{Block, TerrainChunk, TerrainChunkMeta, TerrainChunkSize}, trade::{PendingTrade, SitePrices, TradeId, TradeResult}, uid::Uid, + lod, }; use hashbrown::HashMap; use serde::{Deserialize, Serialize}; @@ -169,6 +170,10 @@ pub enum ServerGeneral { key: Vec2, chunk: Result, }, + LodZoneUpdate { + key: Vec2, + zone: lod::Zone, + }, TerrainBlockUpdates(CompressedData, Block>>), // Always possible PlayerListUpdate(PlayerListUpdate), @@ -293,6 +298,7 @@ impl ServerMsg { | ServerGeneral::ExitInGameSuccess | ServerGeneral::InventoryUpdate(_, _) | ServerGeneral::TerrainChunkUpdate { .. } + | ServerGeneral::LodZoneUpdate { .. } | ServerGeneral::TerrainBlockUpdates(_) | ServerGeneral::SetViewDistance(_) | ServerGeneral::Outcomes(_) diff --git a/common/src/lib.rs b/common/src/lib.rs index ac0470bff2..e1c0a036e8 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -49,6 +49,7 @@ pub mod figure; pub mod generation; #[cfg(not(target_arch = "wasm32"))] pub mod grid; #[cfg(not(target_arch = "wasm32"))] pub mod link; +#[cfg(not(target_arch = "wasm32"))] pub mod lod; #[cfg(not(target_arch = "wasm32"))] pub mod lottery; #[cfg(not(target_arch = "wasm32"))] diff --git a/common/src/lod.rs b/common/src/lod.rs new file mode 100644 index 0000000000..3ccc344c4e --- /dev/null +++ b/common/src/lod.rs @@ -0,0 +1,35 @@ +use vek::*; +use serde::{Serialize, Deserialize}; +use strum::EnumIter; +use crate::{ + terrain::TerrainChunkSize, + vol::RectVolSize, +}; + +// In chunks +pub const ZONE_SIZE: u32 = 64; + +#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Serialize, Deserialize, EnumIter)] +#[repr(u16)] +pub enum ObjectKind { + Tree, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Object { + pub kind: ObjectKind, + pub pos: Vec3, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Zone { + pub objects: Vec, +} + +pub fn to_wpos(wpos: i32) -> i32 { + wpos * (TerrainChunkSize::RECT_SIZE.x * ZONE_SIZE) as i32 +} + +pub fn from_wpos(zone_pos: i32) -> i32 { + zone_pos / (TerrainChunkSize::RECT_SIZE.x * ZONE_SIZE) as i32 +} diff --git a/server/src/client.rs b/server/src/client.rs index f917b0fa46..d357d3d4e1 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -118,6 +118,7 @@ impl Client { }, //Ingame related, terrain ServerGeneral::TerrainChunkUpdate { .. } + | ServerGeneral::LodZoneUpdate { .. } | ServerGeneral::TerrainBlockUpdates(_) => { self.terrain_stream.lock().unwrap().send(g) }, @@ -191,6 +192,7 @@ impl Client { }, //Ingame related, terrain ServerGeneral::TerrainChunkUpdate { .. } + | ServerGeneral::LodZoneUpdate { .. } | ServerGeneral::TerrainBlockUpdates(_) => { PreparedMsg::new(5, &g, &self.terrain_stream_params) }, diff --git a/server/src/lib.rs b/server/src/lib.rs index 0f3600ce95..ad4fb55e9c 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -24,6 +24,7 @@ pub mod error; pub mod events; pub mod input; pub mod location; +pub mod lod; pub mod login_provider; pub mod metrics; pub mod persistence; @@ -449,6 +450,7 @@ impl Server { // Insert the world into the ECS (todo: Maybe not an Arc?) let world = Arc::new(world); state.ecs_mut().insert(Arc::clone(&world)); + state.ecs_mut().insert(lod::Lod::from_world(&world, index.as_index_ref())); state.ecs_mut().insert(index.clone()); // Set starting time for the server. diff --git a/server/src/lod.rs b/server/src/lod.rs new file mode 100644 index 0000000000..9a7a02f8ed --- /dev/null +++ b/server/src/lod.rs @@ -0,0 +1,33 @@ +use common::lod; +use world::World; +use hashbrown::HashMap; +use vek::*; + +static EMPTY_ZONE: lod::Zone = lod::Zone { + objects: Vec::new(), +}; + +pub struct Lod { + pub zones: HashMap, lod::Zone>, +} + +impl Lod { + pub fn from_world(world: &World, index: world::IndexRef) -> Self { + let mut zones = HashMap::new(); + + let zone_sz = (world.sim().get_size() + lod::ZONE_SIZE - 1) / lod::ZONE_SIZE; + + for i in 0..zone_sz.x { + for j in 0..zone_sz.y { + let zone_pos = Vec2::new(i, j).map(|e| e as i32); + zones.insert(zone_pos, world.get_lod_zone(zone_pos, index)); + } + } + + Self { zones } + } + + pub fn zone(&self, zone_pos: Vec2) -> &lod::Zone { + self.zones.get(&zone_pos).unwrap_or(&EMPTY_ZONE) + } +} diff --git a/server/src/sys/msg/in_game.rs b/server/src/sys/msg/in_game.rs index 0b1972eb1b..6ceb6da12a 100644 --- a/server/src/sys/msg/in_game.rs +++ b/server/src/sys/msg/in_game.rs @@ -295,6 +295,7 @@ impl Sys { | ClientGeneral::Character(_) | ClientGeneral::Spectate | ClientGeneral::TerrainChunkRequest { .. } + | ClientGeneral::LodZoneRequest { .. } | ClientGeneral::ChatMsg(_) | ClientGeneral::Command(..) | ClientGeneral::Terminate => { diff --git a/server/src/sys/msg/terrain.rs b/server/src/sys/msg/terrain.rs index e6b39c1808..d806e36ca9 100644 --- a/server/src/sys/msg/terrain.rs +++ b/server/src/sys/msg/terrain.rs @@ -1,4 +1,4 @@ -use crate::{client::Client, metrics::NetworkRequestMetrics, presence::Presence, ChunkRequest}; +use crate::{client::Client, lod::Lod, metrics::NetworkRequestMetrics, presence::Presence, ChunkRequest}; use common::{ comp::Pos, event::{EventBus, ServerEvent}, @@ -20,6 +20,7 @@ impl<'a> System<'a> for Sys { Entities<'a>, Read<'a, EventBus>, ReadExpect<'a, TerrainGrid>, + ReadExpect<'a, Lod>, ReadExpect<'a, NetworkRequestMetrics>, Write<'a, Vec>, ReadStorage<'a, Pos>, @@ -37,6 +38,7 @@ impl<'a> System<'a> for Sys { entities, server_event_bus, terrain, + lod, network_metrics, mut chunk_requests, positions, @@ -101,6 +103,12 @@ impl<'a> System<'a> for Sys { network_metrics.chunks_request_dropped.inc(); } }, + ClientGeneral::LodZoneRequest { key } => { + client.send(ServerGeneral::LodZoneUpdate { + key, + zone: lod.zone(key).clone(), + })?; + }, _ => { debug!( "Kicking possibly misbehaving client due to invalud terrain \ diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 0a7a9556fc..c2d021f14b 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -35,6 +35,10 @@ pub use self::{ Instance as SpriteInstance, SpriteGlobalsBindGroup, SpriteVerts, Vertex as SpriteVertex, VERT_PAGE_SIZE as SPRITE_VERT_PAGE_SIZE, }, + lod_object::{ + Instance as LodObjectInstance, + Vertex as LodObjectVertex, + }, terrain::{Locals as TerrainLocals, TerrainLayout, Vertex as TerrainVertex}, trail::Vertex as TrailVertex, ui::{ diff --git a/voxygen/src/render/pipelines/lod_object.rs b/voxygen/src/render/pipelines/lod_object.rs new file mode 100644 index 0000000000..e08040a24d --- /dev/null +++ b/voxygen/src/render/pipelines/lod_object.rs @@ -0,0 +1,167 @@ +use super::{ + super::{ + buffer::Buffer, AaMode, GlobalsLayouts, Mesh, TerrainLayout, Texture, Vertex as VertexTrait, + }, + lod_terrain, GlobalModel, +}; +use bytemuck::{Pod, Zeroable}; +use std::mem; +use vek::*; + +pub const VERT_PAGE_SIZE: u32 = 256; + +#[repr(C)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] +pub struct Vertex { + pos: [f32; 3], + norm: [f32; 3], + col: [f32; 3], +} + +impl Vertex { + pub fn new(pos: Vec3, norm: Vec3, col: Vec3) -> Self { + Self { + pos: pos.into_array(), + norm: norm.into_array(), + col: col.into_array(), + } + } + + fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { + const ATTRIBUTES: [wgpu::VertexAttribute; 3] = + wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x3, 2 => Float32x3]; + wgpu::VertexBufferLayout { + array_stride: Self::STRIDE, + step_mode: wgpu::InputStepMode::Vertex, + attributes: &ATTRIBUTES, + } + } +} + +// impl Default for Vertex { +// fn default() -> Self { Self::new(Vec2::zero(), Vec3::zero(), Vec3::zero()) } +// } + +impl VertexTrait for Vertex { + const QUADS_INDEX: Option = None;//Some(wgpu::IndexFormat::Uint16); + const STRIDE: wgpu::BufferAddress = mem::size_of::() as wgpu::BufferAddress; +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] +pub struct Instance { + inst_pos: [f32; 3], +} + +impl Instance { + pub fn new( + inst_pos: Vec3, + ) -> Self { + Self { + inst_pos: inst_pos.into_array(), + } + } + + fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { + const ATTRIBUTES: [wgpu::VertexAttribute; 1] = wgpu::vertex_attr_array![ + 3 => Float32x3, + ]; + wgpu::VertexBufferLayout { + array_stride: mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::InputStepMode::Instance, + attributes: &ATTRIBUTES, + } + } +} + +// impl Default for Instance { +// fn default() -> Self { Self::new(Mat4::identity(), 0.0, 0.0, Vec3::zero(), 0, 1.0, 0.0, 0) } +// } + +// TODO: ColLightsWrapper instead? +pub struct Locals; + +pub struct LodObjectPipeline { + pub pipeline: wgpu::RenderPipeline, +} + +impl LodObjectPipeline { + pub fn new( + device: &wgpu::Device, + vs_module: &wgpu::ShaderModule, + fs_module: &wgpu::ShaderModule, + global_layout: &GlobalsLayouts, + aa_mode: AaMode, + ) -> Self { + common_base::span!(_guard, "LodObjectPipeline::new"); + let render_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("LoD object pipeline layout"), + push_constant_ranges: &[], + bind_group_layouts: &[ + &global_layout.globals, + &global_layout.shadow_textures, + ], + }); + + 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("LoD object pipeline"), + layout: Some(&render_pipeline_layout), + vertex: wgpu::VertexState { + module: vs_module, + entry_point: "main", + buffers: &[Vertex::desc(), Instance::desc()], + }, + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: Some(wgpu::Face::Back), + clamp_depth: false, + polygon_mode: wgpu::PolygonMode::Fill, + conservative: false, + }, + depth_stencil: Some(wgpu::DepthStencilState { + format: wgpu::TextureFormat::Depth32Float, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::GreaterEqual, + 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: Some(wgpu::FragmentState { + module: fs_module, + entry_point: "main", + targets: &[wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba16Float, + blend: Some(wgpu::BlendState::REPLACE), + write_mask: wgpu::ColorWrite::ALL, + }], + }), + }); + + Self { + pipeline: render_pipeline, + } + } +} diff --git a/voxygen/src/render/pipelines/mod.rs b/voxygen/src/render/pipelines/mod.rs index f7476b6969..fe5f1f684d 100644 --- a/voxygen/src/render/pipelines/mod.rs +++ b/voxygen/src/render/pipelines/mod.rs @@ -4,6 +4,7 @@ pub mod clouds; pub mod debug; pub mod figure; pub mod fluid; +pub mod lod_object; pub mod lod_terrain; pub mod particle; pub mod postprocess; diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 4f8a17baf2..f3d6096af3 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -21,7 +21,7 @@ use super::{ mesh::Mesh, model::{DynamicModel, Model}, pipelines::{ - blit, bloom, clouds, debug, figure, postprocess, shadow, sprite, terrain, ui, + blit, bloom, clouds, debug, figure, postprocess, shadow, sprite, lod_object, terrain, ui, GlobalsBindGroup, GlobalsLayouts, ShadowTexturesBindGroup, }, texture::Texture, diff --git a/voxygen/src/render/renderer/binding.rs b/voxygen/src/render/renderer/binding.rs index f42808c0a8..5e4074a58f 100644 --- a/voxygen/src/render/renderer/binding.rs +++ b/voxygen/src/render/renderer/binding.rs @@ -1,7 +1,7 @@ use super::{ super::{ pipelines::{ - debug, figure, lod_terrain, shadow, sprite, terrain, ui, ColLights, GlobalModel, + debug, figure, lod_terrain, shadow, sprite, lod_object, terrain, ui, ColLights, GlobalModel, GlobalsBindGroup, }, texture::Texture, diff --git a/voxygen/src/render/renderer/drawer.rs b/voxygen/src/render/renderer/drawer.rs index 1ce91101ca..1bf50519f5 100644 --- a/voxygen/src/render/renderer/drawer.rs +++ b/voxygen/src/render/renderer/drawer.rs @@ -5,7 +5,7 @@ use super::{ model::{DynamicModel, Model, SubModel}, pipelines::{ blit, bloom, clouds, debug, figure, fluid, lod_terrain, particle, shadow, skybox, - sprite, terrain, trail, ui, ColLights, GlobalsBindGroup, ShadowTexturesBindGroup, + sprite, lod_object, terrain, trail, ui, ColLights, GlobalsBindGroup, ShadowTexturesBindGroup, }, }, Renderer, ShadowMap, ShadowMapRenderer, @@ -764,6 +764,17 @@ impl<'pass> FirstPassDrawer<'pass> { } } + pub fn draw_lod_objects<'data: 'pass>( + &mut self, + ) -> LodObjectDrawer<'_, 'pass> { + let mut render_pass = self.render_pass.scope("lod objects", self.borrow.device); + + render_pass.set_pipeline(&self.pipelines.lod_object.pipeline); + set_quad_index_buffer::(&mut render_pass, self.borrow); + + LodObjectDrawer { render_pass } + } + pub fn draw_fluid(&mut self) -> FluidDrawer<'_, 'pass> { let mut render_pass = self.render_pass.scope("fluid", self.borrow.device); @@ -909,6 +920,27 @@ impl<'pass_ref, 'pass: 'pass_ref> Drop for SpriteDrawer<'pass_ref, 'pass> { } } +#[must_use] +pub struct LodObjectDrawer<'pass_ref, 'pass: 'pass_ref> { + render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>, +} + +impl<'pass_ref, 'pass: 'pass_ref> LodObjectDrawer<'pass_ref, 'pass> { + pub fn draw<'data: 'pass>( + &mut self, + model: &'data Model, + instances: &'data Instances, + ) { + self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); + self.render_pass + .set_vertex_buffer(1, instances.buf().slice(..)); + self.render_pass.draw( + 0..model.len() as u32, + 0..instances.count() as u32, + ); + } +} + #[must_use] pub struct FluidDrawer<'pass_ref, 'pass: 'pass_ref> { render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>, diff --git a/voxygen/src/render/renderer/pipeline_creation.rs b/voxygen/src/render/renderer/pipeline_creation.rs index a4e8e34126..3311cab115 100644 --- a/voxygen/src/render/renderer/pipeline_creation.rs +++ b/voxygen/src/render/renderer/pipeline_creation.rs @@ -2,7 +2,7 @@ use super::{ super::{ pipelines::{ blit, bloom, clouds, debug, figure, fluid, lod_terrain, particle, postprocess, shadow, - skybox, sprite, terrain, trail, ui, + skybox, sprite, lod_object, terrain, trail, ui, }, AaMode, BloomMode, CloudMode, FluidMode, LightingMode, PipelineModes, RenderError, ShadowMode, @@ -28,6 +28,7 @@ pub struct Pipelines { // player_shadow: figure::FigurePipeline, pub skybox: skybox::SkyboxPipeline, pub sprite: sprite::SpritePipeline, + pub lod_object: lod_object::LodObjectPipeline, pub terrain: terrain::TerrainPipeline, pub ui: ui::UiPipeline, pub blit: blit::BlitPipeline, @@ -49,6 +50,7 @@ pub struct IngamePipelines { // player_shadow: figure::FigurePipeline, skybox: skybox::SkyboxPipeline, sprite: sprite::SpritePipeline, + lod_object: lod_object::LodObjectPipeline, terrain: terrain::TerrainPipeline, } @@ -85,6 +87,7 @@ impl Pipelines { //player_shadow: ingame.player_shadow, skybox: ingame.skybox, sprite: ingame.sprite, + lod_object: ingame.lod_object, terrain: ingame.terrain, ui: interface.ui, blit: interface.blit, @@ -106,6 +109,7 @@ struct ShaderModules { fluid_frag: wgpu::ShaderModule, sprite_vert: wgpu::ShaderModule, sprite_frag: wgpu::ShaderModule, + lod_object_vert: wgpu::ShaderModule, particle_vert: wgpu::ShaderModule, particle_frag: wgpu::ShaderModule, trail_vert: wgpu::ShaderModule, @@ -293,6 +297,7 @@ impl ShaderModules { fluid_frag: create_shader(&selected_fluid_shader, ShaderKind::Fragment)?, sprite_vert: create_shader("sprite-vert", ShaderKind::Vertex)?, sprite_frag: create_shader("sprite-frag", ShaderKind::Fragment)?, + lod_object_vert: create_shader("lod-object-vert", ShaderKind::Vertex)?, particle_vert: create_shader("particle-vert", ShaderKind::Vertex)?, particle_frag: create_shader("particle-frag", ShaderKind::Fragment)?, trail_vert: create_shader("trail-vert", ShaderKind::Vertex)?, @@ -415,7 +420,7 @@ fn create_ingame_and_shadow_pipelines( needs: PipelineNeeds, pool: &rayon::ThreadPool, // TODO: Reduce the boilerplate in this file - tasks: [Task; 15], + tasks: [Task; 16], ) -> IngameAndShadowPipelines { prof_span!(_guard, "create_ingame_and_shadow_pipelines"); @@ -434,6 +439,7 @@ fn create_ingame_and_shadow_pipelines( terrain_task, fluid_task, sprite_task, + lod_object_task, particle_task, trail_task, lod_terrain_task, @@ -546,6 +552,21 @@ fn create_ingame_and_shadow_pipelines( "sprite pipeline creation", ) }; + // Pipeline for rendering lod objects + let create_lod_object = || { + lod_object_task.run( + || { + lod_object::LodObjectPipeline::new( + device, + &shaders.lod_object_vert, + &shaders.particle_frag, + &layouts.global, + pipeline_modes.aa, + ) + }, + "lod object pipeline creation", + ) + }; // Pipeline for rendering particles let create_particle = || { particle_task.run( @@ -732,6 +753,7 @@ fn create_ingame_and_shadow_pipelines( create_figure_directed_shadow, ) }; + let j7 = create_lod_object; // Ignore this let ( @@ -739,10 +761,10 @@ fn create_ingame_and_shadow_pipelines( ((debug, (skybox, figure)), (terrain, (fluid, bloom))), ((sprite, particle), (lod_terrain, (clouds, trail))), ), - ((postprocess, point_shadow), (terrain_directed_shadow, figure_directed_shadow)), + (((postprocess, point_shadow), (terrain_directed_shadow, figure_directed_shadow)), lod_object), ) = pool.join( || pool.join(|| pool.join(j1, j2), || pool.join(j3, j4)), - || pool.join(j5, j6), + || pool.join(|| pool.join(j5, j6), j7), ); IngameAndShadowPipelines { @@ -758,6 +780,7 @@ fn create_ingame_and_shadow_pipelines( postprocess, skybox, sprite, + lod_object, terrain, // player_shadow_pipeline, }, diff --git a/voxygen/src/render/renderer/shaders.rs b/voxygen/src/render/renderer/shaders.rs index 3a1bb00cfd..0863866175 100644 --- a/voxygen/src/render/renderer/shaders.rs +++ b/voxygen/src/render/renderer/shaders.rs @@ -61,6 +61,7 @@ impl assets::Compound for Shaders { "fluid-frag.shiny", "sprite-vert", "sprite-frag", + "lod-object-vert", "particle-vert", "particle-frag", "trail-vert", diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index b796c14921..1b67de0e19 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -1,17 +1,27 @@ use crate::{ render::{ pipelines::lod_terrain::{LodData, Vertex}, - FirstPassDrawer, LodTerrainVertex, Mesh, Model, Quad, Renderer, + FirstPassDrawer, LodTerrainVertex, LodObjectVertex, Mesh, Model, Quad, Renderer, Instances, LodObjectInstance, Tri, }, + scene::GlobalModel, settings::Settings, }; +use hashbrown::HashMap; use client::Client; -use common::{spiral::Spiral2d, util::srgba_to_linear}; +use common::{ + assets::{ObjAsset, AssetExt}, + spiral::Spiral2d, + util::srgba_to_linear, + lod, +}; use vek::*; pub struct Lod { model: Option<(u32, Model)>, data: LodData, + + zone_objects: HashMap, HashMap>>, + object_data: HashMap>, } // TODO: Make constant when possible. @@ -21,19 +31,31 @@ pub fn water_color() -> Rgba { } impl Lod { - pub fn new(renderer: &mut Renderer, client: &Client, settings: &Settings) -> Self { + pub fn new( + renderer: &mut Renderer, + global_model: &GlobalModel, + client: &Client, + settings: &Settings, + ) -> Self { + let data = LodData::new( + renderer, + client.world_data().chunk_size().as_(), + client.world_data().lod_base.raw(), + client.world_data().lod_alt.raw(), + client.world_data().lod_horizon.raw(), + settings.graphics.lod_detail.max(100).min(2500), + /* TODO: figure out how we want to do this without color borders? + * water_color().into_array().into(), */ + ); Self { + zone_objects: HashMap::new(), + object_data: [ + (lod::ObjectKind::Tree, make_lod_object("tree", renderer, global_model, &data)), + ] + .into_iter() + .collect(), model: None, - data: LodData::new( - renderer, - client.world_data().chunk_size().as_(), - client.world_data().lod_base.raw(), - client.world_data().lod_alt.raw(), - client.world_data().lod_horizon.raw(), - settings.graphics.lod_detail.max(100).min(2500), - /* TODO: figure out how we want to do this without color borders? - * water_color().into_array().into(), */ - ), + data, } } @@ -44,7 +66,8 @@ impl Lod { self.data.tgt_detail = (detail - detail % 2).max(100).min(2500); } - pub fn maintain(&mut self, renderer: &mut Renderer) { + pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) { + // Update LoD terrain mesh according to detail if self .model .as_ref() @@ -58,12 +81,47 @@ impl Lod { .unwrap(), )); } + + // Maintain LoD object instances + for (p, zone) in client.lod_zones() { + self.zone_objects.entry(*p).or_insert_with(|| { + let mut objects = HashMap::<_, Vec<_>>::new(); + for object in zone.objects.iter() { + let pos = p.map(|e| lod::to_wpos(e) as f32).with_z(0.0) + + object.pos.map(|e| e as f32) + + Vec2::broadcast(0.5).with_z(0.0); + objects + .entry(object.kind) + .or_default() + .push(LodObjectInstance::new(pos)); + } + objects + .into_iter() + .map(|(kind, instances)| { + (kind, renderer.create_instances(&instances).expect("Renderer error?!")) + }) + .collect() + }); + } + + self.zone_objects.retain(|p, _| client.lod_zones().contains_key(p)); } pub fn render<'a>(&'a self, drawer: &mut FirstPassDrawer<'a>) { if let Some((_, model)) = self.model.as_ref() { drawer.draw_lod_terrain(model); } + + // Draw LoD objects + for (kind, model) in &self.object_data { + let mut drawer = drawer.draw_lod_objects(); + for instances in self.zone_objects + .values() + .filter_map(|zone| zone.get(kind)) + { + drawer.draw(model, instances); + } + } } } @@ -94,3 +152,27 @@ fn create_lod_terrain_mesh(detail: u32) -> Mesh { }) .collect() } + +fn make_lod_object( + name: &str, + renderer: &mut Renderer, + global_model: &GlobalModel, + lod_data: &LodData, +) -> Model { + let model = ObjAsset::load_expect(&format!("voxygen.lod.{}", name)); + let mesh = model + .read().0 + .triangles() + .map(|vs| { + let [a, b, c] = vs.map(|v| LodObjectVertex::new( + v.position().into(), + v.normal().unwrap_or([0.0, 0.0, 1.0]).into(), + Vec3::broadcast(1.0), + )); + Tri::new(a, b, c) + }) + .collect(); + renderer + .create_model(&mesh) + .expect("Mesh was empty!") +} diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 36b81468ae..3b32cf4f48 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -282,7 +282,7 @@ impl Scene { point_light_matrices: Box::new([PointLightMatrix::default(); MAX_LIGHT_COUNT * 6 + 6]), }; - let lod = Lod::new(renderer, client, settings); + let lod = Lod::new(renderer, &data, client, settings); let globals_bind_group = renderer.bind_globals(&data, lod.get_data()); @@ -681,7 +681,7 @@ impl Scene { renderer.update_postprocess_locals(PostProcessLocals::new(proj_mat_inv, view_mat_inv)); // Maintain LoD. - self.lod.maintain(renderer); + self.lod.maintain(renderer, client); // Maintain debug shapes self.debug.maintain(renderer); diff --git a/world/src/layer/tree.rs b/world/src/layer/tree.rs index 7d95a85602..d26c4e03e8 100644 --- a/world/src/layer/tree.rs +++ b/world/src/layer/tree.rs @@ -4,6 +4,7 @@ use crate::{ column::ColumnGen, util::{gen_cache::StructureGenCache, RandomPerm, Sampler, UnitChooser}, Canvas, + ColumnSample, }; use common::{ assets::AssetHandle, @@ -33,6 +34,23 @@ static MODEL_RAND: RandomPerm = RandomPerm::new(0xDB21C052); static UNIT_CHOOSER: UnitChooser = UnitChooser::new(0x700F4EC7); static QUIRKY_RAND: RandomPerm = RandomPerm::new(0xA634460F); +// Ensure that it's valid to place a tree here +pub fn tree_valid_at(col: &ColumnSample, seed: u32) -> bool { + if col.alt < col.water_level + || col.spawn_rate < 0.9 + || col.water_dist.map(|d| d < 8.0).unwrap_or(false) + || col.path.map(|(d, _, _, _)| d < 12.0).unwrap_or(false) + { + return false + } + + if ((seed.wrapping_mul(13)) & 0xFF) as f32 / 256.0 > col.tree_density { + return false; + } + + true +} + pub fn apply_trees_to( canvas: &mut Canvas, dynamic_rng: &mut impl Rng, @@ -68,17 +86,7 @@ pub fn apply_trees_to( let col = ColumnGen::new(info.chunks()).get((wpos, info.index(), calendar))?; - // Ensure that it's valid to place a *thing* here - if col.alt < col.water_level - || col.spawn_rate < 0.9 - || col.water_dist.map(|d| d < 8.0).unwrap_or(false) - || col.path.map(|(d, _, _, _)| d < 12.0).unwrap_or(false) - { - return None; - } - - // Ensure that it's valid to place a tree here - if ((seed.wrapping_mul(13)) & 0xFF) as f32 / 256.0 > col.tree_density { + if !tree_valid_at(&col, seed) { return None; } diff --git a/world/src/lib.rs b/world/src/lib.rs index f2a6297a4b..23598a46ce 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -56,10 +56,12 @@ use common::{ Block, BlockKind, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize, TerrainGrid, }, vol::{ReadVol, RectVolSize, WriteVol}, + lod, }; use common_net::msg::{world_msg, WorldMapMsg}; use rand::{prelude::*, Rng}; use rand_chacha::ChaCha8Rng; +use rayon::iter::ParallelIterator; use serde::Deserialize; use std::time::Duration; use vek::*; @@ -463,4 +465,32 @@ impl World { Ok((chunk, supplement)) } + + // Zone coordinates + pub fn get_lod_zone( + &self, + pos: Vec2, + index: IndexRef, + ) -> lod::Zone { + let min_wpos = pos.map(lod::to_wpos); + let max_wpos = (pos + 1).map(lod::to_wpos); + + let mut objects = Vec::new(); + + objects.append(&mut self.sim() + .get_area_trees(min_wpos, max_wpos) + .filter(|attr| { + ColumnGen::new(self.sim()).get((attr.pos, index, self.sim().calendar.as_ref())) + .map_or(false, |col| layer::tree::tree_valid_at(&col, attr.seed)) + }) + .map(|tree| lod::Object { + kind: lod::ObjectKind::Tree, + pos: (tree.pos - min_wpos) + .map(|e| e as u16) + .with_z(self.sim().get_alt_approx(tree.pos).unwrap_or(0.0) as u16), + }) + .collect()); + + lod::Zone { objects } + } } diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index f36d3a0640..592046c8e2 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -2134,36 +2134,36 @@ impl WorldSim { /// them spawning). pub fn get_near_trees(&self, wpos: Vec2) -> impl Iterator + '_ { // Deterministic based on wpos - let normal_trees = - self.gen_ctx - .structure_gen - .get(wpos) - .into_iter() - .filter_map(move |(wpos, seed)| { - let lottery = self.make_forest_lottery(wpos); - Some(TreeAttr { - pos: wpos, - seed, - scale: 1.0, - forest_kind: *lottery.choose_seeded(seed).as_ref()?, - inhabited: false, - }) - }); + self.gen_ctx + .structure_gen + .get(wpos) + .into_iter() + .filter_map(move |(wpos, seed)| { + let lottery = self.make_forest_lottery(wpos); + Some(TreeAttr { + pos: wpos, + seed, + scale: 1.0, + forest_kind: *lottery.choose_seeded(seed).as_ref()?, + inhabited: false, + }) + }) + } - // // For testing - // let giant_trees = - // std::array::IntoIter::new(self.gen_ctx.big_structure_gen.get(wpos)) - // // Don't even consider trees if we aren't close - // .filter(move |(pos, _)| pos.distance_squared(wpos) < 512i32.pow(2)) - // .map(move |(pos, seed)| TreeAttr { - // pos, - // seed, - // scale: 5.0, - // forest_kind: ForestKind::Giant, - // inhabited: (seed / 13) % 2 == 0, - // }); - - normal_trees //.chain(giant_trees) + pub fn get_area_trees(&self, wpos_min: Vec2, wpos_max: Vec2) -> impl ParallelIterator + '_ { + self.gen_ctx + .structure_gen + .par_iter(wpos_min, wpos_max) + .filter_map(move |(wpos, seed)| { + let lottery = self.make_forest_lottery(wpos); + Some(TreeAttr { + pos: wpos, + seed, + scale: 1.0, + forest_kind: *lottery.choose_seeded(seed).as_ref()?, + inhabited: false, + }) + }) } } diff --git a/world/src/util/structure.rs b/world/src/util/structure.rs index 2b7b8bfa1a..be3b6d1aee 100644 --- a/world/src/util/structure.rs +++ b/world/src/util/structure.rs @@ -102,19 +102,21 @@ impl StructureGen2d { let x_field = self.x_field; let y_field = self.y_field; let seed_field = self.seed_field; - (0..len).into_par_iter().map(move |xy| { - let index = min_index + Vec2::new((xy % xlen as u64) as i32, (xy / xlen as u64) as i32); - Self::index_to_sample_internal( - freq, - freq_offset, - spread, - spread_mul, - x_field, - y_field, - seed_field, - index, - ) - }) + (0..len) + .into_par_iter() + .map(move |xy| { + let index = min_index + Vec2::new((xy % xlen as u64) as i32, (xy / xlen as u64) as i32); + Self::index_to_sample_internal( + freq, + freq_offset, + spread, + spread_mul, + x_field, + y_field, + seed_field, + index, + ) + }) } } From ac0e7a7724ac32493f2eb0424a51288742d82988 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 01:15:18 +0100 Subject: [PATCH 02/31] Use dedicated fragment shader --- assets/voxygen/shaders/lod-object-frag.glsl | 101 ++++++++++++++++++ assets/voxygen/shaders/lod-object-vert.glsl | 4 +- common/src/lod.rs | 2 +- .../src/render/renderer/pipeline_creation.rs | 4 +- voxygen/src/render/renderer/shaders.rs | 1 + 5 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 assets/voxygen/shaders/lod-object-frag.glsl diff --git a/assets/voxygen/shaders/lod-object-frag.glsl b/assets/voxygen/shaders/lod-object-frag.glsl new file mode 100644 index 0000000000..dc87f56db0 --- /dev/null +++ b/assets/voxygen/shaders/lod-object-frag.glsl @@ -0,0 +1,101 @@ +#version 420 core + +#include + +#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 + +#include + +layout(location = 0) in vec3 f_pos; +layout(location = 1) flat in vec3 f_norm; +layout(location = 2) in vec4 f_col; + +layout(location = 0) out vec4 tgt_color; + +#include +#include +#include + +const float FADE_DIST = 32.0; + +void main() { + #ifdef EXPERIMENTAL_BAREMINIMUM + tgt_color = vec4(simple_lighting(f_pos.xyz, f_col.rgb, 1.0), 1); + return; + #endif + + vec3 cam_to_frag = normalize(f_pos - cam_pos.xyz); + vec3 view_dir = -cam_to_frag; + +#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP || FLUID_MODE == FLUID_MODE_SHINY) + float f_alt = alt_at(f_pos.xy); +#elif (SHADOW_MODE == SHADOW_MODE_NONE || FLUID_MODE == FLUID_MODE_CHEAP) + float f_alt = f_pos.z; +#endif + +#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP) + vec4 f_shadow = textureBicubic(t_horizon, s_horizon, pos_to_tex(f_pos.xy)); + float sun_shade_frac = horizon_at2(f_shadow, f_alt, f_pos, sun_dir); +#elif (SHADOW_MODE == SHADOW_MODE_NONE) + float sun_shade_frac = 1.0; +#endif + float moon_shade_frac = 1.0; + + DirectionalLight sun_info = get_sun_info(sun_dir, sun_shade_frac, f_pos); + DirectionalLight moon_info = get_moon_info(moon_dir, moon_shade_frac); + + vec3 surf_color = f_col.rgb; + float alpha = 1.0; + const float n2 = 1.5; + const float R_s2s0 = pow((1.0 - n2) / (1.0 + n2), 2); + const float R_s1s0 = pow((1.3325 - n2) / (1.3325 + n2), 2); + const float R_s2s1 = pow((1.0 - 1.3325) / (1.0 + 1.3325), 2); + const float R_s1s2 = pow((1.3325 - 1.0) / (1.3325 + 1.0), 2); + float R_s = (f_pos.z < f_alt) ? mix(R_s2s1 * R_s1s0, R_s1s0, medium.x) : mix(R_s2s0, R_s1s2 * R_s2s0, medium.x); + + vec3 k_a = vec3(1.0); + vec3 k_d = vec3(1.0); + vec3 k_s = vec3(R_s); + + vec3 emitted_light, reflected_light; + + // This is a bit of a hack. Because we can't find the volumetric lighting of each particle (they don't talk to the + // CPU) we need to some how find an approximation of how much the sun is blocked. We do this by fading out the sun + // as the particle moves underground. This isn't perfect, but it does at least mean that particles don't look like + // they're exposed to the sun when in dungeons + const float SUN_FADEOUT_DIST = 20.0; + sun_info.block *= clamp((f_pos.z - f_alt) / SUN_FADEOUT_DIST + 1, 0, 1); + + // To account for prior saturation. + float max_light = 0.0; + + vec3 cam_attenuation = vec3(1); + float fluid_alt = max(f_pos.z + 1, floor(f_alt + 1)); + vec3 mu = medium.x == MEDIUM_WATER ? MU_WATER : vec3(0.0); + //#if (FLUID_MODE == FLUID_MODE_SHINY) + // cam_attenuation = + // medium.x == MEDIUM_WATER ? compute_attenuation_point(cam_pos.xyz, view_dir, MU_WATER, fluid_alt, /*cam_pos.z <= fluid_alt ? cam_pos.xyz : f_pos*/f_pos) + // : compute_attenuation_point(f_pos, -view_dir, vec3(0), fluid_alt, /*cam_pos.z <= fluid_alt ? cam_pos.xyz : f_pos*/cam_pos.xyz); + //#endif + + max_light += get_sun_diffuse2(sun_info, moon_info, f_norm, view_dir, f_pos, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light); + + //max_light += lights_at(f_pos, f_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light); + + surf_color = illuminate(max_light, view_dir, surf_color * emitted_light, surf_color * reflected_light); + + // Temporarily disable particle transparency to avoid artifacts + tgt_color = vec4(surf_color, 1.0 /*f_col.a*/); +} diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index d585640c04..66ca50cb1a 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -25,7 +25,6 @@ layout(location = 3) in vec3 inst_pos; layout(location = 0) out vec3 f_pos; layout(location = 1) out vec3 f_norm; layout(location = 2) out vec4 f_col; -layout(location = 3) out float f_reflect; void main() { f_pos = inst_pos + v_pos - focus_off.xyz; @@ -34,8 +33,7 @@ void main() { f_pos.z -= pull_down; f_norm = v_norm; - f_col = vec4(vec3(0, 0.2, 0), 1.0);//vec4(v_col, 1.0); - f_reflect = 1.0; + f_col = vec4(vec3(0, 0.025, 0.015), 1.0);//vec4(v_col, 1.0); gl_Position = all_mat * diff --git a/common/src/lod.rs b/common/src/lod.rs index 3ccc344c4e..449d55010a 100644 --- a/common/src/lod.rs +++ b/common/src/lod.rs @@ -7,7 +7,7 @@ use crate::{ }; // In chunks -pub const ZONE_SIZE: u32 = 64; +pub const ZONE_SIZE: u32 = 32; #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Serialize, Deserialize, EnumIter)] #[repr(u16)] diff --git a/voxygen/src/render/renderer/pipeline_creation.rs b/voxygen/src/render/renderer/pipeline_creation.rs index 3311cab115..de250809a2 100644 --- a/voxygen/src/render/renderer/pipeline_creation.rs +++ b/voxygen/src/render/renderer/pipeline_creation.rs @@ -110,6 +110,7 @@ struct ShaderModules { sprite_vert: wgpu::ShaderModule, sprite_frag: wgpu::ShaderModule, lod_object_vert: wgpu::ShaderModule, + lod_object_frag: wgpu::ShaderModule, particle_vert: wgpu::ShaderModule, particle_frag: wgpu::ShaderModule, trail_vert: wgpu::ShaderModule, @@ -298,6 +299,7 @@ impl ShaderModules { sprite_vert: create_shader("sprite-vert", ShaderKind::Vertex)?, sprite_frag: create_shader("sprite-frag", ShaderKind::Fragment)?, lod_object_vert: create_shader("lod-object-vert", ShaderKind::Vertex)?, + lod_object_frag: create_shader("lod-object-frag", ShaderKind::Fragment)?, particle_vert: create_shader("particle-vert", ShaderKind::Vertex)?, particle_frag: create_shader("particle-frag", ShaderKind::Fragment)?, trail_vert: create_shader("trail-vert", ShaderKind::Vertex)?, @@ -559,7 +561,7 @@ fn create_ingame_and_shadow_pipelines( lod_object::LodObjectPipeline::new( device, &shaders.lod_object_vert, - &shaders.particle_frag, + &shaders.lod_object_frag, &layouts.global, pipeline_modes.aa, ) diff --git a/voxygen/src/render/renderer/shaders.rs b/voxygen/src/render/renderer/shaders.rs index 0863866175..8bbf85ba75 100644 --- a/voxygen/src/render/renderer/shaders.rs +++ b/voxygen/src/render/renderer/shaders.rs @@ -62,6 +62,7 @@ impl assets::Compound for Shaders { "sprite-vert", "sprite-frag", "lod-object-vert", + "lod-object-frag", "particle-vert", "particle-frag", "trail-vert", From 7cce892cffdc63cf3ce9f88411adf40819679ea3 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 01:25:51 +0100 Subject: [PATCH 03/31] Varying normals --- assets/voxygen/shaders/lod-object-frag.glsl | 2 +- assets/voxygen/shaders/lod-object-vert.glsl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/voxygen/shaders/lod-object-frag.glsl b/assets/voxygen/shaders/lod-object-frag.glsl index dc87f56db0..7ed6fa6cac 100644 --- a/assets/voxygen/shaders/lod-object-frag.glsl +++ b/assets/voxygen/shaders/lod-object-frag.glsl @@ -19,7 +19,7 @@ #include layout(location = 0) in vec3 f_pos; -layout(location = 1) flat in vec3 f_norm; +layout(location = 1) in vec3 f_norm; layout(location = 2) in vec4 f_col; layout(location = 0) out vec4 tgt_color; diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index 66ca50cb1a..ae7b28b722 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -33,7 +33,7 @@ void main() { f_pos.z -= pull_down; f_norm = v_norm; - f_col = vec4(vec3(0, 0.025, 0.015), 1.0);//vec4(v_col, 1.0); + f_col = vec4(vec3(0, 0.035, 0.025), 1.0);//vec4(v_col, 1.0); gl_Position = all_mat * From cf346d05c1a8ca5f00271bccd190060c29d0abd3 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 09:25:36 +0100 Subject: [PATCH 04/31] Different kinds of tree --- assets/voxygen/lod/oak.obj | 282 ++++++++++++++++++++ assets/voxygen/lod/pine.obj | 282 ++++++++++++++++++++ assets/voxygen/lod/tree.mtl | 32 --- assets/voxygen/lod/tree.obj | 244 ----------------- assets/voxygen/shaders/lod-object-vert.glsl | 4 +- common/src/lod.rs | 3 +- voxygen/src/render/pipelines/lod_object.rs | 2 - voxygen/src/scene/lod.rs | 3 +- world/src/lib.rs | 7 +- 9 files changed, 576 insertions(+), 283 deletions(-) create mode 100644 assets/voxygen/lod/oak.obj create mode 100644 assets/voxygen/lod/pine.obj delete mode 100644 assets/voxygen/lod/tree.mtl delete mode 100644 assets/voxygen/lod/tree.obj diff --git a/assets/voxygen/lod/oak.obj b/assets/voxygen/lod/oak.obj new file mode 100644 index 0000000000..dd737b167c --- /dev/null +++ b/assets/voxygen/lod/oak.obj @@ -0,0 +1,282 @@ +# Blender v3.0.0 OBJ File: '' +# www.blender.org +o Cube.003 +v -1.814604 0.110646 -2.712528 +v 0.002174 1.562753 10.609200 +v 0.161417 2.086320 -2.749529 +v 2.137438 0.110646 -2.712528 +v 1.363824 0.201342 10.634696 +v 0.161417 -1.865030 -2.675528 +v 0.002174 -1.160069 10.660192 +v -1.359475 0.201342 10.634696 +v -1.765975 -11.462813 12.558847 +v -9.522135 0.240962 9.193778 +v -0.028484 -9.251023 9.371544 +v 0.054180 11.978812 11.981747 +v -0.028484 9.732947 9.016011 +v 9.465164 0.240963 9.193778 +v 6.263892 0.262988 10.369893 +v -0.028484 6.554262 10.252069 +v 13.535484 1.245526 12.154263 +v 0.141971 15.367683 17.018692 +v 17.032104 -0.355504 16.854349 +v -13.233879 1.081083 12.744585 +v -2.845845 -13.345329 16.876486 +v -16.808716 2.270498 18.296967 +v 0.126243 -16.232351 34.672588 +v 9.797964 0.393772 43.178391 +v -1.009909 -8.386520 43.555328 +v -0.173310 -16.022852 25.351990 +v -16.800144 1.228834 36.291180 +v -17.068426 4.313082 29.872881 +v 18.031403 -0.333628 25.101107 +v -0.441979 17.624346 33.618435 +v -2.185088 17.178898 26.278412 +v -0.217867 0.757482 46.887856 +v -10.273464 1.652588 42.715527 +v -0.009768 10.158854 43.467457 +v 18.309916 -0.061841 34.471123 +v -0.028484 -6.028285 10.487717 +v -6.320862 0.262988 10.369893 +vt 0.375000 0.250000 +vt 0.625000 0.500000 +vt 0.375000 0.500000 +vt 0.375000 0.750000 +vt 0.625000 0.750000 +vt 0.375000 1.000000 +vt 0.125000 0.750000 +vt 0.125000 0.500000 +vt 0.625000 0.000000 +vt 0.375000 0.000000 +vt 0.625000 0.250000 +vt 0.625000 1.000000 +vt 0.625000 0.000000 +vt 0.375000 0.250000 +vt 0.375000 0.000000 +vt 0.625000 0.500000 +vt 0.375000 0.500000 +vt 0.375000 0.750000 +vt 0.375000 0.750000 +vt 0.375000 0.500000 +vt 0.625000 0.750000 +vt 0.625000 0.500000 +vt 0.625000 0.750000 +vt 0.625000 1.000000 +vt 0.375000 1.000000 +vt 0.625000 0.250000 +vt 0.625000 0.000000 +vt 0.625000 0.250000 +vt 0.625000 1.000000 +vt 0.625000 1.000000 +vt 0.625000 0.750000 +vt 0.625000 1.000000 +vt 0.625000 0.000000 +vt 0.625000 0.250000 +vt 0.625000 0.250000 +vt 0.625000 0.750000 +vt 0.625000 1.000000 +vt 0.625000 0.500000 +vt 0.625000 0.500000 +vt 0.625000 1.000000 +vt 0.625000 0.250000 +vt 0.625000 0.500000 +vt 0.625000 0.750000 +vt 0.625000 0.000000 +vt 0.625000 0.500000 +vt 0.625000 0.750000 +vt 0.125000 0.750000 +vt 0.125000 0.500000 +vt 0.375000 0.250000 +vt 0.375000 0.000000 +vt 0.625000 0.250000 +vt 0.625000 0.000000 +vt 0.375000 1.000000 +vn -0.8982 0.1977 -0.3926 +vn -0.1957 0.9770 -0.0849 +vn -0.2131 0.7630 -0.6102 +vn 0.1967 0.9772 -0.0803 +vn 0.8552 0.3379 -0.3931 +vn 0.2154 0.7654 -0.6064 +vn 0.9333 -0.3569 -0.0394 +vn 0.3325 -0.7936 -0.5095 +vn 0.9076 -0.0678 -0.4144 +vn 0.0007 0.5089 -0.8608 +vn 0.1244 -0.5841 -0.8021 +vn -0.7101 -0.0125 -0.7040 +vn -0.3554 -0.9334 -0.0499 +vn -0.8968 -0.2104 -0.3893 +vn -0.0834 -0.8360 -0.5423 +vn -0.9801 0.1947 -0.0394 +vn 0.9986 0.0293 -0.0449 +vn 0.0310 -0.9983 -0.0485 +vn 0.6820 0.1365 -0.7185 +vn -0.9799 -0.1963 -0.0368 +vn -0.1047 -0.7127 -0.6936 +vn -0.3089 -0.1712 -0.9356 +vn -0.1300 -0.2706 -0.9539 +vn -0.2470 0.1434 -0.9583 +vn -0.1780 0.6972 -0.6945 +vn -0.2592 0.3056 -0.9162 +vn 0.1669 0.6961 -0.6983 +vn 0.2768 0.0738 -0.9581 +vn 0.1987 0.3154 -0.9279 +vn -0.1214 -0.0001 -0.9926 +vn -0.2247 -0.1041 -0.9689 +vn -0.0725 -0.2173 -0.9734 +vn 0.7438 0.2654 -0.6135 +vn 0.2350 0.8544 -0.4635 +vn 0.9042 0.0051 -0.4270 +vn 0.3107 -0.2158 -0.9257 +vn 0.2374 -0.7967 -0.5558 +vn 0.2813 -0.4432 -0.8511 +vn -0.7591 -0.1502 -0.6335 +vn -0.4072 -0.8234 -0.3951 +vn -0.9229 -0.0267 -0.3841 +vn 0.1886 -0.8079 -0.5583 +vn 0.7833 -0.3512 -0.5129 +vn -0.1126 -0.9448 -0.3078 +vn -0.7071 0.1989 -0.6786 +vn -0.0664 0.8813 -0.4679 +vn -0.1683 0.7076 -0.6863 +vn 0.2439 -0.8272 0.5061 +vn 0.5553 -0.1423 0.8194 +vn 0.0140 -0.5574 0.8302 +vn -0.2733 -0.9576 -0.0906 +vn -0.9047 -0.2867 0.3150 +vn -0.9932 -0.0872 -0.0771 +vn 0.9866 -0.1395 -0.0846 +vn 0.2877 -0.8932 0.3456 +vn 0.1001 -0.9890 -0.1086 +vn -0.9635 0.2397 0.1192 +vn -0.1639 0.8943 0.4164 +vn -0.2322 0.9699 -0.0732 +vn 0.0700 -0.0737 0.9948 +vn -0.1342 0.8431 0.5207 +vn -0.5588 0.2547 0.7892 +vn -0.1235 0.5952 0.7940 +vn 0.1829 0.8408 0.5095 +vn 0.5658 0.1546 0.8099 +vn 0.8460 0.1746 0.5037 +vn -0.8071 -0.2478 0.5358 +vn -0.2499 -0.5501 0.7968 +vn -0.5650 0.0129 0.8250 +vn -0.0990 0.1021 0.9898 +vn 0.1744 0.5999 0.7808 +vn 0.0762 0.0989 0.9922 +vn 0.0109 -0.1327 -0.9911 +vn 0.0118 0.0955 -0.9954 +vn 0.1247 -0.0175 -0.9920 +vn -0.1006 -0.0560 -0.9933 +vn -0.2248 0.0624 -0.9724 +vn 0.0907 0.0329 -0.9953 +vn -0.0303 -0.0927 -0.9952 +vn 0.0943 -0.2169 -0.9716 +vn 0.2093 -0.1005 -0.9727 +vn -0.0305 0.0800 -0.9963 +vn 0.0952 0.1804 -0.9790 +vn 0.0727 -0.0562 -0.9958 +vn 0.9569 0.2750 -0.0931 +vn 0.2075 0.9180 0.3379 +vn 0.9105 0.1897 0.3675 +vn -0.1131 -0.0570 0.9919 +vn 0.2730 0.9004 -0.3387 +vn 0.9558 0.2750 -0.1037 +vn 0.9088 0.0088 -0.4172 +vn -0.8783 0.3374 -0.3389 +vn -0.2442 0.9587 -0.1456 +vn -0.0508 0.8954 -0.4424 +vn 0.8355 -0.4000 -0.3769 +vn 0.0658 -0.9773 -0.2014 +vn -0.1405 -0.8932 -0.4272 +vn -0.4410 -0.8550 -0.2730 +vn -0.9891 -0.1415 0.0401 +vn -0.9600 -0.0622 -0.2730 +vn -0.7339 -0.1307 -0.6666 +vn -0.6694 0.1674 -0.7238 +vn 0.6284 0.1915 -0.7539 +vn 0.0908 -0.1410 -0.9858 +vn 0.1128 0.6894 -0.7156 +vn 0.6835 -0.1212 -0.7198 +vn -0.1345 -0.7455 -0.6528 +vn 0.6776 -0.0633 -0.7327 +vn -0.8444 0.3164 -0.4323 +vn 0.8474 -0.1663 0.5043 +vn -0.0669 -0.9124 0.4037 +vn 0.9056 -0.2115 0.3676 +vn -0.8522 0.0535 0.5205 +vn -0.8359 0.0692 0.5445 +vn -0.0516 -0.8756 0.4803 +vn -0.1403 -0.0212 -0.9899 +vn -0.0716 0.1807 -0.9809 +vn 0.0510 -0.0002 -0.9987 +vn 0.2093 0.0662 -0.9756 +vn 0.0792 0.9866 -0.1429 +vn 0.0927 0.9939 -0.0595 +vn -0.9731 0.2301 -0.0088 +vn 0.9913 -0.1099 -0.0723 +vn -0.2942 -0.9516 -0.0888 +s 1 +f 1/1/1 2/2/2 3/3/3 +f 2/2/4 4/4/5 3/3/6 +f 5/5/7 6/6/8 4/4/9 +f 3/3/10 6/7/11 1/8/12 +f 7/9/13 1/1/14 6/10/15 +f 1/1/1 8/11/16 2/2/2 +f 2/2/4 5/5/17 4/4/5 +f 5/5/7 7/12/18 6/6/8 +f 3/3/10 4/4/19 6/7/11 +f 7/9/13 8/11/20 1/1/14 +f 9/13/21 10/14/22 11/15/23 +f 10/14/24 12/16/25 13/17/26 +f 12/16/27 14/18/28 13/17/29 +f 13/17/30 15/19/31 16/20/32 +f 17/21/33 18/22/34 19/23/35 +f 14/18/36 9/24/37 11/25/38 +f 20/26/39 21/27/40 22/28/41 +f 9/24/42 19/23/43 21/29/44 +f 20/26/45 18/22/46 12/16/47 +f 23/30/48 24/31/49 25/32/50 +f 26/33/51 27/34/52 28/35/53 +f 29/36/54 23/30/55 26/37/56 +f 28/35/57 30/38/58 31/39/59 +f 25/32/50 24/31/49 32/40/60 +f 30/38/61 33/41/62 34/42/63 +f 30/38/64 24/31/65 35/43/66 +f 27/34/67 25/44/68 33/41/69 +f 33/41/62 32/45/70 34/42/63 +f 34/42/71 32/46/72 24/31/65 +f 16/20/73 36/47/74 37/48/75 +f 11/25/76 15/19/77 14/18/78 +f 10/14/79 16/20/80 37/49/81 +f 10/14/82 36/50/83 11/15/84 +f 29/36/85 30/38/86 35/43/87 +f 25/44/68 32/51/88 33/41/69 +f 18/22/89 29/36/90 19/23/91 +f 22/28/92 31/39/93 18/22/94 +f 19/23/95 26/37/96 21/29/97 +f 21/27/98 28/35/99 22/28/100 +f 9/13/21 20/26/101 10/14/22 +f 10/14/24 20/26/102 12/16/25 +f 12/16/27 17/21/103 14/18/28 +f 13/17/30 14/18/104 15/19/31 +f 17/21/33 12/16/105 18/22/34 +f 14/18/36 17/21/106 9/24/37 +f 20/26/39 9/13/107 21/27/40 +f 9/24/42 17/21/108 19/23/43 +f 20/26/45 22/28/109 18/22/46 +f 23/30/48 35/43/110 24/31/49 +f 26/33/51 23/52/111 27/34/52 +f 29/36/54 35/43/112 23/30/55 +f 28/35/57 27/34/113 30/38/58 +f 30/38/61 27/34/114 33/41/62 +f 30/38/64 34/42/71 24/31/65 +f 27/34/67 23/52/115 25/44/68 +f 16/20/73 15/19/116 36/47/74 +f 11/25/76 36/53/117 15/19/77 +f 10/14/79 13/17/118 16/20/80 +f 10/14/82 37/49/119 36/50/83 +f 29/36/85 31/39/120 30/38/86 +f 18/22/89 31/39/121 29/36/90 +f 22/28/92 28/35/122 31/39/93 +f 19/23/95 29/36/123 26/37/96 +f 21/27/98 26/33/124 28/35/99 diff --git a/assets/voxygen/lod/pine.obj b/assets/voxygen/lod/pine.obj new file mode 100644 index 0000000000..36ee034d84 --- /dev/null +++ b/assets/voxygen/lod/pine.obj @@ -0,0 +1,282 @@ +# Blender v3.0.0 OBJ File: '' +# www.blender.org +o Cube.005 +v -1.814604 0.118198 -2.712210 +v 0.002174 1.533206 10.613510 +v 0.161417 2.093968 -2.743709 +v 2.137438 0.118198 -2.712210 +v 1.363824 0.171729 10.635216 +v 0.161417 -1.857573 -2.680711 +v 0.002174 -1.189747 10.656921 +v -1.359475 0.171729 10.635216 +v -0.028485 -3.759396 23.071415 +v -9.522135 0.215361 9.194413 +v -0.028484 -9.277081 9.345748 +v -4.223946 0.435532 23.004536 +v -0.028484 9.707805 9.043077 +v -0.028485 4.630460 22.937658 +v 9.465164 0.215362 9.194413 +v 6.263892 0.234112 10.370585 +v -0.028484 6.525690 10.270280 +v 4.166976 0.435531 23.004536 +v -0.028484 6.975379 21.070749 +v 6.541358 0.406372 21.175476 +v -6.598328 0.406372 21.175476 +v -0.028485 -6.162636 21.280205 +v -0.028485 -4.685975 30.123705 +v 2.329653 0.670892 37.767403 +v -0.028485 -1.686946 37.804993 +v -0.028485 -2.886088 31.833960 +v -5.262825 0.547700 30.040266 +v -3.490429 0.575417 31.778772 +v 3.433459 0.575417 31.778772 +v -0.028485 5.781376 29.956827 +v -0.028485 4.036922 31.723587 +v -0.217867 0.626920 46.889782 +v -0.028485 3.028730 37.729813 +v 5.205855 0.547701 30.040266 +v -2.386622 0.670891 37.767403 +v -0.028484 -6.057464 10.470890 +v -6.320862 0.234112 10.370585 +vt 0.375000 0.250000 +vt 0.625000 0.500000 +vt 0.375000 0.500000 +vt 0.375000 0.750000 +vt 0.625000 0.750000 +vt 0.375000 1.000000 +vt 0.125000 0.750000 +vt 0.125000 0.500000 +vt 0.625000 0.000000 +vt 0.375000 0.000000 +vt 0.625000 0.250000 +vt 0.625000 1.000000 +vt 0.625000 0.000000 +vt 0.375000 0.250000 +vt 0.375000 0.000000 +vt 0.625000 0.250000 +vt 0.375000 0.500000 +vt 0.625000 0.500000 +vt 0.375000 0.750000 +vt 0.375000 0.750000 +vt 0.375000 0.500000 +vt 0.625000 0.750000 +vt 0.625000 0.500000 +vt 0.625000 0.750000 +vt 0.625000 1.000000 +vt 0.375000 1.000000 +vt 0.625000 0.250000 +vt 0.625000 1.000000 +vt 0.625000 1.000000 +vt 0.625000 0.750000 +vt 0.625000 1.000000 +vt 0.625000 0.000000 +vt 0.625000 0.250000 +vt 0.625000 0.250000 +vt 0.625000 0.750000 +vt 0.625000 1.000000 +vt 0.625000 0.500000 +vt 0.625000 0.500000 +vt 0.625000 1.000000 +vt 0.625000 0.500000 +vt 0.625000 0.750000 +vt 0.625000 0.000000 +vt 0.625000 0.250000 +vt 0.625000 0.500000 +vt 0.625000 0.750000 +vt 0.125000 0.750000 +vt 0.125000 0.500000 +vt 0.375000 0.250000 +vt 0.375000 0.000000 +vt 0.625000 0.250000 +vt 0.625000 0.000000 +vt 0.625000 0.000000 +vt 0.375000 1.000000 +vn -0.9098 0.3850 -0.1552 +vn -0.3826 0.9233 0.0342 +vn -0.4235 0.7712 -0.4752 +vn 0.3820 0.9232 0.0433 +vn 0.8349 0.5226 -0.1727 +vn 0.4251 0.7751 -0.4675 +vn 0.8498 -0.5247 0.0514 +vn 0.5200 -0.7889 -0.3275 +vn 0.9491 -0.2490 -0.1929 +vn -0.0001 0.2970 -0.9549 +vn 0.1320 -0.4105 -0.9023 +vn -0.5897 -0.0130 -0.8075 +vn -0.5257 -0.8499 0.0363 +vn -0.9084 -0.3896 -0.1519 +vn -0.2866 -0.8812 -0.3759 +vn -0.9233 0.3829 0.0300 +vn 0.9716 0.2302 0.0554 +vn 0.2295 -0.9719 0.0514 +vn 0.5357 0.1652 -0.8281 +vn -0.9235 -0.3823 0.0330 +vn -0.2406 -0.9459 -0.2176 +vn -0.6348 -0.6281 -0.4501 +vn -0.5976 -0.6255 -0.5017 +vn -0.7077 0.5374 -0.4587 +vn -0.6634 0.6735 -0.3261 +vn -0.7543 0.3547 -0.5524 +vn 0.6371 0.7645 -0.0983 +vn 0.9214 0.3860 -0.0451 +vn 0.2036 0.8812 -0.4267 +vn -0.4074 0.0521 -0.9118 +vn -0.3052 -0.1803 -0.9351 +vn -0.1319 -0.2867 -0.9489 +vn -0.4389 -0.2877 -0.8512 +vn -0.1205 -0.3195 -0.9399 +vn 0.1232 -0.6502 -0.7497 +vn 0.9214 -0.3872 -0.0327 +vn 0.5703 -0.8006 -0.1842 +vn 0.4320 -0.7035 -0.5643 +vn 0.5443 -0.1442 -0.8264 +vn 0.1392 0.6129 -0.7778 +vn 0.0926 0.3553 -0.9301 +vn -0.4389 0.2605 -0.8600 +vn -0.6252 0.1270 -0.7700 +vn -0.1502 -0.1700 -0.9739 +vn 0.0968 -0.2571 -0.9615 +vn 0.4390 -0.2892 -0.8507 +vn 0.6760 0.1387 -0.7237 +vn 0.5455 -0.6954 -0.4679 +vn 0.8810 -0.3670 0.2987 +vn 0.2823 -0.9090 0.3066 +vn 0.7082 0.1905 -0.6798 +vn -0.0958 0.6299 -0.7708 +vn 0.2832 -0.1319 -0.9500 +vn -0.2013 0.6974 -0.6879 +vn -0.2899 0.1482 -0.9455 +vn 0.1167 0.2680 -0.9563 +vn 0.2013 -0.7189 -0.6653 +vn 0.7277 -0.2126 -0.6521 +vn -0.1167 -0.2983 -0.9473 +vn 0.4489 -0.4444 0.7752 +vn -0.7792 0.5992 -0.1840 +vn -0.4567 0.8492 0.2651 +vn 0.0797 0.9166 -0.3918 +vn 0.8333 0.5083 -0.2172 +vn 0.8798 0.3742 0.2931 +vn 0.5376 0.3335 -0.7744 +vn -0.9574 -0.1971 -0.2112 +vn -0.4581 -0.8442 0.2783 +vn -0.8868 -0.3687 0.2788 +vn -0.8858 0.3751 0.2732 +vn -0.4567 0.4611 0.7608 +vn 0.2812 0.9141 0.2922 +vn 0.4428 0.4551 0.7725 +vn 0.0343 -0.1189 -0.9923 +vn 0.0343 0.0872 -0.9956 +vn 0.1152 -0.0158 -0.9932 +vn -0.2463 0.0625 -0.9672 +vn -0.3052 0.1504 -0.9403 +vn 0.4400 0.2184 -0.8710 +vn 0.0384 -0.3071 -0.9509 +vn 0.1994 -0.2835 -0.9380 +vn 0.2818 -0.1806 -0.9423 +vn 0.0401 0.0355 -0.9986 +vn 0.1994 0.2534 -0.9466 +vn 0.0948 0.0642 -0.9934 +vn -0.7082 -0.2121 -0.6734 +vn -0.4213 -0.5139 -0.7473 +vn -0.2832 0.1016 -0.9537 +vn -0.4628 -0.4506 0.7634 +vn 0.7035 0.4738 -0.5297 +vn 0.5159 0.8117 -0.2741 +vn 0.9659 0.1443 -0.2150 +vn -0.5589 0.7644 -0.3215 +vn -0.8159 0.5116 -0.2693 +vn -0.3492 0.6246 -0.6985 +vn 0.7580 -0.6331 -0.1569 +vn 0.8159 -0.5199 -0.2528 +vn 0.0602 -0.8810 -0.4692 +vn -0.7694 -0.5638 -0.3003 +vn -0.5159 -0.8200 -0.2481 +vn -0.8734 -0.0679 -0.4822 +vn -0.7681 -0.4219 -0.4818 +vn -0.1195 0.9847 -0.1266 +vn 0.3562 0.6474 -0.6738 +vn 0.4400 -0.2461 -0.8636 +vn -0.0107 0.1882 -0.9821 +vn 0.3562 -0.6686 -0.6528 +vn -0.0734 0.1622 -0.9840 +vn 0.1599 0.0204 -0.9869 +vn 0.1779 0.0577 -0.9824 +vn 0.3305 -0.8243 -0.4597 +vn 0.3995 0.1420 -0.9057 +vn -0.4846 0.0881 -0.8703 +vn -0.1236 -0.1633 -0.9788 +vn -0.4328 -0.7480 -0.5033 +vn -0.1391 -0.0158 -0.9901 +vn -0.1319 0.2564 -0.9575 +vn -0.0577 0.0570 -0.9967 +vn 0.2818 0.1505 -0.9476 +vn 0.1469 -0.3066 -0.9404 +vn -0.0333 0.8844 -0.4655 +vn -0.8917 -0.0405 -0.4507 +vn 0.8917 0.0261 -0.4518 +vn 0.0333 -0.8988 -0.4370 +s 1 +f 1/1/1 2/2/2 3/3/3 +f 2/2/4 4/4/5 3/3/6 +f 5/5/7 6/6/8 4/4/9 +f 3/3/10 6/7/11 1/8/12 +f 7/9/13 1/1/14 6/10/15 +f 1/1/1 8/11/16 2/2/2 +f 2/2/4 5/5/17 4/4/5 +f 5/5/7 7/12/18 6/6/8 +f 3/3/10 4/4/19 6/7/11 +f 7/9/13 8/11/20 1/1/14 +f 9/13/21 10/14/22 11/15/23 +f 12/16/24 13/17/25 10/14/26 +f 14/18/27 15/19/28 13/17/29 +f 13/17/30 16/20/31 17/21/32 +f 18/22/33 19/23/34 20/24/35 +f 15/19/36 9/25/37 11/26/38 +f 9/13/39 21/27/40 12/16/41 +f 18/22/42 22/28/43 9/25/44 +f 12/16/45 19/23/46 14/18/47 +f 23/29/48 24/30/49 25/31/50 +f 26/32/51 27/33/52 28/34/53 +f 29/35/54 23/29/55 26/36/56 +f 28/34/57 30/37/58 31/38/59 +f 25/31/50 24/30/49 32/39/60 +f 27/33/61 33/40/62 30/37/63 +f 30/37/64 24/30/65 34/41/66 +f 27/33/67 25/42/68 35/43/69 +f 35/43/70 32/44/71 33/40/62 +f 33/40/72 32/45/73 24/30/65 +f 17/21/74 36/46/75 37/47/76 +f 11/26/77 16/20/78 15/19/79 +f 10/14/80 17/21/81 37/48/82 +f 10/14/83 36/49/84 11/15/85 +f 31/38/86 34/41/87 29/35/88 +f 25/42/68 32/50/89 35/43/69 +f 19/23/90 29/35/91 20/24/92 +f 21/27/93 31/38/94 19/23/95 +f 20/24/96 26/36/97 22/28/98 +f 22/51/99 28/34/100 21/27/101 +f 9/13/21 12/16/102 10/14/22 +f 12/16/24 14/18/103 13/17/25 +f 14/18/27 18/22/104 15/19/28 +f 13/17/30 15/19/105 16/20/31 +f 18/22/33 14/18/106 19/23/34 +f 15/19/36 18/22/107 9/25/37 +f 9/13/39 22/51/108 21/27/40 +f 18/22/42 20/24/109 22/28/43 +f 12/16/45 21/27/110 19/23/46 +f 23/29/48 34/41/111 24/30/49 +f 26/32/51 23/52/112 27/33/52 +f 29/35/54 34/41/113 23/29/55 +f 28/34/57 27/33/114 30/37/58 +f 27/33/61 35/43/70 33/40/62 +f 30/37/64 33/40/72 24/30/65 +f 27/33/67 23/52/115 25/42/68 +f 17/21/74 16/20/116 36/46/75 +f 11/26/77 36/53/117 16/20/78 +f 10/14/80 13/17/118 17/21/81 +f 10/14/83 37/48/119 36/49/84 +f 31/38/86 30/37/120 34/41/87 +f 19/23/90 31/38/121 29/35/91 +f 21/27/93 28/34/122 31/38/94 +f 20/24/96 29/35/123 26/36/97 +f 22/51/99 26/32/124 28/34/100 diff --git a/assets/voxygen/lod/tree.mtl b/assets/voxygen/lod/tree.mtl deleted file mode 100644 index 4f81bf8521..0000000000 --- a/assets/voxygen/lod/tree.mtl +++ /dev/null @@ -1,32 +0,0 @@ -# Blender MTL File: 'None' -# Material Count: 3 - -newmtl Material -Ns 323.999994 -Ka 1.000000 1.000000 1.000000 -Kd 0.800000 0.800000 0.800000 -Ks 0.500000 0.500000 0.500000 -Ke 0.000000 0.000000 0.000000 -Ni 1.450000 -d 1.000000 -illum 2 - -newmtl Material.006 -Ns 225.000000 -Ka 1.000000 1.000000 1.000000 -Kd 0.800000 0.800000 0.800000 -Ks 0.500000 0.500000 0.500000 -Ke 0.000000 0.000000 0.000000 -Ni 1.450000 -d 1.000000 -illum 2 - -newmtl Material.009 -Ns 225.000000 -Ka 1.000000 1.000000 1.000000 -Kd 0.800000 0.800000 0.800000 -Ks 0.500000 0.500000 0.500000 -Ke 0.000000 0.000000 0.000000 -Ni 1.450000 -d 1.000000 -illum 2 diff --git a/assets/voxygen/lod/tree.obj b/assets/voxygen/lod/tree.obj deleted file mode 100644 index 584b49c6bf..0000000000 --- a/assets/voxygen/lod/tree.obj +++ /dev/null @@ -1,244 +0,0 @@ -# Blender v3.0.0 OBJ File: '' -# www.blender.org -o Cube -v 1.000000 1.000000 1.000000 -v 1.000000 1.000000 -1.000000 -v 1.000000 -1.000000 1.000000 -v 1.000000 -1.000000 -1.000000 -v -1.000000 1.000000 1.000000 -v -1.000000 1.000000 -1.000000 -v -1.000000 -1.000000 1.000000 -v -1.000000 -1.000000 -1.000000 -vt 0.875000 0.500000 -vt 0.625000 0.750000 -vt 0.625000 0.500000 -vt 0.375000 1.000000 -vt 0.375000 0.750000 -vt 0.625000 0.000000 -vt 0.375000 0.250000 -vt 0.375000 0.000000 -vt 0.375000 0.500000 -vt 0.125000 0.750000 -vt 0.125000 0.500000 -vt 0.625000 0.250000 -vt 0.875000 0.750000 -vt 0.625000 1.000000 -vn 0.0000 0.0000 1.0000 -vn 0.0000 -1.0000 0.0000 -vn -1.0000 0.0000 0.0000 -vn 0.0000 0.0000 -1.0000 -vn 1.0000 0.0000 0.0000 -vn 0.0000 1.0000 0.0000 -s off -f 5/1/1 3/2/1 1/3/1 -f 3/2/2 8/4/2 4/5/2 -f 7/6/3 6/7/3 8/8/3 -f 2/9/4 8/10/4 6/11/4 -f 1/3/5 4/5/5 2/9/5 -f 5/12/6 2/9/6 6/7/6 -f 5/1/1 7/13/1 3/2/1 -f 3/2/2 7/14/2 8/4/2 -f 7/6/3 5/12/3 6/7/3 -f 2/9/4 4/5/4 8/10/4 -f 1/3/5 3/2/5 4/5/5 -f 5/12/6 1/3/6 2/9/6 -o Cube.001 -v -1.814604 0.161418 -2.709981 -v -1.359475 0.002174 10.636601 -v 0.002174 1.363824 10.636601 -v 0.161417 2.137439 -2.709981 -v 1.363824 0.002174 10.636601 -v 2.137438 0.161418 -2.709981 -v 0.002174 -1.359475 10.636601 -v 0.161417 -1.814604 -2.709981 -v -0.028484 -9.424881 9.196677 -v -0.028485 -4.126693 23.008556 -v -4.223946 0.068768 23.008556 -v -9.522135 0.068768 9.196677 -v -0.028485 4.264229 23.008556 -v -0.028484 9.562418 9.196677 -v 4.166976 0.068767 23.008556 -v 9.465164 0.068769 9.196677 -v 6.263892 0.068768 10.372999 -v -0.028484 6.361145 10.372999 -v -0.028484 6.638610 21.179264 -v 6.541358 0.068768 21.179264 -v -0.028485 -6.501075 21.179264 -v -6.598328 0.068768 21.179264 -v -0.028485 -5.165573 30.045181 -v 5.205855 0.068768 30.045181 -v 2.329653 0.068768 37.773296 -v -0.028485 -2.289370 37.773296 -v -3.490429 0.068768 31.783909 -v -0.028485 -3.393177 31.783909 -v -5.262825 0.068767 30.045181 -v 3.433459 0.068768 31.783909 -v -0.028485 3.530712 31.783909 -v -0.028485 5.303108 30.045181 -v -0.217867 -0.120616 46.893818 -v -2.386622 0.068767 37.773296 -v -0.028485 2.426905 37.773296 -v -6.320862 0.068768 10.372999 -v -0.028484 -6.223608 10.372999 -vt 0.375000 0.250000 -vt 0.625000 0.500000 -vt 0.375000 0.500000 -vt 0.375000 0.750000 -vt 0.625000 0.750000 -vt 0.375000 1.000000 -vt 0.125000 0.750000 -vt 0.125000 0.500000 -vt 0.625000 0.000000 -vt 0.375000 0.000000 -vt 0.625000 0.250000 -vt 0.625000 1.000000 -vt 0.625000 0.000000 -vt 0.375000 0.250000 -vt 0.375000 0.000000 -vt 0.625000 0.250000 -vt 0.375000 0.500000 -vt 0.625000 0.500000 -vt 0.375000 0.750000 -vt 0.375000 0.750000 -vt 0.375000 0.500000 -vt 0.625000 0.750000 -vt 0.625000 0.500000 -vt 0.625000 0.750000 -vt 0.625000 1.000000 -vt 0.375000 1.000000 -vt 0.625000 0.250000 -vt 0.625000 1.000000 -vt 0.625000 1.000000 -vt 0.625000 0.750000 -vt 0.625000 1.000000 -vt 0.625000 0.000000 -vt 0.625000 0.250000 -vt 0.625000 0.250000 -vt 0.625000 0.750000 -vt 0.625000 1.000000 -vt 0.625000 0.500000 -vt 0.625000 0.500000 -vt 0.625000 1.000000 -vt 0.625000 0.500000 -vt 0.625000 0.750000 -vt 0.625000 0.000000 -vt 0.625000 0.250000 -vt 0.625000 0.500000 -vt 0.625000 0.750000 -vt 0.125000 0.750000 -vt 0.125000 0.500000 -vt 0.375000 0.250000 -vt 0.375000 0.000000 -vt 0.625000 0.250000 -vt 0.625000 0.000000 -vt 0.625000 0.000000 -vt 0.375000 1.000000 -vn -0.7067 0.7067 0.0325 -vn 0.7062 0.7062 0.0494 -vn 0.7067 -0.7067 0.0325 -vn 0.0000 0.0000 -1.0000 -vn -0.7070 -0.7070 0.0157 -vn -0.6824 -0.6824 0.2618 -vn -0.6824 0.6824 0.2618 -vn 0.6824 0.6824 0.2618 -vn -0.3261 -0.3261 -0.8873 -vn -0.5209 -0.5210 -0.6762 -vn 0.6824 -0.6824 0.2618 -vn 0.5209 0.5210 -0.6762 -vn 0.5210 0.5209 -0.6762 -vn -0.5210 0.5209 -0.6762 -vn -0.5210 0.5210 -0.6762 -vn -0.5209 0.5210 -0.6762 -vn 0.5210 -0.5210 -0.6762 -vn 0.5209 -0.5210 -0.6762 -vn 0.6838 -0.6838 0.2545 -vn 0.6894 -0.6894 0.2227 -vn 0.6895 -0.6895 0.2219 -vn 0.5736 0.5736 -0.5847 -vn -0.5736 0.5736 -0.5847 -vn 0.5736 -0.5736 -0.5847 -vn 0.6956 -0.6956 0.1798 -vn -0.6838 0.6838 0.2545 -vn -0.6894 0.6894 0.2227 -vn 0.6838 0.6838 0.2545 -vn 0.6874 0.6874 0.2342 -vn -0.6838 -0.6838 0.2545 -vn -0.6913 -0.6913 0.2102 -vn -0.6895 0.6895 0.2219 -vn -0.6956 0.6956 0.1798 -vn 0.6917 0.6917 0.2076 -vn -0.3261 0.3261 -0.8873 -vn 0.3261 -0.3261 -0.8873 -vn 0.3261 0.3261 -0.8873 -vn -0.5736 -0.5736 -0.5847 -vn -0.6989 -0.6989 0.1517 -vn 0.6924 0.6924 0.2029 -vn -0.6924 0.6924 0.2029 -vn 0.6924 -0.6924 0.2029 -vn -0.6924 -0.6924 0.2029 -vn 0.5210 -0.5209 -0.6762 -s 1 -f 9/15/7 11/16/7 12/17/7 -f 11/16/8 14/18/8 12/17/8 -f 13/19/9 16/20/9 14/18/9 -f 12/17/10 16/21/10 9/22/10 -f 15/23/11 9/15/11 16/24/11 -f 9/15/7 10/25/7 11/16/7 -f 11/16/8 13/19/8 14/18/8 -f 13/19/9 15/26/9 16/20/9 -f 12/17/10 14/18/10 16/21/10 -f 15/23/11 10/25/11 9/15/11 -f 18/27/12 20/28/12 17/29/12 -f 19/30/13 22/31/13 20/28/13 -f 21/32/14 24/33/14 22/31/14 -f 22/31/15 25/34/15 26/35/15 -f 23/36/16 27/37/16 28/38/16 -f 24/33/17 18/39/17 17/40/17 -f 18/27/18 30/41/19 19/30/19 -f 23/36/20 29/42/21 18/39/22 -f 19/30/23 27/37/24 21/32/24 -f 31/43/25 33/44/26 34/45/27 -f 36/46/28 37/47/28 35/48/28 -f 38/49/29 31/43/29 36/50/29 -f 35/48/30 40/51/30 39/52/30 -f 34/45/27 33/44/26 41/53/31 -f 37/47/32 43/54/33 40/51/32 -f 40/51/34 33/44/35 32/55/34 -f 37/47/36 34/56/37 42/57/37 -f 42/57/38 41/58/39 43/54/33 -f 43/54/35 41/59/40 33/44/35 -f 26/35/10 45/60/10 44/61/10 -f 17/40/41 25/34/41 24/33/41 -f 20/28/42 26/35/42 44/62/42 -f 20/28/43 45/63/43 17/29/43 -f 39/52/44 32/55/44 38/49/44 -f 34/56/37 41/64/45 42/57/37 -f 27/37/46 38/49/46 28/38/46 -f 30/41/47 39/52/47 27/37/47 -f 28/38/48 36/50/48 29/42/48 -f 29/65/49 35/48/49 30/41/49 -f 18/27/12 19/30/12 20/28/12 -f 19/30/13 21/32/13 22/31/13 -f 21/32/14 23/36/14 24/33/14 -f 22/31/15 24/33/15 25/34/15 -f 23/36/16 21/32/16 27/37/16 -f 24/33/17 23/36/17 18/39/17 -f 18/27/18 29/65/18 30/41/19 -f 23/36/20 28/38/20 29/42/21 -f 19/30/23 30/41/50 27/37/24 -f 31/43/25 32/55/25 33/44/26 -f 36/46/28 31/66/28 37/47/28 -f 38/49/29 32/55/29 31/43/29 -f 35/48/30 37/47/30 40/51/30 -f 37/47/32 42/57/38 43/54/33 -f 40/51/34 43/54/35 33/44/35 -f 37/47/36 31/66/36 34/56/37 -f 26/35/10 25/34/10 45/60/10 -f 17/40/41 45/67/41 25/34/41 -f 20/28/42 22/31/42 26/35/42 -f 20/28/43 44/62/43 45/63/43 -f 39/52/44 40/51/44 32/55/44 -f 27/37/46 39/52/46 38/49/46 -f 30/41/47 35/48/47 39/52/47 -f 28/38/48 38/49/48 36/50/48 -f 29/65/49 36/46/49 35/48/49 diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index ae7b28b722..af47d4a48a 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -29,11 +29,11 @@ layout(location = 2) out vec4 f_col; void main() { f_pos = inst_pos + v_pos - focus_off.xyz; - float pull_down = 1.0 / pow(distance(focus_pos.xy, f_pos.xy) / (view_distance.x * 0.95), 20.0); + float pull_down = 1.0 / pow(distance(focus_pos.xy, f_pos.xy) / (view_distance.x * 0.95), 50.0); f_pos.z -= pull_down; f_norm = v_norm; - f_col = vec4(vec3(0, 0.035, 0.025), 1.0);//vec4(v_col, 1.0); + f_col = vec4(vec3(0.01, 0.04, 0.0) * 1, 1.0);//vec4(v_col, 1.0); gl_Position = all_mat * diff --git a/common/src/lod.rs b/common/src/lod.rs index 449d55010a..1c5322bb00 100644 --- a/common/src/lod.rs +++ b/common/src/lod.rs @@ -12,7 +12,8 @@ pub const ZONE_SIZE: u32 = 32; #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Serialize, Deserialize, EnumIter)] #[repr(u16)] pub enum ObjectKind { - Tree, + Oak, + Pine, } #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/voxygen/src/render/pipelines/lod_object.rs b/voxygen/src/render/pipelines/lod_object.rs index e08040a24d..e6195bd2c6 100644 --- a/voxygen/src/render/pipelines/lod_object.rs +++ b/voxygen/src/render/pipelines/lod_object.rs @@ -8,8 +8,6 @@ use bytemuck::{Pod, Zeroable}; use std::mem; use vek::*; -pub const VERT_PAGE_SIZE: u32 = 256; - #[repr(C)] #[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Vertex { diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index 1b67de0e19..ca35070b15 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -50,7 +50,8 @@ impl Lod { Self { zone_objects: HashMap::new(), object_data: [ - (lod::ObjectKind::Tree, make_lod_object("tree", renderer, global_model, &data)), + (lod::ObjectKind::Oak, make_lod_object("oak", renderer, global_model, &data)), + (lod::ObjectKind::Pine, make_lod_object("pine", renderer, global_model, &data)), ] .into_iter() .collect(), diff --git a/world/src/lib.rs b/world/src/lib.rs index 23598a46ce..8a58c6c07d 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -484,7 +484,12 @@ impl World { .map_or(false, |col| layer::tree::tree_valid_at(&col, attr.seed)) }) .map(|tree| lod::Object { - kind: lod::ObjectKind::Tree, + kind: match tree.forest_kind { + all::ForestKind::Oak => lod::ObjectKind::Oak, + all::ForestKind::Pine + | all::ForestKind::Frostpine=> lod::ObjectKind::Pine, + _ => lod::ObjectKind::Oak, + }, pos: (tree.pos - min_wpos) .map(|e| e as u16) .with_z(self.sim().get_alt_approx(tree.pos).unwrap_or(0.0) as u16), From 1db7cc7fde863bd8f3b2a11519860939a3b73e57 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 10:28:32 +0100 Subject: [PATCH 05/31] LoD trees in snow are white --- assets/voxygen/lod/oak.obj | 444 ++++++++++---------- assets/voxygen/lod/pine.obj | 369 +++++++--------- assets/voxygen/shaders/lod-object-vert.glsl | 12 +- client/src/lib.rs | 13 +- common/src/lod.rs | 8 + voxygen/src/render/pipelines/lod_object.rs | 6 +- voxygen/src/scene/lod.rs | 21 +- voxygen/src/scene/mod.rs | 2 +- world/src/lib.rs | 10 +- 9 files changed, 412 insertions(+), 473 deletions(-) diff --git a/assets/voxygen/lod/oak.obj b/assets/voxygen/lod/oak.obj index dd737b167c..508c20f82d 100644 --- a/assets/voxygen/lod/oak.obj +++ b/assets/voxygen/lod/oak.obj @@ -1,43 +1,43 @@ # Blender v3.0.0 OBJ File: '' # www.blender.org -o Cube.003 -v -1.814604 0.110646 -2.712528 -v 0.002174 1.562753 10.609200 -v 0.161417 2.086320 -2.749529 -v 2.137438 0.110646 -2.712528 -v 1.363824 0.201342 10.634696 -v 0.161417 -1.865030 -2.675528 -v 0.002174 -1.160069 10.660192 -v -1.359475 0.201342 10.634696 -v -1.765975 -11.462813 12.558847 -v -9.522135 0.240962 9.193778 -v -0.028484 -9.251023 9.371544 -v 0.054180 11.978812 11.981747 -v -0.028484 9.732947 9.016011 -v 9.465164 0.240963 9.193778 -v 6.263892 0.262988 10.369893 -v -0.028484 6.554262 10.252069 -v 13.535484 1.245526 12.154263 -v 0.141971 15.367683 17.018692 -v 17.032104 -0.355504 16.854349 -v -13.233879 1.081083 12.744585 -v -2.845845 -13.345329 16.876486 -v -16.808716 2.270498 18.296967 -v 0.126243 -16.232351 34.672588 -v 9.797964 0.393772 43.178391 -v -1.009909 -8.386520 43.555328 -v -0.173310 -16.022852 25.351990 -v -16.800144 1.228834 36.291180 -v -17.068426 4.313082 29.872881 -v 18.031403 -0.333628 25.101107 -v -0.441979 17.624346 33.618435 -v -2.185088 17.178898 26.278412 -v -0.217867 0.757482 46.887856 -v -10.273464 1.652588 42.715527 -v -0.009768 10.158854 43.467457 -v 18.309916 -0.061841 34.471123 -v -0.028484 -6.028285 10.487717 -v -6.320862 0.262988 10.369893 +o Cube.006 +v -0.056530 -0.827346 -2.711352 +v 1.178886 0.079466 10.621154 +v 1.287172 0.613093 -2.731962 +v 2.630874 -0.827346 -2.711352 +v 2.104814 -0.913122 10.635355 +v 1.287172 -2.267787 -2.690744 +v 1.178886 -1.905710 10.649555 +v 0.252960 -0.913122 10.635355 +v -0.023462 -9.436724 12.462571 +v -5.297682 -0.867848 9.194902 +v 1.158039 -7.788337 9.293917 +v 1.214251 7.655847 12.079970 +v 1.158039 6.052641 9.095887 +v 7.613757 -0.867847 9.194902 +v 5.436880 -0.865177 10.371088 +v 1.158039 3.721714 10.305462 +v 10.381592 -0.169335 12.163438 +v 1.273949 10.068592 17.144547 +v 12.759308 -1.389768 16.849798 +v -7.821683 -0.295910 12.752341 +v -0.757778 -10.857972 16.764185 +v -10.252585 0.507842 18.314060 +v 1.263254 -13.164757 34.534649 +v 7.840063 -1.143189 43.177551 +v 0.490666 -7.547210 43.481625 +v 1.059556 -12.905995 25.216671 +v -10.246758 -0.456162 36.297924 +v -10.429190 1.864903 29.905817 +v 13.438834 -1.467666 25.095953 +v 0.876860 11.524522 33.761429 +v -0.308461 11.283371 26.418409 +v 1.029258 -0.920301 46.889679 +v -5.808589 -0.220403 42.725170 +v 1.170766 5.971041 43.547592 +v 13.628224 -1.376191 34.467335 +v 1.158039 -5.452066 10.436716 +v -3.120803 -0.865177 10.371088 vt 0.375000 0.250000 vt 0.625000 0.500000 vt 0.375000 0.500000 @@ -91,192 +91,194 @@ vt 0.375000 0.000000 vt 0.625000 0.250000 vt 0.625000 0.000000 vt 0.375000 1.000000 -vn -0.8982 0.1977 -0.3926 -vn -0.1957 0.9770 -0.0849 -vn -0.2131 0.7630 -0.6102 -vn 0.1967 0.9772 -0.0803 -vn 0.8552 0.3379 -0.3931 -vn 0.2154 0.7654 -0.6064 -vn 0.9333 -0.3569 -0.0394 -vn 0.3325 -0.7936 -0.5095 -vn 0.9076 -0.0678 -0.4144 -vn 0.0007 0.5089 -0.8608 -vn 0.1244 -0.5841 -0.8021 -vn -0.7101 -0.0125 -0.7040 -vn -0.3554 -0.9334 -0.0499 -vn -0.8968 -0.2104 -0.3893 -vn -0.0834 -0.8360 -0.5423 -vn -0.9801 0.1947 -0.0394 -vn 0.9986 0.0293 -0.0449 -vn 0.0310 -0.9983 -0.0485 -vn 0.6820 0.1365 -0.7185 -vn -0.9799 -0.1963 -0.0368 -vn -0.1047 -0.7127 -0.6936 -vn -0.3089 -0.1712 -0.9356 -vn -0.1300 -0.2706 -0.9539 -vn -0.2470 0.1434 -0.9583 -vn -0.1780 0.6972 -0.6945 -vn -0.2592 0.3056 -0.9162 -vn 0.1669 0.6961 -0.6983 -vn 0.2768 0.0738 -0.9581 -vn 0.1987 0.3154 -0.9279 -vn -0.1214 -0.0001 -0.9926 -vn -0.2247 -0.1041 -0.9689 -vn -0.0725 -0.2173 -0.9734 -vn 0.7438 0.2654 -0.6135 -vn 0.2350 0.8544 -0.4635 -vn 0.9042 0.0051 -0.4270 -vn 0.3107 -0.2158 -0.9257 -vn 0.2374 -0.7967 -0.5558 -vn 0.2813 -0.4432 -0.8511 -vn -0.7591 -0.1502 -0.6335 -vn -0.4072 -0.8234 -0.3951 -vn -0.9229 -0.0267 -0.3841 -vn 0.1886 -0.8079 -0.5583 -vn 0.7833 -0.3512 -0.5129 -vn -0.1126 -0.9448 -0.3078 -vn -0.7071 0.1989 -0.6786 -vn -0.0664 0.8813 -0.4679 -vn -0.1683 0.7076 -0.6863 -vn 0.2439 -0.8272 0.5061 -vn 0.5553 -0.1423 0.8194 -vn 0.0140 -0.5574 0.8302 -vn -0.2733 -0.9576 -0.0906 -vn -0.9047 -0.2867 0.3150 -vn -0.9932 -0.0872 -0.0771 -vn 0.9866 -0.1395 -0.0846 -vn 0.2877 -0.8932 0.3456 -vn 0.1001 -0.9890 -0.1086 -vn -0.9635 0.2397 0.1192 -vn -0.1639 0.8943 0.4164 -vn -0.2322 0.9699 -0.0732 -vn 0.0700 -0.0737 0.9948 -vn -0.1342 0.8431 0.5207 -vn -0.5588 0.2547 0.7892 -vn -0.1235 0.5952 0.7940 -vn 0.1829 0.8408 0.5095 -vn 0.5658 0.1546 0.8099 -vn 0.8460 0.1746 0.5037 -vn -0.8071 -0.2478 0.5358 -vn -0.2499 -0.5501 0.7968 -vn -0.5650 0.0129 0.8250 -vn -0.0990 0.1021 0.9898 -vn 0.1744 0.5999 0.7808 -vn 0.0762 0.0989 0.9922 -vn 0.0109 -0.1327 -0.9911 -vn 0.0118 0.0955 -0.9954 -vn 0.1247 -0.0175 -0.9920 -vn -0.1006 -0.0560 -0.9933 -vn -0.2248 0.0624 -0.9724 -vn 0.0907 0.0329 -0.9953 -vn -0.0303 -0.0927 -0.9952 -vn 0.0943 -0.2169 -0.9716 -vn 0.2093 -0.1005 -0.9727 -vn -0.0305 0.0800 -0.9963 -vn 0.0952 0.1804 -0.9790 -vn 0.0727 -0.0562 -0.9958 -vn 0.9569 0.2750 -0.0931 -vn 0.2075 0.9180 0.3379 -vn 0.9105 0.1897 0.3675 -vn -0.1131 -0.0570 0.9919 -vn 0.2730 0.9004 -0.3387 -vn 0.9558 0.2750 -0.1037 -vn 0.9088 0.0088 -0.4172 -vn -0.8783 0.3374 -0.3389 -vn -0.2442 0.9587 -0.1456 -vn -0.0508 0.8954 -0.4424 -vn 0.8355 -0.4000 -0.3769 -vn 0.0658 -0.9773 -0.2014 -vn -0.1405 -0.8932 -0.4272 -vn -0.4410 -0.8550 -0.2730 -vn -0.9891 -0.1415 0.0401 -vn -0.9600 -0.0622 -0.2730 -vn -0.7339 -0.1307 -0.6666 -vn -0.6694 0.1674 -0.7238 -vn 0.6284 0.1915 -0.7539 -vn 0.0908 -0.1410 -0.9858 -vn 0.1128 0.6894 -0.7156 -vn 0.6835 -0.1212 -0.7198 -vn -0.1345 -0.7455 -0.6528 -vn 0.6776 -0.0633 -0.7327 -vn -0.8444 0.3164 -0.4323 -vn 0.8474 -0.1663 0.5043 -vn -0.0669 -0.9124 0.4037 -vn 0.9056 -0.2115 0.3676 -vn -0.8522 0.0535 0.5205 -vn -0.8359 0.0692 0.5445 -vn -0.0516 -0.8756 0.4803 -vn -0.1403 -0.0212 -0.9899 -vn -0.0716 0.1807 -0.9809 -vn 0.0510 -0.0002 -0.9987 -vn 0.2093 0.0662 -0.9756 -vn 0.0792 0.9866 -0.1429 -vn 0.0927 0.9939 -0.0595 -vn -0.9731 0.2301 -0.0088 -vn 0.9913 -0.1099 -0.0723 -vn -0.2942 -0.9516 -0.0888 +vn -0.8966 0.1765 -0.4062 +vn -0.2288 0.9705 -0.0765 +vn -0.2401 0.7564 -0.6085 +vn 0.2302 0.9698 -0.0806 +vn 0.8620 0.3110 -0.4002 +vn 0.2392 0.7578 -0.6071 +vn 0.9442 -0.3240 -0.0599 +vn 0.3546 -0.7710 -0.5290 +vn 0.9025 -0.0307 -0.4296 +vn 0.0007 0.5127 -0.8586 +vn 0.1262 -0.5802 -0.8047 +vn -0.7101 -0.0094 -0.7040 +vn -0.3876 -0.9191 -0.0710 +vn -0.8993 -0.1743 -0.4011 +vn -0.1101 -0.8219 -0.5589 +vn -0.8959 0.1772 -0.4073 +vn -0.9859 0.1612 -0.0450 +vn -0.2269 0.9721 -0.0604 +vn 0.9983 -0.0045 -0.0589 +vn 0.0653 -0.9953 -0.0715 +vn 0.6825 0.1375 -0.7179 +vn -0.9856 -0.1618 -0.0495 +vn -0.2108 -0.7706 -0.6015 +vn -0.4336 -0.2123 -0.8757 +vn -0.2529 -0.3602 -0.8979 +vn -0.3874 0.2389 -0.8904 +vn -0.2561 0.7739 -0.5793 +vn -0.3406 0.3973 -0.8521 +vn 0.2485 0.7742 -0.5821 +vn 0.4201 0.1840 -0.8886 +vn 0.2875 0.4133 -0.8640 +vn -0.2301 -0.0956 -0.9685 +vn -0.3452 -0.1854 -0.9200 +vn -0.1865 -0.3124 -0.9315 +vn 0.8101 0.2588 -0.5261 +vn 0.3038 0.8930 -0.3321 +vn 0.9500 -0.0098 -0.3121 +vn 0.4430 -0.2621 -0.8573 +vn 0.2543 -0.8385 -0.4819 +vn 0.2777 -0.4837 -0.8300 +vn -0.8311 -0.1392 -0.5384 +vn -0.4690 -0.8315 -0.2979 +vn -0.9660 -0.0144 -0.2580 +vn 0.2250 -0.8336 -0.5045 +vn 0.8446 -0.3834 -0.3737 +vn -0.0745 -0.9702 -0.2306 +vn -0.7915 0.2405 -0.5619 +vn -0.1336 0.9286 -0.3462 +vn -0.2415 0.7764 -0.5821 +vn 0.3254 -0.8746 0.3595 +vn 0.6695 -0.2019 0.7148 +vn 0.1123 -0.6640 0.7392 +vn -0.3150 -0.9428 -0.1093 +vn -0.8998 -0.2396 0.3646 +vn -0.9982 -0.0504 -0.0328 +vn 0.9910 -0.1057 -0.0818 +vn 0.3170 -0.8837 0.3445 +vn 0.1350 -0.9845 -0.1115 +vn -0.9764 0.2036 0.0715 +vn -0.2097 0.8901 0.4047 +vn -0.2613 0.9617 -0.0824 +vn 0.1886 -0.1849 0.9645 +vn -0.2120 0.8909 0.4017 +vn -0.6695 0.2857 0.6857 +vn -0.2165 0.6666 0.7133 +vn 0.2548 0.8827 0.3949 +vn 0.6830 0.1786 0.7083 +vn 0.9105 0.1969 0.3636 +vn -0.8779 -0.2855 0.3844 +vn -0.3475 -0.6225 0.7012 +vn -0.6954 -0.0407 0.7175 +vn -0.2247 0.1841 0.9569 +vn 0.2627 0.6646 0.6995 +vn 0.2041 0.1782 0.9626 +vn 0.0104 -0.1284 -0.9917 +vn 0.0113 0.0999 -0.9949 +vn 0.1247 -0.0131 -0.9921 +vn -0.2129 0.0541 -0.9756 +vn -0.3480 0.1581 -0.9241 +vn -0.0342 0.1386 -0.9898 +vn 0.0911 -0.1834 -0.9788 +vn 0.2079 -0.3108 -0.9275 +vn 0.3309 -0.1819 -0.9260 +vn 0.0943 0.1844 -0.9783 +vn 0.2125 0.2881 -0.9337 +vn 0.1855 0.0554 -0.9811 +vn 0.9655 0.2473 -0.0819 +vn 0.2169 0.8994 0.3795 +vn 0.9112 0.1527 0.3827 +vn -0.2556 -0.1469 0.9556 +vn 0.2934 0.9034 -0.3128 +vn 0.9662 0.2471 -0.0739 +vn 0.9201 -0.0146 -0.3914 +vn -0.8966 0.3268 -0.2990 +vn -0.2847 0.9551 -0.0818 +vn -0.1067 0.9170 -0.3843 +vn 0.8530 -0.3819 -0.3557 +vn 0.1148 -0.9846 -0.1318 +vn -0.0870 -0.9224 -0.3763 +vn -0.4533 -0.8483 -0.2736 +vn -0.9938 -0.1036 0.0407 +vn -0.9611 -0.0110 -0.2760 +vn -0.8328 -0.1509 -0.5326 +vn -0.7730 0.2351 -0.5892 +vn 0.7297 0.2771 -0.6251 +vn -0.0308 -0.2306 -0.9726 +vn 0.1875 0.7680 -0.6124 +vn 0.7877 -0.1549 -0.5963 +vn -0.2171 -0.7845 -0.5809 +vn 0.7683 -0.1123 -0.6302 +vn -0.8949 0.3391 -0.2900 +vn 0.9127 -0.2032 0.3545 +vn -0.0974 -0.9166 0.3877 +vn 0.9112 -0.1856 0.3677 +vn -0.8730 0.0583 0.4842 +vn -0.9052 0.0940 0.4145 +vn -0.1301 -0.9320 0.3383 +vn -0.1403 -0.0169 -0.9900 +vn -0.1894 0.2897 -0.9382 +vn 0.1609 -0.0994 -0.9819 +vn 0.3335 0.1620 -0.9287 +vn 0.1161 0.9881 -0.1005 +vn 0.1239 0.9922 -0.0145 +vn -0.9798 0.1969 0.0343 +vn 0.9961 -0.0766 -0.0438 +vn -0.3217 -0.9433 -0.0822 s 1 f 1/1/1 2/2/2 3/3/3 f 2/2/4 4/4/5 3/3/6 f 5/5/7 6/6/8 4/4/9 f 3/3/10 6/7/11 1/8/12 f 7/9/13 1/1/14 6/10/15 -f 1/1/1 8/11/16 2/2/2 -f 2/2/4 5/5/17 4/4/5 -f 5/5/7 7/12/18 6/6/8 -f 3/3/10 4/4/19 6/7/11 -f 7/9/13 8/11/20 1/1/14 -f 9/13/21 10/14/22 11/15/23 -f 10/14/24 12/16/25 13/17/26 -f 12/16/27 14/18/28 13/17/29 -f 13/17/30 15/19/31 16/20/32 -f 17/21/33 18/22/34 19/23/35 -f 14/18/36 9/24/37 11/25/38 -f 20/26/39 21/27/40 22/28/41 -f 9/24/42 19/23/43 21/29/44 -f 20/26/45 18/22/46 12/16/47 -f 23/30/48 24/31/49 25/32/50 -f 26/33/51 27/34/52 28/35/53 -f 29/36/54 23/30/55 26/37/56 -f 28/35/57 30/38/58 31/39/59 -f 25/32/50 24/31/49 32/40/60 -f 30/38/61 33/41/62 34/42/63 -f 30/38/64 24/31/65 35/43/66 -f 27/34/67 25/44/68 33/41/69 -f 33/41/62 32/45/70 34/42/63 -f 34/42/71 32/46/72 24/31/65 -f 16/20/73 36/47/74 37/48/75 -f 11/25/76 15/19/77 14/18/78 -f 10/14/79 16/20/80 37/49/81 -f 10/14/82 36/50/83 11/15/84 -f 29/36/85 30/38/86 35/43/87 -f 25/44/68 32/51/88 33/41/69 -f 18/22/89 29/36/90 19/23/91 -f 22/28/92 31/39/93 18/22/94 -f 19/23/95 26/37/96 21/29/97 -f 21/27/98 28/35/99 22/28/100 -f 9/13/21 20/26/101 10/14/22 -f 10/14/24 20/26/102 12/16/25 -f 12/16/27 17/21/103 14/18/28 -f 13/17/30 14/18/104 15/19/31 -f 17/21/33 12/16/105 18/22/34 -f 14/18/36 17/21/106 9/24/37 -f 20/26/39 9/13/107 21/27/40 -f 9/24/42 17/21/108 19/23/43 -f 20/26/45 22/28/109 18/22/46 -f 23/30/48 35/43/110 24/31/49 -f 26/33/51 23/52/111 27/34/52 -f 29/36/54 35/43/112 23/30/55 -f 28/35/57 27/34/113 30/38/58 -f 30/38/61 27/34/114 33/41/62 -f 30/38/64 34/42/71 24/31/65 -f 27/34/67 23/52/115 25/44/68 -f 16/20/73 15/19/116 36/47/74 -f 11/25/76 36/53/117 15/19/77 -f 10/14/79 13/17/118 16/20/80 -f 10/14/82 37/49/119 36/50/83 -f 29/36/85 31/39/120 30/38/86 -f 18/22/89 31/39/121 29/36/90 -f 22/28/92 28/35/122 31/39/93 -f 19/23/95 29/36/123 26/37/96 -f 21/27/98 26/33/124 28/35/99 +f 1/1/16 8/11/17 2/2/18 +f 2/2/4 5/5/19 4/4/5 +f 5/5/7 7/12/20 6/6/8 +f 3/3/10 4/4/21 6/7/11 +f 7/9/13 8/11/22 1/1/14 +f 9/13/23 10/14/24 11/15/25 +f 10/14/26 12/16/27 13/17/28 +f 12/16/29 14/18/30 13/17/31 +f 13/17/32 15/19/33 16/20/34 +f 17/21/35 18/22/36 19/23/37 +f 14/18/38 9/24/39 11/25/40 +f 20/26/41 21/27/42 22/28/43 +f 9/24/44 19/23/45 21/29/46 +f 20/26/47 18/22/48 12/16/49 +f 23/30/50 24/31/51 25/32/52 +f 26/33/53 27/34/54 28/35/55 +f 29/36/56 23/30/57 26/37/58 +f 28/35/59 30/38/60 31/39/61 +f 25/32/52 24/31/51 32/40/62 +f 30/38/63 33/41/64 34/42/65 +f 30/38/66 24/31/67 35/43/68 +f 27/34/69 25/44/70 33/41/71 +f 33/41/64 32/45/72 34/42/65 +f 34/42/73 32/46/74 24/31/67 +f 16/20/75 36/47/76 37/48/77 +f 11/25/78 15/19/79 14/18/80 +f 10/14/81 16/20/82 37/49/83 +f 10/14/84 36/50/85 11/15/86 +f 29/36/87 30/38/88 35/43/89 +f 25/44/70 32/51/90 33/41/71 +f 18/22/91 29/36/92 19/23/93 +f 22/28/94 31/39/95 18/22/96 +f 19/23/97 26/37/98 21/29/99 +f 21/27/100 28/35/101 22/28/102 +f 9/13/23 20/26/103 10/14/24 +f 10/14/26 20/26/104 12/16/27 +f 12/16/29 17/21/105 14/18/30 +f 13/17/32 14/18/106 15/19/33 +f 17/21/35 12/16/107 18/22/36 +f 14/18/38 17/21/108 9/24/39 +f 20/26/41 9/13/109 21/27/42 +f 9/24/44 17/21/110 19/23/45 +f 20/26/47 22/28/111 18/22/48 +f 23/30/50 35/43/112 24/31/51 +f 26/33/53 23/52/113 27/34/54 +f 29/36/56 35/43/114 23/30/57 +f 28/35/59 27/34/115 30/38/60 +f 30/38/63 27/34/116 33/41/64 +f 30/38/66 34/42/73 24/31/67 +f 27/34/69 23/52/117 25/44/70 +f 16/20/75 15/19/118 36/47/76 +f 11/25/78 36/53/119 15/19/79 +f 10/14/81 13/17/120 16/20/82 +f 10/14/84 37/49/121 36/50/85 +f 29/36/87 31/39/122 30/38/88 +f 18/22/91 31/39/123 29/36/92 +f 22/28/94 28/35/124 31/39/95 +f 19/23/97 29/36/125 26/37/98 +f 21/27/100 26/33/126 28/35/101 diff --git a/assets/voxygen/lod/pine.obj b/assets/voxygen/lod/pine.obj index 36ee034d84..14812b2bce 100644 --- a/assets/voxygen/lod/pine.obj +++ b/assets/voxygen/lod/pine.obj @@ -1,43 +1,43 @@ # Blender v3.0.0 OBJ File: '' # www.blender.org -o Cube.005 -v -1.814604 0.118198 -2.712210 -v 0.002174 1.533206 10.613510 -v 0.161417 2.093968 -2.743709 -v 2.137438 0.118198 -2.712210 -v 1.363824 0.171729 10.635216 -v 0.161417 -1.857573 -2.680711 -v 0.002174 -1.189747 10.656921 -v -1.359475 0.171729 10.635216 -v -0.028485 -3.759396 23.071415 -v -9.522135 0.215361 9.194413 -v -0.028484 -9.277081 9.345748 -v -4.223946 0.435532 23.004536 -v -0.028484 9.707805 9.043077 -v -0.028485 4.630460 22.937658 -v 9.465164 0.215362 9.194413 -v 6.263892 0.234112 10.370585 -v -0.028484 6.525690 10.270280 -v 4.166976 0.435531 23.004536 -v -0.028484 6.975379 21.070749 -v 6.541358 0.406372 21.175476 -v -6.598328 0.406372 21.175476 -v -0.028485 -6.162636 21.280205 -v -0.028485 -4.685975 30.123705 -v 2.329653 0.670892 37.767403 -v -0.028485 -1.686946 37.804993 -v -0.028485 -2.886088 31.833960 -v -5.262825 0.547700 30.040266 -v -3.490429 0.575417 31.778772 -v 3.433459 0.575417 31.778772 -v -0.028485 5.781376 29.956827 -v -0.028485 4.036922 31.723587 -v -0.217867 0.626920 46.889782 -v -0.028485 3.028730 37.729813 -v 5.205855 0.547701 30.040266 -v -2.386622 0.670891 37.767403 -v -0.028484 -6.057464 10.470890 -v -6.320862 0.234112 10.370585 +o Cube.007 +v -2.819197 -0.013505 -2.712447 +v 0.008816 2.119261 10.632816 +v 0.256695 3.130596 -2.715924 +v 3.332587 -0.013505 -2.712447 +v 2.128373 -0.047297 10.635213 +v 0.256695 -3.157609 -2.708971 +v 0.008816 -2.213855 10.637607 +v -2.110739 -0.047297 10.635213 +v -0.038908 -6.413302 23.015169 +v -14.816810 0.034971 9.195086 +v -0.038907 -15.070634 9.211782 +v -6.569601 0.262213 23.007790 +v -0.038907 15.140581 9.178390 +v -0.038908 6.937726 23.000408 +v 14.738994 0.034973 9.195086 +v 9.755864 0.054326 10.371477 +v -0.038907 10.066301 10.360410 +v 6.491785 0.262210 23.007790 +v -0.038907 10.685573 21.166832 +v 10.187769 0.232116 21.178389 +v -10.265585 0.232116 21.178389 +v -0.038908 -10.221344 21.189941 +v -0.038908 -7.950523 30.054035 +v 3.631791 0.505130 37.773411 +v -0.038908 -3.246969 37.777557 +v -0.038908 -5.101809 31.789749 +v -8.186729 0.377981 30.044832 +v -5.427802 0.406590 31.783665 +v 5.349986 0.406590 31.783665 +v -0.038908 8.706485 30.035627 +v -0.038908 5.914984 31.777578 +v -0.333702 0.353851 46.894814 +v -0.038908 4.257227 37.769260 +v 8.108912 0.377983 30.044832 +v -3.709605 0.505129 37.773411 +v -0.038907 -9.957649 10.382545 +v -9.833678 0.054326 10.371477 vt 0.375000 0.250000 vt 0.625000 0.500000 vt 0.375000 0.500000 @@ -91,192 +91,109 @@ vt 0.625000 0.250000 vt 0.625000 0.000000 vt 0.625000 0.000000 vt 0.375000 1.000000 -vn -0.9098 0.3850 -0.1552 -vn -0.3826 0.9233 0.0342 -vn -0.4235 0.7712 -0.4752 -vn 0.3820 0.9232 0.0433 -vn 0.8349 0.5226 -0.1727 -vn 0.4251 0.7751 -0.4675 -vn 0.8498 -0.5247 0.0514 -vn 0.5200 -0.7889 -0.3275 -vn 0.9491 -0.2490 -0.1929 -vn -0.0001 0.2970 -0.9549 -vn 0.1320 -0.4105 -0.9023 -vn -0.5897 -0.0130 -0.8075 -vn -0.5257 -0.8499 0.0363 -vn -0.9084 -0.3896 -0.1519 -vn -0.2866 -0.8812 -0.3759 -vn -0.9233 0.3829 0.0300 -vn 0.9716 0.2302 0.0554 -vn 0.2295 -0.9719 0.0514 -vn 0.5357 0.1652 -0.8281 -vn -0.9235 -0.3823 0.0330 -vn -0.2406 -0.9459 -0.2176 -vn -0.6348 -0.6281 -0.4501 -vn -0.5976 -0.6255 -0.5017 -vn -0.7077 0.5374 -0.4587 -vn -0.6634 0.6735 -0.3261 -vn -0.7543 0.3547 -0.5524 -vn 0.6371 0.7645 -0.0983 -vn 0.9214 0.3860 -0.0451 -vn 0.2036 0.8812 -0.4267 -vn -0.4074 0.0521 -0.9118 -vn -0.3052 -0.1803 -0.9351 -vn -0.1319 -0.2867 -0.9489 -vn -0.4389 -0.2877 -0.8512 -vn -0.1205 -0.3195 -0.9399 -vn 0.1232 -0.6502 -0.7497 -vn 0.9214 -0.3872 -0.0327 -vn 0.5703 -0.8006 -0.1842 -vn 0.4320 -0.7035 -0.5643 -vn 0.5443 -0.1442 -0.8264 -vn 0.1392 0.6129 -0.7778 -vn 0.0926 0.3553 -0.9301 -vn -0.4389 0.2605 -0.8600 -vn -0.6252 0.1270 -0.7700 -vn -0.1502 -0.1700 -0.9739 -vn 0.0968 -0.2571 -0.9615 -vn 0.4390 -0.2892 -0.8507 -vn 0.6760 0.1387 -0.7237 -vn 0.5455 -0.6954 -0.4679 -vn 0.8810 -0.3670 0.2987 -vn 0.2823 -0.9090 0.3066 -vn 0.7082 0.1905 -0.6798 -vn -0.0958 0.6299 -0.7708 -vn 0.2832 -0.1319 -0.9500 -vn -0.2013 0.6974 -0.6879 -vn -0.2899 0.1482 -0.9455 -vn 0.1167 0.2680 -0.9563 -vn 0.2013 -0.7189 -0.6653 -vn 0.7277 -0.2126 -0.6521 -vn -0.1167 -0.2983 -0.9473 -vn 0.4489 -0.4444 0.7752 -vn -0.7792 0.5992 -0.1840 -vn -0.4567 0.8492 0.2651 -vn 0.0797 0.9166 -0.3918 -vn 0.8333 0.5083 -0.2172 -vn 0.8798 0.3742 0.2931 -vn 0.5376 0.3335 -0.7744 -vn -0.9574 -0.1971 -0.2112 -vn -0.4581 -0.8442 0.2783 -vn -0.8868 -0.3687 0.2788 -vn -0.8858 0.3751 0.2732 -vn -0.4567 0.4611 0.7608 -vn 0.2812 0.9141 0.2922 -vn 0.4428 0.4551 0.7725 -vn 0.0343 -0.1189 -0.9923 -vn 0.0343 0.0872 -0.9956 -vn 0.1152 -0.0158 -0.9932 -vn -0.2463 0.0625 -0.9672 -vn -0.3052 0.1504 -0.9403 -vn 0.4400 0.2184 -0.8710 -vn 0.0384 -0.3071 -0.9509 -vn 0.1994 -0.2835 -0.9380 -vn 0.2818 -0.1806 -0.9423 -vn 0.0401 0.0355 -0.9986 -vn 0.1994 0.2534 -0.9466 -vn 0.0948 0.0642 -0.9934 -vn -0.7082 -0.2121 -0.6734 -vn -0.4213 -0.5139 -0.7473 -vn -0.2832 0.1016 -0.9537 -vn -0.4628 -0.4506 0.7634 -vn 0.7035 0.4738 -0.5297 -vn 0.5159 0.8117 -0.2741 -vn 0.9659 0.1443 -0.2150 -vn -0.5589 0.7644 -0.3215 -vn -0.8159 0.5116 -0.2693 -vn -0.3492 0.6246 -0.6985 -vn 0.7580 -0.6331 -0.1569 -vn 0.8159 -0.5199 -0.2528 -vn 0.0602 -0.8810 -0.4692 -vn -0.7694 -0.5638 -0.3003 -vn -0.5159 -0.8200 -0.2481 -vn -0.8734 -0.0679 -0.4822 -vn -0.7681 -0.4219 -0.4818 -vn -0.1195 0.9847 -0.1266 -vn 0.3562 0.6474 -0.6738 -vn 0.4400 -0.2461 -0.8636 -vn -0.0107 0.1882 -0.9821 -vn 0.3562 -0.6686 -0.6528 -vn -0.0734 0.1622 -0.9840 -vn 0.1599 0.0204 -0.9869 -vn 0.1779 0.0577 -0.9824 -vn 0.3305 -0.8243 -0.4597 -vn 0.3995 0.1420 -0.9057 -vn -0.4846 0.0881 -0.8703 -vn -0.1236 -0.1633 -0.9788 -vn -0.4328 -0.7480 -0.5033 -vn -0.1391 -0.0158 -0.9901 -vn -0.1319 0.2564 -0.9575 -vn -0.0577 0.0570 -0.9967 -vn 0.2818 0.1505 -0.9476 -vn 0.1469 -0.3066 -0.9404 -vn -0.0333 0.8844 -0.4655 -vn -0.8917 -0.0405 -0.4507 -vn 0.8917 0.0261 -0.4518 -vn 0.0333 -0.8988 -0.4370 +vn -0.7142 0.6988 0.0397 +vn 0.7132 0.6978 0.0661 +vn 0.7135 -0.6979 0.0626 +vn 0.0000 -0.0011 -1.0000 +vn -0.7144 -0.6988 0.0361 +vn -0.6549 -0.6402 0.4015 +vn -0.6600 0.6461 0.3834 +vn 0.6600 0.6461 0.3834 +vn -0.2249 -0.2211 -0.9490 +vn -0.4090 -0.4010 -0.8197 +vn 0.6549 -0.6402 0.4015 +vn 0.4049 0.3952 -0.8245 +vn -0.4049 0.3952 -0.8245 +vn 0.4090 -0.4010 -0.8197 +vn 0.6579 -0.6432 0.3917 +vn 0.6697 -0.6548 0.3503 +vn 0.6699 -0.6550 0.3497 +vn 0.4702 0.4592 -0.7537 +vn -0.4702 0.4592 -0.7537 +vn 0.4753 -0.4658 -0.7464 +vn 0.6850 -0.6698 0.2867 +vn -0.6629 0.6490 0.3734 +vn -0.6742 0.6599 0.3315 +vn 0.6629 0.6490 0.3734 +vn 0.6703 0.6561 0.3468 +vn -0.6579 -0.6432 0.3917 +vn -0.6738 -0.6588 0.3345 +vn -0.6742 -0.6592 0.3332 +vn -0.6746 0.6603 0.3301 +vn -0.6889 0.6742 0.2661 +vn 0.6703 0.6561 0.3467 +vn 0.6802 0.6658 0.3068 +vn -0.2235 0.2176 -0.9501 +vn 0.2249 -0.2211 -0.9490 +vn 0.2235 0.2176 -0.9501 +vn -0.4753 -0.4658 -0.7464 +vn -0.6931 -0.6778 0.2453 +vn 0.6817 0.6673 0.3000 +vn -0.6817 0.6673 0.3000 +vn 0.6774 -0.6624 0.3199 +vn -0.6774 -0.6624 0.3199 s 1 -f 1/1/1 2/2/2 3/3/3 -f 2/2/4 4/4/5 3/3/6 -f 5/5/7 6/6/8 4/4/9 -f 3/3/10 6/7/11 1/8/12 -f 7/9/13 1/1/14 6/10/15 -f 1/1/1 8/11/16 2/2/2 -f 2/2/4 5/5/17 4/4/5 -f 5/5/7 7/12/18 6/6/8 -f 3/3/10 4/4/19 6/7/11 -f 7/9/13 8/11/20 1/1/14 -f 9/13/21 10/14/22 11/15/23 -f 12/16/24 13/17/25 10/14/26 -f 14/18/27 15/19/28 13/17/29 -f 13/17/30 16/20/31 17/21/32 -f 18/22/33 19/23/34 20/24/35 -f 15/19/36 9/25/37 11/26/38 -f 9/13/39 21/27/40 12/16/41 -f 18/22/42 22/28/43 9/25/44 -f 12/16/45 19/23/46 14/18/47 -f 23/29/48 24/30/49 25/31/50 -f 26/32/51 27/33/52 28/34/53 -f 29/35/54 23/29/55 26/36/56 -f 28/34/57 30/37/58 31/38/59 -f 25/31/50 24/30/49 32/39/60 -f 27/33/61 33/40/62 30/37/63 -f 30/37/64 24/30/65 34/41/66 -f 27/33/67 25/42/68 35/43/69 -f 35/43/70 32/44/71 33/40/62 -f 33/40/72 32/45/73 24/30/65 -f 17/21/74 36/46/75 37/47/76 -f 11/26/77 16/20/78 15/19/79 -f 10/14/80 17/21/81 37/48/82 -f 10/14/83 36/49/84 11/15/85 -f 31/38/86 34/41/87 29/35/88 -f 25/42/68 32/50/89 35/43/69 -f 19/23/90 29/35/91 20/24/92 -f 21/27/93 31/38/94 19/23/95 -f 20/24/96 26/36/97 22/28/98 -f 22/51/99 28/34/100 21/27/101 -f 9/13/21 12/16/102 10/14/22 -f 12/16/24 14/18/103 13/17/25 -f 14/18/27 18/22/104 15/19/28 -f 13/17/30 15/19/105 16/20/31 -f 18/22/33 14/18/106 19/23/34 -f 15/19/36 18/22/107 9/25/37 -f 9/13/39 22/51/108 21/27/40 -f 18/22/42 20/24/109 22/28/43 -f 12/16/45 21/27/110 19/23/46 -f 23/29/48 34/41/111 24/30/49 -f 26/32/51 23/52/112 27/33/52 -f 29/35/54 34/41/113 23/29/55 -f 28/34/57 27/33/114 30/37/58 -f 27/33/61 35/43/70 33/40/62 -f 30/37/64 33/40/72 24/30/65 -f 27/33/67 23/52/115 25/42/68 -f 17/21/74 16/20/116 36/46/75 -f 11/26/77 36/53/117 16/20/78 -f 10/14/80 13/17/118 17/21/81 -f 10/14/83 37/48/119 36/49/84 -f 31/38/86 30/37/120 34/41/87 -f 19/23/90 31/38/121 29/35/91 -f 21/27/93 28/34/122 31/38/94 -f 20/24/96 29/35/123 26/36/97 -f 22/51/99 26/32/124 28/34/100 +f 1/1/1 2/2/1 3/3/1 +f 2/2/2 4/4/2 3/3/2 +f 5/5/3 6/6/3 4/4/3 +f 3/3/4 6/7/4 1/8/4 +f 7/9/5 1/1/5 6/10/5 +f 1/1/1 8/11/1 2/2/1 +f 2/2/2 5/5/2 4/4/2 +f 5/5/3 7/12/3 6/6/3 +f 3/3/4 4/4/4 6/7/4 +f 7/9/5 8/11/5 1/1/5 +f 9/13/6 10/14/6 11/15/6 +f 12/16/7 13/17/7 10/14/7 +f 14/18/8 15/19/8 13/17/8 +f 13/17/9 16/20/9 17/21/9 +f 18/22/10 19/23/10 20/24/10 +f 15/19/11 9/25/11 11/26/11 +f 9/13/12 21/27/12 12/16/12 +f 18/22/13 22/28/13 9/25/13 +f 12/16/14 19/23/14 14/18/14 +f 23/29/15 24/30/16 25/31/17 +f 26/32/18 27/33/18 28/34/18 +f 29/35/19 23/29/19 26/36/19 +f 28/34/20 30/37/20 31/38/20 +f 25/31/17 24/30/16 32/39/21 +f 27/33/22 33/40/23 30/37/22 +f 30/37/24 24/30/25 34/41/24 +f 27/33/26 25/42/27 35/43/28 +f 35/43/29 32/44/30 33/40/23 +f 33/40/31 32/45/32 24/30/25 +f 17/21/4 36/46/4 37/47/4 +f 11/26/33 16/20/33 15/19/33 +f 10/14/34 17/21/34 37/48/34 +f 10/14/35 36/49/35 11/15/35 +f 31/38/36 34/41/36 29/35/36 +f 25/42/27 32/50/37 35/43/28 +f 19/23/38 29/35/38 20/24/38 +f 21/27/39 31/38/39 19/23/39 +f 20/24/40 26/36/40 22/28/40 +f 22/51/41 28/34/41 21/27/41 +f 9/13/6 12/16/6 10/14/6 +f 12/16/7 14/18/7 13/17/7 +f 14/18/8 18/22/8 15/19/8 +f 13/17/9 15/19/9 16/20/9 +f 18/22/10 14/18/10 19/23/10 +f 15/19/11 18/22/11 9/25/11 +f 9/13/12 22/51/12 21/27/12 +f 18/22/13 20/24/13 22/28/13 +f 12/16/14 21/27/14 19/23/14 +f 23/29/15 34/41/15 24/30/16 +f 26/32/18 23/52/18 27/33/18 +f 29/35/19 34/41/19 23/29/19 +f 28/34/20 27/33/20 30/37/20 +f 27/33/22 35/43/29 33/40/23 +f 30/37/24 33/40/31 24/30/25 +f 27/33/26 23/52/26 25/42/27 +f 17/21/4 16/20/4 36/46/4 +f 11/26/33 36/53/33 16/20/33 +f 10/14/34 13/17/34 17/21/34 +f 10/14/35 37/48/35 36/49/35 +f 31/38/36 30/37/36 34/41/36 +f 19/23/38 31/38/38 29/35/38 +f 21/27/39 28/34/39 31/38/39 +f 20/24/40 29/35/40 26/36/40 +f 22/51/41 26/32/41 28/34/41 diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index af47d4a48a..4d9c56065c 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -21,20 +21,28 @@ layout(location = 0) in vec3 v_pos; layout(location = 1) in vec3 v_norm; layout(location = 2) in vec3 v_col; layout(location = 3) in vec3 inst_pos; +layout(location = 4) in uint inst_flags; + +const uint FLAG_SNOW_COVERED = 1; layout(location = 0) out vec3 f_pos; layout(location = 1) out vec3 f_norm; layout(location = 2) out vec4 f_col; void main() { - f_pos = inst_pos + v_pos - focus_off.xyz; + vec3 tree_pos = inst_pos - focus_off.xyz; + f_pos = tree_pos + v_pos; - float pull_down = 1.0 / pow(distance(focus_pos.xy, f_pos.xy) / (view_distance.x * 0.95), 50.0); + float pull_down = 1.0 / pow(distance(focus_pos.xy, tree_pos.xy) / (view_distance.x * 0.95), 50.0); f_pos.z -= pull_down; f_norm = v_norm; f_col = vec4(vec3(0.01, 0.04, 0.0) * 1, 1.0);//vec4(v_col, 1.0); + if ((inst_flags & FLAG_SNOW_COVERED) > 0u) { + f_col.rgb = mix(f_col.rgb, vec3(1), pow(max(f_norm.z, 0.0), 0.5)); + } + gl_Position = all_mat * vec4(f_pos, 1); diff --git a/client/src/lib.rs b/client/src/lib.rs index 1c5ebd26c2..a9a18f2b92 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -658,7 +658,7 @@ impl Client { tick: 0, state, view_distance: None, - lod_distance: 2, // TODO: Make configurable + lod_distance: 4, // TODO: Make configurable loaded_distance: 0.0, pending_chunks: HashMap::new(), @@ -1729,21 +1729,20 @@ impl Client { // Request LoD zones that are in range if self.lod_last_requested.map_or(true, |i| i.elapsed() > Duration::from_secs(5)) { - - if let Some(unloaded) = Spiral2d::new() + if let Some(rpos) = Spiral2d::new() .take((1 + self.lod_distance * 2).pow(2) as usize) - .map(|rpos| lod_zone + rpos) - .find(|p| !self.lod_zones.contains_key(p)) + .filter(|rpos| !self.lod_zones.contains_key(&(lod_zone + *rpos))) + .min_by_key(|rpos| rpos.magnitude_squared()) { self.send_msg_err(ClientGeneral::LodZoneRequest { - key: unloaded, + key: lod_zone + rpos, })?; self.lod_last_requested = Some(Instant::now()); } } // Cull LoD zones out of range - self.lod_zones.retain(|p, _| (*p - lod_zone).map(i32::abs).reduce_max() < self.lod_distance as i32 + 1); + self.lod_zones.retain(|p, _| (*p - lod_zone).magnitude_squared() < (self.lod_distance as i32 + 1).pow(2)); } Ok(()) diff --git a/common/src/lod.rs b/common/src/lod.rs index 1c5322bb00..39b2dce76d 100644 --- a/common/src/lod.rs +++ b/common/src/lod.rs @@ -9,6 +9,13 @@ use crate::{ // In chunks pub const ZONE_SIZE: u32 = 32; +bitflags::bitflags! { + #[derive(Serialize, Deserialize)] + pub struct Flags: u8 { + const SNOW_COVERED = 0b00000001; + } +} + #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Serialize, Deserialize, EnumIter)] #[repr(u16)] pub enum ObjectKind { @@ -20,6 +27,7 @@ pub enum ObjectKind { pub struct Object { pub kind: ObjectKind, pub pos: Vec3, + pub flags: Flags, } #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/voxygen/src/render/pipelines/lod_object.rs b/voxygen/src/render/pipelines/lod_object.rs index e6195bd2c6..2276c0a90d 100644 --- a/voxygen/src/render/pipelines/lod_object.rs +++ b/voxygen/src/render/pipelines/lod_object.rs @@ -49,20 +49,24 @@ impl VertexTrait for Vertex { #[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Instance { inst_pos: [f32; 3], + flags: u32, } impl Instance { pub fn new( inst_pos: Vec3, + flags: common::lod::Flags, ) -> Self { Self { inst_pos: inst_pos.into_array(), + flags: flags.bits() as u32, } } fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { - const ATTRIBUTES: [wgpu::VertexAttribute; 1] = wgpu::vertex_attr_array![ + const ATTRIBUTES: [wgpu::VertexAttribute; 2] = wgpu::vertex_attr_array![ 3 => Float32x3, + 4 => Uint32, ]; wgpu::VertexBufferLayout { array_stride: mem::size_of::() as wgpu::BufferAddress, diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index ca35070b15..412ea7bc0f 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -33,7 +33,6 @@ pub fn water_color() -> Rgba { impl Lod { pub fn new( renderer: &mut Renderer, - global_model: &GlobalModel, client: &Client, settings: &Settings, ) -> Self { @@ -50,8 +49,8 @@ impl Lod { Self { zone_objects: HashMap::new(), object_data: [ - (lod::ObjectKind::Oak, make_lod_object("oak", renderer, global_model, &data)), - (lod::ObjectKind::Pine, make_lod_object("pine", renderer, global_model, &data)), + (lod::ObjectKind::Oak, make_lod_object("oak", renderer, &data)), + (lod::ObjectKind::Pine, make_lod_object("pine", renderer, &data)), ] .into_iter() .collect(), @@ -94,7 +93,7 @@ impl Lod { objects .entry(object.kind) .or_default() - .push(LodObjectInstance::new(pos)); + .push(LodObjectInstance::new(pos, object.flags)); } objects .into_iter() @@ -114,13 +113,12 @@ impl Lod { } // Draw LoD objects - for (kind, model) in &self.object_data { - let mut drawer = drawer.draw_lod_objects(); - for instances in self.zone_objects - .values() - .filter_map(|zone| zone.get(kind)) - { - drawer.draw(model, instances); + let mut drawer = drawer.draw_lod_objects(); + for objects in self.zone_objects.values() { + for (kind, instances) in objects { + if let Some(model) = self.object_data.get(kind) { + drawer.draw(model, instances); + } } } } @@ -157,7 +155,6 @@ fn create_lod_terrain_mesh(detail: u32) -> Mesh { fn make_lod_object( name: &str, renderer: &mut Renderer, - global_model: &GlobalModel, lod_data: &LodData, ) -> Model { let model = ObjAsset::load_expect(&format!("voxygen.lod.{}", name)); diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 3b32cf4f48..846ed21e1c 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -282,7 +282,7 @@ impl Scene { point_light_matrices: Box::new([PointLightMatrix::default(); MAX_LIGHT_COUNT * 6 + 6]), }; - let lod = Lod::new(renderer, &data, client, settings); + let lod = Lod::new(renderer, client, settings); let globals_bind_group = renderer.bind_globals(&data, lod.get_data()); diff --git a/world/src/lib.rs b/world/src/lib.rs index 8a58c6c07d..173a2b52ab 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -479,11 +479,12 @@ impl World { objects.append(&mut self.sim() .get_area_trees(min_wpos, max_wpos) - .filter(|attr| { + .filter_map(|attr| { ColumnGen::new(self.sim()).get((attr.pos, index, self.sim().calendar.as_ref())) - .map_or(false, |col| layer::tree::tree_valid_at(&col, attr.seed)) + .filter(|col| layer::tree::tree_valid_at(col, attr.seed)) + .zip(Some(attr)) }) - .map(|tree| lod::Object { + .map(|(col, tree)| lod::Object { kind: match tree.forest_kind { all::ForestKind::Oak => lod::ObjectKind::Oak, all::ForestKind::Pine @@ -493,6 +494,9 @@ impl World { pos: (tree.pos - min_wpos) .map(|e| e as u16) .with_z(self.sim().get_alt_approx(tree.pos).unwrap_or(0.0) as u16), + flags: lod::Flags::empty() + | if col.snow_cover { lod::Flags::SNOW_COVERED } else { lod::Flags::empty() } + , }) .collect()); From 3881d2ea381af0dfe86fb56d753e83163965ff8e Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 11:53:59 +0100 Subject: [PATCH 06/31] Fixed i16 underflow --- world/src/lib.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/world/src/lib.rs b/world/src/lib.rs index 173a2b52ab..bcb98fed2e 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -484,20 +484,27 @@ impl World { .filter(|col| layer::tree::tree_valid_at(col, attr.seed)) .zip(Some(attr)) }) - .map(|(col, tree)| lod::Object { + .filter_map(|(col, tree)| Some(lod::Object { kind: match tree.forest_kind { all::ForestKind::Oak => lod::ObjectKind::Oak, all::ForestKind::Pine | all::ForestKind::Frostpine=> lod::ObjectKind::Pine, _ => lod::ObjectKind::Oak, }, - pos: (tree.pos - min_wpos) - .map(|e| e as u16) - .with_z(self.sim().get_alt_approx(tree.pos).unwrap_or(0.0) as u16), + pos: { + let rpos = tree.pos - min_wpos; + if rpos.is_any_negative() { + return None + } else { + rpos + .map(|e| e as u16) + .with_z(self.sim().get_alt_approx(tree.pos).unwrap_or(0.0) as u16) + } + }, flags: lod::Flags::empty() | if col.snow_cover { lod::Flags::SNOW_COVERED } else { lod::Flags::empty() } , - }) + })) .collect()); lod::Zone { objects } From 2df01385d2d312847078ebf979b87c688c056baf Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 13:51:04 +0100 Subject: [PATCH 07/31] Voxelise trees --- .gitattributes | 2 ++ assets/voxygen/lod/pine.blend | Bin 0 -> 975044 bytes assets/voxygen/lod/pine.obj | 2 +- assets/voxygen/shaders/lod-object-frag.glsl | 33 ++++++++++++++++++-- assets/voxygen/shaders/lod-object-vert.glsl | 2 +- common/assets/Cargo.toml | 1 + common/src/lod.rs | 2 +- voxygen/src/scene/lod.rs | 1 + 8 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 assets/voxygen/lod/pine.blend diff --git a/.gitattributes b/.gitattributes index 9b9dc79491..6aefa43907 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,6 +7,8 @@ *.ogg filter=lfs diff=lfs merge=lfs -text *.ico filter=lfs diff=lfs merge=lfs -text *.tar filter=lfs diff=lfs merge=lfs -text +*.obj filter=lfs diff=lfs merge=lfs -text +*.blend filter=lfs diff=lfs merge=lfs -text assets/world/map/*.bin filter=lfs diff=lfs merge=lfs -text *.ron gitlab-language=rust diff --git a/assets/voxygen/lod/pine.blend b/assets/voxygen/lod/pine.blend new file mode 100644 index 0000000000000000000000000000000000000000..151e01f0cf838d957f1409572ce3a2d0afc0eeb5 GIT binary patch literal 975044 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 literal 0 HcmV?d00001 diff --git a/assets/voxygen/lod/pine.obj b/assets/voxygen/lod/pine.obj index 14812b2bce..372717450b 100644 --- a/assets/voxygen/lod/pine.obj +++ b/assets/voxygen/lod/pine.obj @@ -1,4 +1,4 @@ -# Blender v3.0.0 OBJ File: '' +# Blender v3.0.0 OBJ File: 'pine.blend' # www.blender.org o Cube.007 v -2.819197 -0.013505 -2.712447 diff --git a/assets/voxygen/shaders/lod-object-frag.glsl b/assets/voxygen/shaders/lod-object-frag.glsl index 7ed6fa6cac..bfbf01552d 100644 --- a/assets/voxygen/shaders/lod-object-frag.glsl +++ b/assets/voxygen/shaders/lod-object-frag.glsl @@ -69,6 +69,32 @@ void main() { vec3 k_d = vec3(1.0); vec3 k_s = vec3(R_s); + vec3 my_norm = vec3(f_norm.xy, abs(f_norm.z)); + vec3 voxel_norm; + float my_alt = f_pos.z + focus_off.z; + float f_ao = 1.0; + const float VOXELIZE_DIST = 2000; + float voxelize_factor = clamp(1.0 - (distance(focus_pos.xy, f_pos.xy) - view_distance.x) / VOXELIZE_DIST, 0, 0.75); + vec3 cam_dir = normalize(cam_pos.xyz - f_pos.xyz); + vec3 side_norm = normalize(vec3(my_norm.xy, 0)); + vec3 top_norm = vec3(0, 0, 1); + float side_factor = 1.0 - my_norm.z; + // min(dot(vec3(0, -sign(cam_dir.y), 0), -cam_dir), dot(vec3(-sign(cam_dir.x), 0, 0), -cam_dir)) + if (max(abs(my_norm.x), abs(my_norm.y)) < 0.01 || fract(my_alt) * clamp(dot(normalize(vec3(cam_dir.xy, 0)), side_norm), 0, 1) < cam_dir.z / my_norm.z) { + f_ao *= mix(1.0, clamp(fract(my_alt) / length(my_norm.xy) + clamp(dot(side_norm, -cam_dir), 0, 1), 0, 1), voxelize_factor); + voxel_norm = top_norm; + } else { + f_ao *= mix(1.0, clamp(pow(fract(my_alt), 0.5), 0, 1), voxelize_factor); + + if (fract(f_pos.x) * abs(my_norm.y / cam_dir.x) < fract(f_pos.y) * abs(my_norm.x / cam_dir.y)) { + voxel_norm = vec3(sign(cam_dir.x), 0, 0); + } else { + voxel_norm = vec3(0, sign(cam_dir.y), 0); + } + } + f_ao = min(f_ao, max(f_norm.z * 0.5 + 0.5, 0.0)); + voxel_norm = mix(my_norm, voxel_norm == vec3(0.0) ? f_norm : voxel_norm, voxelize_factor); + vec3 emitted_light, reflected_light; // This is a bit of a hack. Because we can't find the volumetric lighting of each particle (they don't talk to the @@ -90,9 +116,12 @@ void main() { // : compute_attenuation_point(f_pos, -view_dir, vec3(0), fluid_alt, /*cam_pos.z <= fluid_alt ? cam_pos.xyz : f_pos*/cam_pos.xyz); //#endif - max_light += get_sun_diffuse2(sun_info, moon_info, f_norm, view_dir, f_pos, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light); + max_light += get_sun_diffuse2(sun_info, moon_info, voxel_norm, view_dir, f_pos, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, voxel_norm, 1.0, emitted_light, reflected_light); - //max_light += lights_at(f_pos, f_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light); + emitted_light *= f_ao; + reflected_light *= f_ao; + + //max_light += lights_at(f_pos, voxel_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, voxel_norm, 1.0, emitted_light, reflected_light); surf_color = illuminate(max_light, view_dir, surf_color * emitted_light, surf_color * reflected_light); diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index 4d9c56065c..366053d42b 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -37,7 +37,7 @@ void main() { f_pos.z -= pull_down; f_norm = v_norm; - f_col = vec4(vec3(0.01, 0.04, 0.0) * 1, 1.0);//vec4(v_col, 1.0); + f_col = vec4(vec3(0.02, 0.1, 0.01) * (sin(inst_pos.xyy) * 0.33 + 0.66), 1.0);//vec4(v_col, 1.0); if ((inst_flags & FLAG_SNOW_COVERED) > 0u) { f_col.rgb = mix(f_col.rgb, vec3(1), pow(max(f_norm.z, 0.0), 0.5)); diff --git a/common/assets/Cargo.toml b/common/assets/Cargo.toml index 1b59285fed..ac60802103 100644 --- a/common/assets/Cargo.toml +++ b/common/assets/Cargo.toml @@ -11,6 +11,7 @@ assets_manager = {version = "0.7", features = ["bincode", "ron", "json"]} ron = { version = "0.7", default-features = false } dot_vox = "4.0" wavefront = "0.2" +#wavefront = { path = "../../../../wavefront" } image = { version = "0.23.12", default-features = false, features = ["png"] } tracing = "0.1" diff --git a/common/src/lod.rs b/common/src/lod.rs index 39b2dce76d..636bc86b05 100644 --- a/common/src/lod.rs +++ b/common/src/lod.rs @@ -40,5 +40,5 @@ pub fn to_wpos(wpos: i32) -> i32 { } pub fn from_wpos(zone_pos: i32) -> i32 { - zone_pos / (TerrainChunkSize::RECT_SIZE.x * ZONE_SIZE) as i32 + zone_pos.div_euclid((TerrainChunkSize::RECT_SIZE.x * ZONE_SIZE) as i32) } diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index 412ea7bc0f..bf4b4dd3c3 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -166,6 +166,7 @@ fn make_lod_object( v.position().into(), v.normal().unwrap_or([0.0, 0.0, 1.0]).into(), Vec3::broadcast(1.0), + //v.color().unwrap_or([1.0; 3]).into(), )); Tri::new(a, b, c) }) From 79ce90a2e40fc2993117103be54c64de0cd7cd9d Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 14:17:10 +0100 Subject: [PATCH 08/31] convert LoD assets to Git LFS --- assets/voxygen/lod/oak.obj | 287 +--------------------------------- assets/voxygen/lod/pine.blend | Bin 975044 -> 131 bytes assets/voxygen/lod/pine.obj | 202 +----------------------- 3 files changed, 6 insertions(+), 483 deletions(-) diff --git a/assets/voxygen/lod/oak.obj b/assets/voxygen/lod/oak.obj index 508c20f82d..fddacb0eb9 100644 --- a/assets/voxygen/lod/oak.obj +++ b/assets/voxygen/lod/oak.obj @@ -1,284 +1,3 @@ -# Blender v3.0.0 OBJ File: '' -# www.blender.org -o Cube.006 -v -0.056530 -0.827346 -2.711352 -v 1.178886 0.079466 10.621154 -v 1.287172 0.613093 -2.731962 -v 2.630874 -0.827346 -2.711352 -v 2.104814 -0.913122 10.635355 -v 1.287172 -2.267787 -2.690744 -v 1.178886 -1.905710 10.649555 -v 0.252960 -0.913122 10.635355 -v -0.023462 -9.436724 12.462571 -v -5.297682 -0.867848 9.194902 -v 1.158039 -7.788337 9.293917 -v 1.214251 7.655847 12.079970 -v 1.158039 6.052641 9.095887 -v 7.613757 -0.867847 9.194902 -v 5.436880 -0.865177 10.371088 -v 1.158039 3.721714 10.305462 -v 10.381592 -0.169335 12.163438 -v 1.273949 10.068592 17.144547 -v 12.759308 -1.389768 16.849798 -v -7.821683 -0.295910 12.752341 -v -0.757778 -10.857972 16.764185 -v -10.252585 0.507842 18.314060 -v 1.263254 -13.164757 34.534649 -v 7.840063 -1.143189 43.177551 -v 0.490666 -7.547210 43.481625 -v 1.059556 -12.905995 25.216671 -v -10.246758 -0.456162 36.297924 -v -10.429190 1.864903 29.905817 -v 13.438834 -1.467666 25.095953 -v 0.876860 11.524522 33.761429 -v -0.308461 11.283371 26.418409 -v 1.029258 -0.920301 46.889679 -v -5.808589 -0.220403 42.725170 -v 1.170766 5.971041 43.547592 -v 13.628224 -1.376191 34.467335 -v 1.158039 -5.452066 10.436716 -v -3.120803 -0.865177 10.371088 -vt 0.375000 0.250000 -vt 0.625000 0.500000 -vt 0.375000 0.500000 -vt 0.375000 0.750000 -vt 0.625000 0.750000 -vt 0.375000 1.000000 -vt 0.125000 0.750000 -vt 0.125000 0.500000 -vt 0.625000 0.000000 -vt 0.375000 0.000000 -vt 0.625000 0.250000 -vt 0.625000 1.000000 -vt 0.625000 0.000000 -vt 0.375000 0.250000 -vt 0.375000 0.000000 -vt 0.625000 0.500000 -vt 0.375000 0.500000 -vt 0.375000 0.750000 -vt 0.375000 0.750000 -vt 0.375000 0.500000 -vt 0.625000 0.750000 -vt 0.625000 0.500000 -vt 0.625000 0.750000 -vt 0.625000 1.000000 -vt 0.375000 1.000000 -vt 0.625000 0.250000 -vt 0.625000 0.000000 -vt 0.625000 0.250000 -vt 0.625000 1.000000 -vt 0.625000 1.000000 -vt 0.625000 0.750000 -vt 0.625000 1.000000 -vt 0.625000 0.000000 -vt 0.625000 0.250000 -vt 0.625000 0.250000 -vt 0.625000 0.750000 -vt 0.625000 1.000000 -vt 0.625000 0.500000 -vt 0.625000 0.500000 -vt 0.625000 1.000000 -vt 0.625000 0.250000 -vt 0.625000 0.500000 -vt 0.625000 0.750000 -vt 0.625000 0.000000 -vt 0.625000 0.500000 -vt 0.625000 0.750000 -vt 0.125000 0.750000 -vt 0.125000 0.500000 -vt 0.375000 0.250000 -vt 0.375000 0.000000 -vt 0.625000 0.250000 -vt 0.625000 0.000000 -vt 0.375000 1.000000 -vn -0.8966 0.1765 -0.4062 -vn -0.2288 0.9705 -0.0765 -vn -0.2401 0.7564 -0.6085 -vn 0.2302 0.9698 -0.0806 -vn 0.8620 0.3110 -0.4002 -vn 0.2392 0.7578 -0.6071 -vn 0.9442 -0.3240 -0.0599 -vn 0.3546 -0.7710 -0.5290 -vn 0.9025 -0.0307 -0.4296 -vn 0.0007 0.5127 -0.8586 -vn 0.1262 -0.5802 -0.8047 -vn -0.7101 -0.0094 -0.7040 -vn -0.3876 -0.9191 -0.0710 -vn -0.8993 -0.1743 -0.4011 -vn -0.1101 -0.8219 -0.5589 -vn -0.8959 0.1772 -0.4073 -vn -0.9859 0.1612 -0.0450 -vn -0.2269 0.9721 -0.0604 -vn 0.9983 -0.0045 -0.0589 -vn 0.0653 -0.9953 -0.0715 -vn 0.6825 0.1375 -0.7179 -vn -0.9856 -0.1618 -0.0495 -vn -0.2108 -0.7706 -0.6015 -vn -0.4336 -0.2123 -0.8757 -vn -0.2529 -0.3602 -0.8979 -vn -0.3874 0.2389 -0.8904 -vn -0.2561 0.7739 -0.5793 -vn -0.3406 0.3973 -0.8521 -vn 0.2485 0.7742 -0.5821 -vn 0.4201 0.1840 -0.8886 -vn 0.2875 0.4133 -0.8640 -vn -0.2301 -0.0956 -0.9685 -vn -0.3452 -0.1854 -0.9200 -vn -0.1865 -0.3124 -0.9315 -vn 0.8101 0.2588 -0.5261 -vn 0.3038 0.8930 -0.3321 -vn 0.9500 -0.0098 -0.3121 -vn 0.4430 -0.2621 -0.8573 -vn 0.2543 -0.8385 -0.4819 -vn 0.2777 -0.4837 -0.8300 -vn -0.8311 -0.1392 -0.5384 -vn -0.4690 -0.8315 -0.2979 -vn -0.9660 -0.0144 -0.2580 -vn 0.2250 -0.8336 -0.5045 -vn 0.8446 -0.3834 -0.3737 -vn -0.0745 -0.9702 -0.2306 -vn -0.7915 0.2405 -0.5619 -vn -0.1336 0.9286 -0.3462 -vn -0.2415 0.7764 -0.5821 -vn 0.3254 -0.8746 0.3595 -vn 0.6695 -0.2019 0.7148 -vn 0.1123 -0.6640 0.7392 -vn -0.3150 -0.9428 -0.1093 -vn -0.8998 -0.2396 0.3646 -vn -0.9982 -0.0504 -0.0328 -vn 0.9910 -0.1057 -0.0818 -vn 0.3170 -0.8837 0.3445 -vn 0.1350 -0.9845 -0.1115 -vn -0.9764 0.2036 0.0715 -vn -0.2097 0.8901 0.4047 -vn -0.2613 0.9617 -0.0824 -vn 0.1886 -0.1849 0.9645 -vn -0.2120 0.8909 0.4017 -vn -0.6695 0.2857 0.6857 -vn -0.2165 0.6666 0.7133 -vn 0.2548 0.8827 0.3949 -vn 0.6830 0.1786 0.7083 -vn 0.9105 0.1969 0.3636 -vn -0.8779 -0.2855 0.3844 -vn -0.3475 -0.6225 0.7012 -vn -0.6954 -0.0407 0.7175 -vn -0.2247 0.1841 0.9569 -vn 0.2627 0.6646 0.6995 -vn 0.2041 0.1782 0.9626 -vn 0.0104 -0.1284 -0.9917 -vn 0.0113 0.0999 -0.9949 -vn 0.1247 -0.0131 -0.9921 -vn -0.2129 0.0541 -0.9756 -vn -0.3480 0.1581 -0.9241 -vn -0.0342 0.1386 -0.9898 -vn 0.0911 -0.1834 -0.9788 -vn 0.2079 -0.3108 -0.9275 -vn 0.3309 -0.1819 -0.9260 -vn 0.0943 0.1844 -0.9783 -vn 0.2125 0.2881 -0.9337 -vn 0.1855 0.0554 -0.9811 -vn 0.9655 0.2473 -0.0819 -vn 0.2169 0.8994 0.3795 -vn 0.9112 0.1527 0.3827 -vn -0.2556 -0.1469 0.9556 -vn 0.2934 0.9034 -0.3128 -vn 0.9662 0.2471 -0.0739 -vn 0.9201 -0.0146 -0.3914 -vn -0.8966 0.3268 -0.2990 -vn -0.2847 0.9551 -0.0818 -vn -0.1067 0.9170 -0.3843 -vn 0.8530 -0.3819 -0.3557 -vn 0.1148 -0.9846 -0.1318 -vn -0.0870 -0.9224 -0.3763 -vn -0.4533 -0.8483 -0.2736 -vn -0.9938 -0.1036 0.0407 -vn -0.9611 -0.0110 -0.2760 -vn -0.8328 -0.1509 -0.5326 -vn -0.7730 0.2351 -0.5892 -vn 0.7297 0.2771 -0.6251 -vn -0.0308 -0.2306 -0.9726 -vn 0.1875 0.7680 -0.6124 -vn 0.7877 -0.1549 -0.5963 -vn -0.2171 -0.7845 -0.5809 -vn 0.7683 -0.1123 -0.6302 -vn -0.8949 0.3391 -0.2900 -vn 0.9127 -0.2032 0.3545 -vn -0.0974 -0.9166 0.3877 -vn 0.9112 -0.1856 0.3677 -vn -0.8730 0.0583 0.4842 -vn -0.9052 0.0940 0.4145 -vn -0.1301 -0.9320 0.3383 -vn -0.1403 -0.0169 -0.9900 -vn -0.1894 0.2897 -0.9382 -vn 0.1609 -0.0994 -0.9819 -vn 0.3335 0.1620 -0.9287 -vn 0.1161 0.9881 -0.1005 -vn 0.1239 0.9922 -0.0145 -vn -0.9798 0.1969 0.0343 -vn 0.9961 -0.0766 -0.0438 -vn -0.3217 -0.9433 -0.0822 -s 1 -f 1/1/1 2/2/2 3/3/3 -f 2/2/4 4/4/5 3/3/6 -f 5/5/7 6/6/8 4/4/9 -f 3/3/10 6/7/11 1/8/12 -f 7/9/13 1/1/14 6/10/15 -f 1/1/16 8/11/17 2/2/18 -f 2/2/4 5/5/19 4/4/5 -f 5/5/7 7/12/20 6/6/8 -f 3/3/10 4/4/21 6/7/11 -f 7/9/13 8/11/22 1/1/14 -f 9/13/23 10/14/24 11/15/25 -f 10/14/26 12/16/27 13/17/28 -f 12/16/29 14/18/30 13/17/31 -f 13/17/32 15/19/33 16/20/34 -f 17/21/35 18/22/36 19/23/37 -f 14/18/38 9/24/39 11/25/40 -f 20/26/41 21/27/42 22/28/43 -f 9/24/44 19/23/45 21/29/46 -f 20/26/47 18/22/48 12/16/49 -f 23/30/50 24/31/51 25/32/52 -f 26/33/53 27/34/54 28/35/55 -f 29/36/56 23/30/57 26/37/58 -f 28/35/59 30/38/60 31/39/61 -f 25/32/52 24/31/51 32/40/62 -f 30/38/63 33/41/64 34/42/65 -f 30/38/66 24/31/67 35/43/68 -f 27/34/69 25/44/70 33/41/71 -f 33/41/64 32/45/72 34/42/65 -f 34/42/73 32/46/74 24/31/67 -f 16/20/75 36/47/76 37/48/77 -f 11/25/78 15/19/79 14/18/80 -f 10/14/81 16/20/82 37/49/83 -f 10/14/84 36/50/85 11/15/86 -f 29/36/87 30/38/88 35/43/89 -f 25/44/70 32/51/90 33/41/71 -f 18/22/91 29/36/92 19/23/93 -f 22/28/94 31/39/95 18/22/96 -f 19/23/97 26/37/98 21/29/99 -f 21/27/100 28/35/101 22/28/102 -f 9/13/23 20/26/103 10/14/24 -f 10/14/26 20/26/104 12/16/27 -f 12/16/29 17/21/105 14/18/30 -f 13/17/32 14/18/106 15/19/33 -f 17/21/35 12/16/107 18/22/36 -f 14/18/38 17/21/108 9/24/39 -f 20/26/41 9/13/109 21/27/42 -f 9/24/44 17/21/110 19/23/45 -f 20/26/47 22/28/111 18/22/48 -f 23/30/50 35/43/112 24/31/51 -f 26/33/53 23/52/113 27/34/54 -f 29/36/56 35/43/114 23/30/57 -f 28/35/59 27/34/115 30/38/60 -f 30/38/63 27/34/116 33/41/64 -f 30/38/66 34/42/73 24/31/67 -f 27/34/69 23/52/117 25/44/70 -f 16/20/75 15/19/118 36/47/76 -f 11/25/78 36/53/119 15/19/79 -f 10/14/81 13/17/120 16/20/82 -f 10/14/84 37/49/121 36/50/85 -f 29/36/87 31/39/122 30/38/88 -f 18/22/91 31/39/123 29/36/92 -f 22/28/94 28/35/124 31/39/95 -f 19/23/97 29/36/125 26/37/98 -f 21/27/100 26/33/126 28/35/101 +version https://git-lfs.github.com/spec/v1 +oid sha256:6633ea303abbd7fd088603012790865c2a173aab5bef542a571fb8e369605de0 +size 7390 diff --git a/assets/voxygen/lod/pine.blend b/assets/voxygen/lod/pine.blend index 151e01f0cf838d957f1409572ce3a2d0afc0eeb5..0866832fc6ac7bde29e1bef4109d41b72ec2f686 100644 GIT binary patch literal 131 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 diff --git a/assets/voxygen/lod/pine.obj b/assets/voxygen/lod/pine.obj index 372717450b..7822519be5 100644 --- a/assets/voxygen/lod/pine.obj +++ b/assets/voxygen/lod/pine.obj @@ -1,199 +1,3 @@ -# Blender v3.0.0 OBJ File: 'pine.blend' -# www.blender.org -o Cube.007 -v -2.819197 -0.013505 -2.712447 -v 0.008816 2.119261 10.632816 -v 0.256695 3.130596 -2.715924 -v 3.332587 -0.013505 -2.712447 -v 2.128373 -0.047297 10.635213 -v 0.256695 -3.157609 -2.708971 -v 0.008816 -2.213855 10.637607 -v -2.110739 -0.047297 10.635213 -v -0.038908 -6.413302 23.015169 -v -14.816810 0.034971 9.195086 -v -0.038907 -15.070634 9.211782 -v -6.569601 0.262213 23.007790 -v -0.038907 15.140581 9.178390 -v -0.038908 6.937726 23.000408 -v 14.738994 0.034973 9.195086 -v 9.755864 0.054326 10.371477 -v -0.038907 10.066301 10.360410 -v 6.491785 0.262210 23.007790 -v -0.038907 10.685573 21.166832 -v 10.187769 0.232116 21.178389 -v -10.265585 0.232116 21.178389 -v -0.038908 -10.221344 21.189941 -v -0.038908 -7.950523 30.054035 -v 3.631791 0.505130 37.773411 -v -0.038908 -3.246969 37.777557 -v -0.038908 -5.101809 31.789749 -v -8.186729 0.377981 30.044832 -v -5.427802 0.406590 31.783665 -v 5.349986 0.406590 31.783665 -v -0.038908 8.706485 30.035627 -v -0.038908 5.914984 31.777578 -v -0.333702 0.353851 46.894814 -v -0.038908 4.257227 37.769260 -v 8.108912 0.377983 30.044832 -v -3.709605 0.505129 37.773411 -v -0.038907 -9.957649 10.382545 -v -9.833678 0.054326 10.371477 -vt 0.375000 0.250000 -vt 0.625000 0.500000 -vt 0.375000 0.500000 -vt 0.375000 0.750000 -vt 0.625000 0.750000 -vt 0.375000 1.000000 -vt 0.125000 0.750000 -vt 0.125000 0.500000 -vt 0.625000 0.000000 -vt 0.375000 0.000000 -vt 0.625000 0.250000 -vt 0.625000 1.000000 -vt 0.625000 0.000000 -vt 0.375000 0.250000 -vt 0.375000 0.000000 -vt 0.625000 0.250000 -vt 0.375000 0.500000 -vt 0.625000 0.500000 -vt 0.375000 0.750000 -vt 0.375000 0.750000 -vt 0.375000 0.500000 -vt 0.625000 0.750000 -vt 0.625000 0.500000 -vt 0.625000 0.750000 -vt 0.625000 1.000000 -vt 0.375000 1.000000 -vt 0.625000 0.250000 -vt 0.625000 1.000000 -vt 0.625000 1.000000 -vt 0.625000 0.750000 -vt 0.625000 1.000000 -vt 0.625000 0.000000 -vt 0.625000 0.250000 -vt 0.625000 0.250000 -vt 0.625000 0.750000 -vt 0.625000 1.000000 -vt 0.625000 0.500000 -vt 0.625000 0.500000 -vt 0.625000 1.000000 -vt 0.625000 0.500000 -vt 0.625000 0.750000 -vt 0.625000 0.000000 -vt 0.625000 0.250000 -vt 0.625000 0.500000 -vt 0.625000 0.750000 -vt 0.125000 0.750000 -vt 0.125000 0.500000 -vt 0.375000 0.250000 -vt 0.375000 0.000000 -vt 0.625000 0.250000 -vt 0.625000 0.000000 -vt 0.625000 0.000000 -vt 0.375000 1.000000 -vn -0.7142 0.6988 0.0397 -vn 0.7132 0.6978 0.0661 -vn 0.7135 -0.6979 0.0626 -vn 0.0000 -0.0011 -1.0000 -vn -0.7144 -0.6988 0.0361 -vn -0.6549 -0.6402 0.4015 -vn -0.6600 0.6461 0.3834 -vn 0.6600 0.6461 0.3834 -vn -0.2249 -0.2211 -0.9490 -vn -0.4090 -0.4010 -0.8197 -vn 0.6549 -0.6402 0.4015 -vn 0.4049 0.3952 -0.8245 -vn -0.4049 0.3952 -0.8245 -vn 0.4090 -0.4010 -0.8197 -vn 0.6579 -0.6432 0.3917 -vn 0.6697 -0.6548 0.3503 -vn 0.6699 -0.6550 0.3497 -vn 0.4702 0.4592 -0.7537 -vn -0.4702 0.4592 -0.7537 -vn 0.4753 -0.4658 -0.7464 -vn 0.6850 -0.6698 0.2867 -vn -0.6629 0.6490 0.3734 -vn -0.6742 0.6599 0.3315 -vn 0.6629 0.6490 0.3734 -vn 0.6703 0.6561 0.3468 -vn -0.6579 -0.6432 0.3917 -vn -0.6738 -0.6588 0.3345 -vn -0.6742 -0.6592 0.3332 -vn -0.6746 0.6603 0.3301 -vn -0.6889 0.6742 0.2661 -vn 0.6703 0.6561 0.3467 -vn 0.6802 0.6658 0.3068 -vn -0.2235 0.2176 -0.9501 -vn 0.2249 -0.2211 -0.9490 -vn 0.2235 0.2176 -0.9501 -vn -0.4753 -0.4658 -0.7464 -vn -0.6931 -0.6778 0.2453 -vn 0.6817 0.6673 0.3000 -vn -0.6817 0.6673 0.3000 -vn 0.6774 -0.6624 0.3199 -vn -0.6774 -0.6624 0.3199 -s 1 -f 1/1/1 2/2/1 3/3/1 -f 2/2/2 4/4/2 3/3/2 -f 5/5/3 6/6/3 4/4/3 -f 3/3/4 6/7/4 1/8/4 -f 7/9/5 1/1/5 6/10/5 -f 1/1/1 8/11/1 2/2/1 -f 2/2/2 5/5/2 4/4/2 -f 5/5/3 7/12/3 6/6/3 -f 3/3/4 4/4/4 6/7/4 -f 7/9/5 8/11/5 1/1/5 -f 9/13/6 10/14/6 11/15/6 -f 12/16/7 13/17/7 10/14/7 -f 14/18/8 15/19/8 13/17/8 -f 13/17/9 16/20/9 17/21/9 -f 18/22/10 19/23/10 20/24/10 -f 15/19/11 9/25/11 11/26/11 -f 9/13/12 21/27/12 12/16/12 -f 18/22/13 22/28/13 9/25/13 -f 12/16/14 19/23/14 14/18/14 -f 23/29/15 24/30/16 25/31/17 -f 26/32/18 27/33/18 28/34/18 -f 29/35/19 23/29/19 26/36/19 -f 28/34/20 30/37/20 31/38/20 -f 25/31/17 24/30/16 32/39/21 -f 27/33/22 33/40/23 30/37/22 -f 30/37/24 24/30/25 34/41/24 -f 27/33/26 25/42/27 35/43/28 -f 35/43/29 32/44/30 33/40/23 -f 33/40/31 32/45/32 24/30/25 -f 17/21/4 36/46/4 37/47/4 -f 11/26/33 16/20/33 15/19/33 -f 10/14/34 17/21/34 37/48/34 -f 10/14/35 36/49/35 11/15/35 -f 31/38/36 34/41/36 29/35/36 -f 25/42/27 32/50/37 35/43/28 -f 19/23/38 29/35/38 20/24/38 -f 21/27/39 31/38/39 19/23/39 -f 20/24/40 26/36/40 22/28/40 -f 22/51/41 28/34/41 21/27/41 -f 9/13/6 12/16/6 10/14/6 -f 12/16/7 14/18/7 13/17/7 -f 14/18/8 18/22/8 15/19/8 -f 13/17/9 15/19/9 16/20/9 -f 18/22/10 14/18/10 19/23/10 -f 15/19/11 18/22/11 9/25/11 -f 9/13/12 22/51/12 21/27/12 -f 18/22/13 20/24/13 22/28/13 -f 12/16/14 21/27/14 19/23/14 -f 23/29/15 34/41/15 24/30/16 -f 26/32/18 23/52/18 27/33/18 -f 29/35/19 34/41/19 23/29/19 -f 28/34/20 27/33/20 30/37/20 -f 27/33/22 35/43/29 33/40/23 -f 30/37/24 33/40/31 24/30/25 -f 27/33/26 23/52/26 25/42/27 -f 17/21/4 16/20/4 36/46/4 -f 11/26/33 36/53/33 16/20/33 -f 10/14/34 13/17/34 17/21/34 -f 10/14/35 37/48/35 36/49/35 -f 31/38/36 30/37/36 34/41/36 -f 19/23/38 31/38/38 29/35/38 -f 21/27/39 28/34/39 31/38/39 -f 20/24/40 29/35/40 26/36/40 -f 22/51/41 26/32/41 28/34/41 +version https://git-lfs.github.com/spec/v1 +oid sha256:1f789d28ddd4e18c3d79f95377d9c141447deb9ef76d2a4350b32b890f81c659 +size 5109 From a9b20183834987d77caaef2123e0f10b6b0714eb Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 14:20:48 +0100 Subject: [PATCH 09/31] Better snow cover --- assets/voxygen/shaders/lod-object-frag.glsl | 5 +++++ assets/voxygen/shaders/lod-object-vert.glsl | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/assets/voxygen/shaders/lod-object-frag.glsl b/assets/voxygen/shaders/lod-object-frag.glsl index bfbf01552d..47980823c8 100644 --- a/assets/voxygen/shaders/lod-object-frag.glsl +++ b/assets/voxygen/shaders/lod-object-frag.glsl @@ -21,6 +21,7 @@ layout(location = 0) in vec3 f_pos; layout(location = 1) in vec3 f_norm; layout(location = 2) in vec4 f_col; +layout(location = 3) in float snow_cover; layout(location = 0) out vec4 tgt_color; @@ -123,6 +124,10 @@ void main() { //max_light += lights_at(f_pos, voxel_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, voxel_norm, 1.0, emitted_light, reflected_light); + vec3 side_color = mix(surf_color, vec3(1), snow_cover); + vec3 top_color = mix(surf_color, surf_color * 0.3, snow_cover); + surf_color = mix(side_color, top_color, 1.0 - fract((f_pos.z + focus_off.z) * 0.1)); + surf_color = illuminate(max_light, view_dir, surf_color * emitted_light, surf_color * reflected_light); // Temporarily disable particle transparency to avoid artifacts diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index 366053d42b..82d3433d36 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -28,6 +28,7 @@ const uint FLAG_SNOW_COVERED = 1; layout(location = 0) out vec3 f_pos; layout(location = 1) out vec3 f_norm; layout(location = 2) out vec4 f_col; +layout(location = 3) out float snow_cover; void main() { vec3 tree_pos = inst_pos - focus_off.xyz; @@ -40,7 +41,10 @@ void main() { f_col = vec4(vec3(0.02, 0.1, 0.01) * (sin(inst_pos.xyy) * 0.33 + 0.66), 1.0);//vec4(v_col, 1.0); if ((inst_flags & FLAG_SNOW_COVERED) > 0u) { - f_col.rgb = mix(f_col.rgb, vec3(1), pow(max(f_norm.z, 0.0), 0.5)); + snow_cover = 1.0; + //f_col.rgb = mix(f_col.rgb, vec3(1), pow(max(f_norm.z, 0.0), 0.5)); + } else { + snow_cover = 0.0; } gl_Position = From e4e50cb50e631a107f4f22c206fb0921de1b5132 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 14:46:35 +0100 Subject: [PATCH 10/31] Better pulldown --- assets/voxygen/shaders/lod-object-frag.glsl | 6 +++--- assets/voxygen/shaders/lod-object-vert.glsl | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/assets/voxygen/shaders/lod-object-frag.glsl b/assets/voxygen/shaders/lod-object-frag.glsl index 47980823c8..02faef97dd 100644 --- a/assets/voxygen/shaders/lod-object-frag.glsl +++ b/assets/voxygen/shaders/lod-object-frag.glsl @@ -75,7 +75,7 @@ void main() { float my_alt = f_pos.z + focus_off.z; float f_ao = 1.0; const float VOXELIZE_DIST = 2000; - float voxelize_factor = clamp(1.0 - (distance(focus_pos.xy, f_pos.xy) - view_distance.x) / VOXELIZE_DIST, 0, 0.75); + float voxelize_factor = clamp(1.0 - (distance(focus_pos.xy, f_pos.xy) - view_distance.x) / VOXELIZE_DIST, 0, 1.0); vec3 cam_dir = normalize(cam_pos.xyz - f_pos.xyz); vec3 side_norm = normalize(vec3(my_norm.xy, 0)); vec3 top_norm = vec3(0, 0, 1); @@ -125,8 +125,8 @@ void main() { //max_light += lights_at(f_pos, voxel_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, voxel_norm, 1.0, emitted_light, reflected_light); vec3 side_color = mix(surf_color, vec3(1), snow_cover); - vec3 top_color = mix(surf_color, surf_color * 0.3, snow_cover); - surf_color = mix(side_color, top_color, 1.0 - fract((f_pos.z + focus_off.z) * 0.1)); + vec3 top_color = mix(surf_color, surf_color * 0.3, 0.5 + snow_cover * 0.5); + surf_color = mix(side_color, top_color, 1.0 - pow(fract((f_pos.z + focus_off.z) * 0.1), 2.0)); surf_color = illuminate(max_light, view_dir, surf_color * emitted_light, surf_color * reflected_light); diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index 82d3433d36..2b4ada6e4c 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -34,7 +34,7 @@ void main() { vec3 tree_pos = inst_pos - focus_off.xyz; f_pos = tree_pos + v_pos; - float pull_down = 1.0 / pow(distance(focus_pos.xy, tree_pos.xy) / (view_distance.x * 0.95), 50.0); + float pull_down = 1.0 / pow(distance(focus_pos.xy, tree_pos.xy) / (view_distance.x * 0.95), 150.0); f_pos.z -= pull_down; f_norm = v_norm; From 3693a439ac2b8809b08249491f099ef5121f1a53 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 15:11:43 +0100 Subject: [PATCH 11/31] Better reflections --- assets/voxygen/shaders/fluid-frag/shiny.glsl | 2 +- assets/voxygen/shaders/fluid-vert.glsl | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/assets/voxygen/shaders/fluid-frag/shiny.glsl b/assets/voxygen/shaders/fluid-frag/shiny.glsl index 364d106f06..776cb05889 100644 --- a/assets/voxygen/shaders/fluid-frag/shiny.glsl +++ b/assets/voxygen/shaders/fluid-frag/shiny.glsl @@ -188,7 +188,7 @@ void main() { } vec3 reflect_color = get_sky_color(/*reflect_ray_dir*/ray_dir, time_of_day.x, f_pos, vec3(-100000), 0.125, true); - reflect_color = get_cloud_color(reflect_color, ray_dir, f_pos.xyz, time_of_day.x, 100000.0, 0.2); + reflect_color = get_cloud_color(reflect_color, ray_dir, f_pos.xyz, time_of_day.x, 100000.0, 0.1); reflect_color *= f_light; // Prevent the sky affecting light when underground diff --git a/assets/voxygen/shaders/fluid-vert.glsl b/assets/voxygen/shaders/fluid-vert.glsl index f5ee61b3bf..27c8518d0e 100644 --- a/assets/voxygen/shaders/fluid-vert.glsl +++ b/assets/voxygen/shaders/fluid-vert.glsl @@ -54,7 +54,14 @@ void main() { // f_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0)); // f_pos.z -= min(32.0, 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0)); - f_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0)); + // Terrain 'pop-in' effect + #ifndef EXPERIMENTAL_BAREMINIMUM + f_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0)); + // f_pos.z -= min(32.0, 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0)); + #endif + + float pull_down = pow(distance(focus_pos.xy, f_pos.xy) / (view_distance.x * 0.95), 20.0) * 0.7; + f_pos.z -= pull_down; #ifdef EXPERIMENTAL_CURVEDWORLD f_pos.z -= pow(distance(f_pos.xy + focus_off.xy, focus_pos.xy + focus_off.xy) * 0.05, 2); From c3f30b21880bd1c356a1635d1d74dc018731b827 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 15:53:24 +0100 Subject: [PATCH 12/31] Offset for side/top texture --- assets/voxygen/shaders/include/lod.glsl | 4 +++- assets/voxygen/shaders/lod-object-frag.glsl | 7 ++++--- assets/voxygen/shaders/lod-object-vert.glsl | 4 +++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/assets/voxygen/shaders/include/lod.glsl b/assets/voxygen/shaders/include/lod.glsl index 5b755fbb4b..fa417dd021 100644 --- a/assets/voxygen/shaders/include/lod.glsl +++ b/assets/voxygen/shaders/include/lod.glsl @@ -324,7 +324,7 @@ vec3 lod_norm(vec2 f_pos/*vec3 pos*/) { norm.xy += vec2( textureLod(sampler2D(t_noise, s_noise), wpos / 100, 0).x - 0.5, textureLod(sampler2D(t_noise, s_noise), wpos / 100 + 0.5, 0).x - 0.5 - ) * 0.15 / pow(norm.z + 0.1, 3); + ) * 0.25 / pow(norm.z + 0.1, 3); norm = normalize(norm); #endif @@ -373,6 +373,7 @@ vec3 lod_col(vec2 pos) { vec3 col = textureBicubic(t_map, s_map, pos_to_tex(pos)).rgb; + /* #ifdef EXPERIMENTAL_PROCEDURALLODDETAIL col *= pow(vec3( textureLod(sampler2D(t_noise, s_noise), wpos / 40, 0).x - 0.5, @@ -380,6 +381,7 @@ vec3 lod_col(vec2 pos) { textureLod(sampler2D(t_noise, s_noise), wpos / 45 + 0.75, 0).x - 0.5 ) + 1.0, vec3(0.5)); #endif + */ return col; } diff --git a/assets/voxygen/shaders/lod-object-frag.glsl b/assets/voxygen/shaders/lod-object-frag.glsl index 02faef97dd..fe05d2cd01 100644 --- a/assets/voxygen/shaders/lod-object-frag.glsl +++ b/assets/voxygen/shaders/lod-object-frag.glsl @@ -21,7 +21,8 @@ layout(location = 0) in vec3 f_pos; layout(location = 1) in vec3 f_norm; layout(location = 2) in vec4 f_col; -layout(location = 3) in float snow_cover; +layout(location = 3) in vec3 model_pos; +layout(location = 4) in float snow_cover; layout(location = 0) out vec4 tgt_color; @@ -75,7 +76,7 @@ void main() { float my_alt = f_pos.z + focus_off.z; float f_ao = 1.0; const float VOXELIZE_DIST = 2000; - float voxelize_factor = clamp(1.0 - (distance(focus_pos.xy, f_pos.xy) - view_distance.x) / VOXELIZE_DIST, 0, 1.0); + float voxelize_factor = clamp(1.0 - (distance(focus_pos.xy, f_pos.xy) - view_distance.x) / VOXELIZE_DIST, 0, 0.65); vec3 cam_dir = normalize(cam_pos.xyz - f_pos.xyz); vec3 side_norm = normalize(vec3(my_norm.xy, 0)); vec3 top_norm = vec3(0, 0, 1); @@ -126,7 +127,7 @@ void main() { vec3 side_color = mix(surf_color, vec3(1), snow_cover); vec3 top_color = mix(surf_color, surf_color * 0.3, 0.5 + snow_cover * 0.5); - surf_color = mix(side_color, top_color, 1.0 - pow(fract((f_pos.z + focus_off.z) * 0.1), 2.0)); + surf_color = mix(side_color, top_color, 1.0 - pow(fract(model_pos.z * 0.1), 2.0)); surf_color = illuminate(max_light, view_dir, surf_color * emitted_light, surf_color * reflected_light); diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index 2b4ada6e4c..06d6deac34 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -28,11 +28,13 @@ const uint FLAG_SNOW_COVERED = 1; layout(location = 0) out vec3 f_pos; layout(location = 1) out vec3 f_norm; layout(location = 2) out vec4 f_col; -layout(location = 3) out float snow_cover; +layout(location = 3) out vec3 model_pos; +layout(location = 4) out float snow_cover; void main() { vec3 tree_pos = inst_pos - focus_off.xyz; f_pos = tree_pos + v_pos; + model_pos = v_pos; float pull_down = 1.0 / pow(distance(focus_pos.xy, tree_pos.xy) / (view_distance.x * 0.95), 150.0); f_pos.z -= pull_down; From 39e8b5d4684cf750a25d3dfa2d5bcd42179ff6b0 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 15:57:19 +0100 Subject: [PATCH 13/31] Hacky normals --- assets/voxygen/shaders/lod-object-vert.glsl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index 06d6deac34..6aa7f6aae2 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -39,7 +39,8 @@ void main() { float pull_down = 1.0 / pow(distance(focus_pos.xy, tree_pos.xy) / (view_distance.x * 0.95), 150.0); f_pos.z -= pull_down; - f_norm = v_norm; + // Hacky, very bad, 50 is ~ tree height + f_norm = mix(v_norm, vec3(0, 0, 1), clamp(model_pos.z / 50, 0, 1)); f_col = vec4(vec3(0.02, 0.1, 0.01) * (sin(inst_pos.xyy) * 0.33 + 0.66), 1.0);//vec4(v_col, 1.0); if ((inst_flags & FLAG_SNOW_COVERED) > 0u) { From 596ae73117ab7757639440ca93d4d82d391772d1 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 16:10:47 +0100 Subject: [PATCH 14/31] Added NoLodVoxels option --- assets/voxygen/shaders/lod-object-frag.glsl | 5 +++++ assets/voxygen/shaders/lod-terrain-frag.glsl | 5 +++++ voxygen/src/render/mod.rs | 2 ++ 3 files changed, 12 insertions(+) diff --git a/assets/voxygen/shaders/lod-object-frag.glsl b/assets/voxygen/shaders/lod-object-frag.glsl index fe05d2cd01..ceb9164584 100644 --- a/assets/voxygen/shaders/lod-object-frag.glsl +++ b/assets/voxygen/shaders/lod-object-frag.glsl @@ -97,6 +97,11 @@ void main() { f_ao = min(f_ao, max(f_norm.z * 0.5 + 0.5, 0.0)); voxel_norm = mix(my_norm, voxel_norm == vec3(0.0) ? f_norm : voxel_norm, voxelize_factor); + #ifdef EXPERIMENTAL_NOLODVOXELS + f_ao = 1.0; + voxel_norm = normalize(mix(side_norm, top_norm, cam_dir.z)); + #endif + vec3 emitted_light, reflected_light; // This is a bit of a hack. Because we can't find the volumetric lighting of each particle (they don't talk to the diff --git a/assets/voxygen/shaders/lod-terrain-frag.glsl b/assets/voxygen/shaders/lod-terrain-frag.glsl index c1b0e74677..2bc5654f9f 100644 --- a/assets/voxygen/shaders/lod-terrain-frag.glsl +++ b/assets/voxygen/shaders/lod-terrain-frag.glsl @@ -354,6 +354,11 @@ void main() { } } + #ifdef EXPERIMENTAL_NOLODVOXELS + f_ao = 1.0; + voxel_norm = normalize(mix(side_norm, top_norm, cam_dir.z)); + #endif + // vec3 f_ao_view = max(vec3(dot(f_orig_view_dir.yz, sides.yz), dot(f_orig_view_dir.xz, sides.xz), dot(f_orig_view_dir.xy, sides.xy)), 0.0); // delta_sides *= sqrt(1.0 - f_ao_view * f_ao_view); // delta_sides *= 1.0 - mix(view_dir / f_ao_view, vec3(0.0), equal(f_ao_view, vec3(0.0)));// sqrt(1.0 - f_ao_view * f_ao_view); diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index c2d021f14b..e689d40024 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -463,4 +463,6 @@ pub enum ExperimentalShader { BareMinimum, /// Lowers strength of the glow effect for lights near the camera. LowGlowNearCamera, + /// Disable the fake voxel effect on LoD features. + NoLodVoxels, } From 2d7aa1aaa34704ef86d4f204be21f8ca34ca2e72 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 16:39:31 +0100 Subject: [PATCH 15/31] Added no terrain pop experimental shader --- assets/voxygen/shaders/fluid-vert.glsl | 6 ++++-- assets/voxygen/shaders/lod-object-vert.glsl | 6 +++++- assets/voxygen/shaders/lod-terrain-frag.glsl | 2 +- assets/voxygen/shaders/terrain-vert.glsl | 6 ++++-- voxygen/src/render/mod.rs | 2 ++ 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/assets/voxygen/shaders/fluid-vert.glsl b/assets/voxygen/shaders/fluid-vert.glsl index 27c8518d0e..b078b87407 100644 --- a/assets/voxygen/shaders/fluid-vert.glsl +++ b/assets/voxygen/shaders/fluid-vert.glsl @@ -56,8 +56,10 @@ void main() { // Terrain 'pop-in' effect #ifndef EXPERIMENTAL_BAREMINIMUM - f_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0)); - // f_pos.z -= min(32.0, 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0)); + #ifndef EXPERIMENTAL_NOTERRAINPOP + f_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0)); + // f_pos.z -= min(32.0, 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0)); + #endif #endif float pull_down = pow(distance(focus_pos.xy, f_pos.xy) / (view_distance.x * 0.95), 20.0) * 0.7; diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index 6aa7f6aae2..21ae1e6a8f 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -37,7 +37,11 @@ void main() { model_pos = v_pos; float pull_down = 1.0 / pow(distance(focus_pos.xy, tree_pos.xy) / (view_distance.x * 0.95), 150.0); - f_pos.z -= pull_down; + #ifndef EXPERIMENTAL_NOTERRAINPOP + f_pos.z -= pull_down; + #else + f_pos.z -= step(0.1, pull_down) * 10000.0; + #endif // Hacky, very bad, 50 is ~ tree height f_norm = mix(v_norm, vec3(0, 0, 1), clamp(model_pos.z / 50, 0, 1)); diff --git a/assets/voxygen/shaders/lod-terrain-frag.glsl b/assets/voxygen/shaders/lod-terrain-frag.glsl index 2bc5654f9f..29d52cac2f 100644 --- a/assets/voxygen/shaders/lod-terrain-frag.glsl +++ b/assets/voxygen/shaders/lod-terrain-frag.glsl @@ -356,7 +356,7 @@ void main() { #ifdef EXPERIMENTAL_NOLODVOXELS f_ao = 1.0; - voxel_norm = normalize(mix(side_norm, top_norm, cam_dir.z)); + voxel_norm = normalize(mix(side_norm, top_norm, max(cam_dir.z, 0.0))); #endif // vec3 f_ao_view = max(vec3(dot(f_orig_view_dir.yz, sides.yz), dot(f_orig_view_dir.xz, sides.xz), dot(f_orig_view_dir.xy, sides.xy)), 0.0); diff --git a/assets/voxygen/shaders/terrain-vert.glsl b/assets/voxygen/shaders/terrain-vert.glsl index 2751b04d81..d13a240587 100644 --- a/assets/voxygen/shaders/terrain-vert.glsl +++ b/assets/voxygen/shaders/terrain-vert.glsl @@ -81,8 +81,10 @@ void main() { // Terrain 'pop-in' effect #ifndef EXPERIMENTAL_BAREMINIMUM - v_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0)); - // f_pos.z -= min(32.0, 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0)); + #ifndef EXPERIMENTAL_NOTERRAINPOP + v_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0)); + // f_pos.z -= min(32.0, 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0)); + #endif #endif #ifdef EXPERIMENTAL_CURVEDWORLD diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index e689d40024..81adaa28b4 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -465,4 +465,6 @@ pub enum ExperimentalShader { LowGlowNearCamera, /// Disable the fake voxel effect on LoD features. NoLodVoxels, + // Disable the 'pop-in' effect when loading terrain. + NoTerrainPop, } From 63c8ea58b9dbccbba41dfd00a414167f6296dbd0 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 16:46:18 +0100 Subject: [PATCH 16/31] Unbork normals --- assets/voxygen/shaders/lod-object-vert.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index 21ae1e6a8f..9fedc98824 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -44,7 +44,7 @@ void main() { #endif // Hacky, very bad, 50 is ~ tree height - f_norm = mix(v_norm, vec3(0, 0, 1), clamp(model_pos.z / 50, 0, 1)); + f_norm = v_norm;//mix(v_norm, vec3(0, 0, 1), clamp(model_pos.z / 50, 0, 1)); f_col = vec4(vec3(0.02, 0.1, 0.01) * (sin(inst_pos.xyy) * 0.33 + 0.66), 1.0);//vec4(v_col, 1.0); if ((inst_flags & FLAG_SNOW_COVERED) > 0u) { From c199d17deb89f04910693e56dd0d10f50a71bde3 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 17:43:25 +0100 Subject: [PATCH 17/31] Better snow cover --- assets/voxygen/shaders/lod-object-frag.glsl | 2 +- assets/voxygen/shaders/lod-object-vert.glsl | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/assets/voxygen/shaders/lod-object-frag.glsl b/assets/voxygen/shaders/lod-object-frag.glsl index ceb9164584..69b2f81c8c 100644 --- a/assets/voxygen/shaders/lod-object-frag.glsl +++ b/assets/voxygen/shaders/lod-object-frag.glsl @@ -132,7 +132,7 @@ void main() { vec3 side_color = mix(surf_color, vec3(1), snow_cover); vec3 top_color = mix(surf_color, surf_color * 0.3, 0.5 + snow_cover * 0.5); - surf_color = mix(side_color, top_color, 1.0 - pow(fract(model_pos.z * 0.1), 2.0)); + surf_color = mix(side_color, top_color, pow(fract(model_pos.z * 0.1), 2.0)); surf_color = illuminate(max_light, view_dir, surf_color * emitted_light, surf_color * reflected_light); diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index 9fedc98824..12a0c575b4 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -43,6 +43,10 @@ void main() { f_pos.z -= step(0.1, pull_down) * 10000.0; #endif + #ifdef EXPERIMENTAL_CURVEDWORLD + f_pos.z -= pow(distance(f_pos.xy + focus_off.xy, focus_pos.xy + focus_off.xy) * 0.05, 2); + #endif + // Hacky, very bad, 50 is ~ tree height f_norm = v_norm;//mix(v_norm, vec3(0, 0, 1), clamp(model_pos.z / 50, 0, 1)); f_col = vec4(vec3(0.02, 0.1, 0.01) * (sin(inst_pos.xyy) * 0.33 + 0.66), 1.0);//vec4(v_col, 1.0); From add9e5f9feb22e03635b5ec706121f5d21018e2e Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 9 May 2022 21:18:49 +0100 Subject: [PATCH 18/31] Better snow cover --- assets/voxygen/shaders/lod-object-frag.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/voxygen/shaders/lod-object-frag.glsl b/assets/voxygen/shaders/lod-object-frag.glsl index 69b2f81c8c..e065a02e4d 100644 --- a/assets/voxygen/shaders/lod-object-frag.glsl +++ b/assets/voxygen/shaders/lod-object-frag.glsl @@ -130,7 +130,7 @@ void main() { //max_light += lights_at(f_pos, voxel_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, voxel_norm, 1.0, emitted_light, reflected_light); - vec3 side_color = mix(surf_color, vec3(1), snow_cover); + vec3 side_color = mix(surf_color, vec3(0.5, 0.6, 1.0), snow_cover); vec3 top_color = mix(surf_color, surf_color * 0.3, 0.5 + snow_cover * 0.5); surf_color = mix(side_color, top_color, pow(fract(model_pos.z * 0.1), 2.0)); From f35c98d1a18096a520fad4e3acf54b0cf64948c7 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 10 May 2022 12:36:44 +0100 Subject: [PATCH 19/31] Added LoD distance setting --- assets/voxygen/i18n/en/hud/settings.ron | 1 + client/src/lib.rs | 30 +++++--- common/net/src/msg/server.rs | 2 +- common/src/lod.rs | 13 +--- server/src/lib.rs | 4 +- server/src/lod.rs | 2 +- server/src/sys/msg/terrain.rs | 4 +- voxygen/src/hud/settings_window/video.rs | 46 +++++++++-- voxygen/src/render/mod.rs | 5 +- voxygen/src/render/pipelines/lod_object.rs | 21 ++--- voxygen/src/render/renderer.rs | 2 +- voxygen/src/render/renderer/binding.rs | 4 +- voxygen/src/render/renderer/drawer.rs | 15 ++-- .../src/render/renderer/pipeline_creation.rs | 9 ++- voxygen/src/scene/lod.rs | 62 ++++++++------- voxygen/src/session/settings_change.rs | 9 +++ voxygen/src/settings/graphics.rs | 2 + world/src/layer/tree.rs | 5 +- world/src/lib.rs | 76 ++++++++++--------- world/src/sim/mod.rs | 6 +- world/src/util/structure.rs | 28 ++++--- 21 files changed, 206 insertions(+), 140 deletions(-) diff --git a/assets/voxygen/i18n/en/hud/settings.ron b/assets/voxygen/i18n/en/hud/settings.ron index cfe5ffab23..fc1369da8f 100644 --- a/assets/voxygen/i18n/en/hud/settings.ron +++ b/assets/voxygen/i18n/en/hud/settings.ron @@ -59,6 +59,7 @@ "hud.settings.reset_gameplay": "Reset to Defaults", "hud.settings.view_distance": "View Distance", + "hud.settings.lod_distance": "LoD Distance", "hud.settings.sprites_view_distance": "Sprites View Distance", "hud.settings.figures_view_distance": "Entities View Distance", "hud.settings.maximum_fps": "Maximum FPS", diff --git a/client/src/lib.rs b/client/src/lib.rs index a9a18f2b92..0c8360fe8f 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -35,10 +35,12 @@ use common::{ event::{EventBus, LocalEvent}, grid::Grid, link::Is, + lod, mounting::Rider, outcome::Outcome, recipe::RecipeBook, resources::{PlayerEntity, TimeOfDay}, + spiral::Spiral2d, terrain::{ block::Block, map::MapConfig, neighbors, BiomeKind, SitesKind, SpriteKind, TerrainChunk, TerrainChunkSize, @@ -46,8 +48,6 @@ use common::{ trade::{PendingTrade, SitePrices, TradeAction, TradeId, TradeResult}, uid::{Uid, UidAllocator}, vol::RectVolSize, - spiral::Spiral2d, - lod, }; use common_base::{prof_span, span}; use common_net::{ @@ -206,7 +206,7 @@ pub struct Client { state: State, view_distance: Option, - lod_distance: u32, + lod_distance: f32, // TODO: move into voxygen loaded_distance: f32, @@ -658,7 +658,7 @@ impl Client { tick: 0, state, view_distance: None, - lod_distance: 4, // TODO: Make configurable + lod_distance: 2.0, // TODO: Make configurable loaded_distance: 0.0, pending_chunks: HashMap::new(), @@ -890,6 +890,11 @@ impl Client { self.send_msg(ClientGeneral::SetViewDistance(view_distance)); } + pub fn set_lod_distance(&mut self, lod_distance: u32) { + let lod_distance = lod_distance.max(1).min(1000) as f32 / lod::ZONE_SIZE as f32; + self.lod_distance = lod_distance; + } + pub fn use_slot(&mut self, slot: Slot) { self.control_action(ControlAction::InventoryAction(InventoryAction::Use(slot))) } @@ -1004,9 +1009,7 @@ impl Client { &self.available_recipes } - pub fn lod_zones(&self) -> &HashMap, lod::Zone> { - &self.lod_zones - } + pub fn lod_zones(&self) -> &HashMap, lod::Zone> { &self.lod_zones } /// Returns whether the specified recipe can be crafted and the sprite, if /// any, that is required to do so. @@ -1728,11 +1731,15 @@ impl Client { let lod_zone = pos.0.xy().map(|e| lod::from_wpos(e as i32)); // Request LoD zones that are in range - if self.lod_last_requested.map_or(true, |i| i.elapsed() > Duration::from_secs(5)) { + if self + .lod_last_requested + .map_or(true, |i| i.elapsed() > Duration::from_secs(5)) + { if let Some(rpos) = Spiral2d::new() - .take((1 + self.lod_distance * 2).pow(2) as usize) + .take((1 + self.lod_distance.ceil() as i32 * 2).pow(2) as usize) .filter(|rpos| !self.lod_zones.contains_key(&(lod_zone + *rpos))) .min_by_key(|rpos| rpos.magnitude_squared()) + .filter(|rpos| rpos.map(|e| e as f32).magnitude() < self.lod_distance) { self.send_msg_err(ClientGeneral::LodZoneRequest { key: lod_zone + rpos, @@ -1742,7 +1749,10 @@ impl Client { } // Cull LoD zones out of range - self.lod_zones.retain(|p, _| (*p - lod_zone).magnitude_squared() < (self.lod_distance as i32 + 1).pow(2)); + self.lod_zones.retain(|p, _| { + (*p - lod_zone).map(|e| e as f32).magnitude_squared() + < (self.lod_distance + 1.0).powi(2) + }); } Ok(()) diff --git a/common/net/src/msg/server.rs b/common/net/src/msg/server.rs index d8174d2d7c..c581874345 100644 --- a/common/net/src/msg/server.rs +++ b/common/net/src/msg/server.rs @@ -7,13 +7,13 @@ use common::{ calendar::Calendar, character::{self, CharacterItem}, comp::{self, invite::InviteKind, item::MaterialStatManifest}, + lod, outcome::Outcome, recipe::RecipeBook, resources::TimeOfDay, terrain::{Block, TerrainChunk, TerrainChunkMeta, TerrainChunkSize}, trade::{PendingTrade, SitePrices, TradeId, TradeResult}, uid::Uid, - lod, }; use hashbrown::HashMap; use serde::{Deserialize, Serialize}; diff --git a/common/src/lod.rs b/common/src/lod.rs index 636bc86b05..123ff87277 100644 --- a/common/src/lod.rs +++ b/common/src/lod.rs @@ -1,10 +1,7 @@ -use vek::*; -use serde::{Serialize, Deserialize}; +use crate::{terrain::TerrainChunkSize, vol::RectVolSize}; +use serde::{Deserialize, Serialize}; use strum::EnumIter; -use crate::{ - terrain::TerrainChunkSize, - vol::RectVolSize, -}; +use vek::*; // In chunks pub const ZONE_SIZE: u32 = 32; @@ -35,9 +32,7 @@ pub struct Zone { pub objects: Vec, } -pub fn to_wpos(wpos: i32) -> i32 { - wpos * (TerrainChunkSize::RECT_SIZE.x * ZONE_SIZE) as i32 -} +pub fn to_wpos(wpos: i32) -> i32 { wpos * (TerrainChunkSize::RECT_SIZE.x * ZONE_SIZE) as i32 } pub fn from_wpos(zone_pos: i32) -> i32 { zone_pos.div_euclid((TerrainChunkSize::RECT_SIZE.x * ZONE_SIZE) as i32) diff --git a/server/src/lib.rs b/server/src/lib.rs index ad4fb55e9c..7fb2073d81 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -450,7 +450,9 @@ impl Server { // Insert the world into the ECS (todo: Maybe not an Arc?) let world = Arc::new(world); state.ecs_mut().insert(Arc::clone(&world)); - state.ecs_mut().insert(lod::Lod::from_world(&world, index.as_index_ref())); + state + .ecs_mut() + .insert(lod::Lod::from_world(&world, index.as_index_ref())); state.ecs_mut().insert(index.clone()); // Set starting time for the server. diff --git a/server/src/lod.rs b/server/src/lod.rs index 9a7a02f8ed..8cfb1019ac 100644 --- a/server/src/lod.rs +++ b/server/src/lod.rs @@ -1,7 +1,7 @@ use common::lod; -use world::World; use hashbrown::HashMap; use vek::*; +use world::World; static EMPTY_ZONE: lod::Zone = lod::Zone { objects: Vec::new(), diff --git a/server/src/sys/msg/terrain.rs b/server/src/sys/msg/terrain.rs index d806e36ca9..ab1ffec448 100644 --- a/server/src/sys/msg/terrain.rs +++ b/server/src/sys/msg/terrain.rs @@ -1,4 +1,6 @@ -use crate::{client::Client, lod::Lod, metrics::NetworkRequestMetrics, presence::Presence, ChunkRequest}; +use crate::{ + client::Client, lod::Lod, metrics::NetworkRequestMetrics, presence::Presence, ChunkRequest, +}; use common::{ comp::Pos, event::{EventBus, ServerEvent}, diff --git a/voxygen/src/hud/settings_window/video.rs b/voxygen/src/hud/settings_window/video.rs index 0d85de8537..c0d227f82d 100644 --- a/voxygen/src/hud/settings_window/video.rs +++ b/voxygen/src/hud/settings_window/video.rs @@ -39,6 +39,9 @@ widget_ids! { vd_slider, vd_text, vd_value, + ld_slider, + ld_text, + ld_value, lod_detail_slider, lod_detail_text, lod_detail_value, @@ -280,8 +283,6 @@ impl<'a> Widget for Video<'a> { if let Some(new_val) = ImageSlider::discrete( self.global_state.settings.graphics.view_distance, 1, - // FIXME: Move back to 64 once we support multiple texture atlases, or figure out a - // way to increase the size of the terrain atlas. 65, self.imgs.slider_indicator, self.imgs.slider, @@ -306,9 +307,44 @@ impl<'a> Widget for Video<'a> { .color(TEXT_COLOR) .set(state.ids.vd_value, ui); + // LoD Distance + Text::new(self.localized_strings.get("hud.settings.lod_distance")) + .down_from(state.ids.vd_slider, 10.0) + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.ld_text, ui); + + if let Some(new_val) = ImageSlider::discrete( + self.global_state.settings.graphics.lod_distance, + 0, + 250, + self.imgs.slider_indicator, + self.imgs.slider, + ) + .w_h(104.0, 22.0) + .down_from(state.ids.ld_text, 8.0) + .track_breadth(12.0) + .slider_length(10.0) + .pad_track((5.0, 5.0)) + .set(state.ids.ld_slider, ui) + { + events.push(GraphicsChange::AdjustLodDistance(new_val)); + } + + Text::new(&format!( + "{}", + self.global_state.settings.graphics.lod_distance + )) + .right_from(state.ids.ld_slider, 8.0) + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.ld_value, ui); + // Max FPS Text::new(self.localized_strings.get("hud.settings.maximum_fps")) - .down_from(state.ids.vd_slider, 10.0) + .down_from(state.ids.ld_slider, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) @@ -343,7 +379,7 @@ impl<'a> Widget for Video<'a> { // Max Background FPS Text::new(self.localized_strings.get("hud.settings.background_fps")) - .down_from(state.ids.vd_slider, 10.0) + .down_from(state.ids.ld_slider, 10.0) .right_from(state.ids.max_fps_value, 30.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) @@ -391,7 +427,7 @@ impl<'a> Widget for Video<'a> { // Present Mode Text::new(self.localized_strings.get("hud.settings.present_mode")) - .down_from(state.ids.vd_slider, 10.0) + .down_from(state.ids.ld_slider, 10.0) .right_from(state.ids.max_background_fps_value, 30.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 81adaa28b4..4eee800bfc 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -26,6 +26,7 @@ pub use self::{ Locals as FigureLocals, }, fluid::Vertex as FluidVertex, + lod_object::{Instance as LodObjectInstance, Vertex as LodObjectVertex}, lod_terrain::{LodData, Vertex as LodTerrainVertex}, particle::{Instance as ParticleInstance, Vertex as ParticleVertex}, postprocess::Locals as PostProcessLocals, @@ -35,10 +36,6 @@ pub use self::{ Instance as SpriteInstance, SpriteGlobalsBindGroup, SpriteVerts, Vertex as SpriteVertex, VERT_PAGE_SIZE as SPRITE_VERT_PAGE_SIZE, }, - lod_object::{ - Instance as LodObjectInstance, - Vertex as LodObjectVertex, - }, terrain::{Locals as TerrainLocals, TerrainLayout, Vertex as TerrainVertex}, trail::Vertex as TrailVertex, ui::{ diff --git a/voxygen/src/render/pipelines/lod_object.rs b/voxygen/src/render/pipelines/lod_object.rs index 2276c0a90d..b6a40a6d1e 100644 --- a/voxygen/src/render/pipelines/lod_object.rs +++ b/voxygen/src/render/pipelines/lod_object.rs @@ -37,11 +37,12 @@ impl Vertex { } // impl Default for Vertex { -// fn default() -> Self { Self::new(Vec2::zero(), Vec3::zero(), Vec3::zero()) } -// } +// fn default() -> Self { Self::new(Vec2::zero(), Vec3::zero(), +// Vec3::zero()) } } impl VertexTrait for Vertex { - const QUADS_INDEX: Option = None;//Some(wgpu::IndexFormat::Uint16); + const QUADS_INDEX: Option = None; + //Some(wgpu::IndexFormat::Uint16); const STRIDE: wgpu::BufferAddress = mem::size_of::() as wgpu::BufferAddress; } @@ -53,10 +54,7 @@ pub struct Instance { } impl Instance { - pub fn new( - inst_pos: Vec3, - flags: common::lod::Flags, - ) -> Self { + pub fn new(inst_pos: Vec3, flags: common::lod::Flags) -> Self { Self { inst_pos: inst_pos.into_array(), flags: flags.bits() as u32, @@ -77,8 +75,8 @@ impl Instance { } // impl Default for Instance { -// fn default() -> Self { Self::new(Mat4::identity(), 0.0, 0.0, Vec3::zero(), 0, 1.0, 0.0, 0) } -// } +// fn default() -> Self { Self::new(Mat4::identity(), 0.0, 0.0, +// Vec3::zero(), 0, 1.0, 0.0, 0) } } // TODO: ColLightsWrapper instead? pub struct Locals; @@ -100,10 +98,7 @@ impl LodObjectPipeline { device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("LoD object pipeline layout"), push_constant_ranges: &[], - bind_group_layouts: &[ - &global_layout.globals, - &global_layout.shadow_textures, - ], + bind_group_layouts: &[&global_layout.globals, &global_layout.shadow_textures], }); let samples = match aa_mode { diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index f3d6096af3..33dd38667e 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -21,7 +21,7 @@ use super::{ mesh::Mesh, model::{DynamicModel, Model}, pipelines::{ - blit, bloom, clouds, debug, figure, postprocess, shadow, sprite, lod_object, terrain, ui, + blit, bloom, clouds, debug, figure, lod_object, postprocess, shadow, sprite, terrain, ui, GlobalsBindGroup, GlobalsLayouts, ShadowTexturesBindGroup, }, texture::Texture, diff --git a/voxygen/src/render/renderer/binding.rs b/voxygen/src/render/renderer/binding.rs index 5e4074a58f..3730886d0b 100644 --- a/voxygen/src/render/renderer/binding.rs +++ b/voxygen/src/render/renderer/binding.rs @@ -1,8 +1,8 @@ use super::{ super::{ pipelines::{ - debug, figure, lod_terrain, shadow, sprite, lod_object, terrain, ui, ColLights, GlobalModel, - GlobalsBindGroup, + debug, figure, lod_object, lod_terrain, shadow, sprite, terrain, ui, ColLights, + GlobalModel, GlobalsBindGroup, }, texture::Texture, }, diff --git a/voxygen/src/render/renderer/drawer.rs b/voxygen/src/render/renderer/drawer.rs index 1bf50519f5..f7cdfa8e8e 100644 --- a/voxygen/src/render/renderer/drawer.rs +++ b/voxygen/src/render/renderer/drawer.rs @@ -4,8 +4,9 @@ use super::{ instances::Instances, model::{DynamicModel, Model, SubModel}, pipelines::{ - blit, bloom, clouds, debug, figure, fluid, lod_terrain, particle, shadow, skybox, - sprite, lod_object, terrain, trail, ui, ColLights, GlobalsBindGroup, ShadowTexturesBindGroup, + blit, bloom, clouds, debug, figure, fluid, lod_object, lod_terrain, particle, shadow, + skybox, sprite, terrain, trail, ui, ColLights, GlobalsBindGroup, + ShadowTexturesBindGroup, }, }, Renderer, ShadowMap, ShadowMapRenderer, @@ -764,9 +765,7 @@ impl<'pass> FirstPassDrawer<'pass> { } } - pub fn draw_lod_objects<'data: 'pass>( - &mut self, - ) -> LodObjectDrawer<'_, 'pass> { + pub fn draw_lod_objects<'data: 'pass>(&mut self) -> LodObjectDrawer<'_, 'pass> { let mut render_pass = self.render_pass.scope("lod objects", self.borrow.device); render_pass.set_pipeline(&self.pipelines.lod_object.pipeline); @@ -934,10 +933,8 @@ impl<'pass_ref, 'pass: 'pass_ref> LodObjectDrawer<'pass_ref, 'pass> { self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); self.render_pass .set_vertex_buffer(1, instances.buf().slice(..)); - self.render_pass.draw( - 0..model.len() as u32, - 0..instances.count() as u32, - ); + self.render_pass + .draw(0..model.len() as u32, 0..instances.count() as u32); } } diff --git a/voxygen/src/render/renderer/pipeline_creation.rs b/voxygen/src/render/renderer/pipeline_creation.rs index de250809a2..7ce0d19ff6 100644 --- a/voxygen/src/render/renderer/pipeline_creation.rs +++ b/voxygen/src/render/renderer/pipeline_creation.rs @@ -1,8 +1,8 @@ use super::{ super::{ pipelines::{ - blit, bloom, clouds, debug, figure, fluid, lod_terrain, particle, postprocess, shadow, - skybox, sprite, lod_object, terrain, trail, ui, + blit, bloom, clouds, debug, figure, fluid, lod_object, lod_terrain, particle, + postprocess, shadow, skybox, sprite, terrain, trail, ui, }, AaMode, BloomMode, CloudMode, FluidMode, LightingMode, PipelineModes, RenderError, ShadowMode, @@ -763,7 +763,10 @@ fn create_ingame_and_shadow_pipelines( ((debug, (skybox, figure)), (terrain, (fluid, bloom))), ((sprite, particle), (lod_terrain, (clouds, trail))), ), - (((postprocess, point_shadow), (terrain_directed_shadow, figure_directed_shadow)), lod_object), + ( + ((postprocess, point_shadow), (terrain_directed_shadow, figure_directed_shadow)), + lod_object, + ), ) = pool.join( || pool.join(|| pool.join(j1, j2), || pool.join(j3, j4)), || pool.join(|| pool.join(j5, j6), j7), diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index bf4b4dd3c3..ec82b6be4e 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -1,19 +1,20 @@ use crate::{ render::{ pipelines::lod_terrain::{LodData, Vertex}, - FirstPassDrawer, LodTerrainVertex, LodObjectVertex, Mesh, Model, Quad, Renderer, Instances, LodObjectInstance, Tri, + FirstPassDrawer, Instances, LodObjectInstance, LodObjectVertex, LodTerrainVertex, Mesh, + Model, Quad, Renderer, Tri, }, scene::GlobalModel, settings::Settings, }; -use hashbrown::HashMap; use client::Client; use common::{ - assets::{ObjAsset, AssetExt}, + assets::{AssetExt, ObjAsset}, + lod, spiral::Spiral2d, util::srgba_to_linear, - lod, }; +use hashbrown::HashMap; use vek::*; pub struct Lod { @@ -31,11 +32,7 @@ pub fn water_color() -> Rgba { } impl Lod { - pub fn new( - renderer: &mut Renderer, - client: &Client, - settings: &Settings, - ) -> Self { + pub fn new(renderer: &mut Renderer, client: &Client, settings: &Settings) -> Self { let data = LodData::new( renderer, client.world_data().chunk_size().as_(), @@ -44,16 +41,22 @@ impl Lod { client.world_data().lod_horizon.raw(), settings.graphics.lod_detail.max(100).min(2500), /* TODO: figure out how we want to do this without color borders? - * water_color().into_array().into(), */ + * water_color().into_array().into(), */ ); Self { zone_objects: HashMap::new(), object_data: [ - (lod::ObjectKind::Oak, make_lod_object("oak", renderer, &data)), - (lod::ObjectKind::Pine, make_lod_object("pine", renderer, &data)), + ( + lod::ObjectKind::Oak, + make_lod_object("oak", renderer, &data), + ), + ( + lod::ObjectKind::Pine, + make_lod_object("pine", renderer, &data), + ), ] - .into_iter() - .collect(), + .into_iter() + .collect(), model: None, data, } @@ -98,13 +101,19 @@ impl Lod { objects .into_iter() .map(|(kind, instances)| { - (kind, renderer.create_instances(&instances).expect("Renderer error?!")) + ( + kind, + renderer + .create_instances(&instances) + .expect("Renderer error?!"), + ) }) .collect() }); } - self.zone_objects.retain(|p, _| client.lod_zones().contains_key(p)); + self.zone_objects + .retain(|p, _| client.lod_zones().contains_key(p)); } pub fn render<'a>(&'a self, drawer: &mut FirstPassDrawer<'a>) { @@ -159,19 +168,20 @@ fn make_lod_object( ) -> Model { let model = ObjAsset::load_expect(&format!("voxygen.lod.{}", name)); let mesh = model - .read().0 + .read() + .0 .triangles() .map(|vs| { - let [a, b, c] = vs.map(|v| LodObjectVertex::new( - v.position().into(), - v.normal().unwrap_or([0.0, 0.0, 1.0]).into(), - Vec3::broadcast(1.0), - //v.color().unwrap_or([1.0; 3]).into(), - )); + let [a, b, c] = vs.map(|v| { + LodObjectVertex::new( + v.position().into(), + v.normal().unwrap_or([0.0, 0.0, 1.0]).into(), + Vec3::broadcast(1.0), + //v.color().unwrap_or([1.0; 3]).into(), + ) + }); Tri::new(a, b, c) }) .collect(); - renderer - .create_model(&mesh) - .expect("Mesh was empty!") + renderer.create_model(&mesh).expect("Mesh was empty!") } diff --git a/voxygen/src/session/settings_change.rs b/voxygen/src/session/settings_change.rs index 79608fab23..0af724f2aa 100644 --- a/voxygen/src/session/settings_change.rs +++ b/voxygen/src/session/settings_change.rs @@ -69,6 +69,7 @@ pub enum Gameplay { #[derive(Clone)] pub enum Graphics { AdjustViewDistance(u32), + AdjustLodDistance(u32), AdjustLodDetail(u32), AdjustSpriteRenderDistance(u32), AdjustFigureLoDRenderDistance(u32), @@ -344,6 +345,14 @@ impl SettingsChange { settings.graphics.view_distance = view_distance; }, + Graphics::AdjustLodDistance(lod_distance) => { + session_state + .client + .borrow_mut() + .set_lod_distance(lod_distance); + + settings.graphics.lod_distance = lod_distance; + }, Graphics::AdjustLodDetail(lod_detail) => { session_state.scene.lod.set_detail(lod_detail); diff --git a/voxygen/src/settings/graphics.rs b/voxygen/src/settings/graphics.rs index 5c9b8b5f4a..08079e9fe7 100644 --- a/voxygen/src/settings/graphics.rs +++ b/voxygen/src/settings/graphics.rs @@ -30,6 +30,7 @@ impl fmt::Display for Fps { #[serde(default)] pub struct GraphicsSettings { pub view_distance: u32, + pub lod_distance: u32, pub sprite_render_distance: u32, pub particles_enabled: bool, pub lossy_terrain_compression: bool, @@ -51,6 +52,7 @@ impl Default for GraphicsSettings { fn default() -> Self { Self { view_distance: 10, + lod_distance: 100, sprite_render_distance: 100, particles_enabled: true, lossy_terrain_compression: false, diff --git a/world/src/layer/tree.rs b/world/src/layer/tree.rs index d26c4e03e8..73fca950d4 100644 --- a/world/src/layer/tree.rs +++ b/world/src/layer/tree.rs @@ -3,8 +3,7 @@ use crate::{ block::block_from_structure, column::ColumnGen, util::{gen_cache::StructureGenCache, RandomPerm, Sampler, UnitChooser}, - Canvas, - ColumnSample, + Canvas, ColumnSample, }; use common::{ assets::AssetHandle, @@ -41,7 +40,7 @@ pub fn tree_valid_at(col: &ColumnSample, seed: u32) -> bool { || col.water_dist.map(|d| d < 8.0).unwrap_or(false) || col.path.map(|(d, _, _, _)| d < 12.0).unwrap_or(false) { - return false + return false; } if ((seed.wrapping_mul(13)) & 0xFF) as f32 / 256.0 > col.tree_density { diff --git a/world/src/lib.rs b/world/src/lib.rs index bcb98fed2e..d91848059a 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -51,12 +51,12 @@ use common::{ assets, calendar::Calendar, generation::{ChunkSupplement, EntityInfo}, + lod, resources::TimeOfDay, terrain::{ Block, BlockKind, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize, TerrainGrid, }, vol::{ReadVol, RectVolSize, WriteVol}, - lod, }; use common_net::msg::{world_msg, WorldMapMsg}; use rand::{prelude::*, Rng}; @@ -467,45 +467,51 @@ impl World { } // Zone coordinates - pub fn get_lod_zone( - &self, - pos: Vec2, - index: IndexRef, - ) -> lod::Zone { + pub fn get_lod_zone(&self, pos: Vec2, index: IndexRef) -> lod::Zone { let min_wpos = pos.map(lod::to_wpos); let max_wpos = (pos + 1).map(lod::to_wpos); let mut objects = Vec::new(); - objects.append(&mut self.sim() - .get_area_trees(min_wpos, max_wpos) - .filter_map(|attr| { - ColumnGen::new(self.sim()).get((attr.pos, index, self.sim().calendar.as_ref())) - .filter(|col| layer::tree::tree_valid_at(col, attr.seed)) - .zip(Some(attr)) - }) - .filter_map(|(col, tree)| Some(lod::Object { - kind: match tree.forest_kind { - all::ForestKind::Oak => lod::ObjectKind::Oak, - all::ForestKind::Pine - | all::ForestKind::Frostpine=> lod::ObjectKind::Pine, - _ => lod::ObjectKind::Oak, - }, - pos: { - let rpos = tree.pos - min_wpos; - if rpos.is_any_negative() { - return None - } else { - rpos - .map(|e| e as u16) - .with_z(self.sim().get_alt_approx(tree.pos).unwrap_or(0.0) as u16) - } - }, - flags: lod::Flags::empty() - | if col.snow_cover { lod::Flags::SNOW_COVERED } else { lod::Flags::empty() } - , - })) - .collect()); + objects.append( + &mut self + .sim() + .get_area_trees(min_wpos, max_wpos) + .filter_map(|attr| { + ColumnGen::new(self.sim()) + .get((attr.pos, index, self.sim().calendar.as_ref())) + .filter(|col| layer::tree::tree_valid_at(col, attr.seed)) + .zip(Some(attr)) + }) + .filter_map(|(col, tree)| { + Some(lod::Object { + kind: match tree.forest_kind { + all::ForestKind::Oak => lod::ObjectKind::Oak, + all::ForestKind::Pine | all::ForestKind::Frostpine => { + lod::ObjectKind::Pine + }, + _ => lod::ObjectKind::Oak, + }, + pos: { + let rpos = tree.pos - min_wpos; + if rpos.is_any_negative() { + return None; + } else { + rpos.map(|e| e as u16).with_z( + self.sim().get_alt_approx(tree.pos).unwrap_or(0.0) as u16, + ) + } + }, + flags: lod::Flags::empty() + | if col.snow_cover { + lod::Flags::SNOW_COVERED + } else { + lod::Flags::empty() + }, + }) + }) + .collect(), + ); lod::Zone { objects } } diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index 592046c8e2..aef99119db 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -2150,7 +2150,11 @@ impl WorldSim { }) } - pub fn get_area_trees(&self, wpos_min: Vec2, wpos_max: Vec2) -> impl ParallelIterator + '_ { + pub fn get_area_trees( + &self, + wpos_min: Vec2, + wpos_max: Vec2, + ) -> impl ParallelIterator + '_ { self.gen_ctx .structure_gen .par_iter(wpos_min, wpos_max) diff --git a/world/src/util/structure.rs b/world/src/util/structure.rs index be3b6d1aee..2b7b8bfa1a 100644 --- a/world/src/util/structure.rs +++ b/world/src/util/structure.rs @@ -102,21 +102,19 @@ impl StructureGen2d { let x_field = self.x_field; let y_field = self.y_field; let seed_field = self.seed_field; - (0..len) - .into_par_iter() - .map(move |xy| { - let index = min_index + Vec2::new((xy % xlen as u64) as i32, (xy / xlen as u64) as i32); - Self::index_to_sample_internal( - freq, - freq_offset, - spread, - spread_mul, - x_field, - y_field, - seed_field, - index, - ) - }) + (0..len).into_par_iter().map(move |xy| { + let index = min_index + Vec2::new((xy % xlen as u64) as i32, (xy / xlen as u64) as i32); + Self::index_to_sample_internal( + freq, + freq_offset, + spread, + spread_mul, + x_field, + y_field, + seed_field, + index, + ) + }) } } From 06300bc75fb94743b89187d995afcae6d472b373 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 10 May 2022 12:56:24 +0100 Subject: [PATCH 20/31] Updated changelog --- CHANGELOG.md | 2 ++ voxygen/src/render/pipelines/lod_object.rs | 7 +------ voxygen/src/render/renderer.rs | 2 +- voxygen/src/render/renderer/binding.rs | 4 ++-- voxygen/src/render/renderer/drawer.rs | 2 +- voxygen/src/scene/lod.rs | 21 +++++---------------- 6 files changed, 12 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a662753018..df637bcfd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added + - Waypoints saved between sessions and shared with group members. - New rocks - Weapon trails @@ -19,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - NPCs now have rudimentary personalities - Added Belarusian translation - Add FOV check for agents scanning for targets they are hostile to +- Implemented an LoD system for objects, making trees visible far beyond the view distance ### Changed diff --git a/voxygen/src/render/pipelines/lod_object.rs b/voxygen/src/render/pipelines/lod_object.rs index b6a40a6d1e..6f2b2716b3 100644 --- a/voxygen/src/render/pipelines/lod_object.rs +++ b/voxygen/src/render/pipelines/lod_object.rs @@ -1,9 +1,4 @@ -use super::{ - super::{ - buffer::Buffer, AaMode, GlobalsLayouts, Mesh, TerrainLayout, Texture, Vertex as VertexTrait, - }, - lod_terrain, GlobalModel, -}; +use super::super::{AaMode, GlobalsLayouts, Vertex as VertexTrait}; use bytemuck::{Pod, Zeroable}; use std::mem; use vek::*; diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 33dd38667e..4f8a17baf2 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -21,7 +21,7 @@ use super::{ mesh::Mesh, model::{DynamicModel, Model}, pipelines::{ - blit, bloom, clouds, debug, figure, lod_object, postprocess, shadow, sprite, terrain, ui, + blit, bloom, clouds, debug, figure, postprocess, shadow, sprite, terrain, ui, GlobalsBindGroup, GlobalsLayouts, ShadowTexturesBindGroup, }, texture::Texture, diff --git a/voxygen/src/render/renderer/binding.rs b/voxygen/src/render/renderer/binding.rs index 3730886d0b..f42808c0a8 100644 --- a/voxygen/src/render/renderer/binding.rs +++ b/voxygen/src/render/renderer/binding.rs @@ -1,8 +1,8 @@ use super::{ super::{ pipelines::{ - debug, figure, lod_object, lod_terrain, shadow, sprite, terrain, ui, ColLights, - GlobalModel, GlobalsBindGroup, + debug, figure, lod_terrain, shadow, sprite, terrain, ui, ColLights, GlobalModel, + GlobalsBindGroup, }, texture::Texture, }, diff --git a/voxygen/src/render/renderer/drawer.rs b/voxygen/src/render/renderer/drawer.rs index f7cdfa8e8e..4d0912c25c 100644 --- a/voxygen/src/render/renderer/drawer.rs +++ b/voxygen/src/render/renderer/drawer.rs @@ -765,7 +765,7 @@ impl<'pass> FirstPassDrawer<'pass> { } } - pub fn draw_lod_objects<'data: 'pass>(&mut self) -> LodObjectDrawer<'_, 'pass> { + pub fn draw_lod_objects(&mut self) -> LodObjectDrawer<'_, 'pass> { let mut render_pass = self.render_pass.scope("lod objects", self.borrow.device); render_pass.set_pipeline(&self.pipelines.lod_object.pipeline); diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index ec82b6be4e..bebbcc202b 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -4,7 +4,6 @@ use crate::{ FirstPassDrawer, Instances, LodObjectInstance, LodObjectVertex, LodTerrainVertex, Mesh, Model, Quad, Renderer, Tri, }, - scene::GlobalModel, settings::Settings, }; use client::Client; @@ -44,21 +43,15 @@ impl Lod { * water_color().into_array().into(), */ ); Self { + model: None, + data, zone_objects: HashMap::new(), object_data: [ - ( - lod::ObjectKind::Oak, - make_lod_object("oak", renderer, &data), - ), - ( - lod::ObjectKind::Pine, - make_lod_object("pine", renderer, &data), - ), + (lod::ObjectKind::Oak, make_lod_object("oak", renderer)), + (lod::ObjectKind::Pine, make_lod_object("pine", renderer)), ] .into_iter() .collect(), - model: None, - data, } } @@ -161,11 +154,7 @@ fn create_lod_terrain_mesh(detail: u32) -> Mesh { .collect() } -fn make_lod_object( - name: &str, - renderer: &mut Renderer, - lod_data: &LodData, -) -> Model { +fn make_lod_object(name: &str, renderer: &mut Renderer) -> Model { let model = ObjAsset::load_expect(&format!("voxygen.lod.{}", name)); let mesh = model .read() From 19d19df63cbb68701599d728b54c594eee6b6aff Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 10 May 2022 15:43:53 +0100 Subject: [PATCH 21/31] Flush LoD distance on login --- voxygen/src/menu/char_selection/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 98fc90ca56..cc70cc635d 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -135,8 +135,9 @@ impl PlayState for CharSelectionState { { let mut c = self.client.borrow_mut(); c.request_character(character_id); - //Send our ViewDistance + //Send our ViewDistance and LoD distance c.set_view_distance(global_state.settings.graphics.view_distance); + c.set_lod_distance(global_state.settings.graphics.lod_distance); } return PlayStateResult::Switch(Box::new(SessionState::new( global_state, From c7e51a6c5913eb0da9ae190bb0cc29af0d5195ca Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 10 May 2022 16:21:14 +0100 Subject: [PATCH 22/31] Added frustum culling for LoD objects --- voxygen/src/hud/settings_window/video.rs | 2 +- voxygen/src/scene/lod.rs | 81 +++++++++++++++++++++--- voxygen/src/scene/mod.rs | 2 +- 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/voxygen/src/hud/settings_window/video.rs b/voxygen/src/hud/settings_window/video.rs index c0d227f82d..3bf10af9ea 100644 --- a/voxygen/src/hud/settings_window/video.rs +++ b/voxygen/src/hud/settings_window/video.rs @@ -318,7 +318,7 @@ impl<'a> Widget for Video<'a> { if let Some(new_val) = ImageSlider::discrete( self.global_state.settings.graphics.lod_distance, 0, - 250, + 500, self.imgs.slider_indicator, self.imgs.slider, ) diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index bebbcc202b..34c5e89635 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -4,6 +4,7 @@ use crate::{ FirstPassDrawer, Instances, LodObjectInstance, LodObjectVertex, LodTerrainVertex, Mesh, Model, Quad, Renderer, Tri, }, + scene::{camera, Camera}, settings::Settings, }; use client::Client; @@ -14,13 +15,26 @@ use common::{ util::srgba_to_linear, }; use hashbrown::HashMap; +use std::ops::Range; +use treeculler::{BVol, Frustum, AABB}; use vek::*; +// For culling +const MAX_OBJECT_RADIUS: i32 = 64; + +struct ObjectGroup { + instances: Instances, + // None implies no instances + z_range: Option>, + frustum_last_plane_index: u8, + visible: bool, +} + pub struct Lod { model: Option<(u32, Model)>, data: LodData, - zone_objects: HashMap, HashMap>>, + zone_objects: HashMap, HashMap>, object_data: HashMap>, } @@ -62,7 +76,13 @@ impl Lod { self.data.tgt_detail = (detail - detail % 2).max(100).min(2500); } - pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) { + pub fn maintain( + &mut self, + renderer: &mut Renderer, + client: &Client, + focus_pos: Vec3, + camera: &Camera, + ) { // Update LoD terrain mesh according to detail if self .model @@ -78,14 +98,21 @@ impl Lod { )); } - // Maintain LoD object instances + // Create new LoD groups new a new zone has loaded for (p, zone) in client.lod_zones() { self.zone_objects.entry(*p).or_insert_with(|| { let mut objects = HashMap::<_, Vec<_>>::new(); + let mut z_range = None; for object in zone.objects.iter() { let pos = p.map(|e| lod::to_wpos(e) as f32).with_z(0.0) + object.pos.map(|e| e as f32) + Vec2::broadcast(0.5).with_z(0.0); + z_range = Some(z_range.map_or( + pos.z as i32..pos.z as i32, + |z_range: Range| { + z_range.start.min(pos.z as i32)..z_range.end.max(pos.z as i32) + }, + )); objects .entry(object.kind) .or_default() @@ -94,19 +121,53 @@ impl Lod { objects .into_iter() .map(|(kind, instances)| { - ( - kind, - renderer + (kind, ObjectGroup { + instances: renderer .create_instances(&instances) .expect("Renderer error?!"), - ) + z_range: z_range.clone(), + frustum_last_plane_index: 0, + visible: false, + }) }) .collect() }); } + // Remove zones that are unloaded self.zone_objects .retain(|p, _| client.lod_zones().contains_key(p)); + + // Determine visiblity of zones based on view frustum + let camera::Dependents { + view_mat, + proj_mat_treeculler, + .. + } = camera.dependents(); + let focus_off = focus_pos.map(|e| e.trunc()); + let frustum = Frustum::from_modelview_projection( + (proj_mat_treeculler * view_mat * Mat4::translation_3d(-focus_off)).into_col_arrays(), + ); + for (pos, groups) in &mut self.zone_objects { + for group in groups.values_mut() { + if let Some(z_range) = &group.z_range { + let group_min = (pos.map(lod::to_wpos).with_z(z_range.start) + - MAX_OBJECT_RADIUS) + .map(|e| e as f32); + let group_max = ((pos + 1).map(lod::to_wpos).with_z(z_range.end) + + MAX_OBJECT_RADIUS) + .map(|e| e as f32); + let (in_frustum, last_plane_index) = + AABB::new(group_min.into_array(), group_max.into_array()) + .coherent_test_against_frustum( + &frustum, + group.frustum_last_plane_index, + ); + group.visible = in_frustum; + group.frustum_last_plane_index = last_plane_index; + } + } + } } pub fn render<'a>(&'a self, drawer: &mut FirstPassDrawer<'a>) { @@ -116,10 +177,10 @@ impl Lod { // Draw LoD objects let mut drawer = drawer.draw_lod_objects(); - for objects in self.zone_objects.values() { - for (kind, instances) in objects { + for groups in self.zone_objects.values() { + for (kind, group) in groups.iter().filter(|(_, g)| g.visible) { if let Some(model) = self.object_data.get(kind) { - drawer.draw(model, instances); + drawer.draw(model, &group.instances); } } } diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 846ed21e1c..4e740f8558 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -681,7 +681,7 @@ impl Scene { renderer.update_postprocess_locals(PostProcessLocals::new(proj_mat_inv, view_mat_inv)); // Maintain LoD. - self.lod.maintain(renderer, client); + self.lod.maintain(renderer, client, focus_pos, &self.camera); // Maintain debug shapes self.debug.maintain(renderer); From 7382aab13a6136d1cd5f4e79bc3b5c9969f7feb4 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 10 May 2022 17:12:12 +0100 Subject: [PATCH 23/31] Upped default LoD distance --- assets/voxygen/shaders/lod-object-frag.glsl | 17 +---------------- assets/voxygen/shaders/lod-object-vert.glsl | 1 - common/assets/Cargo.toml | 3 +-- voxygen/src/render/pipelines/lod_object.rs | 5 ----- voxygen/src/settings/graphics.rs | 2 +- 5 files changed, 3 insertions(+), 25 deletions(-) diff --git a/assets/voxygen/shaders/lod-object-frag.glsl b/assets/voxygen/shaders/lod-object-frag.glsl index e065a02e4d..a33f320469 100644 --- a/assets/voxygen/shaders/lod-object-frag.glsl +++ b/assets/voxygen/shaders/lod-object-frag.glsl @@ -104,38 +104,23 @@ void main() { vec3 emitted_light, reflected_light; - // This is a bit of a hack. Because we can't find the volumetric lighting of each particle (they don't talk to the - // CPU) we need to some how find an approximation of how much the sun is blocked. We do this by fading out the sun - // as the particle moves underground. This isn't perfect, but it does at least mean that particles don't look like - // they're exposed to the sun when in dungeons - const float SUN_FADEOUT_DIST = 20.0; - sun_info.block *= clamp((f_pos.z - f_alt) / SUN_FADEOUT_DIST + 1, 0, 1); - // To account for prior saturation. float max_light = 0.0; vec3 cam_attenuation = vec3(1); float fluid_alt = max(f_pos.z + 1, floor(f_alt + 1)); vec3 mu = medium.x == MEDIUM_WATER ? MU_WATER : vec3(0.0); - //#if (FLUID_MODE == FLUID_MODE_SHINY) - // cam_attenuation = - // medium.x == MEDIUM_WATER ? compute_attenuation_point(cam_pos.xyz, view_dir, MU_WATER, fluid_alt, /*cam_pos.z <= fluid_alt ? cam_pos.xyz : f_pos*/f_pos) - // : compute_attenuation_point(f_pos, -view_dir, vec3(0), fluid_alt, /*cam_pos.z <= fluid_alt ? cam_pos.xyz : f_pos*/cam_pos.xyz); - //#endif max_light += get_sun_diffuse2(sun_info, moon_info, voxel_norm, view_dir, f_pos, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, voxel_norm, 1.0, emitted_light, reflected_light); emitted_light *= f_ao; reflected_light *= f_ao; - //max_light += lights_at(f_pos, voxel_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, voxel_norm, 1.0, emitted_light, reflected_light); - vec3 side_color = mix(surf_color, vec3(0.5, 0.6, 1.0), snow_cover); vec3 top_color = mix(surf_color, surf_color * 0.3, 0.5 + snow_cover * 0.5); surf_color = mix(side_color, top_color, pow(fract(model_pos.z * 0.1), 2.0)); surf_color = illuminate(max_light, view_dir, surf_color * emitted_light, surf_color * reflected_light); - // Temporarily disable particle transparency to avoid artifacts - tgt_color = vec4(surf_color, 1.0 /*f_col.a*/); + tgt_color = vec4(surf_color, 1.0); } diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index 12a0c575b4..d5880ecae7 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -53,7 +53,6 @@ void main() { if ((inst_flags & FLAG_SNOW_COVERED) > 0u) { snow_cover = 1.0; - //f_col.rgb = mix(f_col.rgb, vec3(1), pow(max(f_norm.z, 0.0), 0.5)); } else { snow_cover = 0.0; } diff --git a/common/assets/Cargo.toml b/common/assets/Cargo.toml index ac60802103..dea2906e65 100644 --- a/common/assets/Cargo.toml +++ b/common/assets/Cargo.toml @@ -10,8 +10,7 @@ lazy_static = "1.4.0" assets_manager = {version = "0.7", features = ["bincode", "ron", "json"]} ron = { version = "0.7", default-features = false } dot_vox = "4.0" -wavefront = "0.2" -#wavefront = { path = "../../../../wavefront" } +wavefront = "0.2" # TODO: Use vertex-colors branch when we have models that have them image = { version = "0.23.12", default-features = false, features = ["png"] } tracing = "0.1" diff --git a/voxygen/src/render/pipelines/lod_object.rs b/voxygen/src/render/pipelines/lod_object.rs index 6f2b2716b3..fabcad7d18 100644 --- a/voxygen/src/render/pipelines/lod_object.rs +++ b/voxygen/src/render/pipelines/lod_object.rs @@ -31,13 +31,8 @@ impl Vertex { } } -// impl Default for Vertex { -// fn default() -> Self { Self::new(Vec2::zero(), Vec3::zero(), -// Vec3::zero()) } } - impl VertexTrait for Vertex { const QUADS_INDEX: Option = None; - //Some(wgpu::IndexFormat::Uint16); const STRIDE: wgpu::BufferAddress = mem::size_of::() as wgpu::BufferAddress; } diff --git a/voxygen/src/settings/graphics.rs b/voxygen/src/settings/graphics.rs index 08079e9fe7..708821252b 100644 --- a/voxygen/src/settings/graphics.rs +++ b/voxygen/src/settings/graphics.rs @@ -52,7 +52,7 @@ impl Default for GraphicsSettings { fn default() -> Self { Self { view_distance: 10, - lod_distance: 100, + lod_distance: 200, sprite_render_distance: 100, particles_enabled: true, lossy_terrain_compression: false, From d4fd9d2d0eb071c433e1c20339e61f9ca38bb8cf Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 10 May 2022 19:19:46 +0100 Subject: [PATCH 24/31] Added LoD houses --- assets/voxygen/lod/house.obj | 3 ++ assets/voxygen/shaders/lod-object-vert.glsl | 8 ++--- common/src/lod.rs | 3 +- voxygen/src/render/pipelines/lod_object.rs | 11 ++++--- voxygen/src/scene/lod.rs | 11 +++++-- world/src/lib.rs | 34 +++++++++++++++++++-- 6 files changed, 57 insertions(+), 13 deletions(-) create mode 100644 assets/voxygen/lod/house.obj diff --git a/assets/voxygen/lod/house.obj b/assets/voxygen/lod/house.obj new file mode 100644 index 0000000000..08fa1d7126 --- /dev/null +++ b/assets/voxygen/lod/house.obj @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:09998d9d613ff3685914167bd09b93c7e6258d280f6f2b76bd0fdc548a416693 +size 1101 diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index d5880ecae7..fe5027f55d 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -21,7 +21,8 @@ layout(location = 0) in vec3 v_pos; layout(location = 1) in vec3 v_norm; layout(location = 2) in vec3 v_col; layout(location = 3) in vec3 inst_pos; -layout(location = 4) in uint inst_flags; +layout(location = 4) in uvec3 inst_col; +layout(location = 5) in uint inst_flags; const uint FLAG_SNOW_COVERED = 1; @@ -47,9 +48,8 @@ void main() { f_pos.z -= pow(distance(f_pos.xy + focus_off.xy, focus_pos.xy + focus_off.xy) * 0.05, 2); #endif - // Hacky, very bad, 50 is ~ tree height - f_norm = v_norm;//mix(v_norm, vec3(0, 0, 1), clamp(model_pos.z / 50, 0, 1)); - f_col = vec4(vec3(0.02, 0.1, 0.01) * (sin(inst_pos.xyy) * 0.33 + 0.66), 1.0);//vec4(v_col, 1.0); + f_norm = v_norm; + f_col = vec4(vec3(inst_col) * (1.0 / 255.0) * v_col * (sin(inst_pos.xyy) * 0.33 + 0.66), 1.0); if ((inst_flags & FLAG_SNOW_COVERED) > 0u) { snow_cover = 1.0; diff --git a/common/src/lod.rs b/common/src/lod.rs index 123ff87277..e778327351 100644 --- a/common/src/lod.rs +++ b/common/src/lod.rs @@ -18,12 +18,13 @@ bitflags::bitflags! { pub enum ObjectKind { Oak, Pine, + House, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Object { pub kind: ObjectKind, - pub pos: Vec3, + pub pos: Vec3, pub flags: Flags, } diff --git a/voxygen/src/render/pipelines/lod_object.rs b/voxygen/src/render/pipelines/lod_object.rs index fabcad7d18..8e86d9aef9 100644 --- a/voxygen/src/render/pipelines/lod_object.rs +++ b/voxygen/src/render/pipelines/lod_object.rs @@ -12,7 +12,7 @@ pub struct Vertex { } impl Vertex { - pub fn new(pos: Vec3, norm: Vec3, col: Vec3) -> Self { + pub fn new(pos: Vec3, norm: Vec3, col: Rgb) -> Self { Self { pos: pos.into_array(), norm: norm.into_array(), @@ -40,21 +40,24 @@ impl VertexTrait for Vertex { #[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Instance { inst_pos: [f32; 3], + inst_col: [u8; 4], flags: u32, } impl Instance { - pub fn new(inst_pos: Vec3, flags: common::lod::Flags) -> Self { + pub fn new(inst_pos: Vec3, col: Rgb, flags: common::lod::Flags) -> Self { Self { inst_pos: inst_pos.into_array(), + inst_col: Rgba::new(col.r, col.g, col.b, 255).into_array(), flags: flags.bits() as u32, } } fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { - const ATTRIBUTES: [wgpu::VertexAttribute; 2] = wgpu::vertex_attr_array![ + const ATTRIBUTES: [wgpu::VertexAttribute; 3] = wgpu::vertex_attr_array![ 3 => Float32x3, - 4 => Uint32, + 4 => Uint8x4, + 5 => Uint32, ]; wgpu::VertexBufferLayout { array_stride: mem::size_of::() as wgpu::BufferAddress, diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index 34c5e89635..3da3ec4818 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -63,6 +63,7 @@ impl Lod { object_data: [ (lod::ObjectKind::Oak, make_lod_object("oak", renderer)), (lod::ObjectKind::Pine, make_lod_object("pine", renderer)), + (lod::ObjectKind::House, make_lod_object("house", renderer)), ] .into_iter() .collect(), @@ -113,10 +114,16 @@ impl Lod { z_range.start.min(pos.z as i32)..z_range.end.max(pos.z as i32) }, )); + // TODO: Put this somewhere more easily configurable, like a manifest + let color = match object.kind { + lod::ObjectKind::Pine => Rgb::new(0, 25, 12), + lod::ObjectKind::Oak => Rgb::new(13, 50, 5), + lod::ObjectKind::House => Rgb::new(20, 15, 0), + }; objects .entry(object.kind) .or_default() - .push(LodObjectInstance::new(pos, object.flags)); + .push(LodObjectInstance::new(pos, color, object.flags)); } objects .into_iter() @@ -226,7 +233,7 @@ fn make_lod_object(name: &str, renderer: &mut Renderer) -> Model= min && e < max) + .reduce_and() + }) + .filter_map(|(_, site)| match &site.kind { + SiteKind::Refactor(site) => { + Some(site.plots().filter_map(|plot| match &plot.kind { + site2::plot::PlotKind::House(_) => Some(site.tile_wpos(plot.root_tile)), + _ => None, + })) + }, + _ => None, + }) + .flatten() + .map(|wpos2d| lod::Object { + kind: lod::ObjectKind::House, + pos: (wpos2d - min_wpos) + .map(|e| e as i16) + .with_z(self.sim().get_alt_approx(wpos2d).unwrap_or(0.0) as i16), + flags: lod::Flags::empty(), + }), + ); + lod::Zone { objects } } } From 907ba3dcbc239fec53508740731883a974fda153 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 10 May 2022 20:30:48 +0100 Subject: [PATCH 25/31] Added giant trees to LoD --- assets/voxygen/lod/giant_tree.obj | 3 +++ common/src/lod.rs | 1 + voxygen/src/scene/lod.rs | 5 +++++ world/src/lib.rs | 23 +++++++++++++++++++++++ 4 files changed, 32 insertions(+) create mode 100644 assets/voxygen/lod/giant_tree.obj diff --git a/assets/voxygen/lod/giant_tree.obj b/assets/voxygen/lod/giant_tree.obj new file mode 100644 index 0000000000..c429152293 --- /dev/null +++ b/assets/voxygen/lod/giant_tree.obj @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:77aa762b67b93613ae13bcfde413c226f100c46433048655335ce423877fa93f +size 145590 diff --git a/common/src/lod.rs b/common/src/lod.rs index e778327351..67e0ceba1e 100644 --- a/common/src/lod.rs +++ b/common/src/lod.rs @@ -19,6 +19,7 @@ pub enum ObjectKind { Oak, Pine, House, + GiantTree, } #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index 3da3ec4818..8216458d13 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -64,6 +64,10 @@ impl Lod { (lod::ObjectKind::Oak, make_lod_object("oak", renderer)), (lod::ObjectKind::Pine, make_lod_object("pine", renderer)), (lod::ObjectKind::House, make_lod_object("house", renderer)), + ( + lod::ObjectKind::GiantTree, + make_lod_object("giant_tree", renderer), + ), ] .into_iter() .collect(), @@ -119,6 +123,7 @@ impl Lod { lod::ObjectKind::Pine => Rgb::new(0, 25, 12), lod::ObjectKind::Oak => Rgb::new(13, 50, 5), lod::ObjectKind::House => Rgb::new(20, 15, 0), + lod::ObjectKind::GiantTree => Rgb::new(13, 50, 5), }; objects .entry(object.kind) diff --git a/world/src/lib.rs b/world/src/lib.rs index 05d1d2fdaa..82f9807572 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -543,6 +543,29 @@ impl World { }), ); + // Add giant trees + objects.extend( + index + .sites + .iter() + .filter(|(_, site)| { + site.get_origin() + .map2(min_wpos.zip(max_wpos), |e, (min, max)| e >= min && e < max) + .reduce_and() + }) + .filter(|(_, site)| matches!(&site.kind, SiteKind::GiantTree(_))) + .map(|(_, site)| lod::Object { + kind: lod::ObjectKind::GiantTree, + pos: { + let wpos2d = site.get_origin(); + (wpos2d - min_wpos) + .map(|e| e as i16) + .with_z(self.sim().get_alt_approx(wpos2d).unwrap_or(0.0) as i16) + }, + flags: lod::Flags::empty(), + }), + ); + lod::Zone { objects } } } From 5e1f16fb7a616963758d62ee16cf341db7b20f4b Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 11 May 2022 00:15:05 +0100 Subject: [PATCH 26/31] Better tree colours --- assets/voxygen/shaders/lod-object-vert.glsl | 2 +- voxygen/src/scene/lod.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index fe5027f55d..198d92ea01 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -49,7 +49,7 @@ void main() { #endif f_norm = v_norm; - f_col = vec4(vec3(inst_col) * (1.0 / 255.0) * v_col * (sin(inst_pos.xyy) * 0.33 + 0.66), 1.0); + f_col = vec4(vec3(inst_col) * (1.0 / 255.0) * v_col * (hash(inst_pos.xyxy) * 0.35 + 0.65), 1.0); if ((inst_flags & FLAG_SNOW_COVERED) > 0u) { snow_cover = 1.0; diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index 8216458d13..ffe082e179 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -121,9 +121,9 @@ impl Lod { // TODO: Put this somewhere more easily configurable, like a manifest let color = match object.kind { lod::ObjectKind::Pine => Rgb::new(0, 25, 12), - lod::ObjectKind::Oak => Rgb::new(13, 50, 5), + lod::ObjectKind::Oak => Rgb::new(10, 50, 5), lod::ObjectKind::House => Rgb::new(20, 15, 0), - lod::ObjectKind::GiantTree => Rgb::new(13, 50, 5), + lod::ObjectKind::GiantTree => Rgb::new(15, 35, 5), }; objects .entry(object.kind) From 9ac84c0a3ad19d140232c3b3c5c401d9a5f06beb Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 11 May 2022 12:20:42 +0100 Subject: [PATCH 27/31] Improved LoD models --- assets/voxygen/lod/giant_tree.obj | 4 ++-- assets/voxygen/lod/house.obj | 4 ++-- assets/voxygen/lod/pine.blend | 3 --- voxygen/src/scene/lod.rs | 2 +- 4 files changed, 5 insertions(+), 8 deletions(-) delete mode 100644 assets/voxygen/lod/pine.blend diff --git a/assets/voxygen/lod/giant_tree.obj b/assets/voxygen/lod/giant_tree.obj index c429152293..8b7c50a5ab 100644 --- a/assets/voxygen/lod/giant_tree.obj +++ b/assets/voxygen/lod/giant_tree.obj @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:77aa762b67b93613ae13bcfde413c226f100c46433048655335ce423877fa93f -size 145590 +oid sha256:691d7fa7459435ba0acf7e94612203c88dd7af5d8737fce1a6fbba5e20a2d24d +size 197600 diff --git a/assets/voxygen/lod/house.obj b/assets/voxygen/lod/house.obj index 08fa1d7126..f2acb016d5 100644 --- a/assets/voxygen/lod/house.obj +++ b/assets/voxygen/lod/house.obj @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:09998d9d613ff3685914167bd09b93c7e6258d280f6f2b76bd0fdc548a416693 -size 1101 +oid sha256:a8fc436550d5a359c260f6a46f3327795383ab5ffa48305f6d6de87305290a60 +size 1411 diff --git a/assets/voxygen/lod/pine.blend b/assets/voxygen/lod/pine.blend deleted file mode 100644 index 0866832fc6..0000000000 --- a/assets/voxygen/lod/pine.blend +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9709cdeb29fe24ebfffde84fe45e7e63914dcb6ef7123272874d7404a6da7c15 -size 975044 diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index ffe082e179..8efc4b8a77 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -123,7 +123,7 @@ impl Lod { lod::ObjectKind::Pine => Rgb::new(0, 25, 12), lod::ObjectKind::Oak => Rgb::new(10, 50, 5), lod::ObjectKind::House => Rgb::new(20, 15, 0), - lod::ObjectKind::GiantTree => Rgb::new(15, 35, 5), + lod::ObjectKind::GiantTree => Rgb::new(8, 35, 5), }; objects .entry(object.kind) From 894e94bb2cb4bc5fac82d11fabc6f4c0a54e1d5f Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 11 May 2022 13:07:57 +0100 Subject: [PATCH 28/31] Made 0 LoD distance not load anything --- client/src/lib.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 0c8360fe8f..09817eb188 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -658,7 +658,7 @@ impl Client { tick: 0, state, view_distance: None, - lod_distance: 2.0, // TODO: Make configurable + lod_distance: 4.0, // TODO: Make configurable loaded_distance: 0.0, pending_chunks: HashMap::new(), @@ -891,7 +891,7 @@ impl Client { } pub fn set_lod_distance(&mut self, lod_distance: u32) { - let lod_distance = lod_distance.max(1).min(1000) as f32 / lod::ZONE_SIZE as f32; + let lod_distance = lod_distance.max(0).min(1000) as f32 / lod::ZONE_SIZE as f32; self.lod_distance = lod_distance; } @@ -1739,7 +1739,9 @@ impl Client { .take((1 + self.lod_distance.ceil() as i32 * 2).pow(2) as usize) .filter(|rpos| !self.lod_zones.contains_key(&(lod_zone + *rpos))) .min_by_key(|rpos| rpos.magnitude_squared()) - .filter(|rpos| rpos.map(|e| e as f32).magnitude() < self.lod_distance) + .filter(|rpos| { + rpos.map(|e| e as f32).magnitude() < (self.lod_distance - 0.5).max(0.0) + }) { self.send_msg_err(ClientGeneral::LodZoneRequest { key: lod_zone + rpos, @@ -1750,8 +1752,7 @@ impl Client { // Cull LoD zones out of range self.lod_zones.retain(|p, _| { - (*p - lod_zone).map(|e| e as f32).magnitude_squared() - < (self.lod_distance + 1.0).powi(2) + (*p - lod_zone).map(|e| e as f32).magnitude_squared() < self.lod_distance.powi(2) }); } From f21a64e898ec5bff8057d9dd66e56229e649f76a Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 11 May 2022 14:47:11 +0100 Subject: [PATCH 29/31] Better oak model --- assets/voxygen/lod/oak.obj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/voxygen/lod/oak.obj b/assets/voxygen/lod/oak.obj index fddacb0eb9..c4690bfb3e 100644 --- a/assets/voxygen/lod/oak.obj +++ b/assets/voxygen/lod/oak.obj @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6633ea303abbd7fd088603012790865c2a173aab5bef542a571fb8e369605de0 -size 7390 +oid sha256:42f0f101c18836a4f7941b551eb38aba600826208509b6e6622e8bb69c647aa5 +size 10420 From 01e1cb34b0f3f83ab84ea891f959a330c2f5fff6 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 11 May 2022 15:00:44 +0100 Subject: [PATCH 30/31] Fixed minor LoD issues --- assets/voxygen/shaders/lod-object-vert.glsl | 6 +++--- client/src/lib.rs | 2 +- voxygen/src/scene/lod.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/assets/voxygen/shaders/lod-object-vert.glsl b/assets/voxygen/shaders/lod-object-vert.glsl index 198d92ea01..75cf4c83da 100644 --- a/assets/voxygen/shaders/lod-object-vert.glsl +++ b/assets/voxygen/shaders/lod-object-vert.glsl @@ -33,11 +33,11 @@ layout(location = 3) out vec3 model_pos; layout(location = 4) out float snow_cover; void main() { - vec3 tree_pos = inst_pos - focus_off.xyz; - f_pos = tree_pos + v_pos; + vec3 obj_pos = inst_pos - focus_off.xyz; + f_pos = obj_pos + v_pos; model_pos = v_pos; - float pull_down = 1.0 / pow(distance(focus_pos.xy, tree_pos.xy) / (view_distance.x * 0.95), 150.0); + float pull_down = 1.0 / pow(distance(focus_pos.xy, obj_pos.xy) / (view_distance.x * 0.95), 150.0); #ifndef EXPERIMENTAL_NOTERRAINPOP f_pos.z -= pull_down; #else diff --git a/client/src/lib.rs b/client/src/lib.rs index 09817eb188..7a1c311dfa 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -658,7 +658,7 @@ impl Client { tick: 0, state, view_distance: None, - lod_distance: 4.0, // TODO: Make configurable + lod_distance: 4.0, loaded_distance: 0.0, pending_chunks: HashMap::new(), diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index 8efc4b8a77..d8ce54672a 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -103,7 +103,7 @@ impl Lod { )); } - // Create new LoD groups new a new zone has loaded + // Create new LoD groups when a new zone has loaded for (p, zone) in client.lod_zones() { self.zone_objects.entry(*p).or_insert_with(|| { let mut objects = HashMap::<_, Vec<_>>::new(); From b42ee3fce27e73d42c6751e64e820f2d8bc62bb5 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 11 May 2022 15:20:19 +0100 Subject: [PATCH 31/31] Avoid expense when LoD voxels are disabled --- assets/voxygen/shaders/lod-object-frag.glsl | 34 ++++++++++---------- assets/voxygen/shaders/lod-terrain-frag.glsl | 31 +++++++++--------- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/assets/voxygen/shaders/lod-object-frag.glsl b/assets/voxygen/shaders/lod-object-frag.glsl index a33f320469..feb33a4362 100644 --- a/assets/voxygen/shaders/lod-object-frag.glsl +++ b/assets/voxygen/shaders/lod-object-frag.glsl @@ -80,26 +80,26 @@ void main() { vec3 cam_dir = normalize(cam_pos.xyz - f_pos.xyz); vec3 side_norm = normalize(vec3(my_norm.xy, 0)); vec3 top_norm = vec3(0, 0, 1); - float side_factor = 1.0 - my_norm.z; - // min(dot(vec3(0, -sign(cam_dir.y), 0), -cam_dir), dot(vec3(-sign(cam_dir.x), 0, 0), -cam_dir)) - if (max(abs(my_norm.x), abs(my_norm.y)) < 0.01 || fract(my_alt) * clamp(dot(normalize(vec3(cam_dir.xy, 0)), side_norm), 0, 1) < cam_dir.z / my_norm.z) { - f_ao *= mix(1.0, clamp(fract(my_alt) / length(my_norm.xy) + clamp(dot(side_norm, -cam_dir), 0, 1), 0, 1), voxelize_factor); - voxel_norm = top_norm; - } else { - f_ao *= mix(1.0, clamp(pow(fract(my_alt), 0.5), 0, 1), voxelize_factor); - - if (fract(f_pos.x) * abs(my_norm.y / cam_dir.x) < fract(f_pos.y) * abs(my_norm.x / cam_dir.y)) { - voxel_norm = vec3(sign(cam_dir.x), 0, 0); - } else { - voxel_norm = vec3(0, sign(cam_dir.y), 0); - } - } - f_ao = min(f_ao, max(f_norm.z * 0.5 + 0.5, 0.0)); - voxel_norm = mix(my_norm, voxel_norm == vec3(0.0) ? f_norm : voxel_norm, voxelize_factor); - #ifdef EXPERIMENTAL_NOLODVOXELS f_ao = 1.0; voxel_norm = normalize(mix(side_norm, top_norm, cam_dir.z)); + #else + float side_factor = 1.0 - my_norm.z; + // min(dot(vec3(0, -sign(cam_dir.y), 0), -cam_dir), dot(vec3(-sign(cam_dir.x), 0, 0), -cam_dir)) + if (max(abs(my_norm.x), abs(my_norm.y)) < 0.01 || fract(my_alt) * clamp(dot(normalize(vec3(cam_dir.xy, 0)), side_norm), 0, 1) < cam_dir.z / my_norm.z) { + f_ao *= mix(1.0, clamp(fract(my_alt) / length(my_norm.xy) + clamp(dot(side_norm, -cam_dir), 0, 1), 0, 1), voxelize_factor); + voxel_norm = top_norm; + } else { + f_ao *= mix(1.0, clamp(pow(fract(my_alt), 0.5), 0, 1), voxelize_factor); + + if (fract(f_pos.x) * abs(my_norm.y / cam_dir.x) < fract(f_pos.y) * abs(my_norm.x / cam_dir.y)) { + voxel_norm = vec3(sign(cam_dir.x), 0, 0); + } else { + voxel_norm = vec3(0, sign(cam_dir.y), 0); + } + } + f_ao = min(f_ao, max(f_norm.z * 0.5 + 0.5, 0.0)); + voxel_norm = mix(my_norm, voxel_norm == vec3(0.0) ? f_norm : voxel_norm, voxelize_factor); #endif vec3 emitted_light, reflected_light; diff --git a/assets/voxygen/shaders/lod-terrain-frag.glsl b/assets/voxygen/shaders/lod-terrain-frag.glsl index 29d52cac2f..2358611b0a 100644 --- a/assets/voxygen/shaders/lod-terrain-frag.glsl +++ b/assets/voxygen/shaders/lod-terrain-frag.glsl @@ -333,30 +333,29 @@ void main() { hit_xy ? vec3(0.0, 0.0, sides.z) : vec3(0.0, 0.0, 0.0); */ vec3 voxel_norm; - const float VOXELIZE_DIST = 2000; float voxelize_factor = clamp(1.0 - (distance(focus_pos.xy, f_pos.xy) - view_distance.x) / VOXELIZE_DIST, 0, 1); vec3 cam_dir = normalize(cam_pos.xyz - f_pos.xyz); vec3 side_norm = normalize(vec3(my_norm.xy, 0)); vec3 top_norm = vec3(0, 0, 1); - float side_factor = 1.0 - my_norm.z; - // min(dot(vec3(0, -sign(cam_dir.y), 0), -cam_dir), dot(vec3(-sign(cam_dir.x), 0, 0), -cam_dir)) - if (max(abs(my_norm.x), abs(my_norm.y)) < 0.01 || fract(my_alt) * clamp(dot(normalize(vec3(cam_dir.xy, 0)), side_norm), 0, 1) < cam_dir.z / my_norm.z) { - //f_ao *= mix(1.0, clamp(fract(my_alt) / length(my_norm.xy) + clamp(dot(side_norm, -cam_dir), 0, 1), 0, 1), voxelize_factor); - voxel_norm = top_norm; - } else { - f_ao *= mix(1.0, clamp(pow(fract(my_alt), 0.5), 0, 1), voxelize_factor); - - if (fract(f_pos.x) * abs(my_norm.y / cam_dir.x) < fract(f_pos.y) * abs(my_norm.x / cam_dir.y)) { - voxel_norm = vec3(sign(cam_dir.x), 0, 0); - } else { - voxel_norm = vec3(0, sign(cam_dir.y), 0); - } - } - #ifdef EXPERIMENTAL_NOLODVOXELS f_ao = 1.0; voxel_norm = normalize(mix(side_norm, top_norm, max(cam_dir.z, 0.0))); + #else + float side_factor = 1.0 - my_norm.z; + // min(dot(vec3(0, -sign(cam_dir.y), 0), -cam_dir), dot(vec3(-sign(cam_dir.x), 0, 0), -cam_dir)) + if (max(abs(my_norm.x), abs(my_norm.y)) < 0.01 || fract(my_alt) * clamp(dot(normalize(vec3(cam_dir.xy, 0)), side_norm), 0, 1) < cam_dir.z / my_norm.z) { + //f_ao *= mix(1.0, clamp(fract(my_alt) / length(my_norm.xy) + clamp(dot(side_norm, -cam_dir), 0, 1), 0, 1), voxelize_factor); + voxel_norm = top_norm; + } else { + f_ao *= mix(1.0, clamp(pow(fract(my_alt), 0.5), 0, 1), voxelize_factor); + + if (fract(f_pos.x) * abs(my_norm.y / cam_dir.x) < fract(f_pos.y) * abs(my_norm.x / cam_dir.y)) { + voxel_norm = vec3(sign(cam_dir.x), 0, 0); + } else { + voxel_norm = vec3(0, sign(cam_dir.y), 0); + } + } #endif // vec3 f_ao_view = max(vec3(dot(f_orig_view_dir.yz, sides.yz), dot(f_orig_view_dir.xz, sides.xz), dot(f_orig_view_dir.xy, sides.xy)), 0.0);