Merge branch 'zesterer/lod-models' into 'master'

New LoD model, wind sway pays attention to wind velocity

See merge request veloren/veloren!3739
This commit is contained in:
Marcel 2023-01-02 14:51:00 +00:00
commit 2ff24259be
14 changed files with 66 additions and 22 deletions

BIN
assets/voxygen/lod/dead.obj (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -20,6 +20,7 @@ layout(std140, set = 0, binding = 0) uniform u_globals {
ivec4 select_pos;
vec4 gamma_exposure;
vec4 last_lightning;
vec2 wind_vel;
float ambiance;
// 0 - FirstPerson
// 1 - ThirdPerson

View File

@ -53,6 +53,7 @@ const float SCALE = 1.0 / 11.0;
const float SCALE_FACTOR = pow(SCALE, 1.3) * 0.2;
const float EXTRA_NEG_Z = 32768.0;
const float VERT_EXTRA_NEG_XY = 128.0;
const float VERT_EXTRA_NEG_Z = 128.0;
const uint VERT_PAGE_SIZE = 256;
@ -74,6 +75,19 @@ vec4 nearest_entity(in vec3 sprite_pos, const float entity_radius_factor) {
return closest;
}
float wind_wave(float off, float scaling, float speed, float strength) {
float aspeed = abs(speed);
// TODO: Right now, the wind model is pretty simplistic. This means that there is frequently no wind at all, which
// looks bad. For now, we add a lower bound on the wind speed to keep things looking nice.
strength = max(strength, 3.0);
aspeed = max(aspeed, 3.0);
return (sin(tick.x * 0.75 * scaling * floor(aspeed) + off) * (1.0 - fract(aspeed))
+ sin(tick.x * 0.75 * scaling * ceil(aspeed) + off) * fract(aspeed)) * abs(strength) * 0.5;
//return sin(tick.x * 1.5 * scaling + off) + sin(tick.x * 0.35 * scaling + off);
}
void main() {
// Matrix to transform this sprite instance from model space to chunk space
mat4 inst_mat;
@ -94,7 +108,11 @@ void main() {
uint v_atlas_pos = pos_atlas_pos_norm_ao.y;
// Expand the model vertex position bits into float values
vec3 v_pos = vec3(v_pos_norm & 0xFFu, (v_pos_norm >> 8) & 0xFFu, float((v_pos_norm >> 16) & 0x0FFFu) - VERT_EXTRA_NEG_Z);
vec3 v_pos = vec3(
float(v_pos_norm & 0xFFu) - VERT_EXTRA_NEG_XY,
float((v_pos_norm >> 8) & 0xFFu) - VERT_EXTRA_NEG_XY,
float((v_pos_norm >> 16) & 0x0FFFu) - VERT_EXTRA_NEG_Z
);
// Position of the sprite block in the chunk
// Used for highlighting the selected sprite, and for opening doors
@ -142,15 +160,16 @@ void main() {
#endif
#ifndef EXPERIMENTAL_BAREMINIMUM
// TODO: take wind_vel into account
// Wind sway effect
f_pos += model_wind_sway * vec3(
sin(tick.x * 1.5 + f_pos.y * 0.1) * sin(tick.x * 0.35),
sin(tick.x * 1.5 + f_pos.x * 0.1) * sin(tick.x * 0.25),
0.0
// NOTE: could potentially replace `v_pos.z * model_z_scale` with a calculation using `inst_chunk_pos` from below
//) * pow(abs(v_pos.z * model_z_scale), 1.3) * SCALE_FACTOR;
) * v_pos.z * model_z_scale * SCALE_FACTOR;
f_pos.xy += (wind_vel * 0.1 + vec2(
wind_wave(f_pos.y * 0.1, 0.9, wind_vel.x, wind_vel.y),
wind_wave(f_pos.x * 0.1, 1.1, wind_vel.y, wind_vel.x)
))
* model_wind_sway
//* mix(10.0, abs(v_pos.z), 1.0 / (1.0 + abs(v_pos.z) * 0.1))
* v_pos.z
* model_z_scale
* SCALE_FACTOR;
if (model_wind_sway > 0.0) {
vec2 center = sprite_pos.xy + 0.5;

View File

@ -700,16 +700,16 @@ Liana: Some((
variations: [
(
model: "voxygen.voxel.sprite.lianas.liana-0",
offset: (-4.0, -4.0, -88.0),
offset: (-4.0, -4.0, -115.0),
lod_axes: (0.0, 0.0, 0.5),
),
(
model: "voxygen.voxel.sprite.lianas.liana-1",
offset: (-4.0, -4.0, -55.0),
offset: (-4.0, -4.0, -72.0),
lod_axes: (0.0, 0.0, 0.5),
),
],
wind_sway: 0.0,
wind_sway: 0.5,
)),
// Velorite
Velorite: Some((
@ -1403,7 +1403,7 @@ SavannaBush: Some((
lod_axes: (1.0, 1.0, 1.0),
),
],
wind_sway: 0.1,
wind_sway: 0.2,
)),
// Dead Bush
DeadBush: Some((
@ -1429,7 +1429,7 @@ DeadBush: Some((
lod_axes: (1.0, 1.0, 1.0),
),
],
wind_sway: 0.1,
wind_sway: 0.2,
)),
// Blueberries
// NOTE: Why are these commented out?
@ -3049,7 +3049,7 @@ GiantKelp: Some((
],
wind_sway: 0.2,
)),
// Red Algae
// Red Algae
RedAlgae: None,
// Underwater Vent
UnderwaterVent: None,

View File

@ -18,6 +18,7 @@ bitflags::bitflags! {
pub enum ObjectKind {
Oak,
Pine,
Dead,
House,
GiantTree,
}

View File

@ -43,7 +43,12 @@ impl Weather {
// Get the rain velocity for this weather
pub fn rain_vel(&self) -> Vec3<f32> {
const FALL_RATE: f32 = 30.0;
Vec3::new(self.wind.x, self.wind.y, -FALL_RATE)
self.wind.with_z(-FALL_RATE)
}
// Get the wind velocity for this weather
pub fn wind_vel(&self) -> Vec2<f32> {
self.wind
}
}

View File

@ -122,6 +122,7 @@ pub fn generate_mesh_base_vol_sprite<'a: 'b, 'b, V: 'a>(
&'b mut Mesh<SpriteVertex>,
bool,
),
offset: Vec3<f32>,
) -> MeshGen<SpriteVertex, SpriteVertex, TerrainVertex, ()>
where
V: BaseVol<Vox = Cell> + ReadVol + SizedVol,
@ -211,7 +212,7 @@ where
// position, pos + mesh_delta, is guaranteed to fit in an f32).
let mesh_delta = lower_bound.as_::<f32>();
let create_opaque = |atlas_pos, pos: Vec3<f32>, norm, _meta| {
SpriteVertex::new(atlas_pos, pos + mesh_delta, norm)
SpriteVertex::new(atlas_pos, pos + offset + mesh_delta, norm)
};
greedy.push(GreedyConfig {

View File

@ -65,11 +65,12 @@ pub struct Globals {
select_pos: [i32; 4],
gamma_exposure: [f32; 4],
last_lightning: [f32; 4],
wind_vel: [f32; 2],
ambiance: f32,
cam_mode: u32,
sprite_render_distance: f32,
// To keep 16-byte-aligned.
globals_dummy: [f32; 1],
globals_dummy: [f32; 3],
}
/// Make sure Globals is 16-byte-aligned.
const _: () = assert!(core::mem::size_of::<Globals>() % 16 == 0);
@ -110,6 +111,7 @@ impl Globals {
gamma: f32,
exposure: f32,
last_lightning: (Vec3<f32>, f64),
wind_vel: Vec2<f32>,
ambiance: f32,
cam_mode: CameraMode,
sprite_render_distance: f32,
@ -162,10 +164,11 @@ impl Globals {
.0
.with_w(last_lightning.1 as f32)
.into_array(),
wind_vel: wind_vel.into_array(),
ambiance: ambiance.clamped(0.0, 1.0),
cam_mode: cam_mode as u32,
sprite_render_distance,
globals_dummy: [0.0; 1],
globals_dummy: [0.0; 3],
}
}
@ -209,6 +212,7 @@ impl Default for Globals {
1.0,
1.0,
(Vec3::zero(), -1000.0),
Vec2::zero(),
1.0,
CameraMode::ThirdPerson,
250.0,

View File

@ -42,6 +42,7 @@ impl Vertex {
// NOTE: Limit to 16 (x) × 16 (y) × 32 (z).
#[allow(clippy::collapsible_else_if)]
pub fn new(atlas_pos: Vec2<u16>, pos: Vec3<f32>, norm: Vec3<f32>) -> Self {
const VERT_EXTRA_NEG_XY: i32 = 128;
const VERT_EXTRA_NEG_Z: i32 = 128; // NOTE: change if number of bits changes below, also we might not need this if meshing always produces positives values for sprites (I have no idea)
#[allow(clippy::bool_to_int_with_if)]
@ -59,8 +60,8 @@ impl Vertex {
// | (((pos + EXTRA_NEG_Z).z.max(0.0).min((1 << 16) as f32) as u32) & 0xFFFF) << 12
// | if meta { 1 } else { 0 } << 28
// | (norm_bits & 0x7) << 29,
pos_norm: ((pos.x as u32) & 0x00FF) // NOTE: temp hack, this doesn't need 8 bits
| ((pos.y as u32) & 0x00FF) << 8
pos_norm: (((pos.x as i32 + VERT_EXTRA_NEG_XY) & 0x00FF) as u32) // NOTE: temp hack, this doesn't need 8 bits
| (((pos.y as i32 + VERT_EXTRA_NEG_XY) & 0x00FF) as u32) << 8
| (((pos.z as i32 + VERT_EXTRA_NEG_Z).clamp(0, 1 << 12) as u32) & 0x0FFF) << 16
| (norm_bits & 0x7) << 29,
atlas_pos: ((atlas_pos.x as u32) & 0xFFFF) | ((atlas_pos.y as u32) & 0xFFFF) << 16,

View File

@ -65,6 +65,7 @@ impl Lod {
object_data: [
(lod::ObjectKind::Oak, make_lod_object("oak", renderer)),
(lod::ObjectKind::Pine, make_lod_object("pine", renderer)),
(lod::ObjectKind::Dead, make_lod_object("dead", renderer)),
(lod::ObjectKind::House, make_lod_object("house", renderer)),
(
lod::ObjectKind::GiantTree,
@ -124,6 +125,7 @@ impl Lod {
let color = match object.kind {
lod::ObjectKind::Pine => Rgb::new(0, 25, 12),
lod::ObjectKind::Oak => Rgb::new(10, 50, 5),
lod::ObjectKind::Dead => Rgb::new(20, 10, 2),
lod::ObjectKind::House => Rgb::new(20, 15, 0),
lod::ObjectKind::GiantTree => Rgb::new(8, 35, 5),
};

View File

@ -111,6 +111,7 @@ pub struct Scene {
ambient_mgr: AmbientMgr,
integrated_rain_vel: f32,
wind_vel: Vec2<f32>,
pub interpolated_time_of_day: Option<f64>,
last_lightning: Option<(Vec3<f32>, f64)>,
}
@ -345,6 +346,7 @@ impl Scene {
ambience: ambient::load_ambience_items(),
},
integrated_rain_vel: 0.0,
wind_vel: Vec2::zero(),
interpolated_time_of_day: None,
last_lightning: None,
}
@ -783,6 +785,7 @@ impl Scene {
scene_data.gamma,
scene_data.exposure,
self.last_lightning.unwrap_or((Vec3::zero(), -1000.0)),
self.wind_vel,
scene_data.ambiance,
self.camera.get_mode(),
scene_data.sprite_render_distance - 20.0,
@ -1101,6 +1104,7 @@ impl Scene {
let weather = client
.state()
.max_weather_near(focus_off.xy() + cam_pos.xy());
self.wind_vel = weather.wind_vel();
if weather.rain > RAIN_THRESHOLD {
let weather = client.state().weather_at(focus_off.xy() + cam_pos.xy());
let rain_vel = weather.rain_vel();

View File

@ -274,6 +274,7 @@ impl Scene {
scene_data.gamma,
scene_data.exposure,
(Vec3::zero(), -1000.0),
Vec2::zero(),
scene_data.ambiance,
self.camera.get_mode(),
250.0,

View File

@ -515,6 +515,7 @@ impl SpriteRenderContext {
generate_mesh_base_vol_sprite(
Segment::from(&model.read().0).scaled_by(lod_scale),
(greedy, sprite_mesh, false),
offset.map(|e: f32| e.floor()) * lod_scale,
);
// Get the number of pages after the model was meshed
let end_page_num = (sprite_mesh.vertices().len()
@ -532,7 +533,7 @@ impl SpriteRenderContext {
SpriteData {
vert_pages: start_page_num as u32..end_page_num as u32,
scale: sprite_scale,
offset,
offset: offset.map(|e| e.rem_euclid(1.0)),
}
});

View File

@ -491,6 +491,7 @@ impl World {
Some(lod::Object {
kind: match tree.forest_kind {
all::ForestKind::Oak => lod::ObjectKind::Oak,
all::ForestKind::Dead => lod::ObjectKind::Dead,
all::ForestKind::Pine
| all::ForestKind::Frostpine
| all::ForestKind::Redwood => lod::ObjectKind::Pine,