Higher detail LOD.

This commit is contained in:
Joshua Yanovski 2020-07-18 18:55:25 +02:00
parent add2cfae04
commit 2101113b46
22 changed files with 340 additions and 256 deletions

View File

@ -46,7 +46,7 @@ flat out uint f_pos_norm;
// out float f_light;
// out vec3 light_pos[2];
const float EXTRA_NEG_Z = /*65536.0*/65536.1;
const float EXTRA_NEG_Z = 65536.0/*65536.1*/;
void main() {
f_pos = vec3((uvec3(v_pos_norm) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0x1FFFFu)) - vec3(0, 0, EXTRA_NEG_Z) + model_offs - focus_off.xyz;

View File

@ -68,4 +68,6 @@
/*
// When sets, shadow maps are used to cast shadows.
#define HAS_SHADOW_MAPS
// When set, "full" LOD terrain informatino is available (e.g. terrain colors).
#define HAS_LOD_FULL_INFO
*/

View File

@ -2,7 +2,7 @@
#include <sky.glsl>
#include <srgb.glsl>
uniform sampler2D t_map;
uniform sampler2D t_alt;
uniform sampler2D t_horizon;
const float MIN_SHADOW = 0.33;
@ -11,7 +11,7 @@ vec2 pos_to_uv(sampler2D sampler, vec2 pos) {
// Want: (pixel + 0.5) / W
vec2 texSize = textureSize(sampler, 0);
vec2 uv_pos = (focus_off.xy + pos + 16) / (32.0 * texSize);
return vec2(uv_pos.x, 1.0 - uv_pos.y);
return vec2(uv_pos.x, /*1.0 - */uv_pos.y);
}
vec2 pos_to_tex(vec2 pos) {
@ -35,6 +35,7 @@ vec4 cubic(float v) {
vec4 textureBicubic(sampler2D sampler, vec2 texCoords) {
vec2 texSize = textureSize(sampler, 0);
vec2 invTexSize = 1.0 / texSize;
/* texCoords.y = texSize.y - texCoords.y; */
texCoords = texCoords/* * texSize */ - 0.5;
@ -52,8 +53,8 @@ vec4 textureBicubic(sampler2D sampler, vec2 texCoords) {
vec4 offset = c + vec4 (xcubic.yw, ycubic.yw) / s;
offset *= invTexSize.xxyy;
// Correct for map rotaton.
offset.zw = 1.0 - offset.zw;
/* // Correct for map rotaton.
offset.zw = 1.0 - offset.zw; */
vec4 sample0 = texture(sampler, offset.xz);
vec4 sample1 = texture(sampler, offset.yz);
@ -73,7 +74,7 @@ vec4 textureBicubic(sampler2D sampler, vec2 texCoords) {
}
float alt_at(vec2 pos) {
return (texture/*textureBicubic*/(t_map, pos_to_uv(t_map, pos)).a * (/*1300.0*//*1278.7266845703125*/view_distance.w) + /*140.0*/view_distance.z - focus_off.z);
return (/*round*/(texture/*textureBicubic*/(t_alt, pos_to_uv(t_alt, pos)).r * (/*1300.0*//*1278.7266845703125*/view_distance.w)) + /*140.0*/view_distance.z - focus_off.z);
//+ (texture(t_noise, pos * 0.002).x - 0.5) * 64.0;
// return 0.0
@ -87,7 +88,7 @@ float alt_at_real(vec2 pos) {
// #if (FLUID_MODE == FLUID_MODE_CHEAP)
// return alt_at(pos);
// #elif (FLUID_MODE == FLUID_MODE_SHINY)
return (textureBicubic(t_map, pos_to_tex(pos)).a * (/*1300.0*//*1278.7266845703125*/view_distance.w) + /*140.0*/view_distance.z - focus_off.z);
return (/*round*/(textureBicubic(t_alt, pos_to_tex(pos)).r * (/*1300.0*//*1278.7266845703125*/view_distance.w)) + /*140.0*/view_distance.z - focus_off.z);
// #endif
//+ (texture(t_noise, pos * 0.002).x - 0.5) * 64.0;
@ -201,14 +202,14 @@ vec2 splay(vec2 pos) {
const float SQRT_2 = sqrt(2.0) / 2.0;
// /const float CBRT_2 = cbrt(2.0) / 2.0;
// vec2 splayed = pos * (view_distance.x * SQRT_2 + pow(len * 0.5, 3.0) * (SPLAY_MULT - view_distance.x));
vec2 splayed = pos * (view_distance.x * SQRT_2 + pow(len/* * SQRT_2*//* * 0.5*/, 3.0) * (textureSize(t_map, 0) * 32.0 - view_distance.x));
vec2 splayed = pos * (view_distance.x * SQRT_2 + pow(len/* * SQRT_2*//* * 0.5*/, 3.0) * (textureSize(t_alt, 0) * 32.0 - view_distance.x));
return splayed;
// Radial: pos.x = r - view_distance.x from focus_pos, pos.y = θ from cam_pos to focus_pos on xy plane.
// const float PI_2 = 3.1415926535897932384626433832795;
// float squared = pos.x * pos.x;
// // // vec2 splayed2 = pos * vec2(squared * (SPLAY_MULT - view_distance.x), PI);
// vec2 splayed2 = pos * vec2(squared * (textureSize(t_map, 0).x * 32.0 - view_distance.x), PI);
// vec2 splayed2 = pos * vec2(squared * (textureSize(t_alt, 0).x * 32.0 - view_distance.x), PI);
// float r = splayed2.x + view_distance.x;
// vec2 theta = vec2(cos(splayed2.y), sin(splayed2.y));
// return r * theta;
@ -273,9 +274,14 @@ vec3 lod_pos(vec2 pos, vec2 focus_pos) {
return vec3(hpos, alt_at_real(hpos));
}
#ifdef HAS_LOD_FULL_INFO
uniform sampler2D t_map;
vec3 lod_col(vec2 pos) {
//return vec3(0, 0.5, 0);
// return /*linear_to_srgb*/vec3(alt_at(pos), textureBicubic(t_map, pos_to_tex(pos)).gb);
return /*linear_to_srgb*/(textureBicubic(t_map, pos_to_tex(pos)).rgb)
;//+ (texture(t_noise, pos * 0.04 + texture(t_noise, pos * 0.005).xy * 2.0 + texture(t_noise, pos * 0.06).xy * 0.6).x - 0.5) * 0.1;
//+ (texture(t_noise, pos * 0.04 + texture(t_noise, pos * 0.005).xy * 2.0 + texture(t_noise, pos * 0.06).xy * 0.6).x - 0.5) * 0.1;
}
#endif

View File

@ -17,6 +17,8 @@
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
#define HAS_LOD_FULL_INFO
#include <globals.glsl>
#include <sky.glsl>
#include <lod.glsl>

View File

@ -74,15 +74,18 @@ pub struct Client {
client_state: ClientState,
thread_pool: ThreadPool,
pub server_info: ServerInfo,
/// Just the "base" layer for LOD; currently includes colors and a 1-byte
/// approximation for height. In the future we'll add more layers, like
/// shadows, rivers, and probably foliage, cities, roads, and other
/// structures.
pub lod_base: Arc<DynamicImage>,
/// Just the "base" layer for LOD; currently includes colors and nothing
/// else. In the future we'll add more layers, like shadows, rivers, and
/// probably foliage, cities, roads, and other structures.
pub lod_base: Vec<u32>,
/// The "height" layer for LOD; currently includes only land altitudes, but
/// in the future should also water depth, and probably other
/// information as well.
pub lod_alt: Vec<u32>,
/// The "shadow" layer for LOD. Includes east and west horizon angles and
/// an approximate max occluder height, which we use to try to
/// approximate soft and volumetric shadows.
pub lod_horizon: Arc<DynamicImage>,
pub lod_horizon: Vec<u32>,
/// A fully rendered map image for use with the map and minimap; note that
/// this can be constructed dynamically by combining the layers of world
/// map data (e.g. with shadow map data or river data), but at present
@ -92,7 +95,7 @@ pub struct Client {
/// in chunks), and the third element holds the minimum height for any land
/// chunk (i.e. the sea level) in its x coordinate, and the maximum land
/// height above this height (i.e. the max height) in its y coordinate.
pub world_map: (Arc<DynamicImage>, Vec2<u32>, Vec2<f32>),
pub world_map: (Arc<DynamicImage>, Vec2<u16>, Vec2<f32>),
pub player_list: HashMap<Uid, PlayerInfo>,
pub character_list: CharacterList,
pub active_character_id: Option<i32>,
@ -144,182 +147,203 @@ impl Client {
let mut stream = block_on(participant.open(10, PROMISES_ORDERED | PROMISES_CONSISTENCY))?;
// Wait for initial sync
let (state, entity, server_info, lod_base, lod_horizon, world_map) = block_on(async {
loop {
match stream.recv().await? {
ServerMsg::InitialSync {
entity_package,
server_info,
time_of_day,
world_map,
} => {
// TODO: Display that versions don't match in Voxygen
if &server_info.git_hash != *common::util::GIT_HASH {
warn!(
"Server is running {}[{}], you are running {}[{}], versions might \
be incompatible!",
server_info.git_hash,
server_info.git_date,
common::util::GIT_HASH.to_string(),
common::util::GIT_DATE.to_string(),
);
}
debug!("Auth Server: {:?}", server_info.auth_provider);
// Initialize `State`
let mut state = State::default();
// Client-only components
state
.ecs_mut()
.register::<comp::Last<comp::CharacterState>>();
let entity = state.ecs_mut().apply_entity_package(entity_package);
*state.ecs_mut().write_resource() = time_of_day;
let map_size = world_map.dimensions;
let max_height = world_map.max_height;
let rgba = world_map.rgba;
assert_eq!(rgba.len(), (map_size.x * map_size.y) as usize);
let [west, east] = world_map.horizons;
let scale_angle =
|a: u8| (a as Alt / 255.0 * <Alt as FloatConst>::FRAC_PI_2()).tan();
let scale_height = |h: u8| h as Alt / 255.0 * max_height as Alt;
debug!("Preparing image...");
let unzip_horizons = |(angles, heights): &(Vec<_>, Vec<_>)| {
(
angles.iter().copied().map(scale_angle).collect::<Vec<_>>(),
heights
.iter()
.copied()
.map(scale_height)
.collect::<Vec<_>>(),
)
};
let horizons = [unzip_horizons(&west), unzip_horizons(&east)];
// Redraw map (with shadows this time).
let mut world_map = vec![0u32; rgba.len()];
let mut map_config = world::sim::MapConfig::default();
map_config.lgain = 1.0;
map_config.gain = max_height;
map_config.horizons = Some(&horizons);
// map_config.light_direction = Vec3::new(1.0, -1.0, 0.0);
map_config.focus.z = 0.0;
let rescale_height = |h: Alt| (h / max_height as Alt) as f32;
let bounds_check = |pos: Vec2<i32>| {
pos.reduce_partial_min() >= 0
&& pos.x < map_size.x as i32
&& pos.y < map_size.y as i32
};
map_config.generate(
|pos| {
let (rgba, downhill_wpos) = if bounds_check(pos) {
let posi =
pos.y as usize * map_size.x as usize + pos.x as usize;
let [r, g, b, a] = rgba[posi].to_le_bytes();
// Compute downhill.
let downhill = {
let mut best = -1;
let mut besth = a;
// TODO: Fix to work for dynamic WORLD_SIZE (i.e. map_size).
for nposi in neighbors(posi) {
let nbh = rgba[nposi].to_le_bytes()[3];
if nbh < besth {
besth = nbh;
best = nposi as isize;
}
}
best
};
let downhill_wpos = if downhill < 0 {
None
} else {
Some(
Vec2::new(
(downhill as usize % map_size.x as usize) as i32,
(downhill as usize / map_size.x as usize) as i32,
) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
)
};
(Rgba::new(r, g, b, a), downhill_wpos)
} else {
(Rgba::zero(), None)
};
let wpos = pos * TerrainChunkSize::RECT_SIZE.map(|e| e as i32);
let downhill_wpos = downhill_wpos.unwrap_or(
wpos + TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
let (state, entity, server_info, lod_base, lod_alt, lod_horizon, world_map) = block_on(
async {
loop {
match stream.recv().await? {
ServerMsg::InitialSync {
entity_package,
server_info,
time_of_day,
world_map,
} => {
// TODO: Display that versions don't match in Voxygen
if &server_info.git_hash != *common::util::GIT_HASH {
warn!(
"Server is running {}[{}], you are running {}[{}], versions \
might be incompatible!",
server_info.git_hash,
server_info.git_date,
common::util::GIT_HASH.to_string(),
common::util::GIT_DATE.to_string(),
);
let alt = rescale_height(scale_height(rgba.a));
world::sim::MapSample {
rgb: Rgb::from(rgba),
alt: alt as Alt,
downhill_wpos,
connections: None,
}
},
|wpos| {
let pos =
wpos.map2(TerrainChunkSize::RECT_SIZE, |e, f| e / f as i32);
rescale_height(if bounds_check(pos) {
let posi =
pos.y as usize * map_size.x as usize + pos.x as usize;
scale_height(rgba[posi].to_le_bytes()[3])
} else {
0.0
})
},
|pos, (r, g, b, a)| {
world_map[pos.y * map_size.x as usize + pos.x] =
u32::from_le_bytes([r, g, b, a]);
},
);
let make_raw = |rgba| -> Result<_, Error> {
let mut raw = vec![0u8; 4 * world_map.len()/*map_size.x * map_size.y*/];
LittleEndian::write_u32_into(rgba, &mut raw);
Ok(Arc::new(
image::DynamicImage::ImageRgba8({
}
debug!("Auth Server: {:?}", server_info.auth_provider);
// Initialize `State`
let mut state = State::default();
// Client-only components
state
.ecs_mut()
.register::<comp::Last<comp::CharacterState>>();
let entity = state.ecs_mut().apply_entity_package(entity_package);
*state.ecs_mut().write_resource() = time_of_day;
let map_size = world_map.dimensions;
let max_height = world_map.max_height;
let rgba = world_map.rgba;
let alt = world_map.alt;
let expected_size =
(u32::from(map_size.x) * u32::from(map_size.y)) as usize;
if rgba.len() != expected_size {
return Err(Error::Other(
"Server sent a bad world map image".into(),
));
}
if alt.len() != expected_size {
return Err(Error::Other("Server sent a bad altitude map.".into()));
}
let [west, east] = world_map.horizons;
let scale_angle =
|a: u8| (a as Alt / 255.0 * <Alt as FloatConst>::FRAC_PI_2()).tan();
let scale_height = |h: u8| h as Alt / 255.0 * max_height as Alt;
let scale_height_big =
|h: u32| (h >> 3) as Alt / 8191.0 * max_height as Alt;
debug!("Preparing image...");
let unzip_horizons = |(angles, heights): &(Vec<_>, Vec<_>)| {
(
angles.iter().copied().map(scale_angle).collect::<Vec<_>>(),
heights
.iter()
.copied()
.map(scale_height)
.collect::<Vec<_>>(),
)
};
let horizons = [unzip_horizons(&west), unzip_horizons(&east)];
// Redraw map (with shadows this time).
let mut world_map = vec![0u32; rgba.len()];
let mut map_config = world::sim::MapConfig::default();
map_config.lgain = 1.0;
map_config.gain = max_height;
map_config.horizons = Some(&horizons);
// map_config.light_direction = Vec3::new(1.0, -1.0, 0.0);
map_config.focus.z = 0.0;
let rescale_height = |h: Alt| (h / max_height as Alt) as f32;
let bounds_check = |pos: Vec2<i32>| {
pos.reduce_partial_min() >= 0
&& pos.x < map_size.x as i32
&& pos.y < map_size.y as i32
};
map_config.generate(
|pos| {
let (rgba, alt, downhill_wpos) = if bounds_check(pos) {
let posi =
pos.y as usize * map_size.x as usize + pos.x as usize;
let [r, g, b, a] = rgba[posi].to_le_bytes();
let alti = alt[posi];
// Compute downhill.
let downhill = {
let mut best = -1;
let mut besth = alti;
// TODO: Fix to work for dynamic WORLD_SIZE (i.e.
// map_size).
for nposi in neighbors(posi) {
let nbh = alt[nposi];
if nbh < besth {
besth = nbh;
best = nposi as isize;
}
}
best
};
let downhill_wpos = if downhill < 0 {
None
} else {
Some(
Vec2::new(
(downhill as usize % map_size.x as usize)
as i32,
(downhill as usize / map_size.x as usize)
as i32,
) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
)
};
(Rgba::new(r, g, b, a), alti, downhill_wpos)
} else {
(Rgba::zero(), 0, None)
};
let wpos = pos * TerrainChunkSize::RECT_SIZE.map(|e| e as i32);
let downhill_wpos = downhill_wpos.unwrap_or(
wpos + TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
);
let alt = rescale_height(scale_height_big(alt));
world::sim::MapSample {
rgb: Rgb::from(rgba),
alt: alt as Alt,
downhill_wpos,
connections: None,
}
},
|wpos| {
let pos =
wpos.map2(TerrainChunkSize::RECT_SIZE, |e, f| e / f as i32);
rescale_height(if bounds_check(pos) {
let posi =
pos.y as usize * map_size.x as usize + pos.x as usize;
scale_height_big(alt[posi])
} else {
0.0
})
},
|pos, (r, g, b, a)| {
world_map[pos.y * map_size.x as usize + pos.x] =
u32::from_le_bytes([r, g, b, a]);
},
);
let make_raw = |rgba| -> Result<_, Error> {
let mut raw =
vec![0u8; 4 * world_map.len()/*map_size.x * map_size.y*/];
LittleEndian::write_u32_into(rgba, &mut raw);
Ok(Arc::new(
image::DynamicImage::ImageRgba8({
// Should not fail if the dimensions are correct.
let map =
image::ImageBuffer::from_raw(map_size.x, map_size.y, raw);
image::ImageBuffer::from_raw(u32::from(map_size.x), u32::from(map_size.y), raw);
map.ok_or(Error::Other("Server sent a bad world map image".into()))?
})
// Flip the image, since Voxygen uses an orientation where rotation from
// positive x axis to positive y axis is counterclockwise around the z axis.
.flipv(),
))
};
let lod_base = make_raw(&rgba)?;
let world_map = make_raw(&world_map)?;
let horizons = (west.0, west.1, east.0, east.1)
.into_par_iter()
.map(|(wa, wh, ea, eh)| u32::from_le_bytes([wa, wh, ea, eh]))
.collect::<Vec<_>>();
let lod_horizon = make_raw(&horizons)?;
// TODO: Get sea_level from server.
let map_bounds = Vec2::new(
/* map_config.focus.z */ world::CONFIG.sea_level,
/* map_config.gain */ max_height,
);
debug!("Done preparing image...");
))
};
let lod_base = rgba; //make_raw(&rgba)?;
let lod_alt = alt; //make_raw(&alt)?;
let world_map = make_raw(&world_map)?;
let horizons = (west.0, west.1, east.0, east.1)
.into_par_iter()
.map(|(wa, wh, ea, eh)| u32::from_le_bytes([wa, wh, ea, eh]))
.collect::<Vec<_>>();
let lod_horizon = horizons; //make_raw(&horizons)?;
// TODO: Get sea_level from server.
let map_bounds = Vec2::new(
/* map_config.focus.z */ world::CONFIG.sea_level,
/* map_config.gain */ max_height,
);
debug!("Done preparing image...");
break Ok((
state,
entity,
server_info,
lod_base,
lod_horizon,
(world_map, map_size, map_bounds),
));
},
ServerMsg::TooManyPlayers => break Err(Error::TooManyPlayers),
err => {
warn!("whoops, server mad {:?}, ignoring", err);
},
break Ok((
state,
entity,
server_info,
lod_base,
lod_alt,
lod_horizon,
(world_map, map_size, map_bounds),
));
},
ServerMsg::TooManyPlayers => break Err(Error::TooManyPlayers),
err => {
warn!("whoops, server mad {:?}, ignoring", err);
},
}
}
}
})?;
},
)?;
stream.send(ClientMsg::Ping)?;
@ -335,6 +359,7 @@ impl Client {
server_info,
world_map,
lod_base,
lod_alt,
lod_horizon,
player_list: HashMap::new(),
character_list: CharacterList::default(),

View File

@ -65,12 +65,17 @@ pub struct CharacterInfo {
/// shadow maps intended for height maps.
pub struct WorldMapMsg {
/// World map dimensions (width × height)
pub dimensions: Vec2<u32>,
pub dimensions: Vec2<u16>,
/// Max height (used to scale altitudes).
pub max_height: f32,
/// RGB+A; the alpha channel is currently a proxy for altitude.
/// Entries are in the usual chunk order.
/// RGB+A; the alpha channel is currently unused, but will be used in the
/// future. Entries are in the usual chunk order.
pub rgba: Vec<u32>,
/// Altitudes: bits 2 to 0 are unused, then bits 15 to 3 are used for
/// altitude. The remainder are currently unused, but we have plans to
/// use 7 bits for water depth (using an integer f7 encoding), and we
/// will find other uses for the remaining 12 bits.
pub alt: Vec<u32>,
/// Horizon mapping. This is a variant of shadow mapping that is
/// specifically designed for height maps; it takes advantage of their
/// regular structure (e.g. no holes) to compress all information needed

View File

@ -508,7 +508,7 @@ impl Hud {
// Load world map
let world_map = (
ui.add_graphic_with_rotations(Graphic::Image(client.world_map.0.clone())),
client.world_map.1,
client.world_map.1.map(u32::from),
);
// Load images.
let imgs = Imgs::load(&mut ui).expect("Failed to load images!");

View File

@ -36,8 +36,8 @@ pub use self::{
Globals, Light, Shadow,
},
renderer::{
ColLightFmt, ColLightInfo, LodColorFmt, LodTextureFmt, Renderer, ShadowDepthStencilFmt,
TgtColorFmt, TgtDepthStencilFmt, WinColorFmt, WinDepthFmt,
ColLightFmt, ColLightInfo, LodAltFmt, LodColorFmt, LodTextureFmt, Renderer,
ShadowDepthStencilFmt, TgtColorFmt, TgtDepthStencilFmt, WinColorFmt, WinDepthFmt,
},
texture::Texture,
};

View File

@ -50,7 +50,7 @@ gfx_defines! {
point_shadow_maps: gfx::TextureSampler<f32> = "t_point_shadow_maps",
directed_shadow_maps: gfx::TextureSampler<f32> = "t_directed_shadow_maps",
map: gfx::TextureSampler<[f32; 4]> = "t_map",
alt: gfx::TextureSampler<[f32; 2]> = "t_alt",
horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",
noise: gfx::TextureSampler<f32> = "t_noise",

View File

@ -25,7 +25,7 @@ gfx_defines! {
point_shadow_maps: gfx::TextureSampler<f32> = "t_point_shadow_maps",
directed_shadow_maps: gfx::TextureSampler<f32> = "t_directed_shadow_maps",
map: gfx::TextureSampler<[f32; 4]> = "t_map",
alt: gfx::TextureSampler<[f32; 2]> = "t_alt",
horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",
noise: gfx::TextureSampler<f32> = "t_noise",

View File

@ -23,6 +23,7 @@ gfx_defines! {
locals: gfx::ConstantBuffer<Locals> = "u_locals",
globals: gfx::ConstantBuffer<Globals> = "u_globals",
map: gfx::TextureSampler<[f32; 4]> = "t_map",
alt: gfx::TextureSampler<[f32; 2]> = "t_alt",
horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",
noise: gfx::TextureSampler<f32> = "t_noise",

View File

@ -33,7 +33,7 @@ gfx_defines! {
// lights: gfx::ConstantBuffer<Light> = "u_lights",
// shadows: gfx::ConstantBuffer<Shadow> = "u_shadows",
// map: gfx::TextureSampler<[f32; 4]> = "t_map",
// alt: gfx::TextureSampler<[f32; 2]> = "t_map",
// horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",
// noise: gfx::TextureSampler<f32> = "t_noise",
@ -58,7 +58,7 @@ gfx_defines! {
// lights: gfx::ConstantBuffer<Light> = "u_lights",
// shadows: gfx::ConstantBuffer<Shadow> = "u_shadows",
// map: gfx::TextureSampler<[f32; 4]> = "t_map",
// alt: gfx::TextureSampler<[f32; 2]> = "t_map",
// horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",
// noise: gfx::TextureSampler<f32> = "t_noise",

View File

@ -22,7 +22,7 @@ gfx_defines! {
locals: gfx::ConstantBuffer<Locals> = "u_locals",
globals: gfx::ConstantBuffer<Globals> = "u_globals",
map: gfx::TextureSampler<[f32; 4]> = "t_map",
alt: gfx::TextureSampler<[f32; 2]> = "t_alt",
horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",
noise: gfx::TextureSampler<f32> = "t_noise",

View File

@ -62,7 +62,7 @@ gfx_defines! {
point_shadow_maps: gfx::TextureSampler<f32> = "t_point_shadow_maps",
directed_shadow_maps: gfx::TextureSampler<f32> = "t_directed_shadow_maps",
map: gfx::TextureSampler<[f32; 4]> = "t_map",
alt: gfx::TextureSampler<[f32; 2]> = "t_alt",
horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",
noise: gfx::TextureSampler<f32> = "t_noise",

View File

@ -35,7 +35,7 @@ gfx_defines! {
point_shadow_maps: gfx::TextureSampler<f32> = "t_point_shadow_maps",
directed_shadow_maps: gfx::TextureSampler<f32> = "t_directed_shadow_maps",
map: gfx::TextureSampler<[f32; 4]> = "t_map",
alt: gfx::TextureSampler<[f32; 2]> = "t_alt",
horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",
noise: gfx::TextureSampler<f32> = "t_noise",

View File

@ -51,6 +51,9 @@ pub type WinDepthView = gfx::handle::DepthStencilView<gfx_backend::Resources, Wi
/// Represents the format of LOD shadows.
pub type LodTextureFmt = (gfx::format::R8_G8_B8_A8, gfx::format::Unorm); //[gfx::format::U8Norm; 4];
/// Represents the format of LOD altitudes.
pub type LodAltFmt = (gfx::format::R16_G16, gfx::format::Unorm); //[gfx::format::U8Norm; 4];
/// Represents the format of LOD map colors.
pub type LodColorFmt = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb); //[gfx::format::U8Norm; 4];
@ -1081,7 +1084,7 @@ impl Renderer {
model: &Model<skybox::SkyboxPipeline>,
globals: &Consts<Globals>,
locals: &Consts<skybox::Locals>,
map: &Texture<LodColorFmt>,
alt: &Texture<LodAltFmt>,
horizon: &Texture<LodTextureFmt>,
) {
self.encoder.draw(
@ -1098,7 +1101,7 @@ impl Renderer {
locals: locals.buf.clone(),
globals: globals.buf.clone(),
noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()),
map: (map.srv.clone(), map.sampler.clone()),
alt: (alt.srv.clone(), alt.sampler.clone()),
horizon: (horizon.srv.clone(), horizon.sampler.clone()),
tgt_color: self.tgt_color_view.clone(),
tgt_depth_stencil: (self.tgt_depth_stencil_view.clone()/* , (1, 1) */),
@ -1117,7 +1120,7 @@ impl Renderer {
lights: &Consts<Light>,
shadows: &Consts<Shadow>,
light_shadows: &Consts<shadow::Locals>,
map: &Texture<LodColorFmt>,
alt: &Texture<LodAltFmt>,
horizon: &Texture<LodTextureFmt>,
) {
// return;
@ -1157,7 +1160,7 @@ impl Renderer {
vbuf: model.vbuf.clone(),
// abuf: atlas_model.vbuf.clone(),
col_lights: (col_lights.srv.clone(), col_lights.sampler.clone()),
// col_lights: (map.srv.clone(), map.sampler.clone()),
// col_lights: (alt.srv.clone(), alt.sampler.clone()),
locals: locals.buf.clone(),
globals: globals.buf.clone(),
bones: bones.buf.clone(),
@ -1167,7 +1170,7 @@ impl Renderer {
point_shadow_maps,
directed_shadow_maps,
noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()),
map: (map.srv.clone(), map.sampler.clone()),
alt: (alt.srv.clone(), alt.sampler.clone()),
horizon: (horizon.srv.clone(), horizon.sampler.clone()),
tgt_color: self.tgt_color_view.clone(),
tgt_depth_stencil: (self.tgt_depth_stencil_view.clone()/* , (1, 1) */),
@ -1186,7 +1189,7 @@ impl Renderer {
_lights: &Consts<Light>,
_shadows: &Consts<Shadow>,
_light_shadows: &Consts<shadow::Locals>,
_map: &Texture<LodColorFmt>,
_alt: &Texture<LodAltFmt>,
_horizon: &Texture<LodTextureFmt>,
) {
return;
@ -1226,7 +1229,7 @@ impl Renderer {
vbuf: model.vbuf.clone(),
// abuf: atlas_model.vbuf.clone(),
col_lights: (col_lights.srv.clone(), col_lights.sampler.clone()),
// col_lights: (map.srv.clone(), map.sampler.clone()),
// col_lights: (alt.srv.clone(), alt.sampler.clone()),
locals: locals.buf.clone(),
globals: globals.buf.clone(),
bones: bones.buf.clone(),
@ -1236,7 +1239,7 @@ impl Renderer {
point_shadow_maps,
directed_shadow_maps,
noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()),
map: (map.srv.clone(), map.sampler.clone()),
alt: (alt.srv.clone(), alt.sampler.clone()),
horizon: (horizon.srv.clone(), horizon.sampler.clone()),
tgt_color: self.tgt_color_view.clone(),
tgt_depth_stencil: (self.tgt_depth_stencil_view.clone()/* , (0, 0) */),
@ -1255,7 +1258,7 @@ impl Renderer {
lights: &Consts<Light>,
shadows: &Consts<Shadow>,
light_shadows: &Consts<shadow::Locals>,
map: &Texture<LodColorFmt>,
alt: &Texture<LodAltFmt>,
horizon: &Texture<LodTextureFmt>,
) {
let (point_shadow_maps, directed_shadow_maps) =
@ -1294,7 +1297,7 @@ impl Renderer {
vbuf: model.vbuf.clone(),
// abuf: atlas_model.vbuf.clone(),
col_lights: (col_lights.srv.clone(), col_lights.sampler.clone()),
// col_lights: (map.srv.clone(), map.sampler.clone()),
// col_lights: (alt.srv.clone(), alt.sampler.clone()),
locals: locals.buf.clone(),
globals: globals.buf.clone(),
bones: bones.buf.clone(),
@ -1304,7 +1307,7 @@ impl Renderer {
point_shadow_maps,
directed_shadow_maps,
noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()),
map: (map.srv.clone(), map.sampler.clone()),
alt: (alt.srv.clone(), alt.sampler.clone()),
horizon: (horizon.srv.clone(), horizon.sampler.clone()),
tgt_color: self.tgt_color_view.clone(),
tgt_depth_stencil: (self.tgt_depth_stencil_view.clone()/* , (1, 1) */),
@ -1325,7 +1328,7 @@ impl Renderer {
lights: &Consts<Light>,
shadows: &Consts<Shadow>,
light_shadows: &Consts<shadow::Locals>,
map: &Texture<LodColorFmt>,
alt: &Texture<LodAltFmt>,
horizon: &Texture<LodTextureFmt>,
) {
let (point_shadow_maps, directed_shadow_maps) =
@ -1362,7 +1365,7 @@ impl Renderer {
// since we don't need it for things like shadows.
// abuf: atlas_model.vbuf.clone(),
col_lights: (col_lights.srv.clone(), col_lights.sampler.clone()),
// col_lights: (map.srv.clone(), map.sampler.clone()),
// col_lights: (alt.srv.clone(), alt.sampler.clone()),
locals: locals.buf.clone(),
globals: globals.buf.clone(),
lights: lights.buf.clone(),
@ -1371,7 +1374,7 @@ impl Renderer {
point_shadow_maps,
directed_shadow_maps,
noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()),
map: (map.srv.clone(), map.sampler.clone()),
alt: (alt.srv.clone(), alt.sampler.clone()),
horizon: (horizon.srv.clone(), horizon.sampler.clone()),
tgt_color: self.tgt_color_view.clone(),
tgt_depth_stencil: (self.tgt_depth_stencil_view.clone()/* , (1, 1) */),
@ -1390,7 +1393,7 @@ impl Renderer {
locals: &Consts<shadow::Locals>,
/* lights: &Consts<Light>,
* shadows: &Consts<Shadow>,
* map: &Texture<LodColorFmt>,
* alt: &Texture<LodAltFmt>,
* horizon: &Texture<LodTextureFmt>, */
) {
if !self.mode.shadow.is_map() {
@ -1422,7 +1425,7 @@ impl Renderer {
// lights: lights.buf.clone(),
// shadows: shadows.buf.clone(),
// noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()),
// map: (map.srv.clone(), map.sampler.clone()),
// alt: (alt.srv.clone(), alt.sampler.clone()),
// horizon: (horizon.srv.clone(), horizon.sampler.clone()),
// Shadow stuff
@ -1445,7 +1448,7 @@ impl Renderer {
locals: &Consts<shadow::Locals>,
/* lights: &Consts<Light>,
* shadows: &Consts<Shadow>,
* map: &Texture<LodColorFmt>,
* alt: &Texture<LodAltFmt>,
* horizon: &Texture<LodTextureFmt>, */
) {
if !self.mode.shadow.is_map() {
@ -1477,7 +1480,7 @@ impl Renderer {
// lights: lights.buf.clone(),
// shadows: shadows.buf.clone(),
// noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()),
// map: (map.srv.clone(), map.sampler.clone()),
// alt: (alt.srv.clone(), alt.sampler.clone()),
// horizon: (horizon.srv.clone(), horizon.sampler.clone()),
// Shadow stuff
@ -1501,7 +1504,7 @@ impl Renderer {
locals: &Consts<shadow::Locals>,
/* lights: &Consts<Light>,
* shadows: &Consts<Shadow>,
* map: &Texture<LodColorFmt>,
* alt: &Texture<LodAltFmt>,
* horizon: &Texture<LodTextureFmt>, */
) {
if !self.mode.shadow.is_map() {
@ -1535,7 +1538,7 @@ impl Renderer {
// lights: lights.buf.clone(),
// shadows: shadows.buf.clone(),
// noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()),
// map: (map.srv.clone(), map.sampler.clone()),
// alt: (alt.srv.clone(), alt.sampler.clone()),
// horizon: (horizon.srv.clone(), horizon.sampler.clone()),
// Shadow stuff
@ -1557,7 +1560,7 @@ impl Renderer {
lights: &Consts<Light>,
shadows: &Consts<Shadow>,
light_shadows: &Consts<shadow::Locals>,
map: &Texture<LodColorFmt>,
alt: &Texture<LodAltFmt>,
horizon: &Texture<LodTextureFmt>,
waves: &Texture,
) {
@ -1598,7 +1601,7 @@ impl Renderer {
light_shadows: light_shadows.buf.clone(),
point_shadow_maps,
directed_shadow_maps,
map: (map.srv.clone(), map.sampler.clone()),
alt: (alt.srv.clone(), alt.sampler.clone()),
horizon: (horizon.srv.clone(), horizon.sampler.clone()),
noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()),
waves: (waves.srv.clone(), waves.sampler.clone()),
@ -1623,7 +1626,7 @@ impl Renderer {
lights: &Consts<Light>,
shadows: &Consts<Shadow>,
light_shadows: &Consts<shadow::Locals>,
map: &Texture<LodColorFmt>,
alt: &Texture<LodAltFmt>,
horizon: &Texture<LodTextureFmt>,
) {
let (point_shadow_maps, directed_shadow_maps) =
@ -1668,7 +1671,7 @@ impl Renderer {
point_shadow_maps,
directed_shadow_maps,
noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()),
map: (map.srv.clone(), map.sampler.clone()),
alt: (alt.srv.clone(), alt.sampler.clone()),
horizon: (horizon.srv.clone(), horizon.sampler.clone()),
tgt_color: self.tgt_color_view.clone(),
tgt_depth_stencil: (self.tgt_depth_stencil_view.clone()/* , (1, 1) */),
@ -1684,6 +1687,7 @@ impl Renderer {
globals: &Consts<Globals>,
locals: &Consts<lod_terrain::Locals>,
map: &Texture<LodColorFmt>,
alt: &Texture<LodAltFmt>,
horizon: &Texture<LodTextureFmt>,
) {
self.encoder.draw(
@ -1701,6 +1705,7 @@ impl Renderer {
globals: globals.buf.clone(),
noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()),
map: (map.srv.clone(), map.sampler.clone()),
alt: (alt.srv.clone(), alt.sampler.clone()),
horizon: (horizon.srv.clone(), horizon.sampler.clone()),
tgt_color: self.tgt_color_view.clone(),
tgt_depth_stencil: (self.tgt_depth_stencil_view.clone()/* , (1, 1) */),

View File

@ -2013,7 +2013,7 @@ impl FigureMgr {
lights,
shadows,
shadow_mats,
&lod.map,
&lod.alt,
&lod.horizon,
);
}
@ -2077,7 +2077,7 @@ impl FigureMgr {
lights,
shadows,
shadow_mats,
&lod.map,
&lod.alt,
&lod.horizon,
);
renderer.render_player_shadow(
@ -2089,7 +2089,7 @@ impl FigureMgr {
lights,
shadows,
shadow_mats,
&lod.map,
&lod.alt,
&lod.horizon,
);
}

View File

@ -1,17 +1,19 @@
use crate::{
render::{
pipelines::lod_terrain::{Locals, Vertex},
Consts, FilterMethod, Globals, LodColorFmt, LodTerrainPipeline, LodTextureFmt, Mesh, Model,
Quad, Renderer, Texture, WrapMode,
Consts, Globals, LodAltFmt, LodColorFmt, LodTerrainPipeline, LodTextureFmt, Mesh, Model,
Quad, Renderer, Texture,
},
settings::Settings,
};
use client::Client;
use common::{spiral::Spiral2d, util::srgba_to_linear};
use gfx::texture::SamplerInfo;
use vek::*;
pub struct LodData {
pub map: Texture<LodColorFmt>,
pub alt: Texture<LodAltFmt>,
pub horizon: Texture<LodTextureFmt>,
pub tgt_detail: u32,
}
@ -25,28 +27,54 @@ pub struct Lod {
impl LodData {
pub fn new(
renderer: &mut Renderer,
lod_base: &image::DynamicImage,
lod_horizon: &image::DynamicImage,
map_size: Vec2<u16>,
lod_base: &[u32],
lod_alt: &[u32],
lod_horizon: &[u32],
tgt_detail: u32,
border_color: gfx::texture::PackedColor,
) -> Self {
let kind = gfx::texture::Kind::D2(map_size.x, map_size.y, gfx::texture::AaMode::Single);
let info = gfx::texture::SamplerInfo::new(
gfx::texture::FilterMethod::Bilinear,
gfx::texture::WrapMode::Border,
);
Self {
map: renderer
.create_texture(
lod_base,
Some(FilterMethod::Bilinear),
Some(WrapMode::Border),
Some(border_color),
.create_texture_immutable_raw(
kind,
gfx::texture::Mipmap::Provided,
&[gfx::memory::cast_slice(lod_base)],
SamplerInfo {
border: border_color,
..info
},
)
.expect("Failed to generate map texture"),
alt: renderer
.create_texture_immutable_raw(
kind,
gfx::texture::Mipmap::Provided,
&[gfx::memory::cast_slice(lod_alt)],
SamplerInfo {
border: [0.0, 0.0, 0.0, 0.0].into(),
..info
},
)
.expect("Failed to generate alt texture"),
horizon: renderer
.create_texture(
lod_horizon,
Some(FilterMethod::Trilinear),
Some(WrapMode::Border),
Some([0.0, 1.0, 0.0, 1.0].into()),
.create_texture_immutable_raw(
kind,
gfx::texture::Mipmap::Provided,
&[gfx::memory::cast_slice(lod_horizon)],
SamplerInfo {
// filter: gfx::texture::FilterMethod::Nearest,
// filter: gfx::texture::FilterMethod::TriLinear,
border: [1.0, 0.0, 1.0, 0.0].into(),
..info
},
)
.expect("Failed to generate map texture"),
.expect("Failed to generate horizon texture"),
tgt_detail,
}
}
@ -60,7 +88,9 @@ impl Lod {
locals: renderer.create_consts(&[Locals::default()]).unwrap(),
data: LodData::new(
renderer,
client.world_map.1,
&client.lod_base,
&client.lod_alt,
&client.lod_horizon,
settings.graphics.lod_detail.max(100).min(2500),
[water_color.r, water_color.g, water_color.b, water_color.a].into(),
@ -95,6 +125,7 @@ impl Lod {
globals,
&self.locals,
&self.data.map,
&self.data.alt,
&self.data.horizon,
);
}

View File

@ -1512,7 +1512,7 @@ impl Scene {
&self.skybox.model,
&self.globals,
&self.skybox.locals,
&lod.map,
&lod.alt,
&lod.horizon,
);

View File

@ -105,16 +105,19 @@ impl Scene {
let map_bounds = Vec2::new(-65536.0, 131071.0);
let map_border = [0.0, 0.0, 0.0, 0.0];
let map_image = image::DynamicImage::ImageRgba8(image::RgbaImage::from_pixel(
/* let map_image = image::DynamicImage::ImageRgba8(image::RgbaImage::from_pixel(
1,
1,
image::Rgba([0, 0, 0, 0]),
));
let horizon_image = image::DynamicImage::ImageRgba8(image::RgbaImage::from_pixel(
)); */
let map_image = [0];
let alt_image = [0];
/* let horizon_image = image::DynamicImage::ImageRgba8(image::RgbaImage::from_pixel(
1,
1,
image::Rgba([0, 1, 0, 1]),
));
)); */
let horizon_image = [0x_00_01_00_01];
let mut camera = Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson);
camera.set_focus_pos(Vec3::unit_z() * 1.5);
@ -139,7 +142,7 @@ impl Scene {
.create_consts(&[PostProcessLocals::default()])
.unwrap(),
},
lod: LodData::new(renderer, &map_image, &horizon_image, 1, map_border.into()),// Lod::new(renderer, client, settings),
lod: LodData::new(renderer, Vec2::new(1, 1), &map_image, &alt_image, &horizon_image, 1, map_border.into()),// Lod::new(renderer, client, settings),
map_bounds,//: client.world_map.2,
figure_model_cache: FigureModelCache::new(),
@ -333,7 +336,7 @@ impl Scene {
&self.skybox.model,
&self.globals,
&self.skybox.locals,
&self.lod.map,
&self.lod.alt,
&self.lod.horizon,
);
@ -360,7 +363,7 @@ impl Scene {
&self.lights,
&self.shadows,
&self.shadow_mats,
&self.lod.map,
&self.lod.alt,
&self.lod.horizon,
);
}
@ -375,7 +378,7 @@ impl Scene {
&self.lights,
&self.shadows,
&self.shadow_mats,
&self.lod.map,
&self.lod.alt,
&self.lod.horizon,
);
}

View File

@ -3126,7 +3126,7 @@ impl<V: RectRasterableVol> Terrain<V> {
shadow_mats,
/* lights, */
/* shadows,
* &lod.map,
* &lod.alt,
* &lod.horizon, */
);
});
@ -3148,7 +3148,7 @@ impl<V: RectRasterableVol> Terrain<V> {
shadow_mats,
/* lights, */
/* shadows,
* &lod.map,
* &lod.alt,
* &lod.horizon, */
);
}
@ -3210,7 +3210,7 @@ impl<V: RectRasterableVol> Terrain<V> {
shadow_mats,
// lights,
// shadows,
// &lod.map,
// &lod.alt,
// &lod.horizon,
);
}
@ -3229,7 +3229,7 @@ impl<V: RectRasterableVol> Terrain<V> {
shadow_mats,
// lights,
// shadows,
// &lod.map,
// &lod.alt,
// &lod.horizon,
);
}
@ -3258,7 +3258,7 @@ impl<V: RectRasterableVol> Terrain<V> {
lights,
shadows,
shadow_mats,
&lod.map,
&lod.alt,
&lod.horizon,
);
}
@ -3362,7 +3362,7 @@ impl<V: RectRasterableVol> Terrain<V> {
lights,
shadows,
shadow_mats,
&lod.map,
&lod.alt,
&lod.horizon,
);
}
@ -3391,7 +3391,7 @@ impl<V: RectRasterableVol> Terrain<V> {
lights,
shadows,
shadow_mats,
&lod.map,
&lod.alt,
&lod.horizon,
&self.waves,
)

View File

@ -1382,6 +1382,7 @@ impl WorldSim {
.unwrap();
let mut v = vec![0u32; WORLD_SIZE.x * WORLD_SIZE.y];
let mut alts = vec![0u32; WORLD_SIZE.x * WORLD_SIZE.y];
// TODO: Parallelize again.
let config = MapConfig {
gain: self.max_height,
@ -1400,15 +1401,18 @@ impl WorldSim {
self,
pos.map(|e| e as i32) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
);
let a = (alt.min(1.0).max(0.0) * 255.0) as u8;
let a = 0; //(alt.min(1.0).max(0.0) * 255.0) as u8;
v[pos.y * WORLD_SIZE.x + pos.x] = u32::from_le_bytes([r, g, b, a]);
let posi = pos.y * WORLD_SIZE.x + pos.x;
v[posi] = u32::from_le_bytes([r, g, b, a]);
alts[posi] = (((alt.min(1.0).max(0.0) * 8191.0) as u32) & 0x1FFF) << 3;
},
);
WorldMapMsg {
dimensions: WORLD_SIZE.map(|e| e as u32),
dimensions: WORLD_SIZE.map(|e| e as u16),
max_height: self.max_height,
rgba: v,
alt: alts,
horizons,
}
}