mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Finished adding tether graphics
This commit is contained in:
parent
9a72d52c48
commit
deca7ae258
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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>>;
|
||||
|
@ -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)),
|
||||
}
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user