mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Initial implementation of LoD trees
This commit is contained in:
parent
3a984d24a5
commit
b3126ca687
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -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"
|
||||
|
32
assets/voxygen/lod/tree.mtl
Normal file
32
assets/voxygen/lod/tree.mtl
Normal file
@ -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
|
244
assets/voxygen/lod/tree.obj
Normal file
244
assets/voxygen/lod/tree.obj
Normal file
@ -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
|
43
assets/voxygen/shaders/lod-object-vert.glsl
Normal file
43
assets/voxygen/shaders/lod-object-vert.glsl
Normal file
@ -0,0 +1,43 @@
|
||||
#version 420 core
|
||||
|
||||
#include <constants.glsl>
|
||||
|
||||
#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 <globals.glsl>
|
||||
#include <srgb.glsl>
|
||||
#include <random.glsl>
|
||||
#include <lod.glsl>
|
||||
|
||||
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);
|
||||
}
|
@ -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<String, Option<SpriteKind>>,
|
||||
lod_zones: HashMap<Vec2<i32>, lod::Zone>,
|
||||
lod_last_requested: Option<Instant>,
|
||||
|
||||
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<Uid>,
|
||||
// Note: potentially representable as a client only component
|
||||
group_members: HashMap<Uid, group::Role>,
|
||||
@ -202,6 +206,7 @@ pub struct Client {
|
||||
state: State,
|
||||
|
||||
view_distance: Option<u32>,
|
||||
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<Vec2<i32>, 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<SpriteKind>) {
|
||||
@ -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)| {
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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<ObjAsset> for ObjAssetLoader {
|
||||
fn load(content: std::borrow::Cow<[u8]>, _: &str) -> Result<ObjAsset, BoxedError> {
|
||||
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<PathBuf> {
|
||||
std::env::current_dir().map_or(None, |path| {
|
||||
|
@ -83,6 +83,9 @@ pub enum ClientGeneral {
|
||||
TerrainChunkRequest {
|
||||
key: Vec2<i32>,
|
||||
},
|
||||
LodZoneRequest {
|
||||
key: Vec2<i32>,
|
||||
},
|
||||
//Always possible
|
||||
ChatMsg(String),
|
||||
Command(String, Vec<String>),
|
||||
@ -128,6 +131,7 @@ impl ClientMsg {
|
||||
| ClientGeneral::ExitInGame
|
||||
| ClientGeneral::PlayerPhysics { .. }
|
||||
| ClientGeneral::TerrainChunkRequest { .. }
|
||||
| ClientGeneral::LodZoneRequest { .. }
|
||||
| ClientGeneral::UnlockSkill(_)
|
||||
| ClientGeneral::RequestSiteInfo(_)
|
||||
| ClientGeneral::UnlockSkillGroup(_)
|
||||
|
@ -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<i32>,
|
||||
chunk: Result<SerializedTerrainChunk, ()>,
|
||||
},
|
||||
LodZoneUpdate {
|
||||
key: Vec2<i32>,
|
||||
zone: lod::Zone,
|
||||
},
|
||||
TerrainBlockUpdates(CompressedData<HashMap<Vec3<i32>, 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(_)
|
||||
|
@ -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"))]
|
||||
|
35
common/src/lod.rs
Normal file
35
common/src/lod.rs
Normal file
@ -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<u16>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Zone {
|
||||
pub objects: Vec<Object>,
|
||||
}
|
||||
|
||||
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
|
||||
}
|
@ -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)
|
||||
},
|
||||
|
@ -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.
|
||||
|
33
server/src/lod.rs
Normal file
33
server/src/lod.rs
Normal file
@ -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<Vec2<i32>, 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<i32>) -> &lod::Zone {
|
||||
self.zones.get(&zone_pos).unwrap_or(&EMPTY_ZONE)
|
||||
}
|
||||
}
|
@ -295,6 +295,7 @@ impl Sys {
|
||||
| ClientGeneral::Character(_)
|
||||
| ClientGeneral::Spectate
|
||||
| ClientGeneral::TerrainChunkRequest { .. }
|
||||
| ClientGeneral::LodZoneRequest { .. }
|
||||
| ClientGeneral::ChatMsg(_)
|
||||
| ClientGeneral::Command(..)
|
||||
| ClientGeneral::Terminate => {
|
||||
|
@ -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<ServerEvent>>,
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
ReadExpect<'a, Lod>,
|
||||
ReadExpect<'a, NetworkRequestMetrics>,
|
||||
Write<'a, Vec<ChunkRequest>>,
|
||||
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 \
|
||||
|
@ -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::{
|
||||
|
167
voxygen/src/render/pipelines/lod_object.rs
Normal file
167
voxygen/src/render/pipelines/lod_object.rs
Normal file
@ -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<f32>, norm: Vec3<f32>, col: Vec3<f32>) -> 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<wgpu::IndexFormat> = None;//Some(wgpu::IndexFormat::Uint16);
|
||||
const STRIDE: wgpu::BufferAddress = mem::size_of::<Self>() 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<f32>,
|
||||
) -> 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::<Self>() 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,
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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::<lod_object::Vertex>(&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<lod_object::Vertex>,
|
||||
instances: &'data Instances<lod_object::Instance>,
|
||||
) {
|
||||
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>>,
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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",
|
||||
|
@ -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<LodTerrainVertex>)>,
|
||||
data: LodData,
|
||||
|
||||
zone_objects: HashMap<Vec2<i32>, HashMap<lod::ObjectKind, Instances<LodObjectInstance>>>,
|
||||
object_data: HashMap<lod::ObjectKind, Model<LodObjectVertex>>,
|
||||
}
|
||||
|
||||
// TODO: Make constant when possible.
|
||||
@ -21,19 +31,31 @@ pub fn water_color() -> Rgba<f32> {
|
||||
}
|
||||
|
||||
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<LodTerrainVertex> {
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn make_lod_object(
|
||||
name: &str,
|
||||
renderer: &mut Renderer,
|
||||
global_model: &GlobalModel,
|
||||
lod_data: &LodData,
|
||||
) -> Model<LodObjectVertex> {
|
||||
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!")
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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<i32>,
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
@ -2134,36 +2134,36 @@ impl WorldSim {
|
||||
/// them spawning).
|
||||
pub fn get_near_trees(&self, wpos: Vec2<i32>) -> impl Iterator<Item = TreeAttr> + '_ {
|
||||
// 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<i32>, wpos_max: Vec2<i32>) -> impl ParallelIterator<Item = TreeAttr> + '_ {
|
||||
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,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user