Account for model translation in the physics. The voxel collider still needs to be north-aligned for now.

This commit is contained in:
Avi Weinstock 2021-03-11 23:42:53 -05:00
parent a70e569396
commit d98efb391b
6 changed files with 90 additions and 41 deletions

View File

@ -1,18 +1,23 @@
({
DefaultAirship: (
bone0: (
//offset: (-20.0, -35.0, 1.0),
//offset: (3.0, 7.0, 1.0),
offset: (0.25, 0.25, 0.25),
central: ("object.Human_Airship"),
//offset: (-20.75, -34.75, 1.25),
//offset: (0.0, 0.0, 0.0),
offset: (-20.0, -35.0, 1.0),
//phys_offset: (0.25, 0.25, 0.25),
phys_offset: (0.0, 0.0, 0.0),
central: ("Human_Airship"),
),
bone1: (
offset: (0.0, 40.0, -8.0),
central: ("object.propeller-l"),
phys_offset: (0.0, 0.0, 0.0),
central: ("propeller-l"),
),
bone2: (
offset: (0.0, 0.0, -4.0),
central: ("object.propeller-r"),
phys_offset: (0.0, 0.0, 0.0),
central: ("propeller-r"),
),
),
})

View File

@ -17,7 +17,7 @@ impl From<Body> for super::Body {
impl Body {
pub fn manifest_entry(&self) -> &'static str {
match self {
Body::DefaultAirship => "object.Human_Airship",
Body::DefaultAirship => "Human_Airship",
}
}
}
@ -38,6 +38,7 @@ pub mod figuredata {
use hashbrown::HashMap;
use lazy_static::lazy_static;
use serde::Deserialize;
use vek::Vec3;
#[derive(Deserialize)]
pub struct VoxSimple(pub String);
@ -55,6 +56,7 @@ pub mod figuredata {
#[derive(Deserialize)]
pub struct ShipCentralSubSpec {
pub offset: [f32; 3],
pub phys_offset: [f32; 3],
pub central: VoxSimple,
}
@ -62,7 +64,13 @@ pub mod figuredata {
#[derive(Clone)]
pub struct ShipSpec {
pub central: AssetHandle<Ron<ShipCentralSpec>>,
pub voxes: HashMap<String, Dyna<Block, (), ColumnAccess>>,
pub colliders: HashMap<String, VoxelCollider>,
}
#[derive(Clone)]
pub struct VoxelCollider {
pub dyna: Dyna<Block, (), ColumnAccess>,
pub translation: Vec3<f32>,
}
impl assets::Compound for ShipSpec {
@ -71,26 +79,31 @@ pub mod figuredata {
_: &str,
) -> Result<Self, assets::Error> {
let manifest: AssetHandle<Ron<ShipCentralSpec>> = AssetExt::load("server.manifests.ship_manifest")?;
let mut voxes = HashMap::new();
let mut colliders = HashMap::new();
for (_, spec) in (manifest.read().0).0.iter() {
for bone in [&spec.bone0, &spec.bone1, &spec.bone2].iter() {
// TODO: avoid the requirement for symlinks in "voxygen.voxel.object.", and load
// the models from "server.voxel." instead
let vox =
cache.load::<DotVoxAsset>(&["voxygen.voxel.", &bone.central.0].concat())?;
cache.load::<DotVoxAsset>(&["server.voxel.", &bone.central.0].concat())?;
let dyna = Dyna::<Cell, (), ColumnAccess>::from_vox(&vox.read().0, false);
voxes.insert(bone.central.0.clone(), dyna.map_into(|cell| {
let dyna = dyna.map_into(|cell| {
if let Some(rgb) = cell.get_color() {
Block::new(BlockKind::Misc, rgb)
} else {
Block::air(SpriteKind::Empty)
}
}));
});
let collider = VoxelCollider {
dyna,
translation: Vec3::from(bone.offset) + Vec3::from(bone.phys_offset),
};
colliders.insert(bone.central.0.clone(), collider);
}
}
Ok(ShipSpec {
central: manifest,
voxes,
colliders,
})
}
}
@ -99,6 +112,6 @@ pub mod figuredata {
// TODO: load this from the ECS as a resource, and maybe make it more general than ships
// (although figuring out how to keep the figure bones in sync with the terrain offsets seems
// like a hard problem if they're not the same manifest)
pub static ref VOXEL_COLLIDER_MANIFEST: ShipSpec = AssetExt::load_expect_cloned("server.manifests.ship_manifest");
pub static ref VOXEL_COLLIDER_MANIFEST: AssetHandle<ShipSpec> = AssetExt::load_expect("server.manifests.ship_manifest");
}
}

View File

@ -9,7 +9,7 @@ use vek::{Quaternion, Vec2, Vec3};
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(into = "SerdeOri")]
#[serde(from = "SerdeOri")]
pub struct Ori(Quaternion<f32>);
pub struct Ori(pub Quaternion<f32>);
impl Default for Ori {
/// Returns the default orientation (no rotation; default Dir)

View File

@ -364,7 +364,7 @@ impl<'a> PhysicsSystemData<'a> {
} = self;
// Apply movement inputs
span!(guard, "Apply movement and terrain collision");
let (positions, previous_phys_cache) = (&psdw.positions, &psdw.previous_phys_cache);
let (positions, previous_phys_cache, orientations) = (&psdw.positions, &psdw.previous_phys_cache, &psdw.orientations);
let (pos_writes, land_on_grounds) = (
&psdr.entities,
psdr.scales.maybe(),
@ -372,7 +372,7 @@ impl<'a> PhysicsSystemData<'a> {
&psdr.colliders,
positions,
&mut psdw.velocities,
&psdw.orientations,
orientations,
&mut psdw.physics_states,
previous_phys_cache,
!&psdr.mountings,
@ -548,6 +548,7 @@ impl<'a> PhysicsSystemData<'a> {
previous_cache_other,
mass_other,
collider_other,
ori_other,
_,
_,
_,
@ -560,6 +561,7 @@ impl<'a> PhysicsSystemData<'a> {
previous_phys_cache,
psdr.masses.maybe(),
&psdr.colliders,
orientations,
!&psdr.projectiles,
!&psdr.mountings,
!&psdr.beams,
@ -574,10 +576,12 @@ impl<'a> PhysicsSystemData<'a> {
.center
.distance_squared(previous_cache_other.center)
> collision_boundary.powi(2)
|| entity == entity_other
{
continue;
}*/
if entity == entity_other {
continue;
}
if let Collider::Voxel { id } = collider_other {
// use bounding cylinder regardless of our collider
@ -589,13 +593,31 @@ impl<'a> PhysicsSystemData<'a> {
let z_min = z_min * scale;
let z_max = z_max.clamped(1.2, 1.95) * scale;
let mut physics_state_delta = physics_state.clone();
pos.0 -= pos_other.0;
let cylinder = (radius, z_min, z_max);
if let Some(dyna) = VOXEL_COLLIDER_MANIFEST.voxes.get(id) {
if let Some(voxel_collider) = VOXEL_COLLIDER_MANIFEST.read().colliders.get(id) {
let mut physics_state_delta = physics_state.clone();
//let ori_2d = ori_other.look_dir().xy();
//let ori_2d_quat = Quaternion::rotation_z(ori_2d.y.atan2(ori_2d.x));
//let ori_2d_quat = Quaternion::from_xyzw(ori_2d.x, ori_2d.y, 0.0, 1.0).normalized();
// deliberately don't use scale yet here, because the 11.0/0.8
// thing is in the comp::Scale for visual reasons
let t1 = Mat4::from(Transform {
position: pos_other.0 + voxel_collider.translation,
orientation: Quaternion::identity(),
scale: Vec3::broadcast(1.0),
});
let t2 = Mat4::from(Transform {
position: Vec3::zero(),
orientation: ori_other.0.normalized(),
scale: Vec3::broadcast(1.0),
});
//let transform = t2 * t1;
let transform = t1;
pos.0 = transform.inverted().mul_point(pos.0);
//vel.0 = t2.inverted().mul_point(pos.0);
let cylinder = (radius, z_min, z_max);
cylinder_voxel_collision(
cylinder,
&*dyna,
&voxel_collider.dyna,
entity,
&mut pos,
pos_delta,
@ -603,24 +625,27 @@ impl<'a> PhysicsSystemData<'a> {
&mut physics_state_delta,
&mut land_on_grounds,
);
pos.0 = transform.mul_point(pos.0);
//vel.0 = t2.mul_point(vel.0);
// union in the state updates, so that the state isn't just based on
// the most recent terrain that collision was attempted with
physics_state.on_ground |= physics_state_delta.on_ground;
physics_state.on_ceiling |= physics_state_delta.on_ceiling;
physics_state.on_wall =
physics_state.on_wall.or(physics_state_delta.on_wall);
physics_state
.touch_entities
.append(&mut physics_state_delta.touch_entities);
physics_state.in_liquid =
match (physics_state.in_liquid, physics_state_delta.in_liquid) {
// this match computes `x <|> y <|> liftA2 max x y`
(Some(x), Some(y)) => Some(x.max(y)),
(_, y @ Some(_)) => y,
_ => None,
};
}
pos.0 += pos_other.0;
// union in the state updates, so that the state isn't just based on
// the most recent terrain that collision was attempted with
physics_state.on_ground |= physics_state_delta.on_ground;
physics_state.on_ceiling |= physics_state_delta.on_ceiling;
physics_state.on_wall =
physics_state.on_wall.or(physics_state_delta.on_wall);
physics_state
.touch_entities
.append(&mut physics_state_delta.touch_entities);
physics_state.in_liquid =
match (physics_state.in_liquid, physics_state_delta.in_liquid) {
// this match computes `x <|> y <|> liftA2 max x y`
(Some(x), Some(y)) => Some(x.max(y)),
(_, y @ Some(_)) => y,
_ => None,
};
}
}
if pos != old_pos {

View File

@ -1972,7 +1972,7 @@ fn create_pipelines(
&shaders.figure_vert.read().0,
&shaders.figure_frag.read().0,
&include_ctx,
gfx::state::CullFace::Nothing,
gfx::state::CullFace::Back,
)?;
// Construct a pipeline for rendering terrain

View File

@ -35,6 +35,9 @@ fn load_segment(mesh_name: &str) -> Segment {
}
fn graceful_load_vox(mesh_name: &str) -> AssetHandle<DotVoxAsset> {
let full_specifier: String = ["voxygen.voxel.", mesh_name].concat();
graceful_load_vox_fullspec(&full_specifier)
}
fn graceful_load_vox_fullspec(full_specifier: &str) -> AssetHandle<DotVoxAsset> {
match DotVoxAsset::load(&full_specifier) {
Ok(dot_vox) => dot_vox,
Err(_) => {
@ -46,6 +49,9 @@ fn graceful_load_vox(mesh_name: &str) -> AssetHandle<DotVoxAsset> {
fn graceful_load_segment(mesh_name: &str) -> Segment {
Segment::from(&graceful_load_vox(mesh_name).read().0)
}
fn graceful_load_segment_fullspec(full_specifier: &str) -> Segment {
Segment::from(&graceful_load_vox_fullspec(full_specifier).read().0)
}
fn graceful_load_segment_flipped(mesh_name: &str, flipped: bool) -> Segment {
Segment::from_vox(&graceful_load_vox(mesh_name).read().0, flipped)
}
@ -4241,7 +4247,7 @@ fn mesh_ship_bone<K: fmt::Debug+Eq+Hash, V, F: Fn(&V) -> &ShipCentralSubSpec>(ma
},
};
let bone = f(spec);
let central = graceful_load_segment(&bone.central.0);
let central = graceful_load_segment_fullspec(&["server.voxel.", &bone.central.0].concat());
(central, Vec3::from(bone.offset))
}