Renamed tether renderer to rope, fixed tether lengths

This commit is contained in:
Joshua Barretto 2023-10-20 13:06:21 +01:00
parent 879a28fbb6
commit 7589774967
12 changed files with 93 additions and 65 deletions

View File

@ -24,7 +24,7 @@ layout (std140, set = 2, binding = 0)
uniform u_locals {
vec4 pos_a;
vec4 pos_b;
float tether_length;
float rope_length;
};
layout(location = 0) out vec3 f_pos;
@ -43,7 +43,7 @@ void main() {
wind_wave(pos.y * 1.5, 1.9, wind_vel.x, wind_vel.y),
wind_wave(pos.x * 1.5, 2.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);
float dip = (1 - pow(abs(v_pos.z - 0.5) * 2.0, 2)) * max(rope_length - dist, 0.0);
pos += vec3(ideal_wind_sway * min(pow(dip, 2), 0.005), -0.5 * dip);
f_pos = pos + focus_pos.xyz;

View File

@ -19,7 +19,7 @@ impl<'a> System<'a> for Sys {
Entities<'a>,
Read<'a, DeltaTime>,
ReadStorage<'a, Is<Follower>>,
WriteStorage<'a, Pos>,
ReadStorage<'a, Pos>,
WriteStorage<'a, Vel>,
WriteStorage<'a, Ori>,
ReadStorage<'a, Body>,

View File

@ -41,7 +41,7 @@ use common::{
event::{EventBus, ServerEvent},
generation::{EntityConfig, EntityInfo},
link::Is,
mounting::Rider,
mounting::{Rider, Volume, VolumeRider},
npc::{self, get_npc_name},
outcome::Outcome,
parse_cmd_args,
@ -1817,16 +1817,33 @@ fn handle_spawn_ship(
.state
.read_component_cloned::<Is<Rider>>(target)
.map(|is_rider| is_rider.mount)
.or_else(|| {
server
.state
.read_component_cloned::<Is<VolumeRider>>(target)
.and_then(|is_volume_rider| {
if let Volume::Entity(uid) = is_volume_rider.pos.kind {
Some(uid)
} else {
None
}
})
})
.or_else(|| server.state.ecs().uid_from_entity(target));
let tether_follower = server.state.ecs().uid_from_entity(new_entity);
if let (Some(leader), Some(follower)) = (tether_leader, tether_follower) {
let tether_length = tether_leader
.and_then(|uid| server.state.ecs().entity_from_uid(uid))
.and_then(|e| server.state.read_component_cloned::<comp::Body>(e))
.map(|b| b.dimensions().z * 2.0 + 0.5)
.unwrap_or(6.0);
server
.state
.link(Tethered {
leader,
follower,
tether_length: 6.0,
tether_length,
})
.map_err(|_| "Failed to tether entities")?;
} else {

View File

@ -9,11 +9,11 @@ pub mod lod_terrain;
pub mod particle;
pub mod postprocess;
pub mod rain_occlusion;
pub mod rope;
pub mod shadow;
pub mod skybox;
pub mod sprite;
pub mod terrain;
pub mod tether;
pub mod trail;
pub mod ui;

View File

@ -8,15 +8,15 @@ use vek::*;
pub struct Locals {
pos_a: [f32; 4],
pos_b: [f32; 4],
tether_length: f32,
rope_length: f32,
}
impl Locals {
pub fn new(pos_a: Vec3<f32>, pos_b: Vec3<f32>, tether_length: f32) -> Self {
pub fn new(pos_a: Vec3<f32>, pos_b: Vec3<f32>, rope_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,
rope_length,
}
}
}
@ -58,11 +58,11 @@ impl VertexTrait for Vertex {
const STRIDE: wgpu::BufferAddress = mem::size_of::<Self>() as wgpu::BufferAddress;
}
pub struct TetherLayout {
pub struct RopeLayout {
pub locals: wgpu::BindGroupLayout,
}
impl TetherLayout {
impl RopeLayout {
pub fn new(device: &wgpu::Device) -> Self {
Self {
locals: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
@ -101,23 +101,23 @@ impl TetherLayout {
}
}
pub struct TetherPipeline {
pub struct RopePipeline {
pub pipeline: wgpu::RenderPipeline,
}
impl TetherPipeline {
impl RopePipeline {
pub fn new(
device: &wgpu::Device,
vs_module: &wgpu::ShaderModule,
fs_module: &wgpu::ShaderModule,
global_layout: &GlobalsLayouts,
layout: &TetherLayout,
layout: &RopeLayout,
aa_mode: AaMode,
) -> Self {
common_base::span!(_guard, "TetherPipeline::new");
common_base::span!(_guard, "RopePipeline::new");
let render_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Tether pipeline layout"),
label: Some("Rope pipeline layout"),
push_constant_ranges: &[],
bind_group_layouts: &[
&global_layout.globals,
@ -129,7 +129,7 @@ impl TetherPipeline {
let samples = aa_mode.samples();
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Tether pipeline"),
label: Some("Rope pipeline"),
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: vs_module,

View File

@ -24,8 +24,8 @@ use super::{
mesh::Mesh,
model::{DynamicModel, Model},
pipelines::{
blit, bloom, clouds, debug, figure, postprocess, rain_occlusion, shadow, sprite, terrain,
tether, ui, GlobalsBindGroup, GlobalsLayouts, ShadowTexturesBindGroup,
blit, bloom, clouds, debug, figure, postprocess, rain_occlusion, rope, shadow, sprite,
terrain, ui, GlobalsBindGroup, GlobalsLayouts, ShadowTexturesBindGroup,
},
texture::Texture,
AddressMode, FilterMode, OtherModes, PipelineModes, RenderError, RenderMode, ShadowMapMode,
@ -54,7 +54,7 @@ struct ImmutableLayouts {
rain_occlusion: rain_occlusion::RainOcclusionLayout,
sprite: sprite::SpriteLayout,
terrain: terrain::TerrainLayout,
tether: tether::TetherLayout,
rope: rope::RopeLayout,
clouds: clouds::CloudsLayout,
bloom: bloom::BloomLayout,
ui: ui::UiLayout,
@ -384,7 +384,7 @@ impl Renderer {
let rain_occlusion = rain_occlusion::RainOcclusionLayout::new(&device);
let sprite = sprite::SpriteLayout::new(&device);
let terrain = terrain::TerrainLayout::new(&device);
let tether = tether::TetherLayout::new(&device);
let rope = rope::RopeLayout::new(&device);
let clouds = clouds::CloudsLayout::new(&device);
let bloom = bloom::BloomLayout::new(&device);
let postprocess = Arc::new(postprocess::PostProcessLayout::new(
@ -404,7 +404,7 @@ impl Renderer {
rain_occlusion,
sprite,
terrain,
tether,
rope,
clouds,
bloom,
ui,

View File

@ -3,7 +3,7 @@ use crate::render::pipelines::rain_occlusion;
use super::{
super::{
pipelines::{
debug, figure, lod_terrain, shadow, sprite, terrain, tether, ui, AtlasTextures,
debug, figure, lod_terrain, rope, shadow, sprite, terrain, ui, AtlasTextures,
FigureSpriteAtlasData, GlobalModel, GlobalsBindGroup, TerrainAtlasData,
},
texture::Texture,
@ -67,9 +67,9 @@ impl Renderer {
.bind_locals(&self.device, locals, bone_data)
}
pub fn create_tether_bound_locals(&mut self, locals: &[tether::Locals]) -> tether::BoundLocals {
pub fn create_rope_bound_locals(&mut self, locals: &[rope::Locals]) -> rope::BoundLocals {
let locals = self.create_consts(locals);
self.layouts.tether.bind_locals(&self.device, locals)
self.layouts.rope.bind_locals(&self.device, locals)
}
pub fn create_terrain_bound_locals(

View File

@ -6,8 +6,8 @@ use super::{
instances::Instances,
model::{DynamicModel, Model, SubModel},
pipelines::{
blit, bloom, clouds, debug, figure, fluid, lod_object, lod_terrain, particle, shadow,
skybox, sprite, terrain, tether, trail, ui, AtlasTextures, FigureSpriteAtlasData,
blit, bloom, clouds, debug, figure, fluid, lod_object, lod_terrain, particle, rope,
shadow, skybox, sprite, terrain, trail, ui, AtlasTextures, FigureSpriteAtlasData,
GlobalsBindGroup, TerrainAtlasData,
},
AltIndices, CullingMode,
@ -966,13 +966,13 @@ impl<'pass> FirstPassDrawer<'pass> {
ParticleDrawer { render_pass }
}
pub fn draw_tethers(&mut self) -> TetherDrawer<'_, 'pass> {
let mut render_pass = self.render_pass.scope("tethers", self.borrow.device);
pub fn draw_ropes(&mut self) -> RopeDrawer<'_, 'pass> {
let mut render_pass = self.render_pass.scope("ropes", self.borrow.device);
render_pass.set_pipeline(&self.pipelines.tether.pipeline);
set_quad_index_buffer::<tether::Vertex>(&mut render_pass, self.borrow);
render_pass.set_pipeline(&self.pipelines.rope.pipeline);
set_quad_index_buffer::<rope::Vertex>(&mut render_pass, self.borrow);
TetherDrawer { render_pass }
RopeDrawer { render_pass }
}
pub fn draw_sprites<'data: 'pass>(
@ -1121,17 +1121,17 @@ impl<'pass_ref, 'pass: 'pass_ref> ParticleDrawer<'pass_ref, 'pass> {
}
#[must_use]
pub struct TetherDrawer<'pass_ref, 'pass: 'pass_ref> {
pub struct RopeDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
}
impl<'pass_ref, 'pass: 'pass_ref> TetherDrawer<'pass_ref, 'pass> {
impl<'pass_ref, 'pass: 'pass_ref> RopeDrawer<'pass_ref, 'pass> {
// Note: if we ever need to draw less than the whole model, these APIs can be
// changed
pub fn draw<'data: 'pass>(
&mut self,
model: &'data Model<tether::Vertex>,
locals: &'data tether::BoundLocals,
model: &'data Model<rope::Vertex>,
locals: &'data rope::BoundLocals,
) {
self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
self.render_pass.set_bind_group(2, &locals.bind_group, &[]);

View File

@ -4,7 +4,7 @@ use super::{
super::{
pipelines::{
blit, bloom, clouds, debug, figure, fluid, lod_object, lod_terrain, particle,
postprocess, shadow, skybox, sprite, terrain, tether, trail, ui,
postprocess, rope, shadow, skybox, sprite, terrain, trail, ui,
},
AaMode, BloomMode, CloudMode, FluidMode, LightingMode, PipelineModes, ReflectionMode,
RenderError, ShadowMode,
@ -23,7 +23,7 @@ pub struct Pipelines {
pub fluid: fluid::FluidPipeline,
pub lod_terrain: lod_terrain::LodTerrainPipeline,
pub particle: particle::ParticlePipeline,
pub tether: tether::TetherPipeline,
pub rope: rope::RopePipeline,
pub trail: trail::TrailPipeline,
pub clouds: clouds::CloudsPipeline,
pub bloom: Option<bloom::BloomPipelines>,
@ -47,7 +47,7 @@ pub struct IngamePipelines {
fluid: fluid::FluidPipeline,
lod_terrain: lod_terrain::LodTerrainPipeline,
particle: particle::ParticlePipeline,
tether: tether::TetherPipeline,
rope: rope::RopePipeline,
trail: trail::TrailPipeline,
clouds: clouds::CloudsPipeline,
pub bloom: Option<bloom::BloomPipelines>,
@ -95,7 +95,7 @@ impl Pipelines {
fluid: ingame.fluid,
lod_terrain: ingame.lod_terrain,
particle: ingame.particle,
tether: ingame.tether,
rope: ingame.rope,
trail: ingame.trail,
clouds: ingame.clouds,
bloom: ingame.bloom,
@ -130,8 +130,8 @@ struct ShaderModules {
lod_object_frag: wgpu::ShaderModule,
particle_vert: wgpu::ShaderModule,
particle_frag: wgpu::ShaderModule,
tether_vert: wgpu::ShaderModule,
tether_frag: wgpu::ShaderModule,
rope_vert: wgpu::ShaderModule,
rope_frag: wgpu::ShaderModule,
trail_vert: wgpu::ShaderModule,
trail_frag: wgpu::ShaderModule,
ui_vert: wgpu::ShaderModule,
@ -344,8 +344,8 @@ impl ShaderModules {
lod_object_frag: create_shader("lod-object-frag", ShaderKind::Fragment)?,
particle_vert: create_shader("particle-vert", ShaderKind::Vertex)?,
particle_frag: create_shader("particle-frag", ShaderKind::Fragment)?,
tether_vert: create_shader("tether-vert", ShaderKind::Vertex)?,
tether_frag: create_shader("tether-frag", ShaderKind::Fragment)?,
rope_vert: create_shader("rope-vert", ShaderKind::Vertex)?,
rope_frag: create_shader("rope-frag", ShaderKind::Fragment)?,
trail_vert: create_shader("trail-vert", ShaderKind::Vertex)?,
trail_frag: create_shader("trail-frag", ShaderKind::Fragment)?,
ui_vert: create_shader("ui-vert", ShaderKind::Vertex)?,
@ -528,7 +528,7 @@ fn create_ingame_and_shadow_pipelines(
sprite_task,
lod_object_task,
particle_task,
tether_task,
rope_task,
trail_task,
lod_terrain_task,
clouds_task,
@ -673,20 +673,20 @@ fn create_ingame_and_shadow_pipelines(
"particle pipeline creation",
)
};
// Pipeline for rendering tethers
let create_tether = || {
tether_task.run(
// Pipeline for rendering ropes
let create_rope = || {
rope_task.run(
|| {
tether::TetherPipeline::new(
rope::RopePipeline::new(
device,
&shaders.tether_vert,
&shaders.tether_frag,
&shaders.rope_vert,
&shaders.rope_frag,
&layouts.global,
&layouts.tether,
&layouts.rope,
pipeline_modes.aa,
)
},
"tether pipeline creation",
"rope pipeline creation",
)
};
// Pipeline for rendering weapon trails
@ -912,7 +912,7 @@ fn create_ingame_and_shadow_pipelines(
)
})
};
let j8 = create_tether;
let j8 = create_rope;
// Ignore this
let (
@ -925,10 +925,7 @@ fn create_ingame_and_shadow_pipelines(
(postprocess, point_shadow),
(terrain_directed_shadow, (figure_directed_shadow, debug_directed_shadow)),
),
(
(lod_object, (terrain_directed_rain_occlusion, figure_directed_rain_occlusion)),
tether,
),
((lod_object, (terrain_directed_rain_occlusion, figure_directed_rain_occlusion)), rope),
),
) = pool.join(
|| pool.join(|| pool.join(j1, j2), || pool.join(j3, j4)),
@ -942,7 +939,7 @@ fn create_ingame_and_shadow_pipelines(
fluid,
lod_terrain,
particle,
tether,
rope,
trail,
clouds,
bloom,

View File

@ -59,8 +59,8 @@ impl assets::Compound for Shaders {
"debug-vert",
"debug-frag",
"figure-frag",
"tether-vert",
"tether-frag",
"rope-vert",
"rope-frag",
"terrain-vert",
"terrain-frag",
"fluid-vert",

View File

@ -1,5 +1,5 @@
use crate::render::{
pipelines::tether::{BoundLocals, Locals, Vertex},
pipelines::rope::{BoundLocals, Locals, Vertex},
FirstPassDrawer, Mesh, Model, Quad, Renderer,
};
use client::Client;
@ -15,6 +15,20 @@ use vek::*;
pub struct TetherMgr {
model: Model<Vertex>,
/// Used to garbage-collect tethers that no longer exist.
///
/// Because a tether is not an entity, but instead a relationship between
/// two entities, there is no single 'event' that we can listen to in
/// order to determine that a tether has been broken. Instead, every tick,
/// we go through the set of tethers that we observe in the world and
/// mark their entries in the `tethers` map below with a flag.
/// At the end of the tick, every unmarked tether in the `tethers` map below
/// can be deleted.
///
/// Every tick, the 'alive' state of the flag flips between `true` and
/// `false` to avoid the need to wastefully reset the flag of every
/// alive tether on each tick (this is a common optimisation in some garbage
/// collection algoruthms too).
stale_flag: bool,
tethers: HashMap<(Uid, Uid), (BoundLocals, bool)>,
}
@ -61,7 +75,7 @@ impl TetherMgr {
.entry((is_follower.leader, is_follower.follower))
.or_insert_with(|| {
(
renderer.create_tether_bound_locals(&[Locals::default()]),
renderer.create_rope_bound_locals(&[Locals::default()]),
self.stale_flag,
)
});
@ -81,9 +95,9 @@ impl TetherMgr {
}
pub fn render<'a>(&'a self, drawer: &mut FirstPassDrawer<'a>) {
let mut tether_drawer = drawer.draw_tethers();
let mut rope_drawer = drawer.draw_ropes();
for (locals, _) in self.tethers.values() {
tether_drawer.draw(&self.model, locals);
rope_drawer.draw(&self.model, locals);
}
}
}