Finished adding tether graphics

This commit is contained in:
Joshua Barretto
2023-06-06 18:30:40 +01:00
parent 9a72d52c48
commit deca7ae258
11 changed files with 124 additions and 64 deletions

View File

@ -804,4 +804,17 @@ vec3 simple_lighting(vec3 pos, vec3 col, float shade) {
return col * clamp(2.5 / dot(d, d), shade * (get_sun_brightness() + 0.01), 1); return col * clamp(2.5 / dot(d, d), shade * (get_sun_brightness() + 0.01), 1);
} }
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, 6.0);
aspeed = max(aspeed, 5.0);
return (sin(tick_loop(2.0 * PI, 0.35 * scaling * floor(aspeed), off)) * (1.0 - fract(aspeed))
+ sin(tick_loop(2.0 * PI, 0.35 * scaling * ceil(aspeed), off)) * fract(aspeed)) * abs(strength) * 0.25;
//return sin(tick.x * 1.5 * scaling + off) + sin(tick.x * 0.35 * scaling + off);
}
#endif #endif

View File

@ -76,19 +76,6 @@ vec4 nearest_entity(in vec3 sprite_pos, const float entity_radius_factor) {
return closest; 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, 6.0);
aspeed = max(aspeed, 5.0);
return (sin(tick_loop(2.0 * PI, 0.35 * scaling * floor(aspeed), off)) * (1.0 - fract(aspeed))
+ sin(tick_loop(2.0 * PI, 0.35 * scaling * ceil(aspeed), off)) * fract(aspeed)) * abs(strength) * 0.25;
//return sin(tick.x * 1.5 * scaling + off) + sin(tick.x * 0.35 * scaling + off);
}
void main() { void main() {
// Matrix to transform this sprite instance from model space to chunk space // Matrix to transform this sprite instance from model space to chunk space
mat4 inst_mat; mat4 inst_mat;

View File

@ -31,6 +31,7 @@ layout(location = 0) in vec3 f_pos;
// in float f_ao; // in float f_ao;
// flat in uint f_pos_norm; // flat in uint f_pos_norm;
layout(location = 1) in vec3 f_norm; layout(location = 1) in vec3 f_norm;
layout(location = 2) in vec3 m_pos;
// in float f_alt; // in float f_alt;
// in vec4 f_shadow; // in vec4 f_shadow;
// in vec3 light_pos[2]; // in vec3 light_pos[2];
@ -72,7 +73,11 @@ void main() {
float f_ao = 1.0; float f_ao = 1.0;
uint material = 0xFFu; uint material = 0xFFu;
vec3 f_col = vec3(0.1); vec3 f_col = mix(
vec3(0.035, 0.02, 0.01),
vec3(0.06, 0.05, 0.03),
floor(abs(fract(m_pos.z * 10.0) - 0.5) * 6.0) / 3.0
);
#ifdef EXPERIMENTAL_BAREMINIMUM #ifdef EXPERIMENTAL_BAREMINIMUM
tgt_color = vec4(simple_lighting(f_pos.xyz, f_col, f_ao), 1); tgt_color = vec4(simple_lighting(f_pos.xyz, f_col, f_ao), 1);

View File

@ -15,6 +15,7 @@
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN #define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
#include <globals.glsl> #include <globals.glsl>
#include <sky.glsl>
layout(location = 0) in vec3 v_pos; layout(location = 0) in vec3 v_pos;
layout(location = 1) in vec3 v_norm; layout(location = 1) in vec3 v_norm;
@ -23,13 +24,27 @@ layout (std140, set = 2, binding = 0)
uniform u_locals { uniform u_locals {
vec4 pos_a; vec4 pos_a;
vec4 pos_b; vec4 pos_b;
float tether_length;
}; };
layout(location = 0) out vec3 f_pos; layout(location = 0) out vec3 f_pos;
layout(location = 1) out vec3 f_norm; layout(location = 1) out vec3 f_norm;
layout(location = 2) out vec3 m_pos;
void main() { void main() {
vec3 pos = pos_a.xyz + v_pos * vec3(1, 1, 5); m_pos = v_pos;
vec3 rz = normalize(pos_b.xyz - pos_a.xyz);
vec3 rx = normalize(cross(vec3(0, 0, 1), rz));
vec3 ry = normalize(cross(rz, rx));
float dist = distance(pos_a.xyz, pos_b.xyz);
vec3 pos = pos_a.xyz + (rx * v_pos.x + ry * v_pos.y) * 0.1 + rz * v_pos.z * dist;
vec2 ideal_wind_sway = wind_vel * vec2(
wind_wave(pos.y * 1.5, 2.9, wind_vel.x, wind_vel.y),
wind_wave(pos.x * 1.5, 3.1, wind_vel.y, wind_vel.x)
);
float dip = (1 - pow(abs(v_pos.z - 0.5) * 2.0, 2)) * max(tether_length - dist, 0.0);
pos += vec3(ideal_wind_sway * min(pow(dip, 2), 0.005), -0.5 * dip);
f_pos = pos + focus_pos.xyz; f_pos = pos + focus_pos.xyz;
@ -37,7 +52,7 @@ void main() {
f_pos.z -= pow(distance(f_pos.xy + focus_off.xy, focus_pos.xy + focus_off.xy) * 0.05, 2); f_pos.z -= pow(distance(f_pos.xy + focus_off.xy, focus_pos.xy + focus_off.xy) * 0.05, 2);
#endif #endif
f_norm = v_norm; f_norm = rx * v_norm.x + ry * v_norm.y + rz * v_norm.z;
gl_Position = all_mat * vec4(f_pos, 1); gl_Position = all_mat * vec4(f_pos, 1);
} }

View File

@ -1215,7 +1215,13 @@ impl Body {
.into() .into()
} }
pub fn tether_offset(&self) -> Vec3<f32> { Vec3::new(0.0, self.dimensions().y * 0.5, 0.0) } pub fn tether_offset_leader(&self) -> Vec3<f32> {
Vec3::new(0.0, self.dimensions().y * -0.4, self.dimensions().z * 0.7)
}
pub fn tether_offset_follower(&self) -> Vec3<f32> {
Vec3::new(0.0, self.dimensions().y * 0.6, self.dimensions().z * 0.7)
}
pub fn localize(&self) -> Content { pub fn localize(&self) -> Content {
match self { match self {

View File

@ -3,7 +3,7 @@ use crate::{
link::{Is, Link, LinkHandle, Role}, link::{Is, Link, LinkHandle, Role},
terrain::{Block, TerrainGrid}, terrain::{Block, TerrainGrid},
tether, tether,
uid::{Uid, UidAllocator}, uid::{IdMaps, Uid},
vol::ReadVol, vol::ReadVol,
}; };
use hashbrown::HashSet; use hashbrown::HashSet;

View File

@ -2,10 +2,10 @@ use crate::{
comp, comp,
link::{Is, Link, LinkHandle, Role}, link::{Is, Link, LinkHandle, Role},
mounting::{Rider, VolumeRider}, mounting::{Rider, VolumeRider},
uid::{Uid, UidAllocator}, uid::{IdMaps, Uid},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use specs::{saveload::MarkerAllocator, Entities, Read, ReadStorage, WriteStorage}; use specs::{Entities, Read, ReadStorage, WriteStorage};
use vek::*; use vek::*;
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -37,20 +37,20 @@ pub enum TetherError {
impl Link for Tethered { impl Link for Tethered {
type CreateData<'a> = ( type CreateData<'a> = (
Read<'a, UidAllocator>, Read<'a, IdMaps>,
WriteStorage<'a, Is<Leader>>, WriteStorage<'a, Is<Leader>>,
WriteStorage<'a, Is<Follower>>, WriteStorage<'a, Is<Follower>>,
ReadStorage<'a, Is<Rider>>, ReadStorage<'a, Is<Rider>>,
ReadStorage<'a, Is<VolumeRider>>, ReadStorage<'a, Is<VolumeRider>>,
); );
type DeleteData<'a> = ( type DeleteData<'a> = (
Read<'a, UidAllocator>, Read<'a, IdMaps>,
WriteStorage<'a, Is<Leader>>, WriteStorage<'a, Is<Leader>>,
WriteStorage<'a, Is<Follower>>, WriteStorage<'a, Is<Follower>>,
); );
type Error = TetherError; type Error = TetherError;
type PersistData<'a> = ( type PersistData<'a> = (
Read<'a, UidAllocator>, Read<'a, IdMaps>,
Entities<'a>, Entities<'a>,
ReadStorage<'a, comp::Health>, ReadStorage<'a, comp::Health>,
ReadStorage<'a, Is<Leader>>, ReadStorage<'a, Is<Leader>>,
@ -59,15 +59,9 @@ impl Link for Tethered {
fn create( fn create(
this: &LinkHandle<Self>, this: &LinkHandle<Self>,
( (id_maps, is_leaders, is_followers, is_riders, is_volume_rider): &mut Self::CreateData<'_>,
uid_allocator,
is_leaders,
is_followers,
is_riders,
is_volume_rider,
): &mut Self::CreateData<'_>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
let entity = |uid: Uid| uid_allocator.retrieve_entity_internal(uid.into()); let entity = |uid: Uid| id_maps.uid_entity(uid);
if this.leader == this.follower { if this.leader == this.follower {
// Forbid self-tethering // Forbid self-tethering
@ -94,9 +88,9 @@ impl Link for Tethered {
fn persist( fn persist(
this: &LinkHandle<Self>, this: &LinkHandle<Self>,
(uid_allocator, entities, healths, is_leaders, is_followers): &mut Self::PersistData<'_>, (id_maps, entities, healths, is_leaders, is_followers): &mut Self::PersistData<'_>,
) -> bool { ) -> bool {
let entity = |uid: Uid| uid_allocator.retrieve_entity_internal(uid.into()); let entity = |uid: Uid| id_maps.uid_entity(uid);
if let Some((leader, follower)) = entity(this.leader).zip(entity(this.follower)) { if let Some((leader, follower)) = entity(this.leader).zip(entity(this.follower)) {
let is_alive = |entity| { let is_alive = |entity| {
@ -115,9 +109,9 @@ impl Link for Tethered {
fn delete( fn delete(
this: &LinkHandle<Self>, this: &LinkHandle<Self>,
(uid_allocator, is_leaders, is_followers): &mut Self::DeleteData<'_>, (id_maps, is_leaders, is_followers): &mut Self::DeleteData<'_>,
) { ) {
let entity = |uid: Uid| uid_allocator.retrieve_entity_internal(uid.into()); let entity = |uid: Uid| id_maps.uid_entity(uid);
let leader = entity(this.leader); let leader = entity(this.leader);
let follower = entity(this.follower); let follower = entity(this.follower);

View File

@ -3,14 +3,11 @@ use common::{
link::Is, link::Is,
resources::DeltaTime, resources::DeltaTime,
tether::Follower, tether::Follower,
uid::UidAllocator, uid::IdMaps,
util::Dir, util::Dir,
}; };
use common_ecs::{Job, Origin, Phase, System}; use common_ecs::{Job, Origin, Phase, System};
use specs::{ use specs::{Entities, Join, Read, ReadStorage, WriteStorage};
saveload::{Marker, MarkerAllocator},
Entities, Join, Read, ReadStorage, WriteStorage,
};
use vek::*; use vek::*;
/// This system is responsible for controlling mounts /// This system is responsible for controlling mounts
@ -18,7 +15,7 @@ use vek::*;
pub struct Sys; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> System<'a> for Sys {
type SystemData = ( type SystemData = (
Read<'a, UidAllocator>, Read<'a, IdMaps>,
Entities<'a>, Entities<'a>,
Read<'a, DeltaTime>, Read<'a, DeltaTime>,
ReadStorage<'a, Is<Follower>>, ReadStorage<'a, Is<Follower>>,
@ -37,7 +34,7 @@ impl<'a> System<'a> for Sys {
fn run( fn run(
_job: &mut Job<Self>, _job: &mut Job<Self>,
( (
uid_allocator, id_maps,
entities, entities,
dt, dt,
is_followers, is_followers,
@ -49,12 +46,10 @@ impl<'a> System<'a> for Sys {
masses, masses,
): Self::SystemData, ): Self::SystemData,
) { ) {
for (follower, is_follower, follower_body, scale) in for (follower, is_follower, follower_body, follower_scale) in
(&entities, &is_followers, bodies.maybe(), scales.maybe()).join() (&entities, &is_followers, bodies.maybe(), scales.maybe()).join()
{ {
let Some(leader) = uid_allocator let Some(leader) = id_maps.uid_entity(is_follower.leader) else { continue };
.retrieve_entity_internal(is_follower.leader.id())
else { continue };
let (Some(leader_pos), Some(follower_pos)) = ( let (Some(leader_pos), Some(follower_pos)) = (
positions.get(leader).copied(), positions.get(leader).copied(),
@ -67,18 +62,36 @@ impl<'a> System<'a> for Sys {
) else { continue }; ) else { continue };
if velocities.contains(follower) && velocities.contains(leader) { if velocities.contains(follower) && velocities.contains(leader) {
let attach_offset = orientations
.get(leader)
.map(|ori| {
ori.to_quat()
* bodies
.get(leader)
.map(|b| {
b.tether_offset_leader()
* scales.get(leader).copied().unwrap_or(Scale(1.0)).0
})
.unwrap_or_default()
})
.unwrap_or_default();
let attach_pos = leader_pos.0 + attach_offset;
let tether_offset = orientations let tether_offset = orientations
.get(follower) .get(follower)
.map(|ori| { .map(|ori| {
ori.to_quat() ori.to_quat()
* follower_body * follower_body
.map(|b| b.tether_offset() * scale.copied().unwrap_or(Scale(1.0)).0) .map(|b| {
b.tether_offset_follower()
* follower_scale.copied().unwrap_or(Scale(1.0)).0
})
.unwrap_or_default() .unwrap_or_default()
}) })
.unwrap_or_default(); .unwrap_or_default();
let tether_pos = follower_pos.0 + tether_offset; let tether_pos = follower_pos.0 + tether_offset;
let pull_factor = let pull_factor =
(leader_pos.0.distance(tether_pos) - is_follower.tether_length).max(0.0); (attach_pos.distance(tether_pos) - is_follower.tether_length).max(0.0);
let strength = pull_factor * 50000.0; let strength = pull_factor * 50000.0;
let pull_dir = (leader_pos.0 - follower_pos.0) let pull_dir = (leader_pos.0 - follower_pos.0)
.try_normalized() .try_normalized()
@ -91,8 +104,8 @@ impl<'a> System<'a> for Sys {
if let Some(follower_ori) = orientations.get_mut(follower) { if let Some(follower_ori) = orientations.get_mut(follower) {
let turn_strength = pull_factor let turn_strength = pull_factor
* (tether_offset.magnitude() * (leader_pos.0 - tether_pos).magnitude() * (tether_offset.magnitude() * (attach_pos - tether_pos).magnitude()
- tether_offset.dot(leader_pos.0 - tether_pos).abs()) - tether_offset.dot(attach_pos - tether_pos).abs())
* 2.0; * 2.0;
let target_ori = follower_ori.yawed_towards(Dir::new(pull_dir)); let target_ori = follower_ori.yawed_towards(Dir::new(pull_dir));
*follower_ori = follower_ori.slerped_towards(target_ori, turn_strength * dt.0); *follower_ori = follower_ori.slerped_towards(target_ori, turn_strength * dt.0);

View File

@ -1824,7 +1824,7 @@ fn handle_spawn_ship(
.link(Tethered { .link(Tethered {
leader, leader,
follower, follower,
tether_length: 4.0, tether_length: 6.0,
}) })
.map_err(|_| "Failed to tether entities")?; .map_err(|_| "Failed to tether entities")?;
} else { } else {

View File

@ -8,19 +8,21 @@ use vek::*;
pub struct Locals { pub struct Locals {
pos_a: [f32; 4], pos_a: [f32; 4],
pos_b: [f32; 4], pos_b: [f32; 4],
tether_length: f32,
} }
impl Locals { impl Locals {
pub fn new(pos_a: Vec3<f32>, pos_b: Vec3<f32>) -> Self { pub fn new(pos_a: Vec3<f32>, pos_b: Vec3<f32>, tether_length: f32) -> Self {
Self { Self {
pos_a: pos_a.with_w(0.0).into_array(), pos_a: pos_a.with_w(0.0).into_array(),
pos_b: pos_b.with_w(0.0).into_array(), pos_b: pos_b.with_w(0.0).into_array(),
tether_length,
} }
} }
} }
impl Default for Locals { impl Default for Locals {
fn default() -> Self { Self::new(Vec3::zero(), Vec3::zero()) } fn default() -> Self { Self::new(Vec3::zero(), Vec3::zero(), 0.0) }
} }
pub type BoundLocals = Bound<Consts<Locals>>; pub type BoundLocals = Bound<Consts<Locals>>;

View File

@ -13,11 +13,11 @@ use common::{
comp, comp,
link::Is, link::Is,
tether::Follower, tether::Follower,
uid::Uid, uid::{IdMaps, Uid},
util::srgba_to_linear, util::srgba_to_linear,
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
use specs::Join; use specs::{Join, WorldExt};
use vek::*; use vek::*;
pub struct TetherMgr { pub struct TetherMgr {
@ -36,23 +36,48 @@ impl TetherMgr {
} }
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client, focus_off: Vec3<f32>) { pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client, focus_off: Vec3<f32>) {
let positions = client.state().read_storage::<comp::Pos>(); let interpolated = client
.state()
.read_storage::<crate::ecs::comp::Interpolated>();
let scales = client.state().read_storage::<comp::Scale>();
let bodies = client.state().read_storage::<comp::Body>();
let id_maps = client.state().ecs().read_resource::<IdMaps>();
let is_followers = client.state().read_storage::<Is<Follower>>(); let is_followers = client.state().read_storage::<Is<Follower>>();
for (pos, is_follower) in (&positions, &is_followers).join() { for (interp, is_follower, body, scale) in
(&interpolated, &is_followers, bodies.maybe(), scales.maybe()).join()
{
let Some(leader) = id_maps.uid_entity(is_follower.leader) else { continue };
let pos_a = interpolated.get(leader).map_or(Vec3::zero(), |i| i.pos)
+ interpolated.get(leader).zip(bodies.get(leader)).map_or(
Vec3::zero(),
|(i, body)| {
i.ori.to_quat()
* body.tether_offset_leader()
* scales.get(leader).copied().unwrap_or(comp::Scale(1.0)).0
},
);
let pos_b = interp.pos
+ body.map_or(Vec3::zero(), |body| {
interp.ori.to_quat()
* body.tether_offset_follower()
* scale.copied().unwrap_or(comp::Scale(1.0)).0
});
let (locals, stale_flag) = self let (locals, stale_flag) = self
.tethers .tethers
.entry((is_follower.leader, is_follower.follower)) .entry((is_follower.leader, is_follower.follower))
.or_insert_with(|| { .or_insert_with(|| {
( (
renderer.create_tether_bound_locals(&[Locals::new( renderer.create_tether_bound_locals(&[Locals::default()]),
pos.0 - focus_off,
pos.0 - focus_off,
)]),
self.stale_flag, self.stale_flag,
) )
}); });
renderer.update_consts(locals, &[Locals::new(pos.0 - focus_off, pos.0 - focus_off)]); renderer.update_consts(locals, &[Locals::new(
pos_a - focus_off,
pos_b - focus_off,
is_follower.tether_length,
)]);
*stale_flag = self.stale_flag; *stale_flag = self.stale_flag;
} }
@ -86,8 +111,8 @@ fn create_tether_mesh() -> Mesh<Vertex> {
let z = s as f32 / SEGMENTS as f32; let z = s as f32 / SEGMENTS as f32;
Quad { Quad {
a: Vertex::new(start.with_z(z), start.with_z(0.0)), a: Vertex::new(start.with_z(z), start.with_z(0.0)),
b: Vertex::new(start.with_z(z + 1.0), start.with_z(0.0)), b: Vertex::new(start.with_z(z + 1.0 / SEGMENTS as f32), start.with_z(0.0)),
c: Vertex::new(end.with_z(z + 1.0), end.with_z(0.0)), c: Vertex::new(end.with_z(z + 1.0 / SEGMENTS as f32), end.with_z(0.0)),
d: Vertex::new(end.with_z(z), end.with_z(0.0)), d: Vertex::new(end.with_z(z), end.with_z(0.0)),
} }
}) })