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);
}
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

View File

@ -76,19 +76,6 @@ 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, 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() {
// Matrix to transform this sprite instance from model space to chunk space
mat4 inst_mat;

View File

@ -31,6 +31,7 @@ layout(location = 0) in vec3 f_pos;
// in float f_ao;
// flat in uint f_pos_norm;
layout(location = 1) in vec3 f_norm;
layout(location = 2) in vec3 m_pos;
// in float f_alt;
// in vec4 f_shadow;
// in vec3 light_pos[2];
@ -72,7 +73,11 @@ void main() {
float f_ao = 1.0;
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
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
#include <globals.glsl>
#include <sky.glsl>
layout(location = 0) in vec3 v_pos;
layout(location = 1) in vec3 v_norm;
@ -23,13 +24,27 @@ layout (std140, set = 2, binding = 0)
uniform u_locals {
vec4 pos_a;
vec4 pos_b;
float tether_length;
};
layout(location = 0) out vec3 f_pos;
layout(location = 1) out vec3 f_norm;
layout(location = 2) out vec3 m_pos;
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;
@ -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);
#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);
}

View File

@ -1215,7 +1215,13 @@ impl Body {
.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 {
match self {

View File

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

View File

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

View File

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

View File

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

View File

@ -8,19 +8,21 @@ use vek::*;
pub struct Locals {
pos_a: [f32; 4],
pos_b: [f32; 4],
tether_length: f32,
}
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 {
pos_a: pos_a.with_w(0.0).into_array(),
pos_b: pos_b.with_w(0.0).into_array(),
tether_length,
}
}
}
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>>;

View File

@ -13,11 +13,11 @@ use common::{
comp,
link::Is,
tether::Follower,
uid::Uid,
uid::{IdMaps, Uid},
util::srgba_to_linear,
};
use hashbrown::HashMap;
use specs::Join;
use specs::{Join, WorldExt};
use vek::*;
pub struct TetherMgr {
@ -36,23 +36,48 @@ impl TetherMgr {
}
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>>();
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
.tethers
.entry((is_follower.leader, is_follower.follower))
.or_insert_with(|| {
(
renderer.create_tether_bound_locals(&[Locals::new(
pos.0 - focus_off,
pos.0 - focus_off,
)]),
renderer.create_tether_bound_locals(&[Locals::default()]),
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;
}
@ -86,8 +111,8 @@ fn create_tether_mesh() -> Mesh<Vertex> {
let z = s as f32 / SEGMENTS as f32;
Quad {
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)),
c: Vertex::new(end.with_z(z + 1.0), end.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 / SEGMENTS as f32), end.with_z(0.0)),
d: Vertex::new(end.with_z(z), end.with_z(0.0)),
}
})